diff --git a/0.22.0rc4/_images/clipped.png b/0.22.0rc4/_images/clipped.png new file mode 100644 index 000000000..47a842de8 Binary files /dev/null and b/0.22.0rc4/_images/clipped.png differ diff --git a/0.22.0rc4/_images/ec60to30_tris_flat.png b/0.22.0rc4/_images/ec60to30_tris_flat.png new file mode 100644 index 000000000..520282c3d Binary files /dev/null and b/0.22.0rc4/_images/ec60to30_tris_flat.png differ diff --git a/0.22.0rc4/_images/ec60to30_tris_gouraud.png b/0.22.0rc4/_images/ec60to30_tris_gouraud.png new file mode 100644 index 000000000..a841360a3 Binary files /dev/null and b/0.22.0rc4/_images/ec60to30_tris_gouraud.png differ diff --git a/0.22.0rc4/_images/qu240_topo.png b/0.22.0rc4/_images/qu240_topo.png new file mode 100644 index 000000000..695b31c3e Binary files /dev/null and b/0.22.0rc4/_images/qu240_topo.png differ diff --git a/0.22.0rc4/_images/qu240_topo_lonlat.png b/0.22.0rc4/_images/qu240_topo_lonlat.png new file mode 100644 index 000000000..12ae011e0 Binary files /dev/null and b/0.22.0rc4/_images/qu240_topo_lonlat.png differ diff --git a/0.22.0rc4/_images/ragged.png b/0.22.0rc4/_images/ragged.png new file mode 100644 index 000000000..728a6a1fe Binary files /dev/null and b/0.22.0rc4/_images/ragged.png differ diff --git a/0.22.0rc4/_images/so60to10.png b/0.22.0rc4/_images/so60to10.png new file mode 100644 index 000000000..c1d33fbf6 Binary files /dev/null and b/0.22.0rc4/_images/so60to10.png differ diff --git a/0.22.0rc4/_images/so60to12_res.png b/0.22.0rc4/_images/so60to12_res.png new file mode 100644 index 000000000..a573666ce Binary files /dev/null and b/0.22.0rc4/_images/so60to12_res.png differ diff --git a/0.22.0rc4/_images/so_cropped.png b/0.22.0rc4/_images/so_cropped.png new file mode 100644 index 000000000..283c03527 Binary files /dev/null and b/0.22.0rc4/_images/so_cropped.png differ diff --git a/0.22.0rc4/_images/south_atlantic_temperature_transect.png b/0.22.0rc4/_images/south_atlantic_temperature_transect.png new file mode 100644 index 000000000..3c1835d3d Binary files /dev/null and b/0.22.0rc4/_images/south_atlantic_temperature_transect.png differ diff --git a/0.22.0rc4/_modules/index.html b/0.22.0rc4/_modules/index.html new file mode 100644 index 000000000..f323b2bbd --- /dev/null +++ b/0.22.0rc4/_modules/index.html @@ -0,0 +1,182 @@ + + + + + + Overview: module code — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/config.html b/0.22.0rc4/_modules/mpas_tools/config.html new file mode 100644 index 000000000..ef41f595f --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/config.html @@ -0,0 +1,677 @@ + + + + + + mpas_tools.config — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.config

+from configparser import RawConfigParser, ConfigParser, ExtendedInterpolation
+import os
+import inspect
+import sys
+import numpy as np
+import ast
+from io import StringIO
+try:
+    from importlib.resources import files as imp_res_files
+except ImportError:
+    # python<=3.8
+    from importlib_resources import files as imp_res_files
+
+
+
[docs]class MpasConfigParser: + """ + A "meta" config parser that keeps a dictionary of config parsers and their + sources to combine when needed. The custom config parser allows provenance + of the source of different config options and allows the "user" config + options to always take precedence over other config options (even if they + are added later). + + Attributes + ---------- + combined : {None, configparser.ConfigParser} + The combined config options + + combined_comments : {None, dict} + The combined comments associated with sections and options + + sources : {None, dict} + The source of each section or option + """ + + _np_allowed = dict(linspace=np.linspace, xrange=range, + range=range, array=np.array, arange=np.arange, + pi=np.pi, Pi=np.pi, int=int, __builtins__=None) + +
[docs] def __init__(self): + """ + Make a new (empty) config parser + """ + + self._configs = dict() + self._user_config = dict() + self._comments = dict() + self.combined = None + self.combined_comments = None + self.sources = None
+ +
[docs] def add_user_config(self, filename): + """ + Add a the contents of a user config file to the parser. These options + take precedence over all other options. + + Parameters + ---------- + filename : str + The relative or absolute path to the config file + """ + self._add(filename, user=True)
+ +
[docs] def add_from_file(self, filename): + """ + Add the contents of a config file to the parser. + + Parameters + ---------- + filename : str + The relative or absolute path to the config file + """ + self._add(filename, user=False)
+ +
[docs] def add_from_package(self, package, config_filename, exception=True): + """ + Add the contents of a config file to the parser. + + Parameters + ---------- + package : str or Package + The package where ``config_filename`` is found + + config_filename : str + The name of the config file to add + + exception : bool, optional + Whether to raise an exception if the config file isn't found + """ + try: + path = imp_res_files(package) / config_filename + self._add(path, user=False) + except (ModuleNotFoundError, FileNotFoundError, TypeError): + if exception: + raise
+ +
[docs] def get(self, section, option): + """ + Get an option value for a given section. + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + Returns + ------- + value : str + The value of the config option + """ + if self.combined is None: + self.combine() + return self.combined.get(section, option)
+ +
[docs] def getint(self, section, option): + """ + Get an option integer value for a given section. + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + Returns + ------- + value : int + The value of the config option + """ + if self.combined is None: + self.combine() + return self.combined.getint(section, option)
+ +
[docs] def getfloat(self, section, option): + """ + Get an option float value for a given section. + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + Returns + ------- + value : float + The value of the config option + """ + if self.combined is None: + self.combine() + return self.combined.getfloat(section, option)
+ +
[docs] def getboolean(self, section, option): + """ + Get an option boolean value for a given section. + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + Returns + ------- + value : bool + The value of the config option + """ + if self.combined is None: + self.combine() + return self.combined.getboolean(section, option)
+ +
[docs] def getlist(self, section, option, dtype=str): + """ + Get an option value as a list for a given section. + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + dtype : {Type[str], Type[int], Type[float]} + The type of the elements in the list + + Returns + ------- + value : list + The value of the config option parsed into a list + """ + values = self.get(section, option) + values = [dtype(value) for value in values.replace(',', ' ').split()] + return values
+ +
[docs] def getexpression(self, section, option, dtype=None, use_numpyfunc=False): + """ + Get an option as an expression (typically a list, though tuples and + dicts are also available). The expression is required to have valid + python syntax, so that string entries are required to be in single or + double quotes. + + Parameters + ---------- + section : str + The section in the config file + + option : str + The option in the config file + + dtype : {Type[bool], Type[int], Type[float], Type[list], Type[tuple], Type[str]}, optional + If supplied, each element in a list or tuple, or + each value in a dictionary are cast to this type. This is likely + most useful for ensuring that all elements in a list of numbers are + of type float, rather than int, when the distinction is important. + + use_numpyfunc : bool, optional + If ``True``, the expression is evaluated including functionality + from the numpy package (which can be referenced either as ``numpy`` + or ``np``). + """ + + expression_string = self.get(section, option) + if use_numpyfunc: + assert '__' not in expression_string, \ + f'"__" is not allowed in {expression_string} ' \ + f'for use_numpyfunc=True' + sanitized_str = expression_string.replace('np.', '') \ + .replace('numpy.', '') + result = eval(sanitized_str, MpasConfigParser._np_allowed) + else: + result = ast.literal_eval(expression_string) + + if dtype is not None: + if isinstance(result, list): + result = [dtype(element) for element in result] + elif isinstance(result, tuple): + result = (dtype(element) for element in result) + elif isinstance(result, dict): + for key in result: + result[key] = dtype(result[key]) + + return result
+ +
[docs] def has_section(self, section): + """ + Whether the given section is part of the config + + Parameters + ---------- + section : str + The name of the config section + + Returns + ------- + found : bool + Whether the option was found in the section + """ + if self.combined is None: + self.combine() + return self.combined.has_section(section)
+ +
[docs] def has_option(self, section, option): + """ + Whether the given section has the given option + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + Returns + ------- + found : bool + Whether the option was found in the section + """ + if self.combined is None: + self.combine() + return self.combined.has_option(section, option)
+ +
[docs] def set(self, section, option, value=None, comment=None, user=False): + """ + Set the value of the given option in the given section. The file from + which this function was called is also retained for provenance. + + Parameters + ---------- + section : str + The name of the config section + + option : str + The name of the config option + + value : str, optional + The value to set the option to + + comment : str, optional + A comment to include with the config option when it is written + to a file + + user : bool, optional + Whether this config option was supplied by the user (e.g. through + a command-line flag) and should take priority over other sources + """ + option = option.lower() + calling_frame = inspect.stack(context=2)[1] + filename = os.path.abspath(calling_frame.filename) + + if user: + config_dict = self._user_config + else: + config_dict = self._configs + if filename not in config_dict: + config_dict[filename] = RawConfigParser() + config = config_dict[filename] + if not config.has_section(section): + config.add_section(section) + config.set(section, option, value) + self.combined = None + self.combined_comments = None + self.sources = None + if filename not in self._comments: + self._comments[filename] = dict() + if comment is None: + comment = '' + else: + comment = ''.join([f'# {line}\n' for line in comment.split('\n')]) + self._comments[filename][(section, option)] = comment
+ +
[docs] def write(self, fp, include_sources=True, include_comments=True): + """ + Write the config options to the given file pointer. + + Parameters + ---------- + fp : typing.TestIO + The file pointer to write to. + + include_sources : bool, optional + Whether to include a comment above each option indicating the + source file where it was defined + + include_comments : bool, optional + Whether to include the original comments associated with each + section or option + """ + if self.combined is None: + self.combine() + for section in self.combined.sections(): + section_items = self.combined.items(section=section) + if include_comments and section in self.combined_comments: + fp.write(self.combined_comments[section]) + fp.write(f'[{section}]\n\n') + for option, value in section_items: + if include_comments: + fp.write(self.combined_comments[(section, option)]) + if include_sources: + source = self.sources[(section, option)] + fp.write(f'# source: {source}\n') + value = str(value).replace('\n', '\n\t').replace('$', '$$') + fp.write(f'{option} = {value}\n\n') + fp.write('\n')
+ + def list_files(self): + """ + Get a list of files contributing to the combined config options + + Returns + ------- + filenames : list of str + A list of file paths + + """ + filenames = list(self._configs.keys()) + list(self._user_config.keys()) + return filenames + +
[docs] def copy(self): + """ + Get a deep copy of the config parser + + Returns + ------- + config_copy : mpas_tools.config.MpasConfigParser + The deep copy + """ + config_copy = MpasConfigParser() + for filename, config in self._configs.items(): + config_copy._configs[filename] = MpasConfigParser._deepcopy(config) + + for filename, config in self._user_config.items(): + config_copy._user_config[filename] = \ + MpasConfigParser._deepcopy(config) + + config_copy._comments = dict(self._comments) + return config_copy
+ +
[docs] def __getitem__(self, section): + """ + Get get the config options for a given section. + + Parameters + ---------- + section : str + The name of the section to retrieve. + + Returns + ------- + section_proxy : configparser.SectionProxy + The config options for the given section. + """ + if self.combined is None: + self.combine() + return self.combined[section]
+ + def _add(self, filename, user): + filename = os.path.abspath(filename) + config = RawConfigParser() + if not os.path.exists(filename): + raise FileNotFoundError(f'Config file does not exist: {filename}') + config.read(filenames=filename) + with open(filename) as fp: + comments = self._parse_comments(fp, filename, comments_before=True) + + if user: + self._user_config[filename] = config + else: + self._configs[filename] = config + self._comments[filename] = comments + self.combined = None + self.combined_comments = None + self.sources = None + + def combine(self): + """ + Combine the config files into one. This is normally handled + automatically. + """ + self.combined = ConfigParser(interpolation=ExtendedInterpolation()) + self.sources = dict() + self.combined_comments = dict() + for configs in [self._configs, self._user_config]: + for source, config in configs.items(): + for section in config.sections(): + if section in self._comments[source]: + self.combined_comments[section] = \ + self._comments[source][section] + if not self.combined.has_section(section): + self.combined.add_section(section) + for option, value in config.items(section): + self.sources[(section, option)] = source + self.combined.set(section, option, value) + self.combined_comments[(section, option)] = \ + self._comments[source][(section, option)] + + @staticmethod + def _parse_comments(fp, filename, comments_before=True): + """ Parse the comments in a config file into a dictionary """ + comments = dict() + current_comment = '' + section_name = None + option_name = None + indent_level = 0 + for line_number, line in enumerate(fp, start=1): + value = line.strip() + is_comment = value.startswith('#') + if is_comment: + current_comment = current_comment + line + if len(value) == 0 or is_comment: + # end of value + indent_level = sys.maxsize + continue + + cur_indent_level = len(line) - len(line.lstrip()) + is_continuation = cur_indent_level > indent_level + # a section header or option header? + if section_name is None or option_name is None or \ + not is_continuation: + indent_level = cur_indent_level + # is it a section header? + is_section = value.startswith('[') and value.endswith(']') + if is_section: + if not comments_before: + if option_name is None: + comments[section_name] = current_comment + else: + comments[(section_name, option_name)] = \ + current_comment + section_name = value[1:-1].strip() + option_name = None + + if comments_before: + comments[section_name] = current_comment + current_comment = '' + # an option line? + else: + delimiter_index = value.find('=') + if delimiter_index == -1: + raise ValueError(f'Expected to find "=" on line ' + f'{line_number} of {filename}') + + if not comments_before: + if option_name is None: + comments[section_name] = current_comment + else: + comments[(section_name, option_name)] = \ + current_comment + + option_name = value[:delimiter_index].strip().lower() + + if comments_before: + comments[(section_name, option_name)] = current_comment + current_comment = '' + + return comments + + @staticmethod + def _deepcopy(config): + """ Make a deep copy of the ConfigParser object """ + config_string = StringIO() + config.write(config_string) + # We must reset the buffer to make it ready for reading. + config_string.seek(0) + new_config = ConfigParser() + new_config.read_file(config_string) + return new_config
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/io.html b/0.22.0rc4/_modules/mpas_tools/io.html new file mode 100644 index 000000000..92527a310 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/io.html @@ -0,0 +1,245 @@ + + + + + + mpas_tools.io — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.io

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy
+import netCDF4
+from datetime import datetime
+import sys
+
+
+default_format = 'NETCDF3_64BIT'
+default_engine = None
+default_char_dim_name = 'StrLen'
+default_fills = netCDF4.default_fillvals
+
+
+
[docs]def write_netcdf(ds, fileName, fillValues=None, format=None, engine=None, + char_dim_name=None): + """ + Write an xarray.Dataset to a file with NetCDF4 fill values and the given + name of the string dimension. Also adds the time and command-line to the + history attribute. + + Parameters + ---------- + ds : xarray.Dataset + The dataset to save + + fileName : str + The path for the NetCDF file to write + + fillValues : dict, optional + A dictionary of fill values for different NetCDF types. Default is + ``mpas_tools.io.default_fills``, which can be modified but which + defaults to ``netCDF4.default_fillvals`` + + format : {'NETCDF4', 'NETCDF4_CLASSIC', 'NETCDF3_64BIT', + 'NETCDF3_CLASSIC'}, optional + The NetCDF file format to use. Default is + ``mpas_tools.io.default_format``, which can be modified but which + defaults to ``'NETCDF3_64BIT'`` + + engine : {'netcdf4', 'scipy', 'h5netcdf'}, optional + The library to use for NetCDF output. The default is the same as + in :py:meth:`xarray.Dataset.to_netcdf` and depends on ``format``. + You can override the default by setting + ``mpas_tools.io.default_engine`` + + char_dim_name : str, optional + The name of the dimension used for character strings, or None to let + xarray figure this out. Default is + ``mpas_tools.io.default_char_dim_name``, which can be modified but + which defaults to ``'StrLen'` + + """ + if format is None: + format = default_format + + if fillValues is None: + fillValues = default_fills + + if engine is None: + engine = default_engine + + if char_dim_name is None: + char_dim_name = default_char_dim_name + + encodingDict = {} + variableNames = list(ds.data_vars.keys()) + list(ds.coords.keys()) + for variableName in variableNames: + isNumeric = numpy.issubdtype(ds[variableName].dtype, numpy.number) + if isNumeric and numpy.any(numpy.isnan(ds[variableName])): + dtype = ds[variableName].dtype + for fillType in fillValues: + if dtype == numpy.dtype(fillType): + encodingDict[variableName] = \ + {'_FillValue': fillValues[fillType]} + break + else: + encodingDict[variableName] = {'_FillValue': None} + + isString = numpy.issubdtype(ds[variableName].dtype, numpy.string_) + if isString and char_dim_name is not None: + encodingDict[variableName] = {'char_dim_name': char_dim_name} + + update_history(ds) + + if 'Time' in ds.dims: + # make sure the Time dimension is unlimited because MPAS has trouble + # reading Time otherwise + ds.encoding['unlimited_dims'] = {'Time'} + + ds.to_netcdf(fileName, encoding=encodingDict, format=format, engine=engine)
+ + +def update_history(ds): + '''Add or append history to attributes of a data set''' + + thiscommand = datetime.now().strftime("%a %b %d %H:%M:%S %Y") + ": " + \ + " ".join(sys.argv[:]) + if 'history' in ds.attrs: + newhist = '\n'.join([thiscommand, ds.attrs['history']]) + else: + newhist = thiscommand + ds.attrs['history'] = newhist +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/logging.html b/0.22.0rc4/_modules/mpas_tools/logging.html new file mode 100644 index 000000000..d8f6851e7 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/logging.html @@ -0,0 +1,348 @@ + + + + + + mpas_tools.logging — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.logging

+import sys
+import logging
+import subprocess
+
+
+
[docs]def check_call(args, logger=None, log_command=True, timeout=None, **kwargs): + """ + Call the given subprocess with logging to the given logger. + + Parameters + ---------- + args : list or str + A list or string of argument to the subprocess. If ``args`` is a + string, you must pass ``shell=True`` as one of the ``kwargs``. + + logger : logging.Logger, optional + The logger to write output to + + log_command : bool, optional + Whether to write the command that is running ot the logger + + timeout : int, optional + A timeout in seconds for the call + + **kwargs : dict + Keyword arguments to pass to subprocess.Popen + + Raises + ------ + subprocess.CalledProcessError + If the given subprocess exists with nonzero status + + """ + + if isinstance(args, str): + print_args = args + else: + print_args = ' '.join(args) + + # make a logger if there isn't already one + with LoggingContext(print_args, logger=logger) as logger: + if log_command: + logger.info(f'Running: {print_args}') + + process = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, **kwargs) + stdout, stderr = process.communicate(timeout=timeout) + + if stdout: + stdout = stdout.decode('utf-8') + for line in stdout.split('\n'): + logger.info(line) + if stderr: + stderr = stderr.decode('utf-8') + for line in stderr.split('\n'): + logger.error(line) + + if process.returncode != 0: + raise subprocess.CalledProcessError(process.returncode, + print_args)
+ + +
[docs]class LoggingContext(object): + + """ + A context manager for creating a logger or using an existing logger + + Attributes + ---------- + logger : logging.Logger + A logger that sends output to a log file or stdout/stderr + """ + +
[docs] def __init__(self, name, logger=None, log_filename=None): + """ + If ``logger`` is ``None``, create a new logger either to a log file + or stdout/stderr. If ``logger`` is anything else, just set the logger + attribute + + Parameters + ---------- + name : str + A unique name for the logger (e.g. ``__name__`` of the calling + module) + + logger : logging.Logger, optional + An existing logger that sends output to a log file or stdout/stderr + to be used in this context + + log_filename : str, optional + The name of a file where output should be written. If none is + supplied, output goes to stdout/stderr + """ + self.logger = logger + self.name = name + self.log_filename = log_filename + self.handler = None + self.old_stdout = None + self.old_stderr = None + self.existing_logger = logger is not None
+ + def __enter__(self): + if not self.existing_logger: + if self.log_filename is not None: + # redirect output to a log file + logger = logging.getLogger(self.name) + handler = logging.FileHandler(self.log_filename) + else: + logger = logging.getLogger(self.name) + handler = logging.StreamHandler(sys.stdout) + + formatter = MpasFormatter() + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + logger.propagate = False + self.logger = logger + self.handler = handler + + if self.log_filename is not None: + self.old_stdout = sys.stdout + self.old_stderr = sys.stderr + sys.stdout = StreamToLogger(logger, logging.INFO) + sys.stderr = StreamToLogger(logger, logging.ERROR) + return self.logger + + def __exit__(self, exc_type, exc_val, exc_tb): + if not self.existing_logger: + if self.old_stdout is not None: + self.handler.close() + # restore stdout and stderr + sys.stdout = self.old_stdout + sys.stderr = self.old_stderr + + # remove the handlers from the logger (probably only necessary if + # writeLogFile==False) + self.logger.handlers = [] + + self.stdout = self.original_stdout = sys.stdout + self.stderr = self.original_stderr = sys.stderr
+ + +class MpasFormatter(logging.Formatter): + """ + A custom formatter for logging + Modified from: + https://stackoverflow.com/a/8349076/7728169 + https://stackoverflow.com/a/14859558/7728169 + """ + # Authors + # ------- + # Xylar Asay-Davis + + # printing error messages without a prefix because they are sometimes + # errors and sometimes only warnings sent to stderr + dbg_fmt = "DEBUG: %(module)s: %(lineno)d: %(msg)s" + info_fmt = "%(msg)s" + err_fmt = info_fmt + + def __init__(self, fmt=info_fmt): + logging.Formatter.__init__(self, fmt) + + def format(self, record): + + # Save the original format configured by the user + # when the logger formatter was instantiated + format_orig = self._fmt + + # Replace the original format with one customized by logging level + if record.levelno == logging.DEBUG: + self._fmt = MpasFormatter.dbg_fmt + + elif record.levelno == logging.INFO: + self._fmt = MpasFormatter.info_fmt + + elif record.levelno == logging.ERROR: + self._fmt = MpasFormatter.err_fmt + + # Call the original formatter class to do the grunt work + result = logging.Formatter.format(self, record) + + # Restore the original format configured by the user + self._fmt = format_orig + + return result + + +class StreamToLogger(object): + """ + Modified based on code by: + https://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/ + Copyright (C) 2011 Ferry Boender + License: GPL, see https://www.electricmonk.nl/log/posting-license/ + Fake file-like stream object that redirects writes to a logger instance. + """ + + def __init__(self, logger, log_level=logging.INFO): + self.logger = logger + self.log_level = log_level + self.linebuf = '' + + def write(self, buf): + for line in buf.rstrip().splitlines(): + self.logger.log(self.log_level, str(line.rstrip())) + + def flush(self): + pass +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/merge_grids.html b/0.22.0rc4/_modules/mpas_tools/merge_grids.html new file mode 100644 index 000000000..137df63cd --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/merge_grids.html @@ -0,0 +1,381 @@ + + + + + + mpas_tools.merge_grids — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.merge_grids

+#!/usr/bin/env python
+"""
+Tool to merge 2 MPAS non-contiguous meshes together into a single file
+"""
+
+import os
+import sys
+import json
+import argparse
+
+from datetime import datetime
+
+from netCDF4 import Dataset
+
+
+def parse_args(args=None):
+    parser = argparse.ArgumentParser(description=__doc__,
+                                     formatter_class=argparse.RawTextHelpFormatter)
+
+    parser.add_argument('infile1', metavar='FILENAME1',
+                        help='File name for first mesh to merge')
+
+    parser.add_argument('infile2', metavar='FILENAME2',
+                        help='File name for second mesh to merge')
+
+    parser.add_argument('-o', dest='outfile', default='merged_mesh.nc', metavar='FILENAME',
+                        help='The merged mesh file')
+
+    return parser.parse_args(args)
+
+
+
[docs]def merge_grids(infile1=None, infile2=None, outfile=None, runner=None): + """ + Merges two MPAS non-contiguous meshes together into a single file + + Parameters + ---------- + infile1 : str + The file name for the first mesh to merge + + infile2 : str + The file name for the second mesh to merge + + outfile : str + The file name for the first mesh to merge + + runner : str, optional + The command to write into the global history attribute of the outfile + """ + now = datetime.now().strftime("%a %b %d %H:%M:%S %Y") + if not runner: + runner = '{}.merge_grids(infile1={}, infile2={}, outfile={})'.format( + os.path.splitext(__file__)[0], infile1, infile2, outfile) + + print('Opening files to merge:\n {}\n {}'.format(infile1, infile2)) + print('Creating the merged mesh file: {}'.format(outfile)) + with Dataset(infile1) as nc_in1, Dataset(infile2) as nc_in2, \ + Dataset(outfile, 'w', format="NETCDF3_CLASSIC") as mesh: + nCells1 = nc_in1.dimensions['nCells'].size + nEdges1 = nc_in1.dimensions['nEdges'].size + nVertices1 = nc_in1.dimensions['nVertices'].size + + nCells2 = nc_in2.dimensions['nCells'].size + nEdges2 = nc_in2.dimensions['nEdges'].size + nVertices2 = nc_in2.dimensions['nVertices'].size + + if nc_in1.dimensions['vertexDegree'].size != nc_in2.dimensions['vertexDegree'].size: + raise ValueError("ERROR: The two files have different lengths of the " + "vertexDegree dimension.") + + mesh.createDimension('nCells', nCells1 + nCells2) + mesh.createDimension('nEdges', nEdges1 + nEdges2) + mesh.createDimension('nVertices', nVertices1 + nVertices2) + mesh.createDimension('TWO', 2) + mesh.createDimension('vertexDegree', nc_in1.dimensions['vertexDegree'].size) + if 'StrLen' in nc_in1.dimensions: + mesh.createDimension('StrLen', nc_in1.dimensions['StrLen'].size) + maxEdges = max(nc_in1.dimensions['maxEdges'].size, nc_in2.dimensions['maxEdges'].size) + mesh.createDimension('maxEdges', maxEdges) + mesh.createDimension('maxEdges2', maxEdges * 2) + + optionalDims = ('Time', 'nVertLevels', 'nVertInterfaces') + for dim in optionalDims: + if dim in nc_in1.dimensions and dim in nc_in2.dimensions: + if len(nc_in1.dimensions[dim]) != len(nc_in2.dimensions[dim]): + raise ValueError("ERROR: The two files have different lengths " + "of the {} dimension.".format(dim)) + if dim == 'Time': + mesh.createDimension('Time', size=None) # make unlimited dimension + else: + mesh.createDimension(dim, nc_in1.dimensions[dim].size) + + print('Merging variable:') + vars1 = set(nc_in1.variables) + vars2 = set(nc_in2.variables) + # only copy variables common to both files + for varname in (vars1 & vars2): + print(' {}'.format(varname)) + if nc_in1.variables[varname].dimensions \ + != nc_in2.variables[varname].dimensions: + raise ValueError("ERROR: Variable {} has different dimensions in " + "the two files.".format(varname)) + + theVar = nc_in1.variables[varname] + newVar = mesh.createVariable(varname, theVar.dtype, theVar.dimensions) + # (Assuming here that nCells, nEdges, and nVertices are never both in a variable) + # now assign value + if 'nCells' in theVar.dimensions: + tup1 = () + tup2 = () + tupMerge = () + for ind in range(len(theVar.dimensions)): + if theVar.dimensions[ind] == 'nCells': + tup1 += (slice(0, nCells1),) + tup2 += (slice(0, nCells2),) + tupMerge += (slice(nCells1, nCells1 + nCells2),) + else: + tup1 += (slice(None),) + tup2 += (slice(None),) + tupMerge += (slice(None),) + newVar[tup1] = nc_in1.variables[varname][tup1] + newVar[tupMerge] = nc_in2.variables[varname][tup2] + elif 'nEdges' in theVar.dimensions: + tup1 = () + tup2 = () + tupMerge = () + for ind in range(len(theVar.dimensions)): + if theVar.dimensions[ind] == 'nEdges': + tup1 += (slice(0, nEdges1),) + tup2 += (slice(0, nEdges2),) + tupMerge += (slice(nEdges1, nEdges1 + nEdges2),) + else: + tup1 += (slice(None),) + tup2 += (slice(None),) + tupMerge += (slice(None),) + newVar[tup1] = nc_in1.variables[varname][tup1] + newVar[tupMerge] = nc_in2.variables[varname][tup2] + elif 'nVertices' in theVar.dimensions: + tup1 = () + tup2 = () + tupMerge = () + for ind in range(len(theVar.dimensions)): + if theVar.dimensions[ind] == 'nVertices': + tup1 += (slice(0, nVertices1),) + tup2 += (slice(0, nVertices2),) + tupMerge += (slice(nVertices1, nVertices1 + nVertices2),) + else: + tup1 += (slice(None),) + tup2 += (slice(None),) + tupMerge += (slice(None),) + newVar[tup1] = nc_in1.variables[varname][tup1] + newVar[tupMerge] = nc_in2.variables[varname][tup2] + else: + # just take file 1's version + newVar[:] = theVar[:] + + # Indexes need adjusting: + if varname == "indexToCellID": + newVar[nCells1:] += nCells1 + elif varname == "indexToEdgeID": + newVar[nEdges1:] += nEdges1 + elif varname == "indexToVertexID": + newVar[nVertices1:] += nVertices1 + elif varname == "cellsOnEdge": + part2 = newVar[nEdges1:, :] + part2[part2 > 0] += nCells1 + newVar[nEdges1:, :] = part2 + elif varname == "edgesOnCell": + part2 = newVar[nCells1:, :] + part2[part2 > 0] += nEdges1 + newVar[nCells1:, :] = part2 + elif varname == "edgesOnEdge": + part2 = newVar[nEdges1:, :] + part2[part2 > 0] += nEdges1 + newVar[nEdges1:, :] = part2 + elif varname == "cellsOnCell": + part2 = newVar[nCells1:, :] + part2[part2 > 0] += nCells1 + newVar[nCells1:, :] = part2 + elif varname == "verticesOnCell": + part2 = newVar[nCells1:, :] + part2[part2 > 0] += nVertices1 + newVar[nCells1:, :] = part2 + elif varname == "verticesOnEdge": + part2 = newVar[nEdges1:, :] + part2[part2 > 0] += nVertices1 + newVar[nEdges1:, :] = part2 + elif varname == "edgesOnVertex": + part2 = newVar[nVertices1:, :] + part2[part2 > 0] += nEdges1 + newVar[nVertices1:, :] = part2 + elif varname == "cellsOnVertex": + part2 = newVar[nVertices1:, :] + part2[part2 > 0] += nCells1 + newVar[nVertices1:, :] = part2 + + attrToCopy = ("on_a_sphere", "sphere_radius", "is_periodic") + for attr in attrToCopy: + if attr in nc_in1.ncattrs() and attr in nc_in2.ncattrs(): + if nc_in1.getncattr(attr) == nc_in2.getncattr(attr): + mesh.setncattr(attr, nc_in1.getncattr(attr)) + else: + print( + "Warning: Value for '{0}' global attribute differs between " + "input files. '{0}' being skipped.".format(attr)) + else: + print("Warning: '{0}' global attribute not present in both input " + "files. '{0}' being skipped.".format(attr)) + + # Add merge info to allow exact splitting later + mesh.merge_point = json.dumps({'nCells': nCells1, + 'nEdges': nEdges1, + 'nVertices': nVertices1, + 'maxEdges1': nc_in1.dimensions['maxEdges'].size, + 'maxEdges2': nc_in2.dimensions['maxEdges'].size + }) + + run_command = "{}: {} \n".format(now, runner) + mesh.history = maybe_encode(run_command) + + print('Merge complete! Output file: {}.'.format(outfile))
+ + +# NOTE: Python 2 and 3 string fun conflicting with NC_CHAR vs NC_STRING, see: +# https://github.com/Unidata/netcdf4-python/issues/529 +def maybe_encode(string, encoding='ascii'): + try: + return string.encode(encoding) + except UnicodeEncodeError: + return string + + +def main(): + arguments = parse_args() + arguments.runner = ' '.join(sys.argv[:]) + merge_grids(**vars(arguments)) + + +if __name__ == '__main__': + main() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/conversion.html b/0.22.0rc4/_modules/mpas_tools/mesh/conversion.html new file mode 100644 index 000000000..adeed5208 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/conversion.html @@ -0,0 +1,355 @@ + + + + + + mpas_tools.mesh.conversion — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.mesh.conversion

+import os
+import xarray
+from tempfile import TemporaryDirectory
+import shutil
+
+import mpas_tools.io
+from mpas_tools.io import write_netcdf
+from mpas_tools.logging import check_call
+
+
+
[docs]def convert(dsIn, graphInfoFileName=None, logger=None, dir=None): + """ + Use ``MpasMeshConverter.x`` to convert an input mesh to a valid MPAS + mesh that is fully compliant with the MPAS mesh specification. + https://mpas-dev.github.io/files/documents/MPAS-MeshSpec.pdf + + Parameters + ---------- + dsIn : xarray.Dataset + A data set to convert + + graphInfoFileName : str, optional + A file path (relative or absolute) where the graph file (typically + ``graph.info`` should be written out. By default, ``graph.info`` is + not saved. + + logger : logging.Logger, optional + A logger for the output if not stdout + + dir : str, optional + A directory in which a temporary directory will be added with files + produced during conversion and then deleted upon completion. + + Returns + ------- + dsOut : xarray.Dataset + The MPAS mesh + """ + if dir is not None: + dir = os.path.abspath(dir) + with TemporaryDirectory(dir=dir) as tempdir: + inFileName = '{}/mesh_in.nc'.format(tempdir) + write_netcdf(dsIn, inFileName) + + outFileName = '{}/mesh_out.nc'.format(tempdir) + + if graphInfoFileName is not None: + graphInfoFileName = os.path.abspath(graphInfoFileName) + + outDir = os.path.dirname(outFileName) + + check_call(['MpasMeshConverter.x', inFileName, outFileName], + logger) + + dsOut = xarray.open_dataset(outFileName) + dsOut.load() + + if graphInfoFileName is not None: + shutil.copyfile('{}/graph.info'.format(outDir), + graphInfoFileName) + + return dsOut
+ + +
[docs]def cull(dsIn, dsMask=None, dsInverse=None, dsPreserve=None, + graphInfoFileName=None, logger=None, dir=None): + """ + Use ``MpasCellCuller.x`` to cull cells from a mesh based on the + ``cullCell`` field in the input file or DataSet and/or the provided masks. + ``cullCell``, dsMask and dsInverse are merged together so that the final + mask is the union of these 3. The preserve mask is then used to determine + where cells should *not* be culled. + + Parameters + ---------- + dsIn : xarray.Dataset + A data set to cull, possibly with a ``cullCell`` field set to one where + cells should be removed + + dsMask : xarray.Dataset or list, optional + A data set (or data sets) with region masks that are 1 where cells + should be culled + + dsInverse : xarray.Dataset or list, optional + A data set (or data sets) with region masks that are 0 where cells + should be culled + + dsPreserve : xarray.Dataset or list, optional + A data set (or data sets) with region masks that are 1 where cells + should *not* be culled + + graphInfoFileName : str, optional + A file path (relative or absolute) where the graph file (typically + ``culled_graph.info`` should be written out. By default, + ``culled_graph.info`` is not saved. + + logger : logging.Logger, optional + A logger for the output if not stdout + + dir : str, optional + A directory in which a temporary directory will be added with files + produced during cell culling and then deleted upon completion. + + Returns + ------- + dsOut : xarray.Dataset + The culled mesh + + """ + if dir is not None: + dir = os.path.abspath(dir) + with TemporaryDirectory(dir=dir) as tempdir: + inFileName = '{}/ds_in.nc'.format(tempdir) + write_netcdf(dsIn, inFileName) + outFileName = '{}/ds_out.nc'.format(tempdir) + + args = ['MpasCellCuller.x', inFileName, outFileName] + + if dsMask is not None: + if not isinstance(dsMask, list): + dsMask = [dsMask] + for index, ds in enumerate(dsMask): + fileName = '{}/mask{}.nc'.format(tempdir, index) + write_netcdf(ds, fileName) + args.extend(['-m', fileName]) + + if dsInverse is not None: + if not isinstance(dsInverse, list): + dsInverse = [dsInverse] + for index, ds in enumerate(dsInverse): + fileName = '{}/inverse{}.nc'.format(tempdir, index) + write_netcdf(ds, fileName) + args.extend(['-i', fileName]) + + if dsPreserve is not None: + if not isinstance(dsPreserve, list): + dsPreserve = [dsPreserve] + for index, ds in enumerate(dsPreserve): + fileName = '{}/preserve{}.nc'.format(tempdir, index) + write_netcdf(ds, fileName) + args.extend(['-p', fileName]) + + if graphInfoFileName is not None: + graphInfoFileName = os.path.abspath(graphInfoFileName) + + outDir = os.path.dirname(outFileName) + + check_call(args=args, logger=logger) + + dsOut = xarray.open_dataset(outFileName) + dsOut.load() + + if graphInfoFileName is not None: + shutil.copyfile('{}/culled_graph.info'.format(outDir), + graphInfoFileName) + + return dsOut
+ + +
[docs]def mask(dsMesh, fcMask=None, logger=None, dir=None, cores=1): + """ + Use ``compute_mpas_region_masks`` to create a set of region masks either + from mask feature collections + + Parameters + ---------- + dsMesh : xarray.Dataset, optional + An MPAS mesh on which the masks should be created + + fcMask : geometric_features.FeatureCollection, optional + A feature collection containing features to use to create the mask + + logger : logging.Logger, optional + A logger for the output if not stdout + + dir : str, optional + A directory in which a temporary directory will be added with files + produced during mask creation and then deleted upon completion. + + cores : int, optional + The number of cores to use for python multiprocessing + + Returns + ------- + dsMask : xarray.Dataset + The masks + + """ + if dir is not None: + dir = os.path.abspath(dir) + with TemporaryDirectory(dir=dir) as tempdir: + inFileName = f'{tempdir}/mesh_in.nc' + write_netcdf(dsMesh, inFileName) + outFileName = f'{tempdir}/mask_out.nc' + + geojsonFileName = f'{tempdir}/mask.geojson' + fcMask.to_geojson(geojsonFileName) + args = ['compute_mpas_region_masks', + '-m', inFileName, + '-o', outFileName, + '-g', geojsonFileName, + '-t', 'cell', + '--process_count', f'{cores}', + '--format', mpas_tools.io.default_format, + ] + if mpas_tools.io.default_engine is not None: + args.extend(['--engine', mpas_tools.io.default_engine]) + + check_call(args=args, logger=logger) + + dsOut = xarray.open_dataset(outFileName) + dsOut.load() + + return dsOut
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/build_mesh.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/build_mesh.html new file mode 100644 index 000000000..8738e3552 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/build_mesh.html @@ -0,0 +1,299 @@ + + + + + + mpas_tools.mesh.creation.build_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.build_mesh

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import xarray
+import matplotlib.pyplot as plt
+import cartopy.crs as ccrs
+import cartopy
+
+from mpas_tools.logging import check_call
+
+from mpas_tools.mesh.creation.jigsaw_driver import jigsaw_driver
+from mpas_tools.mesh.creation.jigsaw_to_netcdf import jigsaw_to_netcdf
+from mpas_tools.viz.colormaps import register_sci_viz_colormaps
+from mpas_tools.logging import LoggingContext
+
+
+
[docs]def build_spherical_mesh(cellWidth, lon, lat, earth_radius, + out_filename='base_mesh.nc', plot_cellWidth=True, + dir='./', logger=None): + """ + Build an MPAS mesh using JIGSAW with the given cell sizes as a function of + latitude and longitude. + + The result is a mesh file stored in ``out_filename`` as well as several + intermediate files: ``mesh.log``, ``mesh-HFUN.msh``, ``mesh.jig``, + ``mesh-MESH.msh``, ``mesh.msh``, and ``mesh_triangles.nc``. + + Parameters + ---------- + cellWidth : ndarray + m x n array of cell width in km + + lon : ndarray + longitude in degrees (length n and between -180 and 180) + + lat : ndarray + longitude in degrees (length m and between -90 and 90) + + earth_radius : float + Earth radius in meters + + out_filename : str, optional + The file name of the resulting MPAS mesh + + plot_cellWidth : bool, optional + Whether to produce a plot of ``cellWidth``. If so, it will be written + to ``cellWidthGlobal.png``. + + dir : str, optional + A directory in which a temporary directory will be added with files + produced during mesh conversion and then deleted upon completion. + + logger : logging.Logger, optional + A logger for the output if not stdout + """ + + with LoggingContext(__name__, logger=logger) as logger: + + da = xarray.DataArray(cellWidth, + dims=['lat', 'lon'], + coords={'lat': lat, 'lon': lon}, + name='cellWidth') + cw_filename = 'cellWidthVsLatLon.nc' + da.to_netcdf(cw_filename) + if plot_cellWidth: + register_sci_viz_colormaps() + fig = plt.figure(figsize=[16.0, 8.0]) + ax = plt.axes(projection=ccrs.PlateCarree()) + ax.set_global() + im = ax.imshow(cellWidth, origin='lower', + transform=ccrs.PlateCarree(), + extent=[-180, 180, -90, 90], cmap='3Wbgy5', + zorder=0) + ax.add_feature(cartopy.feature.LAND, edgecolor='black', zorder=1) + gl = ax.gridlines( + crs=ccrs.PlateCarree(), + draw_labels=True, + linewidth=1, + color='gray', + alpha=0.5, + linestyle='-', zorder=2) + gl.top_labels = False + gl.right_labels = False + plt.title( + 'Grid cell size, km, min: {:.1f} max: {:.1f}'.format( + cellWidth.min(),cellWidth.max())) + plt.colorbar(im, shrink=.60) + fig.canvas.draw() + plt.tight_layout() + plt.savefig('cellWidthGlobal.png', bbox_inches='tight') + plt.close() + + logger.info('Step 1. Generate mesh with JIGSAW') + jigsaw_driver(cellWidth, lon, lat, on_sphere=True, + earth_radius=earth_radius, logger=logger) + + logger.info('Step 2. Convert triangles from jigsaw format to netcdf') + jigsaw_to_netcdf(msh_filename='mesh-MESH.msh', + output_name='mesh_triangles.nc', on_sphere=True, + sphere_radius=earth_radius) + + logger.info('Step 3. Convert from triangles to MPAS mesh') + args = ['MpasMeshConverter.x', + 'mesh_triangles.nc', + out_filename] + check_call(args=args, logger=logger)
+ + +
[docs]def build_planar_mesh(cellWidth, x, y, geom_points, geom_edges, + out_filename='base_mesh.nc', logger=None): + """ + Build a planar MPAS mesh + + Parameters + ---------- + cellWidth : ndarray + m x n array of cell width in km + + x, y : ndarray + arrays defining planar coordinates in meters + + geom_points : ndarray + list of point coordinates for bounding polygon for the planar mesh + + geom_edges : ndarray + list of edges between points in ``geom_points`` that define the + bounding polygon + + out_filename : str, optional + The file name of the resulting MPAS mesh + + logger : logging.Logger, optional + A logger for the output if not stdout + """ + + with LoggingContext(__name__, logger=logger) as logger: + + da = xarray.DataArray(cellWidth, + dims=['y', 'x'], + coords={'y': y, 'x': x}, + name='cellWidth') + cw_filename = 'cellWidthVsXY.nc' + da.to_netcdf(cw_filename) + + logger.info('Step 1. Generate mesh with JIGSAW') + jigsaw_driver(cellWidth, x, y, on_sphere=False, + geom_points=geom_points, geom_edges=geom_edges, + logger=logger) + + logger.info('Step 2. Convert triangles from jigsaw format to netcdf') + jigsaw_to_netcdf(msh_filename='mesh-MESH.msh', + output_name='mesh_triangles.nc', on_sphere=False) + + logger.info('Step 3. Convert from triangles to MPAS mesh') + args = ['MpasMeshConverter.x', + 'mesh_triangles.nc', + out_filename] + check_call(args=args, logger=logger)
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/jigsaw_driver.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/jigsaw_driver.html new file mode 100644 index 000000000..68be8edee --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/jigsaw_driver.html @@ -0,0 +1,225 @@ + + + + + + mpas_tools.mesh.creation.jigsaw_driver — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.jigsaw_driver

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy
+import jigsawpy
+from jigsawpy.savejig import savejig
+
+from mpas_tools.logging import check_call
+
+
+
[docs]def jigsaw_driver(cellWidth, x, y, on_sphere=True, earth_radius=6371.0e3, + geom_points=None, geom_edges=None, logger=None): + """ + A function for building a jigsaw mesh + + Parameters + ---------- + cellWidth : ndarray + The size of each cell in the resulting mesh as a function of space + + x, y : ndarray + The x and y coordinates of each point in the cellWidth array (lon and + lat for spherical mesh) + + on_sphere : logical, optional + Whether this mesh is spherical or planar + + earth_radius : float, optional + Earth radius in meters + + geom_points : ndarray, optional + list of point coordinates for bounding polygon for planar mesh + + geom_edges : ndarray, optional + list of edges between points in geom_points that define the bounding polygon + + logger : logging.Logger, optional + A logger for the output if not stdout + """ + # Authors + # ------- + # Mark Petersen, Phillip Wolfram, Xylar Asay-Davis + + # setup files for JIGSAW + opts = jigsawpy.jigsaw_jig_t() + opts.geom_file = 'mesh.msh' + opts.jcfg_file = 'mesh.jig' + opts.mesh_file = 'mesh-MESH.msh' + opts.hfun_file = 'mesh-HFUN.msh' + + # save HFUN data to file + hmat = jigsawpy.jigsaw_msh_t() + if on_sphere: + hmat.mshID = 'ELLIPSOID-GRID' + hmat.xgrid = numpy.radians(x) + hmat.ygrid = numpy.radians(y) + else: + hmat.mshID = 'EUCLIDEAN-GRID' + hmat.xgrid = x + hmat.ygrid = y + hmat.value = cellWidth + jigsawpy.savemsh(opts.hfun_file, hmat) + + # define JIGSAW geometry + geom = jigsawpy.jigsaw_msh_t() + if on_sphere: + geom.mshID = 'ELLIPSOID-MESH' + geom.radii = earth_radius*1e-3*numpy.ones(3, float) + else: + geom.mshID = 'EUCLIDEAN-MESH' + geom.vert2 = geom_points + geom.edge2 = geom_edges + jigsawpy.savemsh(opts.geom_file, geom) + + # build mesh via JIGSAW! + opts.hfun_scal = 'absolute' + opts.hfun_hmax = float("inf") + opts.hfun_hmin = 0.0 + opts.mesh_dims = +2 # 2-dim. simplexes + opts.optm_qlim = 0.9375 + opts.verbosity = +1 + + savejig(opts.jcfg_file, opts) + check_call(['jigsaw', opts.jcfg_file], logger=logger)
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/jigsaw_to_netcdf.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/jigsaw_to_netcdf.html new file mode 100644 index 000000000..742ca8e98 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/jigsaw_to_netcdf.html @@ -0,0 +1,301 @@ + + + + + + mpas_tools.mesh.creation.jigsaw_to_netcdf — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.jigsaw_to_netcdf

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy as np
+
+from netCDF4 import Dataset as NetCDFFile
+from mpas_tools.mesh.creation.open_msh import readmsh
+from mpas_tools.mesh.creation.util import circumcenter
+
+import argparse
+
+
+
[docs]def jigsaw_to_netcdf(msh_filename, output_name, on_sphere, sphere_radius=None): + """ + Converts mesh data defined in triangle format to NetCDF + + Parameters + ---------- + msh_filename : str + A JIGSAW mesh file name + output_name: str + The name of the output file + on_sphere : bool + Whether the mesh is spherical or planar + sphere_radius : float, optional + The radius of the sphere in meters. If ``on_sphere=True`` this argument + is required, otherwise it is ignored. + """ + # Authors: Phillip J. Wolfram, Matthew Hoffman and Xylar Asay-Davis + + grid = NetCDFFile(output_name, 'w', format='NETCDF3_CLASSIC') + + # Get dimensions + # Get nCells + msh = readmsh(msh_filename) + nCells = msh['POINT'].shape[0] + + # Get vertexDegree and nVertices + vertexDegree = 3 # always triangles with JIGSAW output + nVertices = msh['TRIA3'].shape[0] + + if vertexDegree != 3: + ValueError("This script can only compute vertices with triangular " + "dual meshes currently.") + + grid.createDimension('nCells', nCells) + grid.createDimension('nVertices', nVertices) + grid.createDimension('vertexDegree', vertexDegree) + + # Create cell variables and sphere_radius + xCell_full = msh['POINT'][:, 0] + yCell_full = msh['POINT'][:, 1] + zCell_full = msh['POINT'][:, 2] + for cells in [xCell_full, yCell_full, zCell_full]: + assert cells.shape[0] == nCells, 'Number of anticipated nodes is' \ + ' not correct!' + if on_sphere: + grid.on_a_sphere = "YES" + grid.sphere_radius = sphere_radius + # convert from km to meters + xCell_full *= 1e3 + yCell_full *= 1e3 + zCell_full *= 1e3 + else: + grid.on_a_sphere = "NO" + grid.sphere_radius = 0.0 + + # Create cellsOnVertex + cellsOnVertex_full = msh['TRIA3'][:, :3] + 1 + assert cellsOnVertex_full.shape == (nVertices, vertexDegree), \ + 'cellsOnVertex_full is not the right shape!' + + # Create vertex variables + xVertex_full = np.zeros((nVertices,)) + yVertex_full = np.zeros((nVertices,)) + zVertex_full = np.zeros((nVertices,)) + + for iVertex in np.arange(0, nVertices): + cell1 = cellsOnVertex_full[iVertex, 0] + cell2 = cellsOnVertex_full[iVertex, 1] + cell3 = cellsOnVertex_full[iVertex, 2] + + x1 = xCell_full[cell1 - 1] + y1 = yCell_full[cell1 - 1] + z1 = zCell_full[cell1 - 1] + x2 = xCell_full[cell2 - 1] + y2 = yCell_full[cell2 - 1] + z2 = zCell_full[cell2 - 1] + x3 = xCell_full[cell3 - 1] + y3 = yCell_full[cell3 - 1] + z3 = zCell_full[cell3 - 1] + + pv = circumcenter(on_sphere, x1, y1, z1, x2, y2, z2, x3, y3, z3) + xVertex_full[iVertex] = pv.x + yVertex_full[iVertex] = pv.y + zVertex_full[iVertex] = pv.z + + meshDensity_full = grid.createVariable( + 'meshDensity', 'f8', ('nCells',)) + + for iCell in np.arange(0, nCells): + meshDensity_full[iCell] = 1.0 + + del meshDensity_full + + var = grid.createVariable('xCell', 'f8', ('nCells',)) + var[:] = xCell_full + var = grid.createVariable('yCell', 'f8', ('nCells',)) + var[:] = yCell_full + var = grid.createVariable('zCell', 'f8', ('nCells',)) + var[:] = zCell_full + var = grid.createVariable('xVertex', 'f8', ('nVertices',)) + var[:] = xVertex_full + var = grid.createVariable('yVertex', 'f8', ('nVertices',)) + var[:] = yVertex_full + var = grid.createVariable('zVertex', 'f8', ('nVertices',)) + var[:] = zVertex_full + var = grid.createVariable( + 'cellsOnVertex', 'i4', ('nVertices', 'vertexDegree',)) + var[:] = cellsOnVertex_full + + grid.sync() + grid.close()
+ + +def main(): + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument( + "-m", + "--msh", + dest="msh", + required=True, + help="input .msh file generated by JIGSAW.", + metavar="FILE") + parser.add_argument( + "-o", + "--output", + dest="output", + default="grid.nc", + help="output file name.", + metavar="FILE") + parser.add_argument( + "-s", + "--spherical", + dest="spherical", + action="store_true", + default=False, + help="Determines if the input/output should be spherical or not.") + parser.add_argument( + "-r", + "--sphere_radius", + dest="sphere_radius", + type=float, + help="The radius of the sphere in meters") + + args = parser.parse_args() + + jigsaw_to_netcdf(args.msh, args.output, args.spherical, args.sphere_radius) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/mesh_definition_tools.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/mesh_definition_tools.html new file mode 100644 index 000000000..f27573609 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/mesh_definition_tools.html @@ -0,0 +1,353 @@ + + + + + + mpas_tools.mesh.creation.mesh_definition_tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.mesh_definition_tools

+#!/usr/bin/env python
+"""
+These functions are tools used to define the ``cellWidth`` variable on
+regular lat/lon grids.  The ``cellWidth`` variable is a ``jigsaw`` input that
+defines the mesh.
+"""
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy as np
+
+
+
[docs]def mergeCellWidthVsLat( + lat, + cellWidthInSouth, + cellWidthInNorth, + latTransition, + latWidthTransition): + """ + Combine two cell width distributions using a ``tanh`` function. This is + intended as part of the workflow to make an MPAS global mesh. + + Parameters + ---------- + lat : ndarray + vector of length n, with entries between -90 and 90, degrees + + cellWidthInSouth : ndarray + vector of length n, first distribution + + cellWidthInNorth : ndarray + vector of length n, second distribution + + latTransition : float + lat to change from ``cellWidthInSouth`` to ``cellWidthInNorth`` in + degrees + + latWidthTransition : float + width of lat transition in degrees + + Returns + ------- + cellWidthOut : ndarray + vector of length n, entries are cell width as a function of lat + """ + + cellWidthOut = np.ones(lat.size) + if latWidthTransition == 0: + for j in range(lat.size): + if lat[j] < latTransition: + cellWidthOut[j] = cellWidthInSouth[j] + else: + cellWidthOut[j] = cellWidthInNorth[j] + else: + for j in range(lat.size): + weightNorth = 0.5 * \ + (np.tanh((lat[j] - latTransition) / latWidthTransition) + 1.0) + weightSouth = 1.0 - weightNorth + cellWidthOut[j] = weightSouth * cellWidthInSouth[j] + \ + weightNorth * cellWidthInNorth[j] + + return cellWidthOut
+ + +
[docs]def EC_CellWidthVsLat(lat, cellWidthEq=30.0, cellWidthMidLat=60.0, + cellWidthPole=35.0, latPosEq=15.0, latPosPole=73.0, + latTransition=40.0, latWidthEq=6.0, latWidthPole=9.0): + """ + Create Eddy Closure spacing as a function of lat. This is intended as part + of the workflow to make an MPAS global mesh. + + Parameters + ---------- + lat : ndarray + vector of length n, with entries between -90 and 90, degrees + + cellWidthEq : float, optional + Cell width in km at the equator + + cellWidthMidLat : float, optional + Cell width in km at mid latitudes + + cellWidthPole : float, optional + Cell width in km at the poles + + latPosEq : float, optional + Latitude in degrees of center of the equatorial transition region + + latPosPole : float, optional + Latitude in degrees of center of the polar transition region + + latTransition : float, optional + Latitude in degrees of the change from equatorial to polar function + + latWidthEq : float, optional + Width in degrees latitude of the equatorial transition region + + latWidthPole : float, optional + Width in degrees latitude of the polar transition region + + Returns + ------- + cellWidthOut : ndarray + 1D array of same length as ``lat`` with entries that are cell width as + a function of lat + + Examples + -------- + Default + + >>> EC60to30 = EC_CellWidthVsLat(lat) + + Half the default resolution: + + >>> EC120to60 = EC_CellWidthVsLat(lat, cellWidthEq=60., cellWidthMidLat=120., cellWidthPole=70.) + """ + + minCellWidth = min(cellWidthEq, min(cellWidthMidLat, cellWidthPole)) + densityEq = (minCellWidth / cellWidthEq)**4 + densityMidLat = (minCellWidth / cellWidthMidLat)**4 + densityPole = (minCellWidth / cellWidthPole)**4 + densityEqToMid = ((densityEq - densityMidLat) * (1.0 + np.tanh( + (latPosEq - np.abs(lat)) / latWidthEq)) / 2.0) + densityMidLat + densityMidToPole = ((densityMidLat - densityPole) * (1.0 + np.tanh( + (latPosPole - np.abs(lat)) / latWidthPole)) / 2.0) + densityPole + mask = np.abs(lat) < latTransition + densityEC = np.array(densityMidToPole) + densityEC[mask] = densityEqToMid[mask] + cellWidthOut = minCellWidth / densityEC**0.25 + + return cellWidthOut
+ + +
[docs]def RRS_CellWidthVsLat(lat, cellWidthEq, cellWidthPole): + """ + Create Rossby Radius Scaling as a function of lat. This is intended as + part of the workflow to make an MPAS global mesh. + + Parameters + ---------- + lat : ndarray + vector of length n, with entries between -90 and 90, degrees + + cellWidthEq : float, optional + Cell width in km at the equator + + cellWidthPole : float, optional + Cell width in km at the poles + + Returns + ------- + cellWidthOut : ndarray + 1D array of same length as ``lat`` with entries that are cell width as + a function of lat + + Examples + -------- + >>> RRS18to6 = EC_CellWidthVsLat(lat, 18., 6.) + """ + + # ratio between high and low resolution + gamma = (cellWidthPole / cellWidthEq)**4.0 + + densityRRS = (1.0 - gamma) * \ + np.power(np.sin(np.deg2rad(np.absolute(lat))), 4.0) + gamma + cellWidthOut = cellWidthPole / np.power(densityRRS, 0.25) + return cellWidthOut
+ + +
[docs]def AtlanticPacificGrid(lat, lon, cellWidthInAtlantic, cellWidthInPacific): + """ + Combine two cell width distributions using a ``tanh`` function. + + Parameters + ---------- + lat : ndarray + vector of length n, with entries between -90 and 90, degrees + + lon : ndarray + vector of length m, with entries between -180, 180, degrees + + cellWidthInAtlantic : float, optional + vector of length n, cell width in Atlantic as a function of lon, km + + cellWidthInPacific : float, optional + vector of length n, cell width in Pacific as a function of lon, km + + Returns + ------- + cellWidthOut : ndarray + m by n array, grid cell width on globe, km + + """ + cellWidthOut = np.zeros((lat.size, lon.size)) + for i in range(lon.size): + for j in range(lat.size): + # set to Pacific mask as default + cellWidthOut[j, i] = cellWidthInPacific[j] + # test if in Atlantic Basin: + if lat[j] > 65.0: + if (lon[i] > -150.0) & (lon[i] < 170.0): + cellWidthOut[j, i] = cellWidthInAtlantic[j] + elif lat[j] > 20.0: + if (lon[i] > -100.0) & (lon[i] < 35.0): + cellWidthOut[j, i] = cellWidthInAtlantic[j] + elif lat[j] > 0.0: + if (lon[i] > -2.0 * lat[j] - 60.0) & (lon[i] < 35.0): + cellWidthOut[j, i] = cellWidthInAtlantic[j] + else: + if (lon[i] > -60.0) & (lon[i] < 20.0): + cellWidthOut[j, i] = cellWidthInAtlantic[j] + return cellWidthOut
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/mpas_to_triangle.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/mpas_to_triangle.html new file mode 100644 index 000000000..cc2a9ad78 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/mpas_to_triangle.html @@ -0,0 +1,255 @@ + + + + + + mpas_tools.mesh.creation.mpas_to_triangle — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.mpas_to_triangle

+
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import sys
+from netCDF4 import Dataset as NetCDFFile
+from optparse import OptionParser
+
+
+
[docs]def mpas_to_triangle(mpasfile, trifile): + """ + Script to convert from MPAS netCDF format to the Triangle format: + https://www.cs.cmu.edu/~quake/triangle.node.html + https://www.cs.cmu.edu/~quake/triangle.ele.html + + Parameters + ---------- + mpasfile : str + The path to an MPAS mesh in NetCDF format + + trifile : str + The prefix for the Triangle output files. Files with extensions + ``.node`` and ``.ele`` will be produced. + + Only works for planar meshes. + """ + fin = NetCDFFile(mpasfile, 'r') + if fin.on_a_sphere == "YES": + sys.abort("ERROR: This script only works for planar meshes!") + + if len(fin.dimensions['vertexDegree']) != 3: + sys.abort("ERROR: This script only works for vertexDegree of 3!") + + nCells = len(fin.dimensions['nCells']) + nVertices = len(fin.dimensions['nVertices']) + + xCell = fin.variables['xCell'][:] + yCell = fin.variables['yCell'][:] + ConC = fin.variables['cellsOnCell'][:] + nConC = fin.variables['nEdgesOnCell'][:] + ConV = fin.variables['cellsOnVertex'][:] + + # create node file + fnode = open(trifile + ".node", 'w') + # write node file header: First line: <# of vertices> <dimension (must + # be 2)> <# of attributes> <# of boundary markers (0 or 1)> + fnode.write("{:d} 2 0 1\n".format(nCells)) + # Remaining lines: <vertex #> <x> <y> [attributes] [boundary marker] + for i in range(nCells): + if ConC[i, 0:nConC[i]].min() == 0: + isBdy = 1 + else: + isBdy = 0 + fnode.write( + "{:d} {:f} {:f} {:d}\n".format( + i + 1, + xCell[i], + yCell[i], + isBdy)) + fnode.write("# Generated from MPAS file: {}\n".format(mpasfile)) + fnode.close() + + # create ele file + fele = open(trifile + ".ele", "w") + + # calculate number of non-degenerate triangles + numtri = 0 + for i in range(nVertices): + if ConV[i, :].min() > 0: + numtri += 1 + + # write ele file header: First line: <# of triangles> <nodes per + # triangle> <# of attributes> + fele.write("{:d} 3 0\n".format(numtri)) + # Remaining lines: <triangle #> <node> <node> <node> ... [attributes] + cnt = 0 + for i in range(nVertices): + # write non-generate triangles only + if ConV[i, :].min() > 0: + cnt += 1 + fele.write("{:d} {:d} {:d} {:d}\n".format( + cnt, ConV[i, 0], ConV[i, 1], ConV[i, 2])) + fele.write("# Generated from MPAS file: {}\n".format(mpasfile)) + fele.close() + + fin.close() + print("Conversion complete.")
+ + +def main(): + parser = OptionParser() + parser.add_option( + "-m", + "--mpas", + dest="mpasfile", + help="input MPAS netCDF file.", + metavar="FILE") + parser.add_option( + "-t", + "--triangle", + dest="trifile", + help="output file name template to be in triangle format (FILE.1.node," + " FILE.1.ele).", + metavar="FILE") + + options, args = parser.parse_args() + + if not options.mpasfile: + parser.error("An input MPAS file is required.") + + if not options.trifile: + parser.error("A output Triangle format file name is required.") + + mpas_to_triangle(mpasfile=options.mpasfile, trifile=options.trifile) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/signed_distance.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/signed_distance.html new file mode 100644 index 000000000..a6f722653 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/signed_distance.html @@ -0,0 +1,399 @@ + + + + + + mpas_tools.mesh.creation.signed_distance — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.signed_distance

+import numpy as np
+from scipy.spatial import KDTree
+import timeit
+import shapely.geometry
+import shapely.ops
+from functools import partial
+from inpoly import inpoly2
+
+from geometric_features.plot import subdivide_geom
+
+from mpas_tools.mesh.creation.util import lonlat2xyz
+
+
+
[docs]def signed_distance_from_geojson(fc, lon_grd, lat_grd, earth_radius, + max_length=None, workers=-1): + """ + Get the distance for each point on a lon/lat grid from the closest point + on the boundary of the geojson regions. + + Parameters + ---------- + fc : geometrics_features.FeatureCollection + The regions to be rasterized + + lon_grd : numpy.ndarray + A 1D array of longitude values + + lat_grd : numpy.ndarray + A 1D array of latitude values + + earth_radius : float + Earth radius in meters + + max_length : float, optional + The maximum distance (in degrees) between points on the boundary of the + geojson region. If the boundary is too coarse, it will be subdivided. + + workers : int, optional + The number of threads used for finding nearest neighbors. The default + is all available threads (``workers=-1``) + + Returns + ------- + signed_distance : numpy.ndarray + A 2D field of distances (negative inside the region, positive outside) + to the shape boundary + """ + distance = distance_from_geojson(fc, lon_grd, lat_grd, earth_radius, + nn_search='kdtree', max_length=max_length, + workers=workers) + + mask = mask_from_geojson(fc, lon_grd, lat_grd) + + signed_distance = (-2.0 * mask + 1.0) * distance + return signed_distance
+ + +
[docs]def mask_from_geojson(fc, lon_grd, lat_grd): + """ + Make a rasterized mask on a lon/lat grid from shapes (geojson multipolygon + data). + + Parameters + ---------- + fc : geometrics_features.FeatureCollection + The regions to be rasterized + + lon_grd : numpy.ndarray + A 1D array of longitude values + + lat_grd : numpy.ndarray + A 1D array of latitude values + + Returns + ------- + mask : numpy.ndarray + A 2D mask with the shapes rasterized (0.0 outside, 1.0 inside) + """ + + print("Mask from geojson") + print("-----------------") + + nodes = list() + edges = list() + for feature in fc.features: + if feature['geometry']['type'] == 'Polygon': + for poly in feature['geometry']['coordinates']: + _add_poly(poly, edges, nodes) + + elif feature['geometry']['type'] == 'MultiPolygon': + for mpoly in feature['geometry']['coordinates']: + for poly in mpoly: + _add_poly(poly, edges, nodes) + + nodes = np.array(nodes) + edges = np.array(edges) + + Lon, Lat = np.meshgrid(lon_grd, lat_grd) + + points = np.vstack([Lon.ravel(), Lat.ravel()]).T + + in_shape, _ = inpoly2(points, nodes, edges) + + mask = in_shape.reshape(Lon.shape) + return mask
+ + +
[docs]def distance_from_geojson(fc, lon_grd, lat_grd, earth_radius, + nn_search='kdtree', max_length=None, + workers=-1): + # {{{ + """ + Get the distance for each point on a lon/lat grid from the closest point + on the boundary of the geojson regions. + + Parameters + ---------- + fc : geometrics_features.FeatureCollection + The regions to be rasterized + + lon_grd : numpy.ndarray + A 1D array of longitude values + + lat_grd : numpy.ndarray + A 1D array of latitude values + + earth_radius : float + Earth radius in meters + + nn_search: {'kdtree'}, optional + The method used to find the nearest point on the shape boundary + + max_length : float, optional + The maximum distance (in degrees) between points on the boundary of the + geojson region. If the boundary is too coarse, it will be subdivided. + + workers : int, optional + The number of threads used for finding nearest neighbors. The default + is all available threads (``workers=-1``) + + Returns + ------- + distance : numpy.ndarray + A 2D field of distances to the shape boundary + """ + + if nn_search != 'kdtree': + raise ValueError(f'nn_search method {nn_search} not available.') + + print("Distance from geojson") + print("---------------------") + + shapes = _subdivide_shapes(fc, max_length) + + print(" Finding region boundaries") + boundary_lon = [] + boundary_lat = [] + for shape in shapes: + # get the boundary of each shape + x, y = shape.boundary.coords.xy + boundary_lon.extend(x) + boundary_lat.extend(y) + + boundary_lon = np.array(boundary_lon) + boundary_lat = np.array(boundary_lat) + + # Remove point at +/- 180 lon and +/- 90 lat because these are "fake". + # Need a little buffer (0.01 degrees) to avoid misses due to rounding. + mask = np.logical_not(np.logical_or( + np.logical_or(boundary_lon <= -179.99, boundary_lon >= 179.99), + np.logical_or(boundary_lat <= -89.99, boundary_lat >= 89.99))) + + boundary_lon = boundary_lon[mask] + boundary_lat = boundary_lat[mask] + + print(" Mean boundary latitude: {0:.2f}".format(np.mean(boundary_lat))) + + # Convert coastline points to x,y,z and create kd-tree + npoints = len(boundary_lon) + boundary_xyz = np.zeros((npoints, 3)) + boundary_xyz[:, 0], boundary_xyz[:, 1], boundary_xyz[:, 2] = \ + lonlat2xyz(boundary_lon, boundary_lat, earth_radius) + tree = KDTree(boundary_xyz) + + # Convert background grid coordinates to x,y,z and put in a nx_grd x 3 + # array for kd-tree query + Lon_grd, Lat_grd = np.meshgrid(lon_grd, lat_grd) + X_grd, Y_grd, Z_grd = lonlat2xyz(Lon_grd, Lat_grd, earth_radius) + pts = np.vstack([X_grd.ravel(), Y_grd.ravel(), Z_grd.ravel()]).T + + # Find distances of background grid coordinates to the coast + print(" Finding distance") + start = timeit.default_timer() + distance, _ = tree.query(pts, workers=workers) + end = timeit.default_timer() + print(" Done") + print(" {0:.0f} seconds".format(end-start)) + + # Make distance array that corresponds with cell_width array + distance = np.reshape(distance, Lon_grd.shape) + + return distance
+ + +def _subdivide_shapes(fc, max_length): + + shapes = [] + for feature in fc.features: + # get the boundary of each shape + shape = shapely.geometry.shape(feature['geometry']) + if max_length is not None: + # subdivide the shape if it's too coarse + geom_type = shape.geom_type + shape = subdivide_geom(shape, geom_type, max_length) + shapes.append(shape) + + return shapes + + +def _is_uniform(vector, epsilon=1e-10): + d = vector[1:] - vector[0:-1] + diff = d - np.mean(d) + return np.all(np.abs(diff) < epsilon) + + +def _shapes_to_pixel_coords(lon, lat, shapes): + intx = partial(_interpx, lon) + inty = partial(_interpy, lat) + new_shapes = [] + for shape in shapes: + shape = shapely.ops.transform(intx, shape) + shape = shapely.ops.transform(inty, shape) + new_shapes.append(shape) + return new_shapes + + +def _interpx(lon, x, y): + nlon = len(lon) + lon_pixels = np.arange(nlon, dtype=float) + x = np.interp(x, lon, lon_pixels) + return x, y + + +def _interpy(lat, x, y): + nlat = len(lat) + lat_pixels = np.arange(nlat, dtype=float) + y = np.interp(y, lat, lat_pixels) + return x, y + + +def _add_poly(poly, edges, nodes): + node_count = len(nodes) + edge_count = len(poly) + poly_edges = [[node_count + edge, + node_count + (edge + 1) % edge_count] for edge in + range(edge_count)] + edges.extend(poly_edges) + nodes.extend(poly) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/creation/triangle_to_netcdf.html b/0.22.0rc4/_modules/mpas_tools/mesh/creation/triangle_to_netcdf.html new file mode 100644 index 000000000..b865372f0 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/creation/triangle_to_netcdf.html @@ -0,0 +1,316 @@ + + + + + + mpas_tools.mesh.creation.triangle_to_netcdf — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.creation.triangle_to_netcdf

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy as np
+
+from netCDF4 import Dataset as NetCDFFile
+from mpas_tools.mesh.creation.util import circumcenter
+
+import argparse
+
+
+
[docs]def triangle_to_netcdf(node, ele, output_name): + """ + Converts mesh data defined in triangle format to NetCDF + + Parameters + ---------- + node : str + A node file name + ele : str + An element file name + output_name: str + The name of the output file + """ + # Authors: Phillip J. Wolfram, Matthew Hoffman and Xylar Asay-Davis + on_sphere = False + grid = NetCDFFile(output_name, 'w', format='NETCDF3_CLASSIC') + + # Get dimensions + # Get nCells + cell_info = open(node, 'r') + nCells = -1 # There is one header line + for block in iter(lambda: cell_info.readline(), ""): + if block.startswith("#"): + continue # skip comment lines + nCells = nCells + 1 + cell_info.close() + + # Get vertexDegree and nVertices + cov_info = open(ele, 'r') + vertexDegree = 3 # always triangles with Triangle! + nVertices = -1 # There is one header line + for block in iter(lambda: cov_info.readline(), ""): + if block.startswith("#"): + continue # skip comment lines + nVertices = nVertices + 1 + cov_info.close() + + if vertexDegree != 3: + ValueError("This script can only compute vertices with triangular " + "dual meshes currently.") + + grid.createDimension('nCells', nCells) + grid.createDimension('nVertices', nVertices) + grid.createDimension('vertexDegree', vertexDegree) + + # Create cell variables and sphere_radius + xCell_full = np.zeros((nCells,)) + yCell_full = np.zeros((nCells,)) + zCell_full = np.zeros((nCells,)) + + cell_info = open(node, 'r') + cell_info.readline() # read header + i = 0 + for block in iter(lambda: cell_info.readline(), ""): + block_arr = block.split() + if block_arr[0] == "#": + continue # skip comment lines + xCell_full[i] = float(block_arr[1]) + yCell_full[i] = float(block_arr[2]) + zCell_full[i] = 0.0 # z-position is always 0.0 in a planar mesh + i = i + 1 + cell_info.close() + + grid.on_a_sphere = "NO" + grid.sphere_radius = 0.0 + + cellsOnVertex_full = np.zeros( + (nVertices, vertexDegree), dtype=np.int32) + + cov_info = open(ele, 'r') + cov_info.readline() # read header + iVertex = 0 + for block in iter(lambda: cov_info.readline(), ""): + block_arr = block.split() + if block_arr[0] == "#": + continue # skip comment lines + cellsOnVertex_full[iVertex, :] = int(-1) + # skip the first column, which is the triangle number, and then + # only get the next 3 columns + for j in np.arange(0, 3): + cellsOnVertex_full[iVertex, j] = int(block_arr[j + 1]) + + iVertex = iVertex + 1 + + cov_info.close() + + # Create vertex variables + xVertex_full = np.zeros((nVertices,)) + yVertex_full = np.zeros((nVertices,)) + zVertex_full = np.zeros((nVertices,)) + + for iVertex in np.arange(0, nVertices): + cell1 = cellsOnVertex_full[iVertex, 0] + cell2 = cellsOnVertex_full[iVertex, 1] + cell3 = cellsOnVertex_full[iVertex, 2] + + x1 = xCell_full[cell1 - 1] + y1 = yCell_full[cell1 - 1] + z1 = zCell_full[cell1 - 1] + x2 = xCell_full[cell2 - 1] + y2 = yCell_full[cell2 - 1] + z2 = zCell_full[cell2 - 1] + x3 = xCell_full[cell3 - 1] + y3 = yCell_full[cell3 - 1] + z3 = zCell_full[cell3 - 1] + + pv = circumcenter(on_sphere, x1, y1, z1, x2, y2, z2, x3, y3, z3) + xVertex_full[iVertex] = pv.x + yVertex_full[iVertex] = pv.y + zVertex_full[iVertex] = pv.z + + meshDensity_full = grid.createVariable( + 'meshDensity', 'f8', ('nCells',)) + + meshDensity_full[0:nCells] = 1.0 + + var = grid.createVariable('xCell', 'f8', ('nCells',)) + var[:] = xCell_full + var = grid.createVariable('yCell', 'f8', ('nCells',)) + var[:] = yCell_full + var = grid.createVariable('zCell', 'f8', ('nCells',)) + var[:] = zCell_full + var = grid.createVariable('xVertex', 'f8', ('nVertices',)) + var[:] = xVertex_full + var = grid.createVariable('yVertex', 'f8', ('nVertices',)) + var[:] = yVertex_full + var = grid.createVariable('zVertex', 'f8', ('nVertices',)) + var[:] = zVertex_full + var = grid.createVariable( + 'cellsOnVertex', 'i4', ('nVertices', 'vertexDegree',)) + var[:] = cellsOnVertex_full + + grid.sync() + grid.close()
+ + +def main(): + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument( + "-n", + "--node", + dest="node", + required=True, + help="input .node file generated by Triangle.", + metavar="FILE") + parser.add_argument( + "-e", + "--ele", + dest="ele", + required=True, + help="input .ele file generated by Triangle.", + metavar="FILE") + parser.add_argument( + "-o", + "--output", + dest="output", + default="grid.nc", + help="output file name.", + metavar="FILE") + options = parser.parse_args() + + triangle_to_netcdf(options.node, options.ele, options.output) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/interpolation.html b/0.22.0rc4/_modules/mpas_tools/mesh/interpolation.html new file mode 100644 index 000000000..c1c0a2b86 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/interpolation.html @@ -0,0 +1,211 @@ + + + + + + mpas_tools.mesh.interpolation — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.mesh.interpolation

+import numpy as np
+
+
+
[docs]def interp_bilin(x, y, field, xCell, yCell): + """ + Perform bilinear interpolation of ``field`` on a tensor grid to cell centers + on an MPAS mesh. ``xCell`` and ``yCell`` must be bounded by ``x`` and ``y``, + respectively. + + If x and y coordinates are longitude and latitude, respectively, it is + recommended that they be passed in degrees to avoid round-off problems at + the north and south poles and at the date line. + + Parameters + ---------- + x : ndarray + x coordinate of the input field (length n) + + y : ndarray + y coordinate fo the input field (length m) + + field : ndarray + a field of size m x n + + xCell : ndarray + x coordinate of MPAS cell centers + + yCell : ndarray + y coordinate of MPAS cell centers + + Returns + ------- + mpasField : ndarray + ``field`` interpoyed to MPAS cell centers + """ + + assert np.all(xCell >= x[0]) + assert np.all(xCell <= x[-1]) + assert np.all(yCell >= y[0]) + assert np.all(yCell <= y[-1]) + + # find float indices into the x and y arrays of cells on the MPAS mesh + xFrac = np.interp(xCell, x, np.arange(len(x))) + yFrac = np.interp(yCell, y, np.arange(len(y))) + + # xIndices/yIndices are the integer indices of the lower bound for bilinear + # interpoyion; xFrac/yFrac are the fraction of the way ot the next index + xIndices = np.array(xFrac, dtype=int) + xFrac -= xIndices + yIndices = np.array(yFrac, dtype=int) + yFrac -= yIndices + + # If points are exactly at the upper index, this is going to give us a bit + # of trouble so we'll move them down one index and adjust the fraction + # accordingly + mask = xIndices == len(x) - 1 + xIndices[mask] -= 1 + xFrac[mask] += 1. + + mask = yIndices == len(y) - 1 + yIndices[mask] -= 1 + yFrac[mask] += 1. + + mpasField = \ + (1. - xFrac) * (1. - yFrac) * field[yIndices, xIndices] + \ + xFrac * (1. - yFrac) * field[yIndices, xIndices + 1] + \ + (1. - xFrac) * yFrac * field[yIndices + 1, xIndices] + \ + xFrac * yFrac * field[yIndices + 1, xIndices + 1] + + return mpasField
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/mesh/mask.html b/0.22.0rc4/_modules/mpas_tools/mesh/mask.html new file mode 100644 index 000000000..c0d2117d0 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/mesh/mask.html @@ -0,0 +1,1453 @@ + + + + + + mpas_tools.mesh.mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.mesh.mask

+import xarray as xr
+import numpy
+from scipy.spatial import KDTree
+import shapely.geometry
+import shapely.ops
+from shapely.geometry import box, Polygon, MultiPolygon, GeometryCollection
+from shapely.strtree import STRtree
+import progressbar
+from functools import partial
+import argparse
+from igraph import Graph
+
+from geometric_features import read_feature_collection
+
+from mpas_tools.transects import subdivide_great_circle, \
+    lon_lat_to_cartesian, cartesian_to_lon_lat
+from mpas_tools.parallel import create_pool
+from mpas_tools.io import write_netcdf
+from mpas_tools.logging import LoggingContext
+from mpas_tools.cime.constants import constants
+
+
+
[docs]def compute_mpas_region_masks(dsMesh, fcMask, maskTypes=('cell', 'vertex'), + logger=None, pool=None, chunkSize=1000, + showProgress=False, subdivisionThreshold=30.): + """ + Use shapely and processes to create a set of masks from a feature collection + made up of regions (polygons) + + Parameters + ---------- + dsMesh : xarray.Dataset + An MPAS mesh on which the masks should be created + + fcMask : geometric_features.FeatureCollection + A feature collection containing features to use to create the mask + + maskTypes : tuple of {'cell', 'edge', 'vertex'}, optional + Which type(s) of masks to make. Masks are created based on whether + the latitude and longitude associated with each of these locations + (e.g. ``dsMesh.latCell`` and ``dsMesh.lonCell`` for ``'cell'``) are + inside or outside of the regions in ``fcMask``. + + logger : logging.Logger, optional + A logger for the output if not stdout + + pool : multiprocessing.Pool, optional + A pool for performing multiprocessing + + chunkSize : int, optional + The number of cells, vertices or edges that are processed in one + operation. Experimentation has shown that 1000 is a reasonable + compromise between dividing the work into sufficient subtasks to + distribute the load and having sufficient work for each thread. + + showProgress : bool, optional + Whether to show a progress bar + + subdivisionThreshold : float, optional + A threshold in degrees (lon or lat) above which the mask region will + be subdivided into smaller polygons for faster intersection checking + + Returns + ------- + dsMask : xarray.Dataset + The masks + + """ + + suffixes = {'cell': 'Cell', 'edge': 'Edge', 'vertex': 'Vertex'} + dims = {'cell': 'nCells', 'edge': 'nEdges', 'vertex': 'nVertices'} + + dsMasks = xr.Dataset() + + for maskType in maskTypes: + suffix = suffixes[maskType] + dim = dims[maskType] + lonName = 'lon{}'.format(suffix) + latName = 'lat{}'.format(suffix) + lat = numpy.rad2deg(dsMesh[latName].values) + + # transform longitudes to [-180, 180) + lon = numpy.mod(numpy.rad2deg(dsMesh[lonName].values) + 180., + 360.) - 180. + + if logger is not None: + logger.info(' Computing {} masks:'.format(maskType)) + + # create shapely geometry for lon and lat + points = [shapely.geometry.Point(x, y) for x, y in zip(lon, lat)] + regionNames, masks, properties, nChar = _compute_region_masks( + fcMask, points, logger, pool, chunkSize, showProgress, + subdivisionThreshold) + + nPoints = len(points) + + if logger is not None: + logger.info(' Adding masks to dataset...') + nRegions = len(regionNames) + # create a new data array for masks + masksVarName = 'region{}Masks'.format(suffix) + dsMasks[masksVarName] = \ + ((dim, 'nRegions'), numpy.zeros((nPoints, nRegions), dtype=int)) + + for index in range(nRegions): + mask = masks[index] + dsMasks[masksVarName][:, index] = numpy.array(mask, dtype=int) + + if 'regionNames' not in dsMasks: + # create a new data array for mask names + dsMasks['regionNames'] = (('nRegions',), + numpy.zeros((nRegions,), + dtype='|S{}'.format(nChar))) + + for index in range(nRegions): + dsMasks['regionNames'][index] = regionNames[index] + + for propertyName in properties: + if propertyName not in dsMasks: + dsMasks[propertyName] = (('nRegions',), + properties[propertyName]) + if logger is not None: + logger.info(' Done.') + + return dsMasks
+ + +def entry_point_compute_mpas_region_masks(): + """ Entry point for ``compute_mpas_region_masks()``""" + + parser = argparse.ArgumentParser() + parser.add_argument("-m", "--mesh_file_name", dest="mesh_file_name", + type=str, required=True, + help="An MPAS mesh file") + parser.add_argument("-g", "--geojson_file_name", + dest="geojson_file_name", type=str, required=True, + help="An Geojson file containing mask regions") + parser.add_argument("-o", "--mask_file_name", dest="mask_file_name", + type=str, required=True, + help="An output MPAS region masks file") + parser.add_argument("-t", "--mask_types", nargs='+', dest="mask_types", + type=str, + help="Which type(s) of masks to make: cell, edge or " + "vertex. Default is cell and vertex.") + parser.add_argument("-c", "--chunk_size", dest="chunk_size", type=int, + default=1000, + help="The number of cells, vertices or edges that are " + "processed in one operation") + parser.add_argument("--show_progress", dest="show_progress", + action="store_true", + help="Whether to show a progress bar") + parser.add_argument("-s", "--subdivision", dest="subdivision", type=float, + default=30., + help="A threshold in degrees (lon or lat) above which " + "the mask region will be subdivided into smaller " + "polygons for faster intersection checking") + parser.add_argument( + "--process_count", required=False, dest="process_count", type=int, + help="The number of processes to use to compute masks. The " + "default is to use all available cores") + parser.add_argument( + "--multiprocessing_method", dest="multiprocessing_method", + default='forkserver', + help="The multiprocessing method use for python mask creation " + "('fork', 'spawn' or 'forkserver')") + parser.add_argument("--format", dest="format", type=str, + help="NetCDF file format") + parser.add_argument("--engine", dest="engine", type=str, + help="NetCDF output engine") + args = parser.parse_args() + + dsMesh = xr.open_dataset(args.mesh_file_name, decode_cf=False, + decode_times=False) + fcMask = read_feature_collection(args.geojson_file_name) + + pool = create_pool(process_count=args.process_count, + method=args.multiprocessing_method) + + if args.mask_types is None: + args.mask_types = ('cell', 'vertex') + + with LoggingContext('compute_mpas_region_masks') as logger: + dsMasks = compute_mpas_region_masks( + dsMesh=dsMesh, fcMask=fcMask, maskTypes=args.mask_types, + logger=logger, pool=pool, chunkSize=args.chunk_size, + showProgress=args.show_progress, + subdivisionThreshold=args.subdivision) + + write_netcdf(dsMasks, args.mask_file_name, format=args.format, + engine=args.engine) + + +
[docs]def compute_mpas_transect_masks(dsMesh, fcMask, earthRadius, + maskTypes=('cell', 'edge', 'vertex'), + logger=None, pool=None, chunkSize=1000, + showProgress=False, subdivisionResolution=10e3, + addEdgeSign=False): + """ + Use shapely and processes to create a set of masks from a feature + collection made up of transects (line strings) + + Parameters + ---------- + dsMesh : xarray.Dataset + An MPAS mesh on which the masks should be created + + fcMask : geometric_features.FeatureCollection + A feature collection containing features to use to create the mask + + earthRadius : float + The radius of the earth in meters + + maskTypes : tuple of {'cell', 'edge', 'vertex'}, optional + Which type(s) of masks to make. Masks are created based on whether + the latitude and longitude associated with each of these locations + (e.g. ``dsMesh.latCell`` and ``dsMesh.lonCell`` for ``'cell'``) are + inside or outside of the transects in ``fcMask``. + + logger : logging.Logger, optional + A logger for the output if not stdout + + pool : multiprocessing.Pool, optional + A pool for performing multiprocessing + + chunkSize : int, optional + The number of cells, vertices or edges that are processed in one + operation. Experimentation has shown that 1000 is a reasonable + compromise between dividing the work into sufficient subtasks to + distribute the load and having sufficient work for each thread. + + showProgress : bool, optional + Whether to show a progress bar + + subdivisionResolution : float, optional + The maximum resolution (in meters) of segments in a transect. If a + transect is too coarse, it will be subdivided. Pass ``None`` for no + subdivision. + + addEdgeSign : bool, optional + Whether to add the ``edgeSign`` variable, which requires significant + extra computation + + Returns + ------- + dsMask : xarray.Dataset + The masks + + """ + + suffixes = {'cell': 'Cell', 'edge': 'Edge', 'vertex': 'Vertex'} + dims = {'cell': 'nCells', 'edge': 'nEdges', 'vertex': 'nVertices'} + + dsMasks = xr.Dataset() + + for maskType in maskTypes: + suffix = suffixes[maskType] + dim = dims[maskType] + + if logger is not None: + logger.info(' Computing {} masks:'.format(maskType)) + + polygons, nPolygons, duplicatePolygons = \ + _get_polygons(dsMesh, maskType) + transectNames, masks, properties, nChar, shapes = \ + _compute_transect_masks(fcMask, polygons, logger, pool, chunkSize, + showProgress, subdivisionResolution, + earthRadius) + + if logger is not None: + if addEdgeSign and maskType == 'edge': + logger.info(' Adding masks and edge signs to dataset...') + else: + logger.info(' Adding masks to dataset...') + nTransects = len(transectNames) + # create a new data array for masks + masksVarName = 'transect{}Masks'.format(suffix) + dsMasks[masksVarName] = \ + ((dim, 'nTransects'), + numpy.zeros((nPolygons, nTransects), dtype=int)) + + if addEdgeSign and maskType == 'edge': + dsMasks['transectEdgeMaskSigns'] = \ + ((dim, 'nTransects'), + numpy.zeros((nPolygons, nTransects), dtype=int)) + + for index in range(nTransects): + maskAndDuplicates = masks[index] + mask = maskAndDuplicates[0:nPolygons] + + mask[duplicatePolygons] = \ + numpy.logical_or(mask[duplicatePolygons], + maskAndDuplicates[nPolygons:]) + dsMasks[masksVarName][:, index] = numpy.array(mask, dtype=int) + + if addEdgeSign and maskType == 'edge': + print(transectNames[index]) + dsMasks['transectEdgeMaskSigns'][:, index] = \ + _compute_edge_sign(dsMesh, mask, shapes[index]) + + if 'transectNames' not in dsMasks: + # create a new data array for mask names + dsMasks['transectNames'] = \ + (('nTransects',), numpy.zeros((nTransects,), + dtype='|S{}'.format(nChar))) + + for index in range(nTransects): + dsMasks['transectNames'][index] = transectNames[index] + + for propertyName in properties: + if propertyName not in dsMasks: + dsMasks[propertyName] = (('nTransects',), + properties[propertyName]) + if logger is not None: + logger.info(' Done.') + + return dsMasks
+ + +def entry_point_compute_mpas_transect_masks(): + """ Entry point for ``compute_mpas_transect_masks()``""" + + parser = argparse.ArgumentParser() + parser.add_argument("-m", "--mesh_file_name", dest="mesh_file_name", + type=str, required=True, + help="An MPAS mesh file") + parser.add_argument("-g", "--geojson_file_name", + dest="geojson_file_name", type=str, required=True, + help="An Geojson file containing transects") + parser.add_argument("-o", "--mask_file_name", dest="mask_file_name", + type=str, required=True, + help="An output MPAS transect masks file") + parser.add_argument("-t", "--mask_types", nargs='+', dest="mask_types", + type=str, + help="Which type(s) of masks to make: cell, edge or " + "vertex. Default is cell, edge and vertex.") + parser.add_argument("-c", "--chunk_size", dest="chunk_size", type=int, + default=1000, + help="The number of cells, vertices or edges that are " + "processed in one operation") + parser.add_argument("--show_progress", dest="show_progress", + action="store_true", + help="Whether to show a progress bar") + parser.add_argument("-s", "--subdivision", dest="subdivision", type=float, + help="The maximum resolution (in meters) of segments " + "in a transect. If a transect is too coarse, it " + "will be subdivided. Default is no subdivision.") + parser.add_argument( + "--process_count", required=False, dest="process_count", type=int, + help="The number of processes to use to compute masks. The " + "default is to use all available cores") + parser.add_argument( + "--multiprocessing_method", dest="multiprocessing_method", + default='forkserver', + help="The multiprocessing method use for python mask creation " + "('fork', 'spawn' or 'forkserver')") + parser.add_argument("--add_edge_sign", dest="add_edge_sign", + action="store_true", + help="Whether to add the transectEdgeMaskSigns " + "variable") + parser.add_argument("--format", dest="format", type=str, + help="NetCDF file format") + parser.add_argument("--engine", dest="engine", type=str, + help="NetCDF output engine") + args = parser.parse_args() + + dsMesh = xr.open_dataset(args.mesh_file_name, decode_cf=False, + decode_times=False) + fcMask = read_feature_collection(args.geojson_file_name) + + pool = create_pool(process_count=args.process_count, + method=args.multiprocessing_method) + + if args.mask_types is None: + args.mask_types = ('cell', 'edge', 'vertex') + + earth_radius = constants['SHR_CONST_REARTH'] + + with LoggingContext('compute_mpas_transect_masks') as logger: + dsMasks = compute_mpas_transect_masks( + dsMesh=dsMesh, fcMask=fcMask, earthRadius=earth_radius, + maskTypes=args.mask_types, logger=logger, pool=pool, + chunkSize=args.chunk_size, showProgress=args.show_progress, + subdivisionResolution=args.subdivision, + addEdgeSign=args.add_edge_sign) + + write_netcdf(dsMasks, args.mask_file_name, format=args.format, + engine=args.engine) + + +
[docs]def compute_mpas_flood_fill_mask(dsMesh, fcSeed, logger=None, workers=-1): + """ + Flood fill from the given set of seed points to create a contiguous mask. + The flood fill operates using cellsOnCell, starting from the cells + whose centers are closest to the seed points. + + Parameters + ---------- + dsMesh : xarray.Dataset + An MPAS mesh on which the masks should be created + + fcSeed : geometric_features.FeatureCollection + A feature collection containing points at which to start the flood fill + + logger : logging.Logger, optional + A logger for the output if not stdout + + workers : int, optional + The number of threads used for finding nearest neighbors. The default + is all available threads (``workers=-1``) + + Returns + ------- + dsMask : xarray.Dataset + The masks + + """ + + dsMasks = xr.Dataset() + + lat = numpy.rad2deg(dsMesh.latCell.values) + + # transform longitudes to [-180, 180) + lon = numpy.mod(numpy.rad2deg(dsMesh.lonCell.values) + 180., + 360.) - 180. + + if logger is not None: + logger.info(' Computing flood fill mask on cells:') + + mask = _compute_seed_mask(fcSeed, lon, lat, workers) + + cellsOnCell = dsMesh.cellsOnCell.values - 1 + + mask = _flood_fill_mask(mask, cellsOnCell) + + if logger is not None: + logger.info(' Adding masks to dataset...') + # create a new data array for the mask + masksVarName = 'cellSeedMask' + dsMasks[masksVarName] = (('nCells',), numpy.array(mask, dtype=int)) + + if logger is not None: + logger.info(' Done.') + + return dsMasks
+ + +def entry_point_compute_mpas_flood_fill_mask(): + """ Entry point for ``compute_mpas_flood_fill_mask()``""" + + parser = argparse.ArgumentParser() + parser.add_argument("-m", "--mesh_file_name", dest="mesh_file_name", + type=str, required=True, + help="An MPAS mesh file") + parser.add_argument("-g", "--geojson_file_name", + dest="geojson_file_name", type=str, required=True, + help="An Geojson file containing points at which to " + "start the flood fill") + parser.add_argument("-o", "--mask_file_name", dest="mask_file_name", + type=str, required=True, + help="An output MPAS region masks file") + parser.add_argument("--format", dest="format", type=str, + help="NetCDF file format") + parser.add_argument("--engine", dest="engine", type=str, + help="NetCDF output engine") + args = parser.parse_args() + + dsMesh = xr.open_dataset(args.mesh_file_name, decode_cf=False, + decode_times=False) + fcSeed = read_feature_collection(args.geojson_file_name) + + with LoggingContext('compute_mpas_flood_fill_mask') as logger: + dsMasks = compute_mpas_flood_fill_mask( + dsMesh=dsMesh, fcSeed=fcSeed, logger=logger) + + write_netcdf(dsMasks, args.mask_file_name, format=args.format, + engine=args.engine) + + +
[docs]def compute_lon_lat_region_masks(lon, lat, fcMask, logger=None, pool=None, + chunkSize=1000, showProgress=False, + subdivisionThreshold=30.): + """ + Use shapely and processes to create a set of masks from a feature + collection made up of regions (polygons) on a tensor lon/lat grid + + Parameters + ---------- + lon : numpy.ndarray + A 1D array of longitudes in degrees between -180 and 180 + + lat : numpy.ndarray + A 1D array of latitudes in degrees between -90 and 90 + + fcMask : geometric_features.FeatureCollection + A feature collection containing features to use to create the mask + + logger : logging.Logger, optional + A logger for the output if not stdout + + pool : multiprocessing.Pool, optional + A pool for performing multiprocessing + + chunkSize : int, optional + The number of cells, vertices or edges that are processed in one + operation. Experimentation has shown that 1000 is a reasonable + compromise between dividing the work into sufficient subtasks to + distribute the load and having sufficient work for each thread. + + showProgress : bool, optional + Whether to show a progress bar + + subdivisionThreshold : float, optional + A threshold in degrees (lon or lat) above which the mask region will + be subdivided into smaller polygons for faster intersection checking + + Returns + ------- + dsMask : xarray.Dataset + The masks + + """ + + dsMasks = xr.Dataset() + + Lon, Lat = numpy.meshgrid(lon, lat) + + shape = Lon.shape + + Lon = Lon.ravel() + Lat = Lat.ravel() + + # create shapely geometry for lon and lat + points = [shapely.geometry.Point(x, y) for x, y in zip(Lon, Lat)] + regionNames, masks, properties, nChar = _compute_region_masks( + fcMask, points, logger, pool, chunkSize, showProgress, + subdivisionThreshold) + + nlon = len(lon) + nlat = len(lat) + + if logger is not None: + logger.info(' Adding masks to dataset...') + nRegions = len(regionNames) + # create a new data array for masks + masksVarName = 'regionMasks' + dsMasks[masksVarName] = \ + (('lat', 'lon', 'nRegions'), numpy.zeros((nlat, nlon, nRegions), + dtype=int)) + + for index in range(nRegions): + mask = masks[index] + dsMasks[masksVarName][:, :, index] = \ + numpy.array(mask.reshape(shape), dtype=int) + + # create a new data array for mask names + dsMasks['regionNames'] = (('nRegions',), + numpy.zeros((nRegions,), + dtype='|S{}'.format(nChar))) + + for index in range(nRegions): + dsMasks['regionNames'][index] = regionNames[index] + + for propertyName in properties: + if propertyName not in dsMasks: + dsMasks[propertyName] = (('nRegions',), + properties[propertyName]) + if logger is not None: + logger.info(' Done.') + + return dsMasks
+ + +def entry_point_compute_lon_lat_region_masks(): + """ Entry point for ``compute_lon_lat_region_masks()``""" + + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--grid_file_name", dest="grid_file_name", + type=str, required=True, + help="An input lon/lat grid file") + parser.add_argument("--lon", dest="lon", default="lon", type=str, + help="The name of the longitude coordinate") + parser.add_argument("--lat", dest="lat", default="lat", type=str, + help="The name of the latitude coordinate") + parser.add_argument("-g", "--geojson_file_name", + dest="geojson_file_name", type=str, required=True, + help="An Geojson file containing mask regions") + parser.add_argument("-o", "--mask_file_name", dest="mask_file_name", + type=str, required=True, + help="An output MPAS region masks file") + parser.add_argument("-c", "--chunk_size", dest="chunk_size", type=int, + default=1000, + help="The number of grid points that are " + "processed in one operation") + parser.add_argument("--show_progress", dest="show_progress", + action="store_true", + help="Whether to show a progress bar") + parser.add_argument("-s", "--subdivision", dest="subdivision", type=float, + default=30., + help="A threshold in degrees (lon or lat) above which " + "the mask region will be subdivided into smaller " + "polygons for faster intersection checking") + parser.add_argument( + "--process_count", required=False, dest="process_count", type=int, + help="The number of processes to use to compute masks. The " + "default is to use all available cores") + parser.add_argument( + "--multiprocessing_method", dest="multiprocessing_method", + default='forkserver', + help="The multiprocessing method use for python mask creation " + "('fork', 'spawn' or 'forkserver')") + parser.add_argument("--format", dest="format", type=str, + help="NetCDF file format") + parser.add_argument("--engine", dest="engine", type=str, + help="NetCDF output engine") + args = parser.parse_args() + + dsGrid = xr.open_dataset(args.grid_file_name, decode_cf=False, + decode_times=False) + lon = dsGrid[args.lon].values + lat = dsGrid[args.lat].values + + fcMask = read_feature_collection(args.geojson_file_name) + + pool = create_pool(process_count=args.process_count, + method=args.multiprocessing_method) + + with LoggingContext('compute_lon_lat_region_masks') as logger: + dsMasks = compute_lon_lat_region_masks( + lon=lon, lat=lat, fcMask=fcMask, logger=logger, pool=pool, + chunkSize=args.chunk_size, showProgress=args.show_progress, + subdivisionThreshold=args.subdivision) + + write_netcdf(dsMasks, args.mask_file_name, format=args.format, + engine=args.engine) + + +def compute_projection_grid_region_masks( + lon, lat, fcMask, logger=None, pool=None, chunkSize=1000, + showProgress=False, subdivisionThreshold=30., xdim='x', ydim='y'): + """ + Use shapely and processes to create a set of masks from a feature + collection made up of regions (polygons) on a projection grid such as + a polar-stereographic grid. + + Parameters + ---------- + lon : numpy.ndarray + A 2D array of longitudes in degrees between -180 and 180 + + lat : numpy.ndarray + A 2D array of latitudes in degrees between -90 and 90 + + fcMask : geometric_features.FeatureCollection + A feature collection containing features to use to create the mask + + logger : logging.Logger, optional + A logger for the output if not stdout + + pool : multiprocessing.Pool, optional + A pool for performing multiprocessing + + chunkSize : int, optional + The number of cells, vertices or edges that are processed in one + operation. Experimentation has shown that 1000 is a reasonable + compromise between dividing the work into sufficient subtasks to + distribute the load and having sufficient work for each thread. + + showProgress : bool, optional + Whether to show a progress bar + + subdivisionThreshold : float, optional + A threshold in degrees (lon or lat) above which the mask region will + be subdivided into smaller polygons for faster intersection checking + + xdim : str, optional + The name of the x dimension + + ydim : str, optional + The name of the y dimension + + Returns + ------- + dsMask : xarray.Dataset + The masks + + """ + + dsMasks = xr.Dataset() + + # make sure -180 <= lon < 180 + lon = numpy.mod(lon + 180., 360.) - 180. + + ny, nx = lon.shape + + # create shapely geometry for lon and lat + points = [shapely.geometry.Point(x, y) for x, y in + zip(lon.ravel(), lat.ravel())] + regionNames, masks, properties, nChar = _compute_region_masks( + fcMask, points, logger, pool, chunkSize, showProgress, + subdivisionThreshold) + + if logger is not None: + logger.info(' Adding masks to dataset...') + nRegions = len(regionNames) + # create a new data array for masks + masksVarName = 'regionMasks' + dsMasks[masksVarName] = \ + ((ydim, xdim, 'nRegions'), numpy.zeros((ny, nx, nRegions), dtype=int)) + + for index in range(nRegions): + mask = masks[index] + dsMasks[masksVarName][:, :, index] = \ + numpy.array(mask.reshape((ny, nx)), dtype=int) + + # create a new data array for mask names + dsMasks['regionNames'] = (('nRegions',), + numpy.zeros((nRegions,), + dtype='|S{}'.format(nChar))) + + for index in range(nRegions): + dsMasks['regionNames'][index] = regionNames[index] + + for propertyName in properties: + if propertyName not in dsMasks: + dsMasks[propertyName] = (('nRegions',), + properties[propertyName]) + if logger is not None: + logger.info(' Done.') + + return dsMasks + + +def entry_point_compute_projection_grid_region_masks(): + """ Entry point for ``compute_projection_grid_region_masks()``""" + + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--grid_file_name", dest="grid_file_name", + type=str, required=True, + help="An input lon/lat grid file") + parser.add_argument("--lon", dest="lon", default="lon", type=str, + help="The name of the 2D longitude coordinate") + parser.add_argument("--lat", dest="lat", default="lat", type=str, + help="The name of the 2D latitude coordinate") + parser.add_argument("-g", "--geojson_file_name", + dest="geojson_file_name", type=str, required=True, + help="An Geojson file containing mask regions") + parser.add_argument("-o", "--mask_file_name", dest="mask_file_name", + type=str, required=True, + help="An output MPAS region masks file") + parser.add_argument("-c", "--chunk_size", dest="chunk_size", type=int, + default=1000, + help="The number of grid points that are " + "processed in one operation") + parser.add_argument("--show_progress", dest="show_progress", + action="store_true", + help="Whether to show a progress bar") + parser.add_argument("-s", "--subdivision", dest="subdivision", type=float, + default=30., + help="A threshold in degrees (lon or lat) above which " + "the mask region will be subdivided into smaller " + "polygons for faster intersection checking") + parser.add_argument( + "--process_count", required=False, dest="process_count", type=int, + help="The number of processes to use to compute masks. The " + "default is to use all available cores") + parser.add_argument( + "--multiprocessing_method", dest="multiprocessing_method", + default='forkserver', + help="The multiprocessing method use for python mask creation " + "('fork', 'spawn' or 'forkserver')") + parser.add_argument("--format", dest="format", type=str, + help="NetCDF file format") + parser.add_argument("--engine", dest="engine", type=str, + help="NetCDF output engine") + args = parser.parse_args() + + dsGrid = xr.open_dataset(args.grid_file_name, decode_cf=False, + decode_times=False) + lon = dsGrid[args.lon] + lat = dsGrid[args.lat] + + ydim, xdim = lon.dims + + fcMask = read_feature_collection(args.geojson_file_name) + + pool = create_pool(process_count=args.process_count, + method=args.multiprocessing_method) + + with LoggingContext('compute_lon_lat_region_masks') as logger: + dsMasks = compute_projection_grid_region_masks( + lon=lon.values, lat=lat.values, fcMask=fcMask, logger=logger, + pool=pool, chunkSize=args.chunk_size, + showProgress=args.show_progress, + subdivisionThreshold=args.subdivision, xdim=xdim, ydim=ydim) + + write_netcdf(dsMasks, args.mask_file_name, format=args.format, + engine=args.engine) + + +def _compute_mask_from_shapes(shapes1, shapes2, func, pool, chunkSize, + showProgress): + """ + If multiprocessing, break shapes2 into chunks and use multiprocessing to + apply the given function one chunk at a time + """ + nShapes2 = len(shapes2) + if pool is None: + mask = func(shapes1, shapes2) + else: + nChunks = int(numpy.ceil(nShapes2 / chunkSize)) + chunks = [] + indices = [0] + for iChunk in range(nChunks): + start = iChunk * chunkSize + end = min((iChunk + 1) * chunkSize, nShapes2) + chunks.append(shapes2[start:end]) + indices.append(end) + + partial_func = partial(func, shapes1) + if showProgress: + widgets = [' ', progressbar.Percentage(), ' ', + progressbar.Bar(), ' ', progressbar.ETA()] + bar = progressbar.ProgressBar(widgets=widgets, + maxval=nChunks).start() + else: + bar = None + + mask = numpy.zeros((nShapes2,), bool) + for iChunk, maskChunk in \ + enumerate(pool.imap(partial_func, chunks)): + mask[indices[iChunk]:indices[iChunk + 1]] = maskChunk + if showProgress: + bar.update(iChunk + 1) + if showProgress: + bar.finish() + return mask + + +def _get_region_names_and_properties(fc): + regionNames = [] + for feature in fc.features: + name = feature['properties']['name'] + regionNames.append(name) + + propertyNames = set() + for feature in fc.features: + for propertyName in feature['properties']: + if propertyName not in ['name', 'author', 'tags', 'component', + 'object']: + propertyNames.add(propertyName) + + properties = {} + for propertyName in propertyNames: + properties[propertyName] = [] + for feature in fc.features: + if propertyName in feature['properties']: + propertyVal = feature['properties'][propertyName] + properties[propertyName].append(propertyVal) + else: + properties[propertyName].append('') + + return regionNames, properties + + +def _compute_region_masks(fcMask, points, logger, pool, chunkSize, + showProgress, threshold): + """ + Build a region mask file from the given mesh and geojson file defining + a set of regions. + """ + + regionNames, properties = _get_region_names_and_properties(fcMask) + + masks = [] + + nChar = 0 + for feature in fcMask.features: + name = feature['properties']['name'] + + if logger is not None: + logger.info(' {}'.format(name)) + + shape = shapely.geometry.shape(feature['geometry']) + shapes = _katana(shape, threshold=threshold) + + mask = _compute_mask_from_shapes( + shapes1=shapes, shapes2=points, func=_contains, + pool=pool, chunkSize=chunkSize, showProgress=showProgress) + + nChar = max(nChar, len(name)) + + masks.append(mask) + + return regionNames, masks, properties, nChar + + +def _contains(shapes, points): + tree = STRtree(points) + mask = numpy.zeros(len(points), dtype=bool) + for shape in shapes: + indicesInShape = tree.query(shape, predicate='covers') + mask[indicesInShape] = True + return mask + + +def _katana(geometry, threshold, count=0, maxcount=250): + """ + From https://snorfalorpagus.net/blog/2016/03/13/splitting-large-polygons-for-faster-intersections/ + + Split a Polygon into two parts across it's shortest dimension + + Copyright (c) 2016, Joshua Arnott + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + """ + bounds = geometry.bounds + width = bounds[2] - bounds[0] + height = bounds[3] - bounds[1] + if max(width, height) <= threshold or count == maxcount: + # either the polygon is smaller than the threshold, or the maximum + # number of recursions has been reached + return [geometry] + if height >= width: + # split left to right + a = box(bounds[0], bounds[1], bounds[2], bounds[1]+height/2) + b = box(bounds[0], bounds[1]+height/2, bounds[2], bounds[3]) + else: + # split top to bottom + a = box(bounds[0], bounds[1], bounds[0]+width/2, bounds[3]) + b = box(bounds[0]+width/2, bounds[1], bounds[2], bounds[3]) + result = [] + for d in (a, b,): + c = geometry.intersection(d) + if isinstance(c, GeometryCollection): + c = c.geoms + else: + c = [c] + for e in c: + if isinstance(e, (Polygon, MultiPolygon)): + result.extend(_katana(e, threshold, count+1, maxcount)) + if count > 0: + return result + # convert multipart into singlepart + final_result = [] + for g in result: + if isinstance(g, MultiPolygon): + final_result.extend(g.geoms) + else: + final_result.append(g) + return final_result + + +def _compute_transect_masks(fcMask, polygons, logger, pool, chunkSize, + showProgress, subdivisionResolution, earthRadius): + """ + Build a transect mask file from the given mesh and geojson file defining + a set of transects. + """ + + transectNames, properties = _get_region_names_and_properties(fcMask) + + masks = [] + shapes = [] + + nChar = 0 + for feature in fcMask.features: + name = feature['properties']['name'] + + if logger is not None: + logger.info(' {}'.format(name)) + + geom_type = feature['geometry']['type'] + if geom_type == 'LineString': + coordinates = [feature['geometry']['coordinates']] + elif geom_type == 'MultiLineString': + coordinates = feature['geometry']['coordinates'] + else: + raise ValueError('Unexpected geometry type {}'.format(geom_type)) + + new_coords = [] + for coord_index, coords in enumerate(coordinates): + + if subdivisionResolution is None: + new_coords.append(coords) + else: + lon, lat = zip(*coords) + x, y, z = lon_lat_to_cartesian( + lon, lat, earthRadius, degrees=True) + x, y, z, _, _ = subdivide_great_circle( + x, y, z, subdivisionResolution, earthRadius) + lon, lat = cartesian_to_lon_lat( + x, y, z, earthRadius, degrees=True) + new_coords.append([list(a) for a in zip(lon, lat)]) + + if geom_type == 'LineString': + shape = shapely.geometry.LineString(new_coords[0]) + else: + shape = shapely.geometry.MultiLineString(new_coords) + + mask = _compute_mask_from_shapes( + shapes1=shape, shapes2=polygons, func=_intersects, + pool=pool, chunkSize=chunkSize, showProgress=showProgress) + + nChar = max(nChar, len(name)) + + masks.append(mask) + shapes.append(shape) + + return transectNames, masks, properties, nChar, shapes + + +def _intersects(shape, polygons): + tree = STRtree(polygons) + mask = numpy.zeros(len(polygons), dtype=bool) + indicesInShape = tree.query(shape, predicate='intersects') + mask[indicesInShape] = True + return mask + + +def _get_polygons(dsMesh, maskType): + if maskType == 'cell': + # polygons are vertices on cell + vertexIndices = dsMesh.verticesOnCell.values - 1 + nVerticesOnCell = dsMesh.nEdgesOnCell.values + maxVertices = vertexIndices.shape[1] + for iVertex in range(maxVertices): + mask = iVertex >= nVerticesOnCell + # copy the last valid vertex + vertexIndices[mask, iVertex] = \ + vertexIndices[mask, nVerticesOnCell[mask]-1] + lonVertex = dsMesh.lonVertex.values + latVertex = dsMesh.latVertex.values + lonCenter = dsMesh.lonCell.values + elif maskType == 'vertex': + # polygons are cells on vertex + vertexIndices = dsMesh.cellsOnVertex.values - 1 + maxVertices = vertexIndices.shape[1] + firstValid = vertexIndices[:, 0] + for iVertex in range(1, maxVertices): + mask = firstValid < 0 + firstValid[mask] = vertexIndices[mask, iVertex] + assert(numpy.all(firstValid >= 0)) + for iVertex in range(maxVertices): + mask = vertexIndices[:, iVertex] < 0 + vertexIndices[mask, iVertex] = firstValid[mask] + lonVertex = dsMesh.lonCell.values + latVertex = dsMesh.latCell.values + lonCenter = dsMesh.lonVertex.values + elif maskType == 'edge': + # oh, dear, this is a bit more complicated. Polygons are kites + # involving both vertices and cell centers + verticesOnEdge = dsMesh.verticesOnEdge - 1 + cellsOnEdge = dsMesh.cellsOnEdge - 1 + + nEdges = dsMesh.sizes['nEdges'] + nCells = dsMesh.sizes['nCells'] + vertexIndices = -1 * numpy.ones((nEdges, 4), int) + vertexIndices[:, 0] = cellsOnEdge[:, 0] + vertexIndices[:, 1] = verticesOnEdge[:, 0] + nCells + vertexIndices[:, 2] = cellsOnEdge[:, 1] + vertexIndices[:, 3] = verticesOnEdge[:, 1] + nCells + + # if there are invalid cells, just point to the next vertex; all + # vertices on cell should be valid + mask = vertexIndices[:, 0] < 0 + vertexIndices[mask, 0] = vertexIndices[mask, 1] + + mask = vertexIndices[:, 2] < 0 + vertexIndices[mask, 2] = vertexIndices[mask, 3] + + lonVertex = numpy.append(dsMesh.lonCell.values, + dsMesh.lonVertex.values) + latVertex = numpy.append(dsMesh.latCell.values, + dsMesh.latVertex.values) + + lonCenter = dsMesh.lonEdge.values + + else: + raise ValueError('Unknown mask type {}'.format(maskType)) + + assert numpy.all(vertexIndices >= 0) + + latVertex = numpy.rad2deg(latVertex) + # transform longitudes to [-180, 180) + lonVertex = numpy.mod(numpy.rad2deg(lonVertex) + 180., 360.) - 180. + lonCenter = numpy.mod(numpy.rad2deg(lonCenter) + 180., 360.) - 180. + + lon = lonVertex[vertexIndices] + lat = latVertex[vertexIndices] + + lon, lat, duplicatePolygons = _copy_dateline_lon_lat_vertices(lon, lat, + lonCenter) + + nPolygons = len(lonCenter) + + polygons = [] + for index in range(lon.shape[0]): + coords = zip(lon[index, :], lat[index, :]) + polygons.append(shapely.geometry.Polygon(coords)) + + return polygons, nPolygons, duplicatePolygons + + +def _copy_dateline_lon_lat_vertices(lonVertex, latVertex, lonCenter): + + nPolygons, _ = lonVertex.shape + + lonDiff = lonVertex - lonCenter.reshape(nPolygons, 1) + + # which polygons have vertices that are out of range to the west? + outOfRange = lonDiff < -180. + duplicatePolygonsEast = numpy.flatnonzero(numpy.any(outOfRange, axis=1)) + lonVertex[outOfRange] += 360. + lonVertexToAdd = lonVertex[duplicatePolygonsEast, :] - 360. + latVertexToAdd = latVertex[duplicatePolygonsEast, :] + + # which polygons have vertices that are out of range to the east? + outOfRange = lonDiff >= 180. + duplicatePolygonsWest = numpy.flatnonzero(numpy.any(outOfRange, axis=1)) + lonVertex[outOfRange] -= 360. + lonVertexToAdd = numpy.append(lonVertexToAdd, + lonVertex[duplicatePolygonsWest, :] + 360., + axis=0) + latVertexToAdd = numpy.append(latVertexToAdd, + latVertex[duplicatePolygonsWest, :], + axis=0) + + lonVertex = numpy.append(lonVertex, lonVertexToAdd, axis=0) + latVertex = numpy.append(latVertex, latVertexToAdd, axis=0) + + duplicatePolygons = numpy.append(duplicatePolygonsEast, + duplicatePolygonsWest) + + # TODO: we still need to do something about cells that contain the poles + + return lonVertex, latVertex, duplicatePolygons + + +def _compute_seed_mask(fcSeed, lon, lat, workers): + """ + Find the cell centers (points) closes to the given seed points and set + the resulting mask to 1 there + """ + points = numpy.vstack((lon, lat)).T + + tree = KDTree(points) + + mask = numpy.zeros(len(lon), dtype=int) + + points = numpy.zeros((len(fcSeed.features), 2)) + for index, feature in enumerate(fcSeed.features): + points[index, :] = feature['geometry']['coordinates'] + + _, indices = tree.query(points, workers=workers) + + for index in indices: + mask[index] = 1 + + return mask + + +def _flood_fill_mask(mask, cellsOnCell): + """ + Flood fill starting with a mask of seed points + """ + + maxNeighbors = cellsOnCell.shape[1] + + while True: + neighbors = cellsOnCell[mask == 1, :] + maskCount = 0 + for iNeighbor in range(maxNeighbors): + indices = neighbors[:, iNeighbor] + # we only want to mask valid neighbors and locations that aren't + # already masked + indices = indices[indices >= 0] + localMask = mask[indices] == 0 + maskCount += numpy.count_nonzero(localMask) + indices = indices[localMask] + mask[indices] = 1 + + if maskCount == 0: + break + + return mask + + +def _compute_edge_sign(dsMesh, edgeMask, shape): + """ Compute the edge sign along a transect """ + + edge_indices = numpy.flatnonzero(edgeMask) + voe = dsMesh.verticesOnEdge.isel(nEdges=edge_indices).values - 1 + + lon = numpy.rad2deg(dsMesh.lonVertex.values[voe]) + lon = numpy.mod(lon + 180., 360.) - 180. + lat = numpy.rad2deg(dsMesh.latVertex.values[voe]) + + lonEdge = numpy.rad2deg(dsMesh.lonEdge.values[edge_indices]) + lonEdge = numpy.mod(lonEdge + 180., 360.) - 180. + + lon, lat, duplicate_edges = \ + _copy_dateline_lon_lat_vertices(lon, lat, lonEdge) + + nEdges = dsMesh.sizes['nEdges'] + nVertices = dsMesh.sizes['nVertices'] + + # give periodic copies unique edge and vertex indices + edge_indices = numpy.append(edge_indices, + edge_indices[duplicate_edges] + nEdges) + + voe = numpy.append(voe, voe[duplicate_edges, :] + nVertices, axis=0) + + unique_vertices = numpy.unique(voe.ravel()) + + local_voe = numpy.zeros(voe.shape, dtype=int) + distance = [] + unique_lon = [] + unique_lat = [] + for local_v, v in enumerate(unique_vertices): + local_mask = voe == v + + x = lon[local_mask][0] + y = lat[local_mask][0] + distance.append(shape.project(shapely.geometry.Point(x, y))) + unique_lon.append(x) + unique_lat.append(y) + + local_voe[local_mask] = local_v + + graph = Graph(n=len(unique_vertices), + edges=zip(local_voe[:, 0], local_voe[:, 1])) + graph.vs['distance'] = distance + graph.vs['lon'] = unique_lon + graph.vs['lat'] = unique_lat + graph.vs['vertices'] = numpy.arange(len(unique_vertices)) + graph.es['edges'] = edge_indices + graph.es['vertices'] = [(v0, v1) for v0, v1 in zip(voe[:, 0], voe[:, 1])] + + edgeSign = numpy.zeros(edgeMask.shape, dtype=int) + + clusters = graph.connected_components() + for cluster_index in range(len(clusters)): + cluster = clusters.subgraph(cluster_index) + distance = cluster.vs['distance'] + if len(cluster.es) == 1: + edges = cluster.es.select(0) + edge = edges[0] + if edge.source_vertex['distance'] < edge.target_vertex['distance']: + sign = [1] + else: + sign = [-1] + else: + start = numpy.argmin(distance) + end = numpy.argmax(distance) + indices = \ + cluster.get_shortest_paths(v=start, to=end, output='epath')[0] + edges = cluster.es.select(indices) + if len(edges) == 1: + edge = edges[0] + if edge.source_vertex['distance'] < \ + edge.target_vertex['distance']: + sign = [1] + else: + sign = [-1] + else: + verts = numpy.array(edges['vertices']) + sign = numpy.zeros(len(indices), dtype=int) + for index in range(len(indices)-1): + if verts[index, 1] in verts[index+1, :]: + sign[index] = 1 + elif verts[index, 0] in verts[index+1, :]: + sign[index] = -1 + else: + raise ValueError('could not find vertex ' + '{}'.format(index)) + + if verts[-1, 0] in verts[-2, :]: + sign[-1] = 1 + elif verts[-1, 1] in verts[-2, :]: + sign[-1] = -1 + else: + raise ValueError('could not find vertex -1') + + sign = numpy.array(sign) + edge_indices = numpy.array(edges['edges']) + valid = numpy.array(edge_indices) < nEdges + edgeSign[edge_indices[valid]] = sign[valid] + duplicate = numpy.logical_not(valid) + edgeSign[edge_indices[duplicate] - nEdges] = sign[duplicate] + + return edgeSign +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/build_mesh.html b/0.22.0rc4/_modules/mpas_tools/ocean/build_mesh.html new file mode 100644 index 000000000..db7326988 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/build_mesh.html @@ -0,0 +1,312 @@ + + + + + + mpas_tools.ocean.build_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.ocean.build_mesh

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+from mpas_tools.mesh.creation import build_spherical_mesh as \
+    create_spherical_mesh
+from mpas_tools.mesh.creation import build_planar_mesh as create_planar_mesh
+from mpas_tools.cime.constants import constants
+from mpas_tools.ocean.inject_bathymetry import inject_bathymetry
+from mpas_tools.ocean.inject_meshDensity import inject_spherical_meshDensity, \
+    inject_planar_meshDensity
+from mpas_tools.ocean.inject_preserve_floodplain import \
+    inject_preserve_floodplain
+from mpas_tools.viz.paraview_extractor import extract_vtk
+from mpas_tools.logging import LoggingContext
+
+
+
[docs]def build_spherical_mesh(cellWidth, lon, lat, out_filename='base_mesh.nc', + plot_cellWidth=True, vtk_dir='base_mesh_vtk', + preserve_floodplain=False, floodplain_elevation=20.0, + do_inject_bathymetry=False, logger=None, + use_progress_bar=True): + """ + Build an MPAS mesh using JIGSAW with the given cell sizes as a function of + latitude and longitude + + The result is a mesh file stored in ``out_filename`` as well as several + intermediate files: ``mesh.log``, ``mesh-HFUN.msh``, ``mesh.jig``, + ``mesh-MESH.msh``, ``mesh.msh``, and ``mesh_triangles.nc``. + + Parameters + ---------- + cellWidth : ndarray + m x n array of cell width in km + + lon : ndarray + longitude in degrees (length n and between -180 and 180) + + lat : ndarray + longitude in degrees (length m and between -90 and 90) + + out_filename : str, optional + The file name of the resulting MPAS mesh + + plot_cellWidth : bool, optional + Whether to produce a plot of ``cellWidth``. If so, it will be written + to ``cellWidthGlobal.png``. + + vtk_dir : str, optional + The name of the directory where mesh data will be extracted for viewing + in ParaVeiw. + + preserve_floodplain : bool, optional + Whether a flood plain (bathymetry above z = 0) should be preserved in + the mesh + + floodplain_elevation : float, optional + The elevation in meters to which the flood plain is preserved + + do_inject_bathymetry : bool, optional + Whether one of the default bathymetry datasets, ``earth_relief_15s.nc`` + or ``topo.msh``, should be added to the MPAS mesh + + logger : logging.Logger, optional + A logger for the output if not stdout + + use_progress_bar : bool, optional + Whether to display progress bars (problematic in logging to a file) + """ + + with LoggingContext(__name__, logger=logger) as logger: + + earth_radius = constants['SHR_CONST_REARTH'] + + create_spherical_mesh(cellWidth, lon, lat, earth_radius, out_filename, + plot_cellWidth, logger=logger) + + logger.info('Step 4. Inject meshDensity into the mesh file') + inject_spherical_meshDensity(cellWidth, lon, lat, + mesh_filename=out_filename) + + _shared_steps(out_filename, vtk_dir, preserve_floodplain, + floodplain_elevation, do_inject_bathymetry, logger, + use_progress_bar)
+ + +
[docs]def build_planar_mesh(cellWidth, x, y, geom_points, geom_edges, + out_filename='base_mesh.nc', vtk_dir='base_mesh_vtk', + preserve_floodplain=False, floodplain_elevation=20.0, + do_inject_bathymetry=False, logger=None, + use_progress_bar=True): + """ + Build a planar MPAS mesh + + Parameters + ---------- + cellWidth : ndarray + m x n array of cell width in km + + x, y : ndarray + arrays defining planar coordinates in meters + + geom_points : ndarray + list of point coordinates for bounding polygon for the planar mesh + + geom_edges : ndarray + list of edges between points in ``geom_points`` that define the + bounding polygon + + out_filename : str, optional + The file name of the resulting MPAS mesh + + vtk_dir : str, optional + The name of the directory where mesh data will be extracted for viewing + in ParaVeiw. + + preserve_floodplain : bool, optional + Whether a flood plain (bathymetry above z = 0) should be preserved in + the mesh + + floodplain_elevation : float, optional + The elevation in meters to which the flood plain is preserved + + do_inject_bathymetry : bool, optional + Whether one of the default bathymetry datasets, ``earth_relief_15s.nc`` + or ``topo.msh``, should be added to the MPAS mesh + + logger : logging.Logger, optional + A logger for the output if not stdout + + use_progress_bar : bool, optional + Whether to display progress bars (problematic in logging to a file) + """ + + with LoggingContext(__name__, logger=logger) as logger: + + create_planar_mesh(cellWidth, x, y, geom_points, geom_edges, + out_filename, logger=logger) + + logger.info('Step 4. Inject meshDensity into the mesh file') + inject_planar_meshDensity(cellWidth, x, y, mesh_filename=out_filename) + + _shared_steps(out_filename, vtk_dir, preserve_floodplain, + floodplain_elevation, do_inject_bathymetry, logger, + use_progress_bar)
+ + +def _shared_steps(out_filename, vtk_dir, preserve_floodplain, + floodplain_elevation, do_inject_bathymetry, logger, + use_progress_bar): + step = 5 + + if do_inject_bathymetry: + logger.info('Step {}. Injecting bathymetry'.format(step)) + inject_bathymetry(mesh_file=out_filename) + step += 1 + + if preserve_floodplain: + logger.info('Step {}. Injecting flag to preserve floodplain'.format( + step)) + inject_preserve_floodplain(mesh_file=out_filename, + floodplain_elevation=floodplain_elevation) + step += 1 + + logger.info('Step {}. Create vtk file for visualization'.format(step)) + extract_vtk(ignore_time=True, lonlat=True, dimension_list=['maxEdges='], + variable_list=['allOnCells'], filename_pattern=out_filename, + out_dir=vtk_dir, use_progress_bar=use_progress_bar) + + logger.info("***********************************************") + logger.info("** The global mesh file is {} **".format(out_filename)) + logger.info("***********************************************") +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/coastal_tools.html b/0.22.0rc4/_modules/mpas_tools/ocean/coastal_tools.html new file mode 100644 index 000000000..190b55241 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/coastal_tools.html @@ -0,0 +1,1315 @@ + + + + + + mpas_tools.ocean.coastal_tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.ocean.coastal_tools

+#!/usr/bin/env python
+"""
+name: coastal_tools
+authors: Steven Brus
+
+last modified: 07/09/2018
+
+"""
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy as np
+from skimage import measure
+from netCDF4 import Dataset
+import matplotlib.pyplot as plt
+from scipy.spatial import KDTree
+from scipy.io import savemat
+import timeit
+import cartopy.crs as ccrs
+import cartopy.feature as cfeature
+import mpas_tools.mesh.creation.mesh_definition_tools as mdt
+from mpas_tools.mesh.creation.util import lonlat2xyz
+
+# Constants
+km = 1000.0
+deg2rad = np.pi / 180.0
+rad2deg = 180.0 / np.pi
+
+call_count = 0
+
+##########################################################################
+# Bounding box declarations (for coastal refinements)
+##########################################################################
+
+# ---------------
+# Region boxes
+# ---------------
+
+# Bays and estuaries
+Delaware_Bay = {"include": [np.array([-75.61903, -74.22, 37.8, 40.312747])],
+                "exclude": []}
+Galveston_Bay = {"include": [np.array([-95.45, -94.4, 29, 30])],
+                 "exclude": []}
+
+# Regions
+Delaware_Region = {"include": [np.array([-77, -69.8, 35.5, 41])],
+                   "exclude": []}
+
+# Coastlines
+US_East_Coast = {"include": [np.array([-81.7, -62.3, 25.1, 44.50])],  # East FL to Bay of Fundy
+                 "exclude": [np.array([-66.0, -64.0, 31.5, 33.0]),    # Bermuda
+                             np.array([-79.75, -70.0, 20.0, 28.5]),   # Bahamas
+                             np.array([-65.15, -62.43, 43.0, 45.55]), # Gulf of St. Lawence
+                             np.array([-66.65, -62.43, 43.0, 45.0])]} # ''
+
+US_Gulf_Coast = {"include": [np.array([-98.0, -80.0, 24.0, 31.0]),    # West FL to NE Mexico
+                             np.array([-98.5, -95.5, 20.0, 24.0]),    # East Mexico
+                             np.array([-91.0, -86.0, 20.0, 22.0])     # Yucatan
+                             ],
+                 "exclude": []}
+
+Caribbean = {"include": [np.array([-89.85, -59.73, 9.35, 20.86]),
+                         ],
+             "exclude": []}
+
+US_West_Coast = {"include": [np.array([-127.0, -116.0, 32.5, 49.0]),  # California
+                             np.array([-117.5, -108.0, 22.8, 32.5])   # Baja and West Mexico
+                             ],
+                 "exclude": [np.array([-116.5, -115.0, 32.8, 33.8]),  # Salton Sea
+                             np.array([-120.5, -116.5, 35.5, 40.5]),  # Lake Tahoe, etc.
+                             np.array([[-111.89, 21.24],              # Baja
+                                       [-107.17, 22.48],
+                                       [-113.94, 30.77],
+                                       [-119.44, 33.09]])]}
+
+Hawaii = {"include": [np.array([-161.0, -154.0, 18.0, 23.0])],
+          "exclude": []}
+
+Alaska = {"include": [np.array([-170.0, -141.0, 49.0, 63.0]),
+                      np.array([-141.0, -129.5, 49.0, 61.0]),  # Southeast
+                      np.array([-129.5, -121.0, 49.0, 55.0])   # Connects AK to CA
+                      ],
+          "exclude": [np.array([-171.0, -151.79, 49.54, 58.83])]}  # Aleutian Islands
+
+Bering_Sea_E = {"include": [np.array([-180.0, -168.5, 56.00, 64.0])],
+                "exclude": []}
+
+Bering_Sea_W = {"include": [np.array([161.90, 180.0, 57.85, 66.63])],
+                "exclude": []}
+
+Aleutian_Islands_E = {"include": [np.array([-180.0, -151.79, 49.54, 58.83])],
+                      "exclude": [np.array([-173.16, -164.37, 55.81, 57.55])]}
+
+Aleutian_Islands_W = {"include": [np.array([164.9, 180.0, 50.77, 56.31])],
+                      "exclude": [np.array([178.5, 179.5, 51.25, 51.75])]}
+
+Greenland = {"include":[np.array([-81.5,-12.5,60,85])],
+             "exclude":[np.array([[-87.6,58.7],
+                                  [-51.9,56.6],
+                                  [-68.9,75.5],
+                                  [-107.0,73.3]]),
+                        np.array([[-119.0,74.5],
+                                  [-92.7,75.9],
+                                  [-52.84,83.25],
+                                  [-100.8,84.0]]),
+                        np.array([[-101.3,68.5],
+                                  [-82.4,72.3],
+                                  [-68.7,81.24],
+                                  [-117.29,77.75]]),
+                        np.array([-25.0,-10.0,62.5,67.5])]}
+Atlantic = {"include": [np.array([-78.5, -77.5, 23.5, 25.25])],  # Bahamas, use with large transition start to fill Atlantic
+            "exclude": []}
+
+# Combined coastlines
+CONUS = {"include": [], "exclude": []}
+CONUS["include"].extend(US_East_Coast["include"])
+CONUS["include"].extend(US_Gulf_Coast["include"])
+CONUS["include"].extend(US_West_Coast["include"])
+CONUS["exclude"].extend(US_East_Coast["exclude"])
+CONUS["exclude"].extend(US_West_Coast["exclude"])
+
+Continental_US = {"include": [], "exclude": []}
+Continental_US["include"].extend(CONUS["include"])
+Continental_US["include"].extend(Alaska["include"])
+Continental_US["exclude"].extend(CONUS["exclude"])
+
+# ----------------
+# Plotting boxes
+# ----------------
+
+Western_Atlantic = np.array([-98.186645, -59.832744, 7.791301, 45.942453])
+Contiguous_US = np.array([-132.0, -59.832744, 7.791301, 51.0])
+North_America = np.array([-175.0, -60.0, 7.5, 72.0])
+Delaware = np.array([-77, -69.8, 35.5, 41])
+Entire_Globe = np.array([-180, 180, -90, 90])
+
+# -----------------
+# Restrict Boxes
+# -----------------
+
+Empty = {"include": [],
+         "exclude": []}
+
+Delaware_restrict = {"include": [np.array([[-75.853, 39.732],
+                                           [-74.939, 36.678],
+                                           [-71.519, 40.156],
+                                           [-75.153, 40.077]]),
+                                 np.array([[-76.024, 37.188],
+                                           [-75.214, 36.756],
+                                           [-74.512, 37.925],
+                                           [-75.274, 38.318]])],
+                     "exclude": []}
+
+Gulf_restrict = {"include": [np.array([[-85.04, 13.80],
+                                       [-76.90, 16.60],
+                                       [-86.24, 36.80],
+                                       [-105.55, 22.63]])],
+                 "exclude": []}
+
+Caribbean_restrict = {"include": [np.array([[-76.39, 4.55],
+                                            [-53.22, 4.29],
+                                            [-53.22, 38.94],
+                                            [-94.99, 18.47]])],
+                      "exclude": [np.array([[-80.72, 1.66],
+                                            [-73.70, 3.03],
+                                            [-78.94, 9.33],
+                                            [-84.98, 7.67]]),
+                                  np.array([[-100.18, 13.76],
+                                            [-82.93, 6.51],
+                                            [-85.08, 13.74],
+                                            [-95.86, 18.04]])]}
+
+East_Coast_restrict = {"include": [],
+                       "exclude": [np.array([[-72.0, 46.69],
+                                             [-61.74, 45.48],
+                                             [-44.07, 49.49],
+                                             [-63.47, 53.76]])]}
+Bering_Sea_restrict = {"include": [],
+                       "exclude": [np.array([[143.46, 51.79],
+                                             [155.65, 50.13],
+                                             [166.23, 63.78],
+                                             [148.63, 62.30]]),
+                                   np.array([[154.36, 68.22],
+                                             [-173.80, 65.94],
+                                             [-161.81, 72.02],
+                                             [163.64, 73.70]])]}
+
+Atlantic_restrict = {"include": [np.array([[-86.39, 13.67],
+                                           [-24.44, 21.32],
+                                           [-50.09, 55.98],
+                                           [-105.58, 23.61]]),
+                                 np.array([[-76.39, 4.55],
+                                           [-30.74, -2.66],
+                                           [-30.83, 43.95],
+                                           [-94.99, 18.47]])],
+                     "exclude": [np.array([[-80.72, 1.66],
+                                           [-73.70, 3.03],
+                                           [-78.94, 9.33],
+                                           [-84.98, 7.67]]),
+                                 np.array([[-100.18, 13.76],
+                                           [-82.93, 6.51],
+                                           [-85.08, 13.74],
+                                           [-95.86, 18.04]])]}
+
+##########################################################################
+# User-defined inputs
+##########################################################################
+
+default_params = {
+
+    # Path to bathymetry data and name of file
+    "nc_file": "./earth_relief_15s.nc",
+    "nc_vars": ["lon","lat","z"],
+
+    # Bounding box of coastal refinement region
+    "region_box": Continental_US,
+    "origin": np.array([-100, 40]),
+    "restrict_box": Empty,
+
+    # Coastline extraction parameters
+    "z_contour": 0.0,
+    "n_longest": 10,
+    "smooth_coastline": 0,
+    "point_list": None,
+
+    # Global mesh parameters
+    "grd_box": Entire_Globe,
+    "ddeg": .1,
+    # 'EC' (defaults to 60to30), 'QU' (uses dx_max_global), 'RRS' (uses dx_max_global and dx_min_global)
+    "mesh_type": 'EC',
+    "dx_max_global": 30.0 * km,
+    "dx_min_global": 10.0 * km,
+
+    # Coastal mesh parameters
+    "dx_min_coastal": 10.0 * km,
+    "trans_width": 600.0 * km,
+    "trans_start": 400.0 * km,
+
+    # Bounding box of plotting region
+    "plot_box": North_America,
+
+    # Options
+    "nn_search": "kdtree",
+    "plot_option": True
+
+}
+
+##########################################################################
+# Functions
+##########################################################################
+
+
+
[docs]def coastal_refined_mesh(params, cell_width=None, lon_grd=None, lat_grd=None): + # {{{ + """ + Optionally create a background field of cell widths, then add a region of + refined resolution to the cell widths. + + Parameters + ---------- + params : dict + A dictionary of parameters determining how the mesh is constructed. + See ``mpas_tools.ocean.coastal_tools.default_params``. + + cell_width : ndarray, optional + A 2D array of cell widths in meters. If none is provided, one a base + ``cell_width`` field constructed using parameter values from ``params`` + to call ``create_background_mesh``. + + lon_grd : ndarray, optional + A 1D array of longitudes in degrees in the range from -180 to 180 + + lat_grd : ndarray, optional + A 1D array of latitudes in degrees in the range from -90 to 90 + + Returns + ------- + cell_width : ndarray + A 2D array of cell widths in meters. + + lon_grd : ndarray + A 1D array of longitudes in degrees in the range from -180 to 180 + + lat_grd : ndarray + A 1D array of latitudes in degrees in the range from -90 to 90 + """ + + coastal_refined_mesh.counter += 1 + call_count = coastal_refined_mesh.counter + + if cell_width is None: + # Create the background cell width array + lon_grd, lat_grd, cell_width = create_background_mesh( + params["grd_box"], + params["ddeg"], + params["mesh_type"], + params["dx_min_global"], + params["dx_max_global"], + params["plot_option"], + params["plot_box"], + call_count) + + # Get coastlines from bathy/topo data set + coastlines = extract_coastlines( + params["nc_file"], + params["nc_vars"], + params["region_box"], + params["z_contour"], + params["n_longest"], + params["point_list"], + params["plot_option"], + params["plot_box"], + call_count) + + # Compute distance from background grid points to coastline + D = distance_to_coast( + coastlines, + lon_grd, + lat_grd, + params["nn_search"], + params["smooth_coastline"], + params["plot_option"], + params["plot_box"], + call_count) + + # Blend coastline and background resolution, save cell_width array as .mat file + cell_width = compute_cell_width( + D, + cell_width, + lon_grd, + lat_grd, + params["dx_min_coastal"], + params["trans_start"], + params["trans_width"], + params["restrict_box"], + params["plot_option"], + params["plot_box"], + coastlines, + call_count) + + # Save matfile + # save_matfile(cell_width/km,lon_grd,lat_grd) + print("") + + return (cell_width, lon_grd, lat_grd)
+ + + # }}} +coastal_refined_mesh.counter = 0 + +############################################################## + + +
[docs]def create_background_mesh(grd_box, ddeg, mesh_type, dx_min, dx_max, # {{{ + plot_option=False, plot_box=[], call=None): + """ + Create a background field of cell widths + + Parameters + ---------- + grd_box : list of float + A list of 4 floats defining the bounds (min lon, max lon, min lat, max + lat) of the grid + + ddeg : float + The resolution of the mesh in degrees + + mesh_type : {'QU', 'EC', 'RRS'} + The type of mesh: quasi-uniform (QU), Eddy-closure (EC) or Rossby-radius + scaling (RRS) + + dx_min : float + The resolution in meters of a QU mesh or the minimum resolution of of + an RRS mesh. This parameter is ignored for EC meshes and the default + function arguments to ``EC_CellWidthVsLat()`` are used instead. + + dx_max : float + The maximum resolution in meters of of an RRS mesh. This parameter is + ignored for QU meshes and EC meshes. For EC meshes, the default + function arguments are used instead. + + plot_option : bool, optional + Whether to plot the resulting cell width and save it to files + named ``bckgrnd_grid_cell_width_vs_lat###.png`` and + ``bckgnd_grid_cell_width###.png``, where ``###`` is given by + ``call`` and is meant to indicate how many times this function has been + called during mesh creation. + + plot_box : list of float, optional + The extent of the plot if ``plot_option=True`` + + call : int, optional + The number of times the function has been called, used to give the + plot a unique name. + + + Returns + ------- + cell_width : ndarray + A 2D array of cell widths in meters. + + lon_grd : ndarray + A 1D array of longitudes in degrees in the range from -180 to 180 + + lat_grd : ndarray + A 1D array of latitudes in degrees in the range from -90 to 90 + """ + + print("Create background mesh") + print("------------------------") + + # Create cell width background grid + ny_grd = int((grd_box[3]-grd_box[2])/ddeg) + 1 + nx_grd = int((grd_box[1]-grd_box[0])/ddeg) + 1 + lat_grd = grd_box[2] + ddeg*np.arange(ny_grd) + lon_grd = grd_box[0] + ddeg*np.arange(nx_grd) + print(" Background grid dimensions:", ny_grd, nx_grd) + + # Assign background grid cell width values + if mesh_type == 'QU': + cell_width_lat = dx_max / km * np.ones(lat_grd.size) + elif mesh_type == 'EC': + cell_width_lat = mdt.EC_CellWidthVsLat(lat_grd) + elif mesh_type == 'RRS': + cell_width_lat = mdt.RRS_CellWidthVsLat(lat_grd, dx_max / km, dx_min / km) + else: + raise ValueError('Unknown mesh_type {}'.format(mesh_type)) + cell_width = np.tile(cell_width_lat, (nx_grd, 1)).T * km + + # Plot background cell width + if plot_option: + print(" Plotting background cell width") + + plt.figure() + plt.plot(lat_grd, cell_width_lat) + plt.savefig('bckgrnd_grid_cell_width_vs_lat' + str(call) + '.png') + + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) + plt.contourf(lon_grd, lat_grd, cell_width, transform=ccrs.PlateCarree()) + plot_coarse_coast(ax, plot_box) + plt.colorbar() + plt.savefig( + 'bckgnd_grid_cell_width' + + str(call) + + '.png', + bbox_inches='tight') + plt.close() + print(" Done") + + return (lon_grd, lat_grd, cell_width) # }}}
+ +############################################################## + + +
[docs]def extract_coastlines(nc_file, nc_vars, region_box, z_contour=0, n_longest=10, + point_list=None, plot_option=False, plot_box=None, + call=None): # {{{ + + """ + Extracts a set of coastline contours + + Parameters + ---------- + nc_file : str + A bathymetry dataset on a lon/lat grid in NetCDF format + + nc_vars : list of str + The names of the longitude (nc_vars[0]), latitude (nc_vars[1]) and + bathymetry (nc_vars[2]) variables. + + region_box : dict of list of ndarrays + A region made up of a list of quadrilaterals to ``include`` and another + list to ``exclude``. The quadrilaterals are either bounding rectangles + (min lon, max lon, min lat, max lat) or lists of 4 (lon, lat) points. + + z_contour : float, optional + The isocontour of the bathymetry dataset to extract + + n_longest : int, optional + The maximum number of contours to keep, after sorting from the longest + to the shortest + + point_list : ndarray, optional + A list of points to add to the coastline + + plot_option : bool, optional + Whether to plot the resulting coastline points and the plot to a file + named ``bathy_coastlines###.png``, where ``###`` is given by + ``call`` and is meant to indicate how many times this function has been + called during mesh creation. + + plot_box : list of float, optional + The extent of the plot if ``plot_option=True`` + + call : int, optional + The number of times the function has been called, used to give the + plot a unique name. + + Returns + ------- + coastlines : ndarray + An n x 2 array of (longitude, latitude) points along the coastline + contours + """ + + print("Extract coastlines") + print("------------------") + + # Open NetCDF file and read cooordintes + nc_fid = Dataset(nc_file, "r") + lon = nc_fid.variables[nc_vars[0]][:] + lat = nc_fid.variables[nc_vars[1]][:] + bathy_data = nc_fid.variables[nc_vars[2]] + + # Get coastlines for refined region + coastline_list = [] + for i,box in enumerate(region_box["include"]): + + # Find coordinates and data inside bounding box + xb,rect= get_convex_hull_coordinates(box) + lon_region, lat_region, z_region = get_data_inside_box(lon, lat, bathy_data, xb) + z_data = np.zeros(z_region.shape) + z_data.fill(np.nan) + idx = get_indices_inside_quad(lon_region,lat_region,box) + z_data[idx] = z_region[idx] + print(" Regional bathymetry data shape:", z_region.shape) + + # Find coastline contours + print(" Extracting coastline "+str(i+1)+"/"+str(len(region_box["include"]))) + contours = measure.find_contours(z_data, z_contour) + + # Keep only n_longest coastlines and those not within exclude areas + contours.sort(key=len, reverse=True) + for c in contours[:n_longest]: + # Convert from pixel to lon,lat + c[:, 0] = (xb[3] - xb[2]) / float(len(lat_region)) * c[:, 0] + xb[2] + c[:, 1] = (xb[1] - xb[0]) / float(len(lon_region)) * c[:, 1] + xb[0] + c = np.fliplr(c) + + exclude = False + for area in region_box["exclude"]: + # Determine coastline coordinates in exclude area + idx = get_indices_inside_quad( + c[:, 0], c[:, 1], area, grid=False) + + # Exlude coastlines that are entirely contained in exclude area + if idx.size == c.shape[0]: + exclude = True + break + elif idx.size != 0: + c = np.delete(c, idx, axis=0) + + # Keep coastlines not entirely contained in exclude areas + if not exclude: + cpad = np.vstack((c, [np.nan, np.nan])) + coastline_list.append(cpad) + + print(" Done") + + # Add in user-specified points + if point_list: + for i,points in enumerate(point_list): + cpad = np.vstack((points, [np.nan, np.nan])) + coastline_list.append(cpad) + + # Combine coastlines + coastlines = np.concatenate(coastline_list) + + if plot_option: + print(" Plotting coastlines") + + # Find coordinates and data inside plotting box + lon_plot, lat_plot, z_plot = get_data_inside_box( + lon, lat, bathy_data, plot_box) + + # Plot bathymetry data, coastlines and region boxes + + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) + levels = np.linspace(np.amin(z_plot), np.amax(z_plot), 100) + ds = 100 # Downsample + dsx = np.arange(0, lon_plot.size, ds) # bathy data + dsy = np.arange(0, lat_plot.size, ds) # to speed up + dsxy = np.ix_(dsy, dsx) # plotting + plt.contourf(lon_plot[dsx], lat_plot[dsy], z_plot[dsxy], levels=levels, + transform=ccrs.PlateCarree()) + plot_coarse_coast(ax, plot_box) + plt.plot(coastlines[:, 0], coastlines[:, 1], color='white') + for box in region_box["include"]: + plot_region_box(box, 'b') + for box in region_box["exclude"]: + plot_region_box(box, 'r') + plt.colorbar() + plt.axis('equal') + plt.savefig( + 'bathy_coastlines' + + str(call) + + '.png', + bbox_inches='tight') + plt.close() + print(" Done") + + return coastlines # }}}
+ +############################################################## + + +
[docs]def distance_to_coast(coastlines, lon_grd, lat_grd, nn_search='kdtree', + smooth_window=0, plot_option=False, plot_box=[], + call=None, workers=-1): + # {{{ + """ + Extracts a set of coastline contours + + Parameters + ---------- + coastlines : ndarray + An n x 2 array of (longitude, latitude) points along the coastline + contours returned from ``extract_coastlines()`` + + lon_grd : ndarray + A 1D array of longitudes in degrees in the range from -180 to 180 + + lat_grd : ndarray + A 1D array of latitudes in degrees in the range from -90 to 90 + + nn_search : {'kdtree'}, optional + The algorithm to use for the nearest neightbor search. + + smooth_window : int, optional + The number of adjacent coastline points to average together to smooth + the coastal contours. Use ``0`` to indicate no smoothing. + + plot_option : bool, optional + Whether to plot the resulting coastline points and the plot to a file + named ``bathy_coastlines###.png``, where ``###`` is given by + ``call`` and is meant to indicate how many times this function has been + called during mesh creation. + + plot_box : list of float, optional + The extent of the plot if ``plot_option=True`` + + call : int, optional + The number of times the function has been called, used to give the + plot a unique name. + + workers : int, optional + The number of threads used for finding nearest neighbors. The default + is all available threads (``workers=-1``) + + Returns + ------- + D : ndarray + A len(lat_grd) x len(lon_grd) array of distances in meters on the + lon/lat grid to the closest point in the (smoothed) coastline contour. + """ + + if nn_search != 'kdtree': + raise ValueError(f'nn_search method {nn_search} not available.') + + print("Distance to coast") + print("-----------------") + + # Remove Nan values separating coastlines + coast_pts = coastlines[np.isfinite(coastlines).all(axis=1)] + + # Smooth coast points if necessary + if smooth_window > 1: + coast_pts[:, 0], coast_pts[:, 1] = smooth_coastline( + coast_pts[:, 0], coast_pts[:, 1], smooth_window) + + # Convert coastline points to x,y,z and create kd-tree + npts = coast_pts.shape[0] + coast_pts_xyz = np.zeros((npts,3)) + coast_pts_xyz[:, 0], coast_pts_xyz[:, 1], coast_pts_xyz[:, 2] = lonlat2xyz(coast_pts[:, 0], coast_pts[:, 1]) + tree = KDTree(coast_pts_xyz) + + # Convert backgound grid coordinates to x,y,z and put in a nx_grd x 3 array for kd-tree query + Lon_grd, Lat_grd = np.meshgrid(lon_grd, lat_grd) + X_grd, Y_grd, Z_grd = lonlat2xyz(Lon_grd,Lat_grd) + pts = np.vstack([X_grd.ravel(), Y_grd.ravel(), Z_grd.ravel()]).T + + # Find distances of background grid coordinates to the coast + print(" Finding distance") + start = timeit.default_timer() + d, idx = tree.query(pts, workers=workers) + end = timeit.default_timer() + print(" Done") + print(" " + str(end - start) + " seconds") + + # Make distance array that corresponds with cell_width array + D = np.reshape(d, Lon_grd.shape) + + if plot_option: + print(" Plotting distance to coast") + + # Find coordinates and data inside plotting box + lon_plot, lat_plot, D_plot = get_data_inside_box( + lon_grd, lat_grd, D, plot_box) + + # Plot distance to coast + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) + D_plot = D_plot / km + levels = np.linspace(np.amin(D_plot), np.amax(D_plot), 10) + plt.contourf(lon_plot, lat_plot, D_plot, levels=levels, + transform=ccrs.PlateCarree()) + plot_coarse_coast(ax, plot_box) + plt.plot(coastlines[:, 0], coastlines[:, 1], color='white') + plt.grid( + xdata=lon_plot, + ydata=lat_plot, + c='k', + ls='-', + lw=0.1, + alpha=0.5) + plt.colorbar() + plt.axis('equal') + plt.savefig('distance' + str(call) + '.png', bbox_inches='tight') + plt.close() + print(" Done") + + return D # }}}
+ +############################################################## + + +
[docs]def compute_cell_width(D, cell_width, lon, lat, dx_min, trans_start, + trans_width, restrict_box, plot_option=False, + plot_box=[], coastlines=[], call=None): # {{{ + """ + Blend cell widths from the input field with the new resolution in the + refined region determined by the distance to the coastline contour. + + Parameters + ---------- + D : ndarray + A len(lat) x len(lon) array of distances in meters on the lon/lat grid + to the closest point in the (smoothed) coastline contour returned from + ``distance_to_coast()`` + + cell_width : ndarray + A len(lat) x len(lon) array of cell widths in meters + + lon : ndarray + A 1D array of longitudes in degrees in the range from -180 to 180 + + lat : ndarray + A 1D array of latitudes in degrees in the range from -90 to 90 + + dx_min : float + The resolution in meters of the new refined region. + + trans_start : float + The approximate value of ``D`` in meters at which the transition in + resolution should start + + trans_width : float + The approximate width in meters over which the transition in resolution + should take place + + restrict_box : dict of lists of ndarrays + A region of made up of quadrilaterals to ``include`` and ``exclude`` + that defines where resolution may be altered. Outside of the + ``restrict_box``, the resolution remains unchanged. + + plot_option : bool, optional + Whether to plot the resulting coastline points and the plot to files + named ``cell_width###.png`` and ``trans_func###.png```, where ``###`` + is given by ``call`` and is meant to indicate how many times this + function has been called during mesh creation. + + plot_box : list of float, optional + The extent of the plot if ``plot_option=True`` + + coastlines : ndarray + An n x 2 array of (longitude, latitude) points along the coastline + contours returned from ``extract_coastlines()`` used in plotting if + ``plot_option=True`` + + call : int, optional + The number of times the function has been called, used to give the + plot a unique name. + + Returns + ------- + cell_width : ndarray + A len(lat) x len(lon) array of the new cell widths in meters + """ + + print("Compute cell width") + print("------------------") + + # Compute cell width based on distance + print(" Computing cell width") + backgnd_weight = .5 * \ + (np.tanh((D - trans_start - .5 * trans_width) / (.2 * trans_width)) + 1.0) + dist_weight = 1.0 - backgnd_weight + ## Use later for depth and slope dependent resolution + ##hres = np.maximum(dx_min*bathy_grd/20,dx_min) + ##hres = np.minimum(hres,dx_max) + #hw = np.zeros(Lon_grd.shape) + dx_max + #hw[ocn_idx] = np.sqrt(9.81*bathy_grd[ocn_idx])*12.42*3600/25 + #hs = .20*1/dbathy_grd + #h = np.fmin(hs,hw) + #h = np.fmin(h,dx_max) + #h = np.fmax(dx_min,h) + + cell_width_old = np.copy(cell_width) + + # Apply cell width function + if len(restrict_box["include"]) > 0: + # Only apply inside include regions + for box in restrict_box["include"]: + idx = get_indices_inside_quad(lon, lat, box) + cell_width[idx] = (dx_min*dist_weight[idx] + + np.multiply(cell_width_old[idx], backgnd_weight[idx])) + else: + # Apply everywhere + cell_width = (dx_min*dist_weight + + np.multiply(cell_width_old, backgnd_weight)) + + # Don't apply cell width function in exclude regions (revert to previous values) + if len(restrict_box["exclude"]) > 0: + for box in restrict_box["exclude"]: + idx = get_indices_inside_quad(lon, lat, box) + cell_width[idx] = cell_width_old[idx] + print(" Done") + + if plot_option: + print(" Plotting cell width") + + # Find coordinates and data inside plotting box + lon_plot, lat_plot, cell_width_plot = get_data_inside_box( + lon, lat, cell_width / km, plot_box) + + # Plot cell width + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) + levels = np.linspace(np.amin(cell_width_plot), + np.amax(cell_width_plot), 100) + plt.contourf(lon_plot, lat_plot, cell_width_plot, levels=levels, + transform=ccrs.PlateCarree()) + plot_coarse_coast(ax, plot_box) + plt.plot(coastlines[:, 0], coastlines[:, 1], color='white') + if restrict_box: + for box in restrict_box["include"]: + plot_region_box(box, 'b') + for box in restrict_box["exclude"]: + plot_region_box(box, 'r') + plt.colorbar() + plt.axis('equal') + plt.savefig('cell_width' + str(call) + '.png', bbox_inches='tight') + plt.close() + + # Plot cell width transistion functions + ts = trans_start/km + tw = trans_width/km + d = np.linspace(0,2*(ts+tw),1000) + bw = .5*(np.tanh((d-ts-.5*tw)/(.2*tw))+1) + dw = 1-bw + plt.figure() + plt.plot(d,bw) + plt.plot(d,dw) + plt.legend(('background','coastal region')) + plt.plot([ts,ts],[0.0,1.0],'k-') + plt.plot([ts+tw,ts+tw],[0.0,1.0],'k-') + plt.tight_layout() + plt.xlabel('distance (km)') + plt.ylabel('weight') + plt.savefig('trans_func'+str(call)+'.png',bbox_inches='tight') + plt.close() + print(" Done") + + return cell_width # }}}
+ +############################################################## + + +
[docs]def save_matfile(cell_width, lon, lat): + + savemat('cellWidthVsLatLon.mat', + mdict={'cellWidth': cell_width, + 'lon': lon, + 'lat': lat})
+ +############################################################## + + +
[docs]def CPP_projection(lon, lat, origin): + + R = 6378206.4 + origin = origin * deg2rad + x = R * (lon * deg2rad - origin[0]) * np.cos(origin[1]) + y = R * lat * deg2rad + + return x, y
+ +############################################################## + + +
[docs]def smooth_coastline(x, y, window): + xs = np.copy(x) + ys = np.copy(y) + offset = (window-1)/2 + for pt in range(offset-1, x.size-offset): + xs[pt] = np.mean(x[pt-offset:pt+offset]) + ys[pt] = np.mean(y[pt-offset:pt+offset]) + return xs, ys
+############################################################## + + +
[docs]def get_data_inside_box(lon, lat, data, box, idx=False): + + # Find indicies of coordinates inside bounding box + lon_idx, = np.where((lon >= box[0]) & (lon <= box[1])) + lat_idx, = np.where((lat >= box[2]) & (lat <= box[3])) + + # Get indicies inside bounding box + lon_region = lon[lon_idx] + lat_region = lat[lat_idx] + latlon_idx = np.ix_(lat_idx, lon_idx) + + # Return data inside bounding box + if idx == False: + + try: # Numpy indexing + z_region = data[latlon_idx] + except: # NetCDF indexing + z_region = data[lat_idx, lon_idx] + + return (lon_region, lat_region, z_region) + + # Return indicies of data inside bounding box + elif idx == True: + + return latlon_idx
+ +############################################################## + + +
[docs]def get_indices_inside_quad(lon, lat, box, grid=True): + + wrap = flag_wrap(box) + + lon_adj = np.copy(lon) + if wrap: + idx = np.where((lon_adj >= -180.0) & (lon_adj <= -90.0)) + lon_adj[idx] = lon_adj[idx] + 360.0 + + if grid: + # Create vectors of all coordinates + Lon_grd, Lat_grd = np.meshgrid(lon_adj, lat) + X = Lon_grd.ravel() + Y = Lat_grd.ravel() + else: + X = lon_adj + Y = lat + + xb,rect = get_convex_hull_coordinates(box) + + # Find indices of coordinates in convex hull of quad region + idxx = np.where((X >= xb[0]) & (X <= xb[1])) + idxy = np.where((Y >= xb[2]) & (Y <= xb[3])) + idx_ch = np.intersect1d(idxx, idxy) + idx = np.copy(idx_ch) + + if rect == True: + if grid == True: + idx = np.unravel_index(idx, Lon_grd.shape) + return idx + + # Initialize the local coordinate vectors to be outside unit square + R = 0.0 * X - 10.0 + S = 0.0 * Y - 10.0 + + # Initialize the coordinate vectors for points inside convex hull of quad region + r = 0.0 * R[idx] + s = 0.0 * S[idx] + x = X[idx] + y = Y[idx] + + # Map all coordinates in convex hull of quad region to unit square + # by solving inverse transformaion with Newton's method + tol = 1e-8 + maxit = 25 + for it in range(0, maxit): + + # Compute shape fuctions + phi1 = np.multiply((1.0 - r), (1.0 - s)) + phi2 = np.multiply((1.0 + r), (1.0 - s)) + phi3 = np.multiply((1.0 + r), (1.0 + s)) + phi4 = np.multiply((1.0 - r), (1.0 + s)) + + # Compute functions that are being solved + f1 = .25 * (phi1 * box[0, 0] + phi2 * box[1, 0] + + phi3 * box[2, 0] + phi4 * box[3, 0]) - x + f2 = .25 * (phi1 * box[0, 1] + phi2 * box[1, 1] + + phi3 * box[2, 1] + phi4 * box[3, 1]) - y + + # Compute Jacobian + df1ds = .25 * ((r - 1.0) * box[0, 0] - (1.0 + r) * box[1, 0] + (1.0 + r) * box[2, 0] + (1.0 - r) * box[3, 0]) + df1dr = .25 * ((s - 1.0) * box[0, 0] + (1.0 - s) * box[1, 0] + (1.0 + s) * box[2, 0] - (1.0 + s) * box[3, 0]) + df2ds = .25 * ((r - 1.0) * box[0, 1] - (1.0 + r) * box[1, 1] + (1.0 + r) * box[2, 1] + (1.0 - r) * box[3, 1]) + df2dr = .25 * ((s - 1.0) * box[0, 1] + (1.0 - s) * box[1, 1] + (1.0 + s) * box[2, 1] - (1.0 + s) * box[3, 1]) + + # Inverse of 2x2 matrix + det_recip = np.multiply(df1dr, df2ds) - np.multiply(df2dr, df1ds) + det_recip = 1.0 / det_recip + dr = np.multiply(det_recip, np.multiply(df2ds, f1) - np.multiply(df1ds, f2)) + ds = np.multiply(det_recip, -np.multiply(df2dr, f1) + np.multiply(df1dr, f2)) + + # Apply Newton's method + rnew = r - dr + snew = s - ds + + # Find converged values + err = R[idx] - rnew + idxr = np.where(np.absolute(err) < tol) + err = S[idx] - snew + idxs = np.where(np.absolute(err) < tol) + idx_conv = np.intersect1d(idxr, idxs) + + # Update solution + R[idx] = rnew + S[idx] = snew + + # Find indicies of unconverged values + idx = np.delete(idx, idx_conv) + # print("Iteration: ", it, "unconverged values: ", idx.size) + + # Terminate once all values are converged + if idx.size == 0: + break + + # Initialize to unconverged values for next iteration + r = R[idx] + s = S[idx] + x = X[idx] + y = Y[idx] + + # Find any remaining unconverged values + if grid == True: + idx_nc = np.unravel_index(idx, Lon_grd.shape) + else: + idx_nc = np.copy(idx) + + # Find indicies of coordinates inside quad region + lon_idx, = np.where((R >= -1.0) & (R <= 1.0)) + lat_idx, = np.where((S >= -1.0) & (S <= 1.0)) + idx = np.intersect1d(lon_idx, lat_idx) + if grid == True: + idx = np.unravel_index(idx, Lon_grd.shape) + + ## Plot values inside quad region + # plt.figure() + # plt.plot(X,Y,'.') + # if grid == True: + # plt.plot(Lon_grd[idx],Lat_grd[idx],'.') + # plt.plot(Lon_grd[idx_nc],Lat_grd[idx_nc],'.') + # else: + # plt.plot(lon[idx],lat[idx],'.') + # plt.plot(lon[idx_nc],lat[idx_nc],'.') + # plt.plot(box[:,0],box[:,1],'o') + # plt.savefig("restrict_box.png") + + return idx
+ +############################################################## + +
[docs]def get_convex_hull_coordinates(box): + + wrap = flag_wrap(box) + + xb = np.zeros(4) + if box.size == 4: + if wrap: + for i in range(2): + if box[i] >= -180.0 and box[i] <= -90.0: + box[i] = box[i] + 360.0 + + xb[0] = box[0] + xb[1] = box[1] + xb[2] = box[2] + xb[3] = box[3] + rect = True + else: + if wrap: + for i in range(4): + if box[i, 0] >= -180.0 and box[i, 0] <= -90.0: + box[i, 0] = box[i, 0] + 360.0 + + xb[0] = np.amin(box[:, 0]) + xb[1] = np.amax(box[:, 0]) + xb[2] = np.amin(box[:, 1]) + xb[3] = np.amax(box[:, 1]) + rect = False + + return xb,rect
+ +############################################################## + +def flag_wrap(box): + + wrap = False + if box.size == 4: + if box[0] > 0.0 and box[1] < 0.0: + wrap = True + else: + if np.any(box[:,0] > 0.0) and np.any(box[:,0] < 0.0): + wrap = True + + return wrap + +############################################################## + +
[docs]def plot_coarse_coast(ax, plot_box): + + ax.set_extent(plot_box, crs=ccrs.PlateCarree()) + ax.add_feature(cfeature.COASTLINE)
+ +############################################################## + + +
[docs]def plot_region_box(box, color): + ls = color + '-' + if box.size == 4: + plt.plot([box[0], box[1]], [box[2], box[2]], ls) + plt.plot([box[1], box[1]], [box[2], box[3]], ls) + plt.plot([box[1], box[0]], [box[3], box[3]], ls) + plt.plot([box[0], box[0]], [box[3], box[2]], ls) + else: + plt.plot([box[0, 0], box[1, 0]], [box[0, 1], box[1, 1]], ls) + plt.plot([box[1, 0], box[2, 0]], [box[1, 1], box[2, 1]], ls) + plt.plot([box[2, 0], box[3, 0]], [box[2, 1], box[3, 1]], ls) + plt.plot([box[3, 0], box[0, 0]], [box[3, 1], box[0, 1]], ls)
+ + +########################################################################## +# Incorporate later for depth and slope dependent resolution +########################################################################## + + +## +## Interpolate bathymetry onto background grid +#Lon_grd = Lon_grd*deg2rad +#Lat_grd = Lat_grd*deg2rad +#bathy = inject_bathymetry.interpolate_bathymetry(data_path+nc_file,Lon_grd.ravel(),Lat_grd.ravel()) +#bathy_grd = -1.0*np.reshape(bathy,(ny_grd,nx_grd)) +#ocn_idx = np.where(bathy_grd > 0) +# +# if plot_option: +# plt.figure() +# levels = np.linspace(0,11000,100) +# plt.contourf(lon_grd,lat_grd,bathy_grd,levels=levels) +# plot_coarse_coast(plot_box) +# plt.colorbar() +# plt.axis('equal') +# plt.savefig('bckgnd_grid_bathy.png',bbox_inches='tight') + +## Interpolate bathymetry gradient onto background grid +#dbathy = inject_bathymetry.interpolate_bathymetry(data_path+nc_file,Lon_grd.ravel(),Lat_grd.ravel(),grad=True) +#dbathy = np.reshape(dbathy,(ny_grd,nx_grd)) +#dbathy_grd = np.zeros((ny_grd,nx_grd)) +#dbathy_grd[ocn_idx] = dbathy[ocn_idx] +# +# if plot_option: +# plt.figure() +# plt.contourf(lon_grd,lat_grd,1/dbathy_grd) +# plot_coarse_coast(plot_box) +# plt.colorbar() +# plt.axis('equal') +# plt.savefig('bckgnd_grid_bathy_grad.png',bbox_inches='tight') +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/coastline_alteration.html b/0.22.0rc4/_modules/mpas_tools/ocean/coastline_alteration.html new file mode 100644 index 000000000..d96b0c2c3 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/coastline_alteration.html @@ -0,0 +1,510 @@ + + + + + + mpas_tools.ocean.coastline_alteration — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.ocean.coastline_alteration

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy
+import xarray
+
+
+
[docs]def add_critical_land_blockages(dsMask, dsBlockages): + """ + Add the masks associated with one or more transects to the land mask + + Parameters + ---------- + dsMask : xarray.Dataset + The mask to which critical blockages should be added + + dsBlockages : xarray.Dataset + The transect masks defining critical land regions that should block + ocean flow (e.g. the Antarctic Peninsula) + + Returns + ------- + dsMask : xarray.Dataset + The mask with critical blockages included + """ + + dsMask = dsMask.copy() + + nTransects = dsBlockages.sizes['nTransects'] + for transectIndex in range(nTransects): + dsMask.regionCellMasks[:, 0] = numpy.maximum( + dsBlockages.transectCellMasks[:, transectIndex], + dsMask.regionCellMasks[:, 0]) + + return dsMask
+ + +
[docs]def widen_transect_edge_masks(dsMask, dsMesh, latitude_threshold=43.0): + """ + Alter critical passages at polar latitudes to be at least two cells wide, to + avoid sea ice blockage + + Parameters + ---------- + dsMask : xarray.Dataset + The mask to which critical blockages should be added + + dsMesh : xarray.Dataset + The transect masks defining critical land regions that should block + ocean flow (e.g. the Antarctic Peninsula) + + latitude_threshold : float + Minimum latitude, degrees, for transect widening + + Returns + ------- + dsMask : xarray.Dataset + The mask with critical blockages included + """ + latitude_threshold_radians = numpy.deg2rad(latitude_threshold) + + dsMask = dsMask.copy() + + maxEdges = dsMesh.sizes['maxEdges'] + + latMask = numpy.abs(dsMesh.latEdge) > latitude_threshold_radians + + edgeMask = numpy.logical_and( + latMask, dsMask.transectEdgeMasks == 1) + for iEdge in range(maxEdges): + eoc = dsMesh.edgesOnCell[:, iEdge]-1 + mask = numpy.logical_and(eoc >= 0, + edgeMask[eoc]) + # cells with a neighboring transect edge should be masked to 1 + dsMask['transectCellMasks'] = dsMask.transectCellMasks.where( + numpy.logical_not(mask), 1.) + + return dsMask
+ + +
[docs]def add_land_locked_cells_to_mask(dsMask, dsMesh, latitude_threshold=43.0, + nSweeps=10): + """ + Find ocean cells that are land-locked, and alter the cell mask so that they + are counted as land cells. + + Parameters + ---------- + dsMask : xarray.Dataset + A land-mask data set + + dsMesh : xarray.Dataset + MPAS Mesh data set + + latitude_threshold : float, optional + Minimum latitude, in degrees, for transect widening + + nSweeps : int, optional + Maximum number of sweeps to search for land-locked cells + + Returns + ------- + dsMask : xarray.Dataset + A copy of the land-mask data set with land-locked cells added to the + mask for the first region + """ + + dsMask = xarray.Dataset(dsMask) + dsMesh = dsMesh.copy(deep=True) + + landMask = dsMask.regionCellMasks.max(dim='nRegions') > 0 + + dsMask['landMaskDiagnostic'] = xarray.where(landMask, 1, 0) + + print("Running add_land_locked_cells_to_mask.py. Total number of cells: " + "{}".format(dsMesh.sizes['nCells'])) + + cellsOnCell = dsMesh.cellsOnCell - 1 + nEdgesOnCell = dsMesh.nEdgesOnCell + + nextCellsOnCell = cellsOnCell.copy(deep=True) + prevCellsOnCell = cellsOnCell.copy(deep=True) + for iEdgeOnCell in range(nextCellsOnCell.shape[1]): + iP1 = numpy.mod(iEdgeOnCell + 1, nEdgesOnCell) + nextCellsOnCell[:, iEdgeOnCell] = cellsOnCell[:, iP1] + iM1 = numpy.mod(iEdgeOnCell - 1, nEdgesOnCell) + prevCellsOnCell[:, iEdgeOnCell] = cellsOnCell[:, iM1] + + dsMesh['cellsOnCell'] = cellsOnCell + dsMesh['nextCellsOnCell'] = nextCellsOnCell + dsMesh['prevCellsOnCell'] = prevCellsOnCell + dsMesh['latCell'] = numpy.rad2deg(dsMesh.latCell) + dsMesh['lonCell'] = numpy.rad2deg(dsMesh.lonCell) + + landMask, removable = _remove_cells_with_isolated_edges1( + dsMask, dsMesh, landMask, latitude_threshold) + landMask = _remove_cells_with_isolated_edges2( + dsMask, dsMesh, landMask, removable, nSweeps) + oceanMask = _flood_fill(dsMask, dsMesh, landMask, removable) + landMask = _revert_cells_with_connected_edges( + dsMask, dsMesh, oceanMask, landMask, removable, nSweeps) + + return dsMask
+ + +def _remove_cells_with_isolated_edges1(dsMask, dsMesh, landMask, + latitude_threshold): + print("Step 1: Searching for land-locked cells. Remove cells that only " + "have isolated active edges.") + + landMaskNew = landMask.copy(deep=True) + + active = numpy.logical_not(landMask) + removable = numpy.logical_and( + numpy.abs(dsMesh.latCell) >= latitude_threshold, active) + + cellsOnCell = dsMesh.cellsOnCell + valid = numpy.logical_and(removable, cellsOnCell >= 0) + activeEdge = numpy.logical_and(valid, active[cellsOnCell]) + + nextCellsOnCell = dsMesh.nextCellsOnCell + valid = numpy.logical_and(removable, nextCellsOnCell >= 0) + activeNextEdge = numpy.logical_and(valid, active[nextCellsOnCell]) + + # which vertices have adjacent active edges on this cell? + activeAdjacentEdges = numpy.logical_and(activeEdge, activeNextEdge) + + # which removable cells have no pairs of adjacent active cells? + noActiveAdjacentEdges = numpy.logical_and( + removable, numpy.logical_not(numpy.any(activeAdjacentEdges, axis=1))) + + landMaskNew[noActiveAdjacentEdges] = 1 + landLockedCounter = numpy.count_nonzero(noActiveAdjacentEdges) + + dsMask.regionCellMasks[:, 0] = numpy.maximum(dsMask.regionCellMasks[:, 0], + 1*noActiveAdjacentEdges) + + dsMask.landMaskDiagnostic[noActiveAdjacentEdges] = 2 + + print(" Number of landLocked cells: {}".format(landLockedCounter)) + + return landMaskNew, removable + + +def _remove_cells_with_isolated_edges2(dsMask, dsMesh, landMask, removable, + nSweeps): + print("Step 2: Searching for land-locked cells. Remove cells that have " + "any isolated active edges.") + + cellsOnCell = dsMesh.cellsOnCell + nextCellsOnCell = dsMesh.nextCellsOnCell + prevCellsOnCell = dsMesh.prevCellsOnCell + + for iSweep in range(nSweeps): + landLockedCounter = 0 + landMaskNew = landMask.copy(deep=True) + + active = numpy.logical_not(landMask) + mask = numpy.logical_and(removable, active) + + valid = numpy.logical_and(mask, cellsOnCell >= 0) + activeEdge = numpy.logical_and(valid, active[cellsOnCell]) + valid = numpy.logical_and(mask, nextCellsOnCell >= 0) + activeNextEdge = numpy.logical_and(valid, active[nextCellsOnCell]) + valid = numpy.logical_and(mask, prevCellsOnCell >= 0) + activePrevEdge = numpy.logical_and(valid, active[prevCellsOnCell]) + + # an edge is land-locked if it is active but neither neighbor is active + landLockedEdges = numpy.logical_and( + activeEdge, + numpy.logical_not( + numpy.logical_or(activePrevEdge, activeNextEdge))) + + landLockedCells = numpy.any(landLockedEdges, axis=1) + + landLockedCounter = numpy.count_nonzero(landLockedCells) + if landLockedCounter > 0: + landMaskNew[landLockedCells] = 1 + dsMask.regionCellMasks[landLockedCells, 0] = 1 + dsMask.landMaskDiagnostic[landLockedCells] = 3 + + landMask = landMaskNew + print(" Sweep: {} Number of landLocked cells removed: {}".format( + iSweep + 1, landLockedCounter)) + if landLockedCounter == 0: + break + + return landMask + + +def _flood_fill(dsMask, dsMesh, landMask, removable): + print("Step 3: Perform flood fill, starting from open ocean.") + + # init flood fill to 0 for water, -1 for land, 1 for known open ocean + floodFill = xarray.where( + numpy.logical_and(removable, numpy.logical_not(landMask)), 0, -1) + + latCell = dsMesh.latCell + lonCell = dsMesh.lonCell + + cellsOnCell = dsMesh.cellsOnCell + + # North Pole + mask = latCell > 84.0 + openOceanMask = mask + + # Arctic + mask = numpy.logical_and( + numpy.logical_and(lonCell > 160.0, lonCell < 230.0), + latCell > 73.0) + openOceanMask = numpy.logical_or(openOceanMask, mask) + + # North Atlantic + mask = numpy.logical_and( + numpy.logical_and(lonCell > 315.0, lonCell < 340.0), + numpy.logical_and(latCell > 15.0, latCell < 45.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + mask = numpy.logical_and( + numpy.logical_and(lonCell > 290.0, lonCell < 300.0), + numpy.logical_and(latCell > 72.0, latCell < 75.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + mask = numpy.logical_and( + numpy.logical_and(lonCell > 0.0, lonCell < 10.0), + numpy.logical_and(latCell > 70.0, latCell < 75.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + + # North Pacific + mask = numpy.logical_and( + numpy.logical_and(lonCell > 150.0, lonCell < 225.0), + numpy.logical_and(latCell > 0.0, latCell < 45.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + + # South Atlantic + mask = numpy.logical_and( + numpy.logical_and(lonCell > 0.0, lonCell < 5.0), + numpy.logical_and(latCell > -60.0, latCell < 0.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + + # South Pacific + mask = numpy.logical_and( + numpy.logical_and(lonCell > 180.0, lonCell < 280.0), + numpy.logical_and(latCell > -60.0, latCell < -10.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + + # Southern Ocean + mask = numpy.logical_and( + numpy.logical_and(lonCell > 0.0, lonCell < 165.0), + numpy.logical_and(latCell > -60.0, latCell < -45.0)) + openOceanMask = numpy.logical_or(openOceanMask, mask) + + mask = numpy.logical_and(floodFill == 0, openOceanMask) + floodFill[mask] = 1 + + nFloodableCells = numpy.count_nonzero(floodFill == 0) + print(" Initial number of flood cells: {}".format(nFloodableCells)) + + dsMask.landMaskDiagnostic[floodFill == 1] = 5 + + # sweep over neighbors of known open ocean points + for iSweep in range(dsMesh.sizes['nCells']): + + newFloodCellsThisSweep = 0 + mask = floodFill == 0 + cellIndices = numpy.nonzero(mask.values)[0] + for iCellOnCell in range(cellsOnCell.shape[1]): + neighbors = cellsOnCell[cellIndices, iCellOnCell] + filledNeighbors = numpy.logical_and(neighbors >= 0, + floodFill[neighbors] == 1) + fillIndices = cellIndices[filledNeighbors.values] + if(len(fillIndices) > 0): + floodFill[fillIndices] = 1 + newFloodCellsThisSweep += len(fillIndices) + + print(" Sweep {} new flood cells this sweep: {}".format( + iSweep, newFloodCellsThisSweep)) + + if (newFloodCellsThisSweep == 0): + break + + oceanMask = (floodFill == 1) + + print('oceanMask:', numpy.count_nonzero(oceanMask)) + + return oceanMask + + +def _revert_cells_with_connected_edges(dsMask, dsMesh, oceanMask, landMask, + removable, nSweeps): + print("Step 4: Searching for land-locked cells, step 3: revert cells with " + "connected active edges") + + cellsOnCell = dsMesh.cellsOnCell + nextCellsOnCell = dsMesh.nextCellsOnCell + prevCellsOnCell = dsMesh.prevCellsOnCell + + for iSweep in range(nSweeps): + landMaskNew = numpy.array(landMask) + + # only remove a cell that was added in Step 2, + # _remove_cells_with_isolated_edges2 + mask = numpy.logical_and(removable, dsMask.landMaskDiagnostic == 3) + + notLand = numpy.logical_not(landMask) + valid = numpy.logical_and(mask, cellsOnCell >= 0) + oceanEdge = numpy.logical_and(valid, oceanMask[cellsOnCell]) + valid = numpy.logical_and(mask, nextCellsOnCell >= 0) + activeNextEdge = numpy.logical_and(valid, notLand[nextCellsOnCell]) + valid = numpy.logical_and(mask, prevCellsOnCell >= 0) + activePrevEdge = numpy.logical_and(valid, notLand[prevCellsOnCell]) + + reactivate = numpy.any( + numpy.logical_and( + oceanEdge, + numpy.logical_or(activePrevEdge, activeNextEdge)), axis=1) + + landLockedCounter = numpy.count_nonzero(reactivate) + if landLockedCounter > 0: + landMaskNew[reactivate] = 0 + dsMask.regionCellMasks[reactivate, 0] = 0 + oceanMask[reactivate] = 1 + dsMask.landMaskDiagnostic[reactivate] = 4 + + landMask = landMaskNew + print(" Sweep: {} Number of land-locked cells returned: {}".format( + iSweep + 1, landLockedCounter)) + if landLockedCounter == 0: + break + + return landMask +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/depth.html b/0.22.0rc4/_modules/mpas_tools/ocean/depth.html new file mode 100644 index 000000000..d6351764c --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/depth.html @@ -0,0 +1,480 @@ + + + + + + mpas_tools.ocean.depth — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.ocean.depth

+import xarray
+import numpy
+import argparse
+import sys
+from datetime import datetime
+import netCDF4
+
+from mpas_tools.io import write_netcdf
+
+
+
[docs]def compute_depth(refBottomDepth): + """ + Computes depth and depth bounds given refBottomDepth + + Parameters + ---------- + refBottomDepth : xarray.DataArray + the depth of the bottom of each vertical layer in the initial state + (perfect z-level coordinate) + + Returns + ------- + depth : numpy.ndarray + the vertical coordinate defining the middle of each layer + + depth_bnds : numpy.ndarray + the vertical coordinate defining the top and bottom of each layer + """ + # Authors + # ------- + # Xylar Asay-Davis + + refBottomDepth = refBottomDepth.values + + depth_bnds = numpy.zeros((len(refBottomDepth), 2)) + + depth_bnds[0, 0] = 0. + depth_bnds[1:, 0] = refBottomDepth[0:-1] + depth_bnds[:, 1] = refBottomDepth + depth = 0.5*(depth_bnds[:, 0] + depth_bnds[:, 1]) + + return depth, depth_bnds
+ + +
[docs]def compute_zmid(bottomDepth, maxLevelCell, layerThickness, + depth_dim='nVertLevels'): + """ + Computes zMid given data arrays for bottomDepth, maxLevelCell and + layerThickness + + Parameters + ---------- + bottomDepth : xarray.DataArray + the depth of the ocean bottom (positive) + + maxLevelCell : xarray.DataArray + the 1-based vertical index of the bottom of the ocean + + layerThickness : xarray.DataArray + the thickness of MPAS-Ocean layers (possibly as a function of time) + + depth_dim : str, optional + the name of the vertical dimension + + Returns + ------- + zMid : xarray.DataArray + the vertical coordinate defining the middle of each layer, masked below + the bathymetry + """ + # Authors + # ------- + # Xylar Asay-Davis + + nDepth = layerThickness.sizes[depth_dim] + + vertIndex = \ + xarray.DataArray.from_dict({'dims': (depth_dim,), + 'data': numpy.arange(nDepth)}) + + layerThickness = layerThickness.where(vertIndex < maxLevelCell) + + thicknessSum = layerThickness.sum(dim=depth_dim) + thicknessCumSum = layerThickness.cumsum(dim=depth_dim) + zSurface = -bottomDepth+thicknessSum + + zLayerBot = zSurface - thicknessCumSum + + zMid = zLayerBot + 0.5*layerThickness + + zMid = zMid.where(vertIndex < maxLevelCell) + if 'Time' in zMid.dims: + zMid = zMid.transpose('Time', 'nCells', depth_dim) + else: + zMid = zMid.transpose('nCells', depth_dim) + + return zMid
+ + +
[docs]def add_depth(inFileName, outFileName, coordFileName=None): + """ + Add a 1D depth coordinate to an MPAS-Ocean file. + + Parameters + ---------- + inFileName : str + An input MPAS-Ocean file that depth should be added to, used for coords + if another file is not provided via ``coordFileName``. + + outFileName : str + An output MPAS-Ocean file with depth added + + coordFileName : str, optional + An MPAS-Ocean file with ``refBottomDepth`` + """ + + if coordFileName is None: + coordFileName = inFileName + + ds = xarray.open_dataset(inFileName, mask_and_scale=False) + if 'nVertLevels' in ds.dims: + ds = ds.rename({'nVertLevels': 'depth'}) + + dsCoord = xarray.open_dataset(coordFileName, mask_and_scale=False) + dsCoord = dsCoord.rename({'nVertLevels': 'depth'}) + + depth, depth_bnds = compute_depth(dsCoord.refBottomDepth) + ds.coords['depth'] = ('depth', depth) + ds.depth.attrs['long_name'] = 'reference depth of the center of ' \ + 'each vertical level' + ds.depth.attrs['standard_name'] = 'depth' + ds.depth.attrs['units'] = 'meters' + ds.depth.attrs['axis'] = 'Z' + ds.depth.attrs['positive'] = 'down' + ds.depth.attrs['valid_min'] = depth_bnds[0, 0] + ds.depth.attrs['valid_max'] = depth_bnds[-1, 1] + ds.depth.attrs['bounds'] = 'depth_bnds' + + ds.coords['depth_bnds'] = (('depth', 'nbnd'), depth_bnds) + ds.depth_bnds.attrs['long_name'] = 'Gridcell depth interfaces' + + for varName in ds.data_vars: + var = ds[varName] + if 'depth' in var.dims: + var = var.assign_coords(depth=ds.depth) + ds[varName] = var + + time = datetime.now().strftime('%c') + + history = '{}: {}'.format(time, ' '.join(sys.argv)) + + if 'history' in ds.attrs: + ds.attrs['history'] = '{}\n{}'.format(history, + ds.attrs['history']) + else: + ds.attrs['history'] = history + + write_netcdf(ds, outFileName)
+ + +def main_add_depth(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-c", "--coordFileName", dest="coordFileName", + type=str, required=False, + help="An MPAS-Ocean file with refBottomDepth") + parser.add_argument("-i", "--inFileName", dest="inFileName", type=str, + required=True, + help="An input MPAS-Ocean file that depth should be" + "added to, used for coords if another file is" + "not provided via -c.") + parser.add_argument("-o", "--outFileName", dest="outFileName", type=str, + required=True, + help="An output MPAS-Ocean file with depth added") + args = parser.parse_args() + + add_depth(args.inFileName, args.outFileName, + coordFileName=args.coordFileName) + + +
[docs]def add_zmid(inFileName, outFileName, coordFileName=None): + """ + Add a 3D, time-independent depth coordinate to an MPAS-Ocean file. + + Parameters + ---------- + inFileName : str + An input MPAS-Ocean file that ``zMid`` should be added to, used for + coords if another file is not provided via ``coordFileName``. + + outFileName : str + An output MPAS-Ocean file with ``zMid`` added + + coordFileName : str, optional + An MPAS-Ocean file with ``bottomDepth``, ``maxLevelCell`` and + ``layerThickness`` but not ``zMid`` + """ + if coordFileName is None: + coordFileName = inFileName + + ds = xarray.open_dataset(inFileName, mask_and_scale=False) + if 'nVertLevels' in ds.dims: + ds = ds.rename({'nVertLevels': 'depth'}) + + # dsCoord doesn't have masking disabled because we want it for zMid + dsCoord = xarray.open_dataset(coordFileName) + dsCoord = dsCoord.rename({'nVertLevels': 'depth'}) + if 'Time' in dsCoord.dims: + dsCoord = dsCoord.isel(Time=0) + + ds.coords['zMid'] = compute_zmid(dsCoord.bottomDepth, + dsCoord.maxLevelCell, + dsCoord.layerThickness, + depth_dim='depth') + fillValue = netCDF4.default_fillvals['f8'] + ds.coords['zMid'] = ds.zMid.where(ds.zMid.notnull(), other=fillValue) + ds.zMid.attrs['units'] = 'meters' + ds.zMid.attrs['positive'] = 'up' + ds.zMid.attrs['_FillValue'] = fillValue + + for varName in ds.data_vars: + var = ds[varName] + if 'nCells' in var.dims and 'depth' in var.dims: + var = var.assign_coords(zMid=ds.zMid) + ds[varName] = var + + time = datetime.now().strftime('%c') + + history = '{}: {}'.format(time, ' '.join(sys.argv)) + + if 'history' in ds.attrs: + ds.attrs['history'] = '{}\n{}'.format(history, + ds.attrs['history']) + else: + ds.attrs['history'] = history + + write_netcdf(ds, outFileName)
+ + +def main_add_zmid(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-c", "--coordFileName", dest="coordFileName", + type=str, required=False, + help="An MPAS-Ocean file with bottomDepth, maxLevelCell" + "and layerThickness but not zMid") + parser.add_argument("-i", "--inFileName", dest="inFileName", type=str, + required=True, + help="An input MPAS-Ocean file that zMid should be" + "added to, used for coords if another file is" + "not provided via -c.") + parser.add_argument("-o", "--outFileName", dest="outFileName", type=str, + required=True, + help="An output MPAS-Ocean file with zMid added") + args = parser.parse_args() + + add_zmid(args.inFileName, args.outFileName, + coordFileName=args.coordFileName) + + +
[docs]def write_time_varying_zmid(inFileName, outFileName, coordFileName=None, + prefix=''): + """ + Add a 3D, time-independent depth coordinate to an MPAS-Ocean file. + + Parameters + ---------- + inFileName : str + An input MPAS-Ocean file with some form of ``layerThickness``, and also + ``bottomDepth`` and ``maxLevelCell`` if no ``coordFileName`` + is provided. + + outFileName : str + An output MPAS-Ocean file with ``zMid`` for each time in the input file + + coordFileName : str, optional + An MPAS-Ocean file with ``bottomDepth`` and ``maxLevelCell`` + + prefix : str, optional + A prefix on ``layerThickness`` (in) and ``zMid`` (out), such as + ``timeMonthly_avg_`` + """ + if coordFileName is None: + coordFileName = inFileName + + dsCoord = xarray.open_dataset(coordFileName) + dsCoord = dsCoord.rename({'nVertLevels': 'depth'}) + + dsIn = xarray.open_dataset(inFileName) + dsIn = dsIn.rename({'nVertLevels': 'depth'}) + inVarName = '{}layerThickness'.format(prefix) + outVarName = '{}zMid'.format(prefix) + layerThickness = dsIn[inVarName] + + zMid = compute_zmid(dsCoord.bottomDepth, dsCoord.maxLevelCell, + layerThickness, depth_dim='depth') + + dsOut = xarray.Dataset() + dsOut[outVarName] = zMid + fillValue = netCDF4.default_fillvals['f8'] + dsOut[outVarName] = dsOut[outVarName].where(dsOut[outVarName].notnull(), + other=fillValue) + dsOut[outVarName].attrs['units'] = 'meters' + dsOut[outVarName].attrs['positive'] = 'up' + dsOut[outVarName].attrs['_FillValue'] = fillValue + + time = datetime.now().strftime('%c') + + history = '{}: {}'.format(time, ' '.join(sys.argv)) + dsOut.attrs['history'] = history + + write_netcdf(dsOut, outFileName)
+ + +def main_write_time_varying_zmid(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-c", "--coordFileName", dest="coordFileName", + type=str, required=False, + help="An MPAS-Ocean file with bottomDepth and " + "maxLevelCell") + parser.add_argument("-i", "--inFileName", dest="inFileName", type=str, + required=True, + help="An input MPAS-Ocean file with some form of" + "layerThickness, and also bottomDepth and" + "maxLevelCell if no coordinate file is provided.") + parser.add_argument("-o", "--outFileName", dest="outFileName", type=str, + required=True, + help="An output MPAS-Ocean file with zMid for each" + "time in the input file") + parser.add_argument("-p", "--prefix", dest="prefix", type=str, + required=False, default="", + help="A prefix on layerThickness (in) and zMid (out)," + "such as 'timeMonthly_avg_'") + args = parser.parse_args() + + write_time_varying_zmid( + args.inFileName, args.outFileName, coordFileName=args.coordFileName, + prefix=args.prefix) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/inject_bathymetry.html b/0.22.0rc4/_modules/mpas_tools/ocean/inject_bathymetry.html new file mode 100644 index 000000000..194bdc990 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/inject_bathymetry.html @@ -0,0 +1,257 @@ + + + + + + mpas_tools.ocean.inject_bathymetry — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.ocean.inject_bathymetry

+# Simple script to inject bathymetry onto a mesh
+# Phillip Wolfram, 01/19/2018
+
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+from mpas_tools.mesh.creation.open_msh import readmsh
+from mpas_tools.mesh.interpolation import interp_bilin
+import numpy as np
+from scipy import interpolate
+import netCDF4 as nc4
+import timeit
+import os
+import sys
+
+
+
[docs]def inject_bathymetry(mesh_file): + # Open NetCDF mesh file and read mesh points + nc_mesh = nc4.Dataset(mesh_file, 'r+') + lon_mesh = np.mod( + nc_mesh.variables['lonCell'][:] + np.pi, + 2 * np.pi) - np.pi + lat_mesh = nc_mesh.variables['latCell'][:] + + # Interpolate bathymetry on to mesh points + if os.path.isfile("earth_relief_15s.nc"): + bathymetry = interpolate_SRTM(lon_mesh, lat_mesh) + elif os.path.isfile("topo.msh"): + bathymetry = interpolate_topomsh(lon_mesh, lat_mesh) + else: + print("Bathymetry data file not found") + raise SystemExit(0) + + # Create new NetCDF variables in mesh file, if necessary + nc_vars = nc_mesh.variables.keys() + if 'bottomDepthObserved' not in nc_vars: + nc_mesh.createVariable('bottomDepthObserved', 'f8', ('nCells')) + + # Write to mesh file + nc_mesh.variables['bottomDepthObserved'][:] = bathymetry + nc_mesh.close()
+ + +def interpolate_SRTM(lon_pts, lat_pts): + + # Open NetCDF data file and read cooordintes + nc_data = nc4.Dataset("earth_relief_15s.nc", "r") + lon_data = np.deg2rad(nc_data.variables['lon'][:]) + lat_data = np.deg2rad(nc_data.variables['lat'][:]) + + # Setup interpolation boxes (for large bathymetry datasets) + n = 15 + xbox = np.deg2rad(np.linspace(-180, 180, n)) + ybox = np.deg2rad(np.linspace(-90, 90, n)) + dx = xbox[1] - xbox[0] + dy = ybox[1] - ybox[0] + boxes = [] + for i in range(n - 1): + for j in range(n - 1): + boxes.append(np.asarray( + [xbox[i], xbox[i + 1], ybox[j], ybox[j + 1]])) + + # Initialize bathymetry + bathymetry = np.zeros(np.shape(lon_pts)) + bathymetry.fill(np.nan) + + # Interpolate inside each box + start = timeit.default_timer() + for i, box in enumerate(boxes): + print(i + 1, "/", len(boxes)) + + # Get data inside box (plus a small overlap region) + overlap = 0.1 + lon_idx, = np.where( + (lon_data >= box[0] - overlap * dx) & (lon_data <= box[1] + overlap * dx)) + lat_idx, = np.where( + (lat_data >= box[2] - overlap * dy) & (lat_data <= box[3] + overlap * dy)) + xdata = lon_data[lon_idx] + ydata = lat_data[lat_idx] + zdata = nc_data.variables['z'][lat_idx, lon_idx] + + # Get points inside box + lon_idx, = np.where((lon_pts >= box[0]) & (lon_pts <= box[1])) + lat_idx, = np.where((lat_pts >= box[2]) & (lat_pts <= box[3])) + idx = np.intersect1d(lon_idx, lat_idx) + xpts = lon_pts[idx] + ypts = lat_pts[idx] + + bathymetry[idx] = interp_bilin(xdata, ydata, zdata, xpts, ypts) + + end = timeit.default_timer() + print(end - start, " seconds") + + return bathymetry + + +def interpolate_topomsh(lon_pts, lat_pts): + + topo = readmsh('topo.msh') + xpos = np.deg2rad(topo['COORD1']) + ypos = np.deg2rad(topo['COORD2']) + zlev = np.reshape(topo['VALUE'], (len(ypos), len(xpos))) + + Y, X = np.meshgrid(ypos, xpos) + + bathy = interpolate.LinearNDInterpolator( + np.vstack((X.ravel(), Y.ravel())).T, zlev.ravel()) + bathymetry = bathy(np.vstack((lon_pts, lat_pts)).T) + + return bathymetry + + +def main(): + # Open NetCDF mesh file and read mesh points + mesh_file = sys.argv[1] + inject_bathymetry(mesh_file) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/inject_meshDensity.html b/0.22.0rc4/_modules/mpas_tools/ocean/inject_meshDensity.html new file mode 100644 index 000000000..0b66324f3 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/inject_meshDensity.html @@ -0,0 +1,281 @@ + + + + + + mpas_tools.ocean.inject_meshDensity — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.ocean.inject_meshDensity

+#!/usr/bin/env python
+# Simple script to inject mesh density onto a mesh
+# example usage:
+#   ./inject_meshDensity.py cellWidthVsLatLon.nc base_mesh.nc
+# where:
+#   cellWidthVsLatLon.nc is a netcdf file with cellWidth
+#   base_mesh.nc is the mpas netcdf file where meshDensity is added
+# Mark Petersen, 7/24/2018
+
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy as np
+import netCDF4 as nc4
+import sys
+
+from mpas_tools.mesh.interpolation import interp_bilin
+
+
+
[docs]def inject_meshDensity_from_file(cw_filename, mesh_filename, on_sphere=True): + """ + Add a ``meshDensity`` field into an MPAS mesh. The mesh density is defined + as: + + meshDensity = (minCellWidth / cellWidth)**4 + + Parameters + ---------- + cw_filename : str + The file name to read ``cellWidth`` and coordinates from + + mesh_filename : str + The mesh file to add ``meshDensity`` to + + on_sphere : bool, optional + Whether the mesh is spherical (as opposed to planar) + """ + print('Read cell width field from nc file regular grid...') + ds = nc4.Dataset(cw_filename,'r') + cellWidth = ds.variables['cellWidth'][:] + if on_sphere: + lon = ds.variables['lon'][:] + lat = ds.variables['lat'][:] + ds.close() + inject_spherical_meshDensity(cellWidth, lon, lat, mesh_filename) + else: + x = ds.variables['x'][:] + y = ds.variables['y'][:] + ds.close() + inject_spherical_meshDensity(cellWidth, x, y, mesh_filename)
+ + + +
[docs]def inject_spherical_meshDensity(cellWidth, lon, lat, mesh_filename): + """ + Add a ``meshDensity`` field into a spherical MPAS mesh. The mesh density is + defined as: + + meshDensity = (minCellWidth / cellWidth)**4 + + Parameters + ---------- + cellWidth : ndarray + m x n array of cell width in km + + lon : ndarray + longitude in degrees (length n and between -180 and 180) + + lat : ndarray + longitude in degrees (length m and between -90 and 90) + + mesh_filename : str + The mesh file to add ``meshDensity`` to + """ + + minCellWidth = cellWidth.min() + meshDensityVsXY = (minCellWidth / cellWidth)**4 + print(' minimum cell width in grid definition: {0:.0f} km'.format( + minCellWidth)) + print(' maximum cell width in grid definition: {0:.0f} km'.format( + cellWidth.max())) + + print('Open unstructured MPAS mesh file...') + ds = nc4.Dataset(mesh_filename, 'r+') + meshDensity = ds.variables['meshDensity'] + lonCell = ds.variables['lonCell'][:] + latCell = ds.variables['latCell'][:] + + lonCell = np.mod(np.rad2deg(lonCell) + 180., 360.) - 180. + latCell = np.rad2deg(latCell) + + print('Interpolating and writing meshDensity...') + mpasMeshDensity = interp_bilin(lon, lat, meshDensityVsXY, lonCell, latCell) + + meshDensity[:] = mpasMeshDensity + + ds.close()
+ + +
[docs]def inject_planar_meshDensity(cellWidth, x, y, mesh_filename): + """ + Add a ``meshDensity`` field into a planar MPAS mesh. The mesh density is + defined as: + + meshDensity = (minCellWidth / cellWidth)**4 + + Parameters + ---------- + cellWidth : ndarray + m x n array of cell width in km + + x, y : ndarray + Planar coordinates in meters + + mesh_filename : str + The mesh file to add ``meshDensity`` to + """ + minCellWidth = cellWidth.min() + meshDensityVsXY = (minCellWidth / cellWidth)**4 + print(' minimum cell width in grid definition: {0:.0f} km'.format(minCellWidth)) + print(' maximum cell width in grid definition: {0:.0f} km'.format(cellWidth.max())) + + print('Open unstructured MPAS mesh file...') + ds = nc4.Dataset(mesh_filename, 'r+') + meshDensity = ds.variables['meshDensity'] + xCell = ds.variables['xCell'][:] + yCell = ds.variables['xCell'][:] + + print('Interpolating and writing meshDensity...') + mpasMeshDensity = interp_bilin(x, y, meshDensityVsXY, xCell, yCell) + + meshDensity[:] = mpasMeshDensity + + ds.close()
+ + +if __name__ == "__main__": + + inject_meshDensity_from_file(cw_filename=sys.argv[1], + mesh_filename=sys.argv[2]) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/inject_preserve_floodplain.html b/0.22.0rc4/_modules/mpas_tools/ocean/inject_preserve_floodplain.html new file mode 100644 index 000000000..2a2f79700 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/inject_preserve_floodplain.html @@ -0,0 +1,169 @@ + + + + + + mpas_tools.ocean.inject_preserve_floodplain — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.ocean.inject_preserve_floodplain

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import netCDF4 as nc4
+import argparse
+
+
+
[docs]def inject_preserve_floodplain(mesh_file, floodplain_elevation): + + nc_mesh = nc4.Dataset(mesh_file, 'r+') + nc_vars = nc_mesh.variables.keys() + + if 'cellSeedMask' not in nc_vars: + nc_mesh.createVariable('cellSeedMask', 'i', ('nCells')) + nc_mesh.variables['cellSeedMask'][:] = \ + nc_mesh.variables['bottomDepthObserved'][:] < floodplain_elevation + + nc_mesh.close()
+ + +def main(): + + parser = argparse.ArgumentParser() + parser.add_argument('mesh_file', action='store', type=str) + parser.add_argument('floodplain_elevation', action='store', type=float) + cl_args = parser.parse_args() + + inject_preserve_floodplain(cl_args.mesh_file, cl_args.floodplain_elevation) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/moc.html b/0.22.0rc4/_modules/mpas_tools/ocean/moc.html new file mode 100644 index 000000000..47b0b1cb9 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/moc.html @@ -0,0 +1,529 @@ + + + + + + mpas_tools.ocean.moc — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.ocean.moc

+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import xarray
+import numpy
+import logging
+import sys
+from geometric_features.aggregation.ocean import moc
+
+import mpas_tools.mesh.conversion
+from mpas_tools.io import write_netcdf
+
+
+
[docs]def make_moc_basins_and_transects(gf, mesh_filename, + mask_and_transect_filename, + geojson_filename=None, + mask_filename=None, + logger=None, + dir=None): + """ + Builds features defining the ocean basins and southern transects used in + computing the meridional overturning circulation (MOC) + + Parameters + ---------- + gf : geometric_features.GeometricFeatures + An object that knows how to download and read geometric features + + mesh_filename : str + A file with MPAS mesh information + + mask_and_transect_filename : str + A file to write the MOC region masks and southern-boundary transects to + + geojson_filename : str, optional + A file to write MOC regions to + + mask_filename : str, optional + A file to write MOC region masks to + + logger : ``logging.Logger``, optional + A logger for the output if not stdout + + dir : str, optional + A directory in which a temporary directory will be added with files + produced during conversion and then deleted upon completion. + + Returns + ------- + fc : geometric_features.FeatureCollection + The new feature collection + """ + # Authors + # ------- + # Xylar Asay-Davis + + fcMOC = moc(gf) + + if geojson_filename is not None: + fcMOC.to_geojson(geojson_filename) + + dsMesh = xarray.open_dataset(mesh_filename) + dsMasks = mpas_tools.mesh.conversion.mask(dsMesh=dsMesh, fcMask=fcMOC, + logger=logger, dir=dir) + + if mask_filename is not None: + write_netcdf(dsMasks, mask_filename, char_dim_name='StrLen') + + dsMasksAndTransects = add_moc_southern_boundary_transects(dsMasks, dsMesh, + logger=logger) + write_netcdf(dsMasksAndTransects, mask_and_transect_filename, + char_dim_name='StrLen')
+ + +
[docs]def add_moc_southern_boundary_transects(dsMask, dsMesh, logger=None): + """ + Parameters + ---------- + dsMask : ``xarray.Dataset`` + Region masks defining MOC basins + + dsMesh : ``xarray.Dataset``, optional + An MPAS mesh on which the masks should be created + + logger : ``logging.Logger``, optional + A logger for the output if not stdout + + Returns + ------- + dsMask : ``xarray.Dataset`` + Region masks defining MOC basins and the corresponding southern-boundary + transects + """ + + useStdout = logger is None + if useStdout: + logger = logging.getLogger() + logger.addHandler(logging.StreamHandler(sys.stdout)) + logger.setLevel(logging.INFO) + + southernBoundaryEdges, southernBoundaryEdgeSigns, \ + southernBoundaryVertices = \ + _extract_southern_boundary(dsMesh, dsMask, latBuffer=3.*numpy.pi/180., + logger=logger) + + _add_transects_to_moc(dsMesh, dsMask, southernBoundaryEdges, + southernBoundaryEdgeSigns, + southernBoundaryVertices) + + if useStdout: + logger.handlers = [] + + return dsMask
+ + +def _extract_southern_boundary(mesh, mocMask, latBuffer, logger): + """ + Extracts the southern boundary of each region mask in mocMask. Mesh info + is taken from mesh. latBuffer is a number of radians above the southern- + most point that should be considered to definitely be in the southern + boundary. + """ + + nCells = mesh.dims['nCells'] + nEdges = mesh.dims['nEdges'] + + nRegions = mocMask.dims['nRegions'] + assert(mocMask.dims['nCells'] == nCells) + + # convert to python zero-based indices + cellsOnEdge = mesh.variables['cellsOnEdge'].values-1 + verticesOnEdge = mesh.variables['verticesOnEdge'].values-1 + edgesOnVertex = mesh.variables['edgesOnVertex'].values-1 + + latEdge = mesh.variables['latEdge'].values + + cellsOnEdgeInRange = numpy.logical_and(cellsOnEdge >= 0, + cellsOnEdge < nCells) + # make sure both cells on the dummy edge at the end are out of range + cellsOnEdgeInRange[-1, :] = False + + southernBoundaryEdges = [] + southernBoundaryEdgeSigns = [] + southernBoundaryVertices = [] + + for iRegion in range(nRegions): + name = mocMask.regionNames[iRegion].values.astype('U') + logger.info(name) + cellMask = mocMask.variables['regionCellMasks'][:, iRegion].values + + # land cells are outside not in the MOC region + cellsOnEdgeMask = numpy.zeros(cellsOnEdge.shape, bool) + # set mask values for cells that are in range (not land) + cellsOnEdgeMask[cellsOnEdgeInRange] = \ + cellMask[cellsOnEdge[cellsOnEdgeInRange]] == 1 + + logger.info(' computing edge sign...') + edgeSign = numpy.zeros(nEdges) + # positive sign if the first cell on edge is in the region + mask = numpy.logical_and(cellsOnEdgeMask[:, 0], + numpy.logical_not(cellsOnEdgeMask[:, 1])) + edgeSign[mask] = -1. + # negative sign if the second cell on edge is in the region + mask = numpy.logical_and(cellsOnEdgeMask[:, 1], + numpy.logical_not(cellsOnEdgeMask[:, 0])) + edgeSign[mask] = 1. + isMOCBoundaryEdge = edgeSign != 0. + edgesMOCBoundary = numpy.arange(nEdges)[isMOCBoundaryEdge] + logger.info(' done.') + + startEdge = numpy.argmin(latEdge[isMOCBoundaryEdge]) + startEdge = edgesMOCBoundary[startEdge] + minLat = latEdge[startEdge] + + logger.info(' getting edge sequence...') + # follow the boundary from this point to get a loop of edges + # Note: it is possible but unlikely that the southern-most point is + # not within bulk region of the MOC mask if the region is not a single + # shape + edgeSequence, edgeSequenceSigns, vertexSequence = \ + _get_edge_sequence_on_boundary(startEdge, edgeSign, edgesOnVertex, + verticesOnEdge) + + logger.info(' done: {} edges in transect.'.format(len(edgeSequence))) + + aboveSouthernBoundary = latEdge[edgeSequence] > minLat + latBuffer + + # find and eliminate the longest contiguous sequence (if any) from the + # edge sequence that is above the possible region of the soutehrn + # boundary + + belowToAbove = \ + numpy.logical_and(numpy.logical_not(aboveSouthernBoundary[0:-1]), + aboveSouthernBoundary[1:]) + + aboveToBelow = \ + numpy.logical_and(aboveSouthernBoundary[0:-1], + numpy.logical_not(aboveSouthernBoundary[1:])) + + startIndices = numpy.arange(1, len(edgeSequence))[belowToAbove] + endIndices = numpy.arange(1, len(edgeSequence))[aboveToBelow] + + assert(len(startIndices) == len(endIndices)) + + if len(startIndices) == 0: + # the whole sequence is the southern boundary + southernBoundaryEdges.append(edgeSequence) + southernBoundaryEdgeSigns.append(edgeSequenceSigns) + southernBoundaryVertices.append(vertexSequence) + continue + + # there are some parts of the sequence above the boundary. Let's + # eliminate the longest one. + + aboveLength = endIndices - startIndices + longest = numpy.argmax(aboveLength) + # we want all the indices in the sequence *not* part of the longest + indices = numpy.arange(endIndices[longest], + startIndices[longest] + len(edgeSequence)) + indices = numpy.mod(indices, len(edgeSequence)) + + southernBoundaryEdges.append(edgeSequence[indices]) + southernBoundaryEdgeSigns.append(edgeSequenceSigns[indices]) + + # we want one extra vertex in the vertex sequence + indices = numpy.arange(endIndices[longest], + startIndices[longest] + len(edgeSequence) + 1) + indices = numpy.mod(indices, len(edgeSequence)) + + southernBoundaryVertices.append(vertexSequence[indices]) + + return southernBoundaryEdges, southernBoundaryEdgeSigns, \ + southernBoundaryVertices + + +def _add_transects_to_moc(mesh, mocMask, southernBoundaryEdges, + southernBoiundaryEdgeSigns, southernBoundaryVertices): + """ + Creates transect fields in mocMask from the edges, edge signs and + vertices defining the southern boundaries. Mesh info (nEdges and + nVertices) is taken from the mesh file. + """ + + nTransects = len(southernBoundaryEdges) + + nEdges = mesh.dims['nEdges'] + nVertices = mesh.dims['nVertices'] + + maxEdgesInTransect = numpy.amax([len(southernBoundaryEdges[iTransect]) + for iTransect in range(nTransects)]) + + maxVerticesInTransect = \ + numpy.amax([len(southernBoundaryVertices[iTransect]) + for iTransect in range(nTransects)]) + + transectEdgeMasks = numpy.zeros((nEdges, nTransects), + numpy.int32) + transectEdgeMaskSigns = numpy.zeros((nEdges, nTransects), + numpy.int32) + transectEdgeGlobalIDs = numpy.zeros((nTransects, maxEdgesInTransect), + numpy.int32) + transectVertexMasks = numpy.zeros((nVertices, nTransects), + numpy.int32) + transectVertexGlobalIDs = numpy.zeros((nTransects, maxVerticesInTransect), + numpy.int32) + + for iTransect in range(nTransects): + transectEdgeMasks[southernBoundaryEdges[iTransect], iTransect] = 1 + + transectEdgeMaskSigns[southernBoundaryEdges[iTransect], iTransect] \ + = southernBoiundaryEdgeSigns[iTransect] + + transectCount = len(southernBoundaryEdges[iTransect]) + transectEdgeGlobalIDs[iTransect, 0:transectCount] \ + = southernBoundaryEdges[iTransect] + 1 + + transectVertexMasks[southernBoundaryVertices[iTransect], iTransect] = 1 + + transectCount = len(southernBoundaryVertices[iTransect]) + transectVertexGlobalIDs[iTransect, 0:transectCount] \ + = southernBoundaryVertices[iTransect] + 1 + + mocMask['transectEdgeMasks'] = \ + (('nEdges', 'nTransects'), transectEdgeMasks) + mocMask['transectEdgeMaskSigns'] = (('nEdges', 'nTransects'), + transectEdgeMaskSigns) + mocMask['transectEdgeGlobalIDs'] = (('nTransects', 'maxEdgesInTransect'), + transectEdgeGlobalIDs) + + mocMask['transectVertexMasks'] = (('nVertices', 'nTransects'), + transectVertexMasks) + mocMask['transectVertexGlobalIDs'] = \ + (('nTransects', 'maxVerticesInTransect'), transectVertexGlobalIDs) + + if 'nRegionsInGroup' not in mocMask: + nRegions = mocMask.sizes['nRegions'] + nRegionGroups = 2 + nRegionsInGroup = nRegions*numpy.ones(nRegionGroups, dtype=int) + regionsInGroup = numpy.zeros((nRegionGroups, nRegions), dtype=int) + regionGroupNames = ['MOCBasinRegionsGroup', 'all'] + regionNames = mocMask.regionNames.values + nChar = 64 + for index in range(nRegionGroups): + regionsInGroup[index, :] = numpy.arange(1, nRegions+1) + + mocMask['nRegionsInGroup'] = (('nRegionGroups',), nRegionsInGroup) + + mocMask['regionsInGroup'] = (('nRegionGroups', 'maxRegionsInGroup'), + regionsInGroup) + + mocMask['regionGroupNames'] = \ + (('nRegionGroups',), numpy.zeros((nRegionGroups,), + dtype='|S{}'.format(nChar))) + + for index in range(nRegionGroups): + mocMask['regionGroupNames'][index] = regionGroupNames[index] + + # we need to make sure the region names use the same string length + mocMask['regionNames'] = \ + (('nRegions',), numpy.zeros((nRegions,), + dtype='|S{}'.format(nChar))) + + for index in range(nRegions): + mocMask['regionNames'][index] = regionNames[index] + + mocMask['transectNames'] = mocMask.regionNames.rename( + {'nRegions': 'nTransects'}) + + mocMask['nTransectsInGroup'] = mocMask.nRegionsInGroup.rename( + {'nRegionGroups': 'nTransectGroups'}) + + mocMask['transectsInGroup'] = mocMask.regionsInGroup.rename( + {'nRegionGroups': 'nTransectGroups', + 'maxRegionsInGroup': 'maxTransectsInGroup'}) + + mocMask['transectGroupNames'] = mocMask.regionGroupNames.rename( + {'nRegionGroups': 'nTransectGroups'}) + + +def _get_edge_sequence_on_boundary(startEdge, edgeSign, edgesOnVertex, + verticesOnEdge): + """ + Follows the boundary from a starting edge to produce a sequence of + edges that form a closed loop. + + startEdge is an edge on the boundary that will be both the start and + end of the loop. + + isBoundaryEdge is a mask that indicates which edges are on the + boundary + + returns lists of edges, edge signs and vertices + """ + + iEdge = startEdge + edgeSequence = [] + vertexSequence = [] + while True: + assert(edgeSign[iEdge] == 1. or edgeSign[iEdge] == -1.) + if edgeSign[iEdge] == 1.: + v = 0 + else: + v = 1 + iVertex = verticesOnEdge[iEdge, v] + + eov = edgesOnVertex[iVertex, :] + + # find the edge that is not iEdge but is on the boundary + nextEdge = -1 + for edge in eov: + if edge != iEdge and edgeSign[edge] != 0: + nextEdge = edge + break + assert(nextEdge != -1) + + edgeSequence.append(iEdge) + vertexSequence.append(iVertex) + + iEdge = nextEdge + + if iEdge == startEdge: + break + + edgeSequence = numpy.array(edgeSequence) + edgeSequenceSigns = edgeSign[edgeSequence] + vertexSequence = numpy.array(vertexSequence) + + return edgeSequence, edgeSequenceSigns, vertexSequence +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/transects.html b/0.22.0rc4/_modules/mpas_tools/ocean/transects.html new file mode 100644 index 000000000..9cda8231e --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/transects.html @@ -0,0 +1,745 @@ + + + + + + mpas_tools.ocean.transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.ocean.transects

+import xarray
+import numpy
+
+
+
[docs]def find_transect_levels_and_weights(dsTransect, layerThickness, bottomDepth, + maxLevelCell, zTransect=None): + """ + Construct a vertical coordinate for a transect produced by + :py:fun:`mpas_tools.viz.transects.find_transect_cells_and_weights()`, then + break each resulting quadrilateral into 2 triangles that can later be + visualized with functions like ``tripcolor`` and ``tricontourf``. Also, + compute interpolation weights such that observations at points on the + original transect and with vertical coordinate ``transectZ`` can be + bilinearly interpolated to the nodes of the transect. + + Parameters + ---------- + dsTransect : xarray.Dataset + A dataset that defines nodes of the transect, the results of calling + :py:fun:`mpas_tools.viz.transects.find_transect_cells_and_weights()` + + layerThickness : xarray.DataArray + layer thicknesses on the MPAS mesh + + bottomDepth : xarray.DataArray + the (positive down) depth of the seafloor on the MPAS mesh + + maxLevelCell : xarray.DataArray + the vertical zero-based index of the bathymetry on the MPAS mesh + + zTransect : xarray.DataArray, optional + the z coordinate of the transect (1D or 2D). If 2D, it must have the + same along-transect dimension as the lon and lat passed to + :py:fun:`mpas_tools.viz.transects.find_transect_cells_and_weights()` + + Returns + ------- + dsTransectTriangles : xarray.Dataset + A dataset that contains nodes and triangles that make up a 2D transect. + For convenience in visualization, the quadrilaterals of each cell making + up the transect have been divided into an upper and lower triangle. The + nodes of the triangles are completely independent of one another, + allowing for potential jumps in fields values between nodes of different + triangles that are at the same location. This is convenient, for + example, when visualizing data with constant values within each MPAS + cell. + + There are ``nTransectTriangles = 2*nTransectCells`` triangles, each with + ``nTriangleNodes = 3`` nodes, where ``nTransectCells`` is the number of + valid transect cells (quadrilaterals) that are above the MPAS-Ocean + bathymetry. + + In addition to the variables and coordinates in ``dsTransect``, the + output dataset contains: + + - nodeHorizBoundsIndices: which of the ``nHorizBounds = 2`` + bounds of a horizontal transect segment a given node is on + - segmentIndices: the transect segment of a given triangle + - cellIndices: the MPAS-Ocean cell of a given triangle + - levelIndices: the MPAS-Ocean vertical level of a given triangle + + - zTransectNode: the vertical height of each triangle node + - ssh, zSeaFloor: the sea-surface height and sea-floor height at + each node of each transect segment + + - interpCellIndices, interpLevelIndices: the MPAS-Ocean cells and + levels from which the value at a given triangle node are + interpolated. This can involve up to ``nWeights = 12`` different + cells and levels. + - interpCellWeights: the weight to multiply each field value by + to perform interpolation to a triangle node. + + - transectInterpVertIndices, transectInterpVertWeights - if + ``zTransect`` is not ``None``, vertical indices and weights for + interpolating from the original transect grid to MPAS-Ocean + transect nodes. + + Interpolation of a DataArray from MPAS cells and levels to transect + triangle nodes can be performed with + ``interp_mpas_to_transect_triangle_nodes()``. Similarly, interpolation of a + DataArray (e.g. an observation) from the original transect grid to + transect triangle nodes can be performed with + ``interp_transect_grid_to_transect_triangle_nodes()`` + + To visualize constant values on MPAS cells, a field can be sampled + at indices ``nCells=cellIndices`` and ``nVertLevels=levelIndices``. + If a smoother visualization is desired, bilinear interpolation can be + performed by first sampling the field at indices + ``nCells=interpCellIndices`` and ``nVertLevels=interpLevelIndices`` and + then multiplying by ``interpCellWeights`` and summing over + ``nWeights``. + """ + + dsTransectCells = _get_transect_cells_and_nodes( + dsTransect, layerThickness, bottomDepth, maxLevelCell) + + dsTransectTriangles = _transect_cells_to_triangles(dsTransectCells) + + if zTransect is not None: + dsTransectTriangles = _add_vertical_interpolation_of_transect_points( + dsTransectTriangles, zTransect) + + return dsTransectTriangles
+ + +
[docs]def interp_mpas_to_transect_triangles(dsTransectTriangles, da): + """ + Interpolate a 3D (``nCells`` by ``nVertLevels``) MPAS-Ocean DataArray + to transect nodes with constant values in each MPAS cell + + Parameters + ---------- + dsTransectTriangles : xarray.Dataset + A dataset that defines triangles making up an MPAS-Ocean transect, the + results of calling ``find_transect_levels_and_weights()`` + + da : xarray.DataArray + An MPAS-Ocean 3D field with dimensions `nCells`` and ``nVertLevels`` + (possibly among others) + + Returns + ------- + daNodes : xarray.DataArray + The data array interpolated to transect nodes with dimensions + ``nTransectTriangles`` and ``nTriangleNodes`` (in addition to whatever + dimensions were in ``da`` besides ``nCells`` and ``nVertLevels``) + """ + + cellIndices = dsTransectTriangles.cellIndices + levelIndices = dsTransectTriangles.levelIndices + + daNodes = da.isel(nCells=cellIndices, nVertLevels=levelIndices) + + return daNodes
+ + +
[docs]def interp_mpas_to_transect_triangle_nodes(dsTransectTriangles, da): + """ + Interpolate a 3D (``nCells`` by ``nVertLevels``) MPAS-Ocean DataArray + to transect nodes, linearly interpolating fields between the closest + neighboring cells + + Parameters + ---------- + dsTransectTriangles : xarray.Dataset + A dataset that defines triangles making up an MPAS-Ocean transect, the + results of calling ``find_transect_levels_and_weights()`` + + da : xarray.DataArray + An MPAS-Ocean 3D field with dimensions `nCells`` and ``nVertLevels`` + (possibly among others) + + Returns + ------- + daNodes : xarray.DataArray + The data array interpolated to transect nodes with dimensions + ``nTransectTriangles`` and ``nTriangleNodes`` (in addition to whatever + dimensions were in ``da`` besides ``nCells`` and ``nVertLevels``) + """ + + interpCellIndices = dsTransectTriangles.interpCellIndices + interpLevelIndices = dsTransectTriangles.interpLevelIndices + interpCellWeights = dsTransectTriangles.interpCellWeights + + da = da.isel(nCells=interpCellIndices, nVertLevels=interpLevelIndices) + + daNodes = (da*interpCellWeights).sum(dim='nWeights') + + return daNodes
+ + +
[docs]def interp_transect_grid_to_transect_triangle_nodes(dsTransectTriangles, da): + """ + Interpolate a DataArray on the original transect grid to triangle nodes on + the MPAS-Ocean transect. + + Parameters + ---------- + dsTransectTriangles : xarray.Dataset + A dataset that defines triangles making up an MPAS-Ocean transect, the + results of calling ``find_transect_levels_and_weights()`` + + da : xarray.DataArray + An field on the original triangle mesh + + Returns + ------- + daNodes : xarray.DataArray + The data array interpolated to transect nodes with dimensions + ``nTransectTriangles`` and ``nTriangleNodes`` + """ + + horizDim = dsTransectTriangles.dTransect.dims[0] + zTransect = dsTransectTriangles.zTransect + vertDim = None + for dim in zTransect.dims: + if dim != horizDim: + vertDim = dim + + horizIndices = dsTransectTriangles.transectIndicesOnHorizNode + horizWeights = dsTransectTriangles.transectWeightsOnHorizNode + + segmentIndices = dsTransectTriangles.segmentIndices + nodeHorizBoundsIndices = dsTransectTriangles.nodeHorizBoundsIndices + + horizIndices = horizIndices.isel(nSegments=segmentIndices, + nHorizBounds=nodeHorizBoundsIndices) + horizWeights = horizWeights.isel(nSegments=segmentIndices, + nHorizBounds=nodeHorizBoundsIndices) + + vertIndices = dsTransectTriangles.transectInterpVertIndices + vertWeights = dsTransectTriangles.transectInterpVertWeights + + kwargs00 = {horizDim: horizIndices, vertDim: vertIndices} + kwargs01 = {horizDim: horizIndices, vertDim: vertIndices+1} + kwargs10 = {horizDim: horizIndices+1, vertDim: vertIndices} + kwargs11 = {horizDim: horizIndices+1, vertDim: vertIndices+1} + + daNodes = (horizWeights * vertWeights * da.isel(**kwargs00) + + horizWeights * (1.0 - vertWeights) * da.isel(**kwargs01) + + (1.0 - horizWeights) * vertWeights * da.isel(**kwargs10) + + (1.0 - horizWeights) * (1.0 - vertWeights) * da.isel(**kwargs11)) + + mask = numpy.logical_and(horizIndices != -1, vertIndices != -1) + + daNodes = daNodes.where(mask) + + return daNodes
+ + +
[docs]def get_outline_segments(dsTransectTriangles, epsilon=1e-3): + """Get a set of line segments that outline the given transect""" + + nSegments = dsTransectTriangles.sizes['nSegments'] + dSeaFloor = dsTransectTriangles.dNode.values + zSeaFloor = dsTransectTriangles.zSeaFloor.values + ssh = dsTransectTriangles.ssh.values + + seaFloorJumps = numpy.abs(dSeaFloor[0:-1, 1] - dSeaFloor[1:, 0]) < epsilon + nSeaFloorJumps = numpy.count_nonzero(seaFloorJumps) + nSurface = nSegments + nSeaFloor = nSegments + nSeaFloorJumps + nLandJumps = nSegments - nSeaFloorJumps + + nOutline = nSurface + nSeaFloor + 2*nLandJumps + + d = numpy.zeros((nOutline, 2)) + z = numpy.zeros((nOutline, 2)) + + d[0:nSegments, :] = dSeaFloor + z[0:nSegments, :] = ssh + d[nSegments:2*nSegments, :] = dSeaFloor + z[nSegments:2*nSegments, :] = zSeaFloor + + dSeaFloorJump = numpy.vstack((dSeaFloor[0:-1, 1], dSeaFloor[1:, 0])).T + zSeaFloorJump = numpy.vstack((zSeaFloor[0:-1, 1], zSeaFloor[1:, 0])).T + slc = slice(2*nSegments, 2*nSegments+nSeaFloorJumps) + d[slc, :] = dSeaFloorJump[seaFloorJumps, :] + z[slc, :] = zSeaFloorJump[seaFloorJumps, :] + + landJumps1 = numpy.ones(nSegments, bool) + landJumps1[1:] = numpy.logical_not(seaFloorJumps) + landJumps2 = numpy.ones(nSegments, bool) + landJumps2[0:-1] = numpy.logical_not(seaFloorJumps) + + offset = 2*nSegments+nSeaFloorJumps + slc = slice(offset, offset + nLandJumps) + d[slc, 0] = dSeaFloor[landJumps1, 0] + d[slc, 1] = dSeaFloor[landJumps1, 0] + z[slc, 0] = ssh[landJumps1, 0] + z[slc, 1] = zSeaFloor[landJumps1, 0] + + offset = 2*nSegments+nSeaFloorJumps+nLandJumps + slc = slice(offset, offset + nLandJumps) + d[slc, 0] = dSeaFloor[landJumps2, 1] + d[slc, 1] = dSeaFloor[landJumps2, 1] + z[slc, 0] = ssh[landJumps2, 1] + z[slc, 1] = zSeaFloor[landJumps2, 1] + + d = d.T + z = z.T + + return d, z
+ + +def _get_transect_cells_and_nodes(dsTransect, layerThickness, bottomDepth, + maxLevelCell): + + if 'Time' in layerThickness.dims: + raise ValueError('Please select a single time level in layerThickness.') + + dsTransect = dsTransect.rename({'nBounds': 'nHorizBounds'}) + + zTop, zMid, zBot, ssh, zSeaFloor, interpCellIndices, interpCellWeights = \ + _get_vertical_coordinate(dsTransect, layerThickness, bottomDepth, + maxLevelCell) + + nVertLevels = layerThickness.sizes['nVertLevels'] + + levelIndices = xarray.DataArray(data=numpy.arange(2*nVertLevels)//2, + dims='nHalfLevels') + + cellMask = (levelIndices <= maxLevelCell).transpose('nCells', 'nHalfLevels') + + dsTransectCells = _add_valid_cells_and_levels( + dsTransect, dsTransect.horizCellIndices.values, levelIndices.values, + cellMask.values) + + # transect cells are made up of half-levels, and each half-level has a top + # and bottom interface, so we need 4 interfaces per MPAS level + + interpCellIndices, interpLevelIndices, interpCellWeights = \ + _get_interp_indices_and_weights(layerThickness, maxLevelCell, + interpCellIndices, interpCellWeights) + + levelIndex, tempIndex = numpy.meshgrid(numpy.arange(nVertLevels), + numpy.arange(2), indexing='ij') + levelIndex = xarray.DataArray(data=levelIndex.ravel(), dims='nHalfLevels') + tempIndex = xarray.DataArray(data=tempIndex.ravel(), dims='nHalfLevels') + zTop = xarray.concat((zTop, zMid), dim='nTemp') + zTop = zTop.isel(nVertLevels=levelIndex, nTemp=tempIndex) + zBot = xarray.concat((zMid, zBot), dim='nTemp') + zBot = zBot.isel(nVertLevels=levelIndex, nTemp=tempIndex) + + zInterface = xarray.concat((zTop, zBot), dim='nVertBounds') + + segmentIndices = dsTransectCells.segmentIndices + halfLevelIndices = dsTransectCells.halfLevelIndices + + dsTransectCells['interpCellIndices'] = interpCellIndices.isel( + nSegments=segmentIndices, nHalfLevels=halfLevelIndices) + dsTransectCells['interpLevelIndices'] = interpLevelIndices.isel( + nSegments=segmentIndices, nHalfLevels=halfLevelIndices) + dsTransectCells['interpCellWeights'] = interpCellWeights.isel( + nSegments=segmentIndices, nHalfLevels=halfLevelIndices) + dsTransectCells['zTransectNode'] = zInterface.isel( + nSegments=segmentIndices, nHalfLevels=halfLevelIndices) + + dsTransectCells['ssh'] = ssh + dsTransectCells['zSeaFloor'] = zSeaFloor + + dims = ['nSegments', 'nTransectCells', 'nHorizBounds', 'nVertBounds', + 'nHorizWeights', 'nWeights'] + for dim in dsTransectCells.dims: + if dim not in dims: + dims.insert(0, dim) + dsTransectCells = dsTransectCells.transpose(*dims) + + return dsTransectCells + + +def _get_vertical_coordinate(dsTransect, layerThickness, bottomDepth, + maxLevelCell): + nVertLevels = layerThickness.sizes['nVertLevels'] + levelIndices = xarray.DataArray(data=numpy.arange(nVertLevels), + dims='nVertLevels') + cellMask = (levelIndices <= maxLevelCell).transpose('nCells', 'nVertLevels') + + ssh = -bottomDepth + layerThickness.sum(dim='nVertLevels') + + interpCellIndices = dsTransect.interpHorizCellIndices + interpCellWeights = dsTransect.interpHorizCellWeights + + interpMask = numpy.logical_and(interpCellIndices > 0, + cellMask.isel(nCells=interpCellIndices)) + + interpCellWeights = interpMask*interpCellWeights + weightSum = interpCellWeights.sum(dim='nHorizWeights') + + cellIndices = dsTransect.horizCellIndices + + validCells = cellMask.isel(nCells=cellIndices) + + _, validWeights = xarray.broadcast(interpCellWeights, validCells) + interpCellWeights = (interpCellWeights/weightSum).where(validWeights) + + layerThicknessTransect = layerThickness.isel(nCells=interpCellIndices) + layerThicknessTransect = (layerThicknessTransect*interpCellWeights).sum( + dim='nHorizWeights') + + sshTransect = ssh.isel(nCells=interpCellIndices) + sshTransect = (sshTransect*dsTransect.interpHorizCellWeights).sum( + dim='nHorizWeights') + + zBot = sshTransect - layerThicknessTransect.cumsum(dim='nVertLevels') + zTop = zBot + layerThicknessTransect + zMid = 0.5*(zTop + zBot) + + zSeaFloor = sshTransect - layerThicknessTransect.sum(dim='nVertLevels') + + return zTop, zMid, zBot, sshTransect, zSeaFloor, interpCellIndices, \ + interpCellWeights + + +def _add_valid_cells_and_levels(dsTransect, cellIndices, levelIndices, + cellMask): + + dims = ('nTransectCells',) + CellIndices, LevelIndices = numpy.meshgrid(cellIndices, levelIndices, + indexing='ij') + mask = numpy.logical_and(CellIndices >= 0, cellMask[cellIndices, :]) + + SegmentIndices, HalfLevelIndices = \ + numpy.meshgrid(numpy.arange(len(cellIndices)), + numpy.arange(len(levelIndices)), indexing='ij') + + segmentIndices = xarray.DataArray(data=SegmentIndices[mask], dims=dims) + + dsTransectCells = dsTransect + dsTransectCells['cellIndices'] = (dims, CellIndices[mask]) + dsTransectCells['levelIndices'] = (dims, LevelIndices[mask]) + dsTransectCells['segmentIndices'] = segmentIndices + dsTransectCells['halfLevelIndices'] = (dims, HalfLevelIndices[mask]) + + return dsTransectCells + + +def _get_interp_indices_and_weights(layerThickness, maxLevelCell, + interpCellIndices, interpCellWeights): + interpCellIndices = interpCellIndices.rename({'nHorizWeights': 'nWeights'}) + interpCellWeights = interpCellWeights.rename({'nHorizWeights': 'nWeights'}) + nVertLevels = layerThickness.sizes['nVertLevels'] + nHalfLevels = 2*nVertLevels + nVertBounds = 2 + + interpMaxLevelCell = maxLevelCell.isel(nCells=interpCellIndices) + + levelIndices = xarray.DataArray( + data=numpy.arange(nHalfLevels)//2, dims='nHalfLevels') + valid = levelIndices <= interpMaxLevelCell + + topLevelIndices = -1*numpy.ones((nHalfLevels, nVertBounds), int) + topLevelIndices[1:, 0] = numpy.arange(nHalfLevels-1)//2 + topLevelIndices[:, 1] = numpy.arange(nHalfLevels)//2 + topLevelIndices = xarray.DataArray( + data=topLevelIndices, dims=('nHalfLevels', 'nVertBounds')) + interpCellIndices, topLevelIndices = \ + xarray.broadcast(interpCellIndices, topLevelIndices) + topLevelIndices = topLevelIndices.where(valid, -1) + + botLevelIndices = numpy.zeros((nHalfLevels, nVertBounds), int) + botLevelIndices[:, 0] = numpy.arange(nHalfLevels)//2 + botLevelIndices[:, 1] = numpy.arange(1, nHalfLevels+1)//2 + botLevelIndices = xarray.DataArray( + data=botLevelIndices, dims=('nHalfLevels', 'nVertBounds')) + _, botLevelIndices = xarray.broadcast(interpCellIndices, botLevelIndices) + botLevelIndices = botLevelIndices.where(valid, -1) + botLevelIndices = numpy.minimum(botLevelIndices, interpMaxLevelCell) + + interpLevelIndices = xarray.concat((topLevelIndices, botLevelIndices), + dim='nWeights') + + topHalfLevelThickness = 0.5*layerThickness.isel( + nCells=interpCellIndices, nVertLevels=topLevelIndices) + topHalfLevelThickness = topHalfLevelThickness.where(topLevelIndices >= 0, + other=0.) + botHalfLevelThickness = 0.5*layerThickness.isel( + nCells=interpCellIndices, nVertLevels=botLevelIndices) + + # vertical weights are proportional to the half-level thickness + interpCellWeights = xarray.concat( + (topHalfLevelThickness*interpCellWeights.isel(nVertLevels=topLevelIndices), + botHalfLevelThickness*interpCellWeights.isel(nVertLevels=botLevelIndices)), + dim='nWeights') + + weightSum = interpCellWeights.sum(dim='nWeights') + _, outMask = xarray.broadcast(interpCellWeights, weightSum > 0.) + interpCellWeights = (interpCellWeights/weightSum).where(outMask) + + interpCellIndices = xarray.concat((interpCellIndices, interpCellIndices), + dim='nWeights') + + return interpCellIndices, interpLevelIndices, interpCellWeights + + +def _transect_cells_to_triangles(dsTransectCells): + + nTransectCells = dsTransectCells.sizes['nTransectCells'] + nTransectTriangles = 2*nTransectCells + triangleTransectCellIndices = numpy.arange(nTransectTriangles)//2 + nodeTransectCellIndices = numpy.zeros((nTransectTriangles, 3), int) + nodeHorizBoundsIndices = numpy.zeros((nTransectTriangles, 3), int) + nodeVertBoundsIndices = numpy.zeros((nTransectTriangles, 3), int) + + for index in range(3): + nodeTransectCellIndices[:, index] = triangleTransectCellIndices + + # the upper triangle + nodeHorizBoundsIndices[0::2, 0] = 0 + nodeVertBoundsIndices[0::2, 0] = 0 + nodeHorizBoundsIndices[0::2, 1] = 1 + nodeVertBoundsIndices[0::2, 1] = 0 + nodeHorizBoundsIndices[0::2, 2] = 0 + nodeVertBoundsIndices[0::2, 2] = 1 + + # the lower triangle + nodeHorizBoundsIndices[1::2, 0] = 0 + nodeVertBoundsIndices[1::2, 0] = 1 + nodeHorizBoundsIndices[1::2, 1] = 1 + nodeVertBoundsIndices[1::2, 1] = 0 + nodeHorizBoundsIndices[1::2, 2] = 1 + nodeVertBoundsIndices[1::2, 2] = 1 + + triangleTransectCellIndices = xarray.DataArray( + data=triangleTransectCellIndices, dims='nTransectTriangles') + nodeTransectCellIndices = xarray.DataArray( + data=nodeTransectCellIndices, + dims=('nTransectTriangles', 'nTriangleNodes')) + nodeHorizBoundsIndices = xarray.DataArray( + data=nodeHorizBoundsIndices, + dims=('nTransectTriangles', 'nTriangleNodes')) + nodeVertBoundsIndices = xarray.DataArray( + data=nodeVertBoundsIndices, + dims=('nTransectTriangles', 'nTriangleNodes')) + + dsTransectTriangles = xarray.Dataset() + dsTransectTriangles['nodeHorizBoundsIndices'] = \ + nodeHorizBoundsIndices + for var_name in dsTransectCells.data_vars: + var = dsTransectCells[var_name] + if 'nTransectCells' in var.dims: + if 'nVertBounds' in var.dims: + assert 'nHorizBounds' in var.dims + dsTransectTriangles[var_name] = var.isel( + nTransectCells=nodeTransectCellIndices, + nHorizBounds=nodeHorizBoundsIndices, + nVertBounds=nodeVertBoundsIndices) + elif 'nHorizBounds' in var.dims: + dsTransectTriangles[var_name] = var.isel( + nTransectCells=nodeTransectCellIndices, + nHorizBounds=nodeHorizBoundsIndices) + else: + dsTransectTriangles[var_name] = var.isel( + nTransectCells=triangleTransectCellIndices) + else: + dsTransectTriangles[var_name] = var + + dsTransectTriangles = dsTransectTriangles.drop_vars('halfLevelIndices') + + return dsTransectTriangles + + +def _add_vertical_interpolation_of_transect_points(dsTransectTriangles, + zTransect): + + dTransect = dsTransectTriangles.dTransect + # make sure zTransect is 2D + zTransect, _ = xarray.broadcast(zTransect, dTransect) + + assert len(zTransect.dims) == 2 + + horizDim = dTransect.dims[0] + vertDim = None + for dim in zTransect.dims: + if dim != horizDim: + vertDim = dim + + assert vertDim is not None + + nzTransect = zTransect.sizes[vertDim] + + horizIndices = dsTransectTriangles.transectIndicesOnHorizNode + horizWeights = dsTransectTriangles.transectWeightsOnHorizNode + kwargs0 = {horizDim: horizIndices} + kwargs1 = {horizDim: horizIndices+1} + zTransectAtHorizNodes = horizWeights*zTransect.isel(**kwargs0) + \ + (1.0 - horizWeights)*zTransect.isel(**kwargs1) + + zTriangleNode = dsTransectTriangles.zTransectNode + + segmentIndices = dsTransectTriangles.segmentIndices + nodeHorizBoundsIndices = dsTransectTriangles.nodeHorizBoundsIndices + + nTransectTriangles = dsTransectTriangles.sizes['nTransectTriangles'] + nTriangleNodes = dsTransectTriangles.sizes['nTriangleNodes'] + transectInterpVertIndices = -1*numpy.ones( + (nTransectTriangles, nTriangleNodes), int) + transectInterpVertWeights = numpy.zeros( + (nTransectTriangles, nTriangleNodes)) + + kwargs = {vertDim: 0, 'nSegments': segmentIndices, + 'nHorizBounds': nodeHorizBoundsIndices} + z0 = zTransectAtHorizNodes.isel(**kwargs) + for zIndex in range(nzTransect-1): + kwargs = {vertDim: zIndex+1, 'nSegments': segmentIndices, + 'nHorizBounds': nodeHorizBoundsIndices} + z1 = zTransectAtHorizNodes.isel(**kwargs) + mask = numpy.logical_and(zTriangleNode <= z0, zTriangleNode > z1) + mask = mask.values + weights = (z1 - zTriangleNode)/(z1 - z0) + + transectInterpVertIndices[mask] = zIndex + transectInterpVertWeights[mask] = weights.values[mask] + z0 = z1 + + dsTransectTriangles['transectInterpVertIndices'] = ( + ('nTransectTriangles', 'nTriangleNodes'), transectInterpVertIndices) + + dsTransectTriangles['transectInterpVertWeights'] = ( + ('nTransectTriangles', 'nTriangleNodes'), transectInterpVertWeights) + + dsTransectTriangles['zTransect'] = zTransect + + return dsTransectTriangles +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/viz/inset.html b/0.22.0rc4/_modules/mpas_tools/ocean/viz/inset.html new file mode 100644 index 000000000..8cee59005 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/viz/inset.html @@ -0,0 +1,316 @@ + + + + + + mpas_tools.ocean.viz.inset — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.ocean.viz.inset

+import matplotlib.path
+import matplotlib.ticker as mticker
+import cartopy
+import cartopy.crs as ccrs
+import numpy
+import shapely.geometry
+
+from geometric_features.plot import subdivide_geom
+
+
+
[docs]def add_inset(fig, fc, latlonbuffer=45., polarbuffer=5., width=1.0, + height=1.0, lowerleft=None, xbuffer=None, ybuffer=None, + maxlength=1.): + """ + Plots an inset map showing the location of a transect or polygon. Shapes + are plotted on a polar grid if they are entirely poleward of +/-50 deg. + latitude and with a lat/lon grid if not. + + Parameters + ---------- + fig : ``matplotlib.figure.Figure`` + A matplotlib figure to add the inset to + + fc : ``geometric_features.FeatureCollection`` + A collection of regions, transects and/or points to plot in the inset + + latlonbuffer : float, optional + The number of degrees lat/lon to use as a buffer around the shape(s) + to plot if a lat/lon plot is used. + + polarbuffer : float, optional + The number of degrees latitude to use as a buffer equatorward of the + shape(s) in polar plots + + width, height : float, optional + width and height in inches of the inset + + lowerleft : pair of floats, optional + the location of the lower left corner of the axis in inches, default + puts the inset in the upper right corner of ``fig``. + + xbuffer, ybuffer : float, optional + right and top buffers from the top-right corner (in inches) if + lowerleft is ``None``. + + maxlength : float or ``None``, optional + Any segments longer than maxlength will be subdivided in the plot to + ensure curvature. If ``None``, no subdivision is performed. + + Returns + ------- + inset : ``matplotlib.axes.Axes`` + The new inset axis + """ + # Authors + # ------- + # Xylar Asay-Davis + + minLon, minLat, maxLon, maxLat = _get_bounds(fc) + + figsize = fig.get_size_inches() + width /= figsize[0] + height /= figsize[1] + if lowerleft is None: + if xbuffer is None: + xbuffer = 0.1*width + else: + xbuffer /= figsize[0] + if ybuffer is None: + ybuffer = xbuffer*figsize[0]/figsize[1] + else: + ybuffer /= figsize[1] + lowerleft = [1.0 - width - xbuffer, 1.0 - height - ybuffer] + else: + lowerleft = [lowerleft[0]/figsize[0], lowerleft[1]/figsize[1]] + bounds = [lowerleft[0], lowerleft[1], width, height] + + if maxLat <= -50: + # an Antarctic-focused map makes the most sense + inset = fig.add_axes(bounds, + projection=ccrs.SouthPolarStereo()) + extent = [-180., 180., -90., max(-65., maxLat+polarbuffer)] + _set_circular_boundary(inset) + xlocator = mticker.FixedLocator(numpy.linspace(-180., 180., 9)) + ylocator = mticker.FixedLocator(numpy.linspace(-90., -50., 9)) + elif minLat >= 50: + # an Arctic-focused map makes the most sense + inset = fig.add_axes(bounds, + projection=ccrs.NorthPolarStereo()) + extent = [-180, 180, min(65., minLat-polarbuffer), 90] + _set_circular_boundary(inset) + xlocator = mticker.FixedLocator(numpy.linspace(-180., 180., 9)) + ylocator = mticker.FixedLocator(numpy.linspace(50., 90., 9)) + else: + inset = fig.add_axes(bounds, + projection=ccrs.PlateCarree()) + extent = [max(-180., minLon-latlonbuffer), + min(180., maxLon+latlonbuffer), + max(-90., minLat-latlonbuffer), + min(90., maxLat+latlonbuffer)] + xlocator = None + ylocator = None + + # kind of like "top" justified -- graphics are toward the "north" end of + # the subplot + inset.set_anchor('N') + + inset.set_extent(extent, ccrs.PlateCarree()) + inset.add_feature(cartopy.feature.LAND, zorder=1) + inset.add_feature(cartopy.feature.OCEAN, zorder=0) + + gl = inset.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, + linewidth=0.5, color='gray', alpha=0.5, + linestyle='--') + + if xlocator is not None: + gl.xlocator = xlocator + + if ylocator is not None: + gl.ylocator = ylocator + + for feature in fc.features: + geomtype = feature['geometry']['type'] + shape = shapely.geometry.shape(feature['geometry']) + if maxlength is not None: + shape = subdivide_geom(shape, shape.geom_type, maxlength) + if geomtype in ['Polygon', 'MultiPolygon']: + inset.add_geometries((shape,), crs=ccrs.PlateCarree(), + edgecolor='blue', facecolor='blue', alpha=0.4, + linewidth=1.) + elif geomtype in ['Point', 'MultiPoint']: + point_x, point_y = shape.xy + inset.scatter(point_x, point_y, s=9, color='k', + transform=ccrs.PlateCarree(), edgecolors='face') + else: + inset.add_geometries((shape,), crs=ccrs.PlateCarree(), + edgecolor='k', facecolor='none', alpha=1., + linewidth=1.) + # put a red point at the beginning and a blue point at the end + # of the transect to help show the orientation + begin = shape.coords[0] + end = shape.coords[-1] + inset.plot(begin[0], begin[1], color='r', marker='o', + markersize=3., transform=ccrs.PlateCarree()) + inset.plot(end[0], end[1], color='g', marker='o', + markersize=3., transform=ccrs.PlateCarree()) + + return inset
+ + +def _set_circular_boundary(ax): + """Set the boundary of the given axis to be circular (for a polar plot)""" + + # Compute a circle in axes coordinates, which we can use as a boundary + # for the map. We can pan/zoom as much as we like - the boundary will be + # permanently circular. + theta = numpy.linspace(0, 2*numpy.pi, 100) + center = numpy.array([0.5, 0.5]) + radius = 0.5 + verts = numpy.vstack([numpy.sin(theta), numpy.cos(theta)]).T + circle = matplotlib.path.Path(verts * radius + center) + + ax.set_boundary(circle, transform=ax.transAxes) + + +def _get_bounds(fc): + """Compute the lon/lat bounding box for all transects and regions""" + + bounds = shapely.geometry.GeometryCollection() + for feature in fc.features: + shape = shapely.geometry.shape(feature['geometry']) + shape_bounds = shapely.geometry.box(*shape.bounds) + bounds = shapely.geometry.box(*bounds.union(shape_bounds).bounds) + + return bounds.bounds +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/ocean/viz/transects.html b/0.22.0rc4/_modules/mpas_tools/ocean/viz/transects.html new file mode 100644 index 000000000..129851ae2 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/ocean/viz/transects.html @@ -0,0 +1,399 @@ + + + + + + mpas_tools.ocean.viz.transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.ocean.viz.transects

+#!/usr/bin/env python
+import argparse
+
+import cmocean
+import numpy as np
+import xarray as xr
+from geometric_features import read_feature_collection, FeatureCollection
+import matplotlib.pyplot as plt
+from matplotlib.tri import Triangulation
+from mpas_tools.viz import mesh_to_triangles
+from mpas_tools.viz.transects import find_transect_cells_and_weights, \
+    make_triangle_tree
+from mpas_tools.ocean.transects import find_transect_levels_and_weights, \
+    interp_mpas_to_transect_triangles, get_outline_segments
+
+from mpas_tools.ocean.viz.inset import add_inset
+from mpas_tools.viz.colormaps import register_sci_viz_colormaps
+
+
+
[docs]def plot_ocean_transects(fc, ds, ds_mesh=None, variable_list=None, cmap=None, + flip=False): + """ + Plot images of the given variables on the given transects. One image + named ``<transect_name>_<variable_name>.png`` will be produced in the + current directory for each transect and variable + + Parameters + ---------- + fc : geometric_features.FeatureCollection + The transects to plot + + ds : xarray.Dataset + The MPAS-Ocean dataset to plot + + ds_mesh : xarray.Dataset, optional + The MPAS-Ocean mesh to use for plotting, the same as ``ds`` by default + + variable_list : list of str, optional + The variables to plot + + cmap : str, optional + The name of a colormap to use + + flip : book, optional + Whether to flip the x axes of all transect plot + """ + if 'Time' in ds.dims: + ds = ds.isel(Time=0) + + if 'Time' in ds_mesh.dims: + ds_mesh = ds_mesh.isel(Time=0) + + transects = _compute_transects(fc, ds_mesh, flip) + + print('\nBuilding transect geometry...') + fc_transects = dict() + for transect in fc.features: + transect_name = transect['properties']['name'] + print(f' {transect_name}') + fc_transects[transect_name] = FeatureCollection(features=[transect]) + + register_sci_viz_colormaps() + + if variable_list is None: + variable_list = list() + for var_name in ds.data_vars: + var = ds[var_name] + if 'nCells' in var.dims and 'nVertLevels' in var.dims: + variable_list.append(var_name) + + print('\nPlotting...') + for var_name in variable_list: + var = ds[var_name] + assert 'nCells' in var.dims and 'nVertLevels' in var.dims + for transect_name, ds_transect in transects.items(): + print(f' {transect_name} {var_name}') + _plot_transect(ds_transect, var, var_name, transect_name, cmap, + fc_transects[transect_name])
+ + +def main(): + + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-g', '--geojson', dest='geojson_filename', + required=True, + help='A geojson file with transects to plot') + parser.add_argument('-m', '--mesh', dest='mesh_filename', + help='An MPAS-Ocean mesh file. If not specified, the ' + 'MPAS-Ocean data file must contain the mesh.') + parser.add_argument('-f', '--file', dest='filename', required=True, + help='An MPAS-Ocean data file') + parser.add_argument("-v", "--variable_list", dest="variable_list", + nargs='+', + help="List of variables to plot. All variables on " + "cells in the data file is the default.") + parser.add_argument('-c', '--colormap', dest='colormap', + help='A colormap to use for the plots, default ' + 'depends on the field name.') + parser.add_argument('--flip', dest='flip', action='store_true', + help='Flip the x axis for all transects') + + args = parser.parse_args() + + fc = read_feature_collection(args.geojson_filename) + ds = xr.open_dataset(args.filename) + if args.mesh_filename is not None: + ds_mesh = xr.open_dataset(args.mesh_filename) + else: + ds_mesh = ds + + variable_list = args.variable_list + + plot_ocean_transects(fc=fc, ds=ds, ds_mesh=ds_mesh, + variable_list=variable_list, cmap=args.colormap, + flip=args.flip) + + +def _compute_transects(fc, ds_mesh, flip): + """ + build a sequence of triangles showing the transect intersecting mpas cells + """ + + ds_tris = mesh_to_triangles(ds_mesh) + + triangle_tree = make_triangle_tree(ds_tris) + + transects = dict() + + for transect in fc.features: + transect_name = transect['properties']['name'] + assert transect['geometry']['type'] == 'LineString' + + coordinates = transect['geometry']['coordinates'] + transect_lon, transect_lat = zip(*coordinates) + transect_lon = np.array(transect_lon) + transect_lat = np.array(transect_lat) + if flip: + transect_lon = transect_lon[::-1] + transect_lat = transect_lat[::-1] + transect_lon = xr.DataArray(data=transect_lon, + dims=('nPoints',)) + transect_lat = xr.DataArray(data=transect_lat, + dims=('nPoints',)) + + ds_mpas_transect = find_transect_cells_and_weights( + transect_lon, transect_lat, ds_tris, ds_mesh, + triangle_tree, degrees=True) + + ds_mpas_transect = find_transect_levels_and_weights( + ds_mpas_transect, ds_mesh.layerThickness, + ds_mesh.bottomDepth, ds_mesh.maxLevelCell - 1) + + if 'landIceFraction' in ds_mesh: + interp_cell_indices = ds_mpas_transect.interpHorizCellIndices + interp_cell_weights = ds_mpas_transect.interpHorizCellWeights + land_ice_fraction = ds_mesh.landIceFraction.isel( + nCells=interp_cell_indices) + land_ice_fraction = (land_ice_fraction * interp_cell_weights).sum( + dim='nHorizWeights') + ds_mpas_transect['landIceFraction'] = land_ice_fraction + + ds_mpas_transect['x'] = ds_mpas_transect.dNode.isel( + nSegments=ds_mpas_transect.segmentIndices, + nHorizBounds=ds_mpas_transect.nodeHorizBoundsIndices) + + ds_mpas_transect['z'] = ds_mpas_transect.zTransectNode + + ds_mpas_transect.compute() + transects[transect_name] = ds_mpas_transect + + return transects + + +def _plot_transect(ds_transect, mpas_field, var_name, transect_name, cmap, fc): + """ + plot a transect showing the field on the MPAS-Ocean mesh and save to a file + """ + transect_prefix = transect_name.replace(' ', '_') + transect_field = interp_mpas_to_transect_triangles(ds_transect, + mpas_field) + units = None + if 'units' in mpas_field.attrs: + units = mpas_field.attrs['units'] + + x_outline, z_outline = get_outline_segments(ds_transect) + x_outline = 1e-3 * x_outline + + colormaps = dict( + temperature='cmo.thermal', + salinity='cmo.haline', + density='cmo.dense', + ) + if cmap is None: + for contains, map_name in colormaps.items(): + if contains in var_name.lower(): + cmap = map_name + + tri_mask = np.logical_not(transect_field.notnull().values) + # if any node of a triangle is masked, the triangle is masked + # tri_mask = np.amax(tri_mask, axis=1) + + triangulation_args = _get_ds_triangulation_args(ds_transect) + + triangulation_args['mask'] = tri_mask + + tris = Triangulation(**triangulation_args) + fig = plt.figure(figsize=(12, 6)) + ax = plt.gca() + plt.tripcolor(tris, facecolors=transect_field.values, shading='flat', + cmap=cmap) + plt.plot(x_outline, z_outline, 'k') + if units is not None: + colorbar_label = f'{var_name} ({units})' + else: + colorbar_label = f'{var_name}' + plt.colorbar(label=colorbar_label) + plt.title(f'{var_name} through {transect_name}') + plt.xlabel('x (km)') + plt.ylabel('z (m)') + + # make a red start axis and green end axis to correspond to the dots + # in the inset + ax.spines['left'].set_color('red') + ax.spines['right'].set_color('green') + ax.spines['left'].set_linewidth(4) + ax.spines['right'].set_linewidth(4) + + plt.tight_layout(pad=0.5, h_pad=0.5, rect=[0.0, 0.0, 1.0, 1.0]) + + add_inset(fig, fc) + plt.savefig(f'{transect_prefix}_{var_name}.png', dpi=200) + plt.close() + + +def _get_ds_triangulation_args(ds_transect): + """ + get arguments for matplotlib Triangulation from triangulation dataset + """ + + n_transect_triangles = ds_transect.sizes['nTransectTriangles'] + d_node = ds_transect.dNode.isel( + nSegments=ds_transect.segmentIndices, + nHorizBounds=ds_transect.nodeHorizBoundsIndices) + x = 1e-3 * d_node.values.ravel() + + z_transect_node = ds_transect.zTransectNode + y = z_transect_node.values.ravel() + + tris = np.arange(3 * n_transect_triangles).reshape( + (n_transect_triangles, 3)) + triangulation_args = dict(x=x, y=y, triangles=tris) + + return triangulation_args + + +if __name__ == '__main__': + main() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/parallel.html b/0.22.0rc4/_modules/mpas_tools/parallel.html new file mode 100644 index 000000000..1449a51fe --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/parallel.html @@ -0,0 +1,175 @@ + + + + + + mpas_tools.parallel — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.parallel

+import multiprocessing
+
+
+
[docs]def create_pool(process_count=None, method='forkserver'): + """ + Crate a pool for creating masks with Python multiprocessing. This should + be called only once at the beginning of the script performing cell culling. + ``pool.terminate()`` should be called before exiting the script. + + Parameters + ---------- + process_count : int, optional + The number of processors or None to use all available processors + + method : {'fork', 'spawn', 'forkserver'} + The mutiprocessing method + + Returns + ------- + pool : multiprocessing.Pool + A pool to use for python-based mask creation. + """ + pool = None + multiprocessing.set_start_method(method) + if process_count is None: + process_count = multiprocessing.cpu_count() + else: + process_count = min(process_count, multiprocessing.cpu_count()) + + if process_count > 1: + pool = multiprocessing.Pool(process_count) + + return pool
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/planar_hex.html b/0.22.0rc4/_modules/mpas_tools/planar_hex.html new file mode 100644 index 000000000..88d3b5566 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/planar_hex.html @@ -0,0 +1,610 @@ + + + + + + mpas_tools.planar_hex — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.planar_hex

+#!/usr/bin/env python
+
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+import numpy
+import xarray
+import argparse
+
+from mpas_tools.io import write_netcdf
+
+
+
[docs]def make_planar_hex_mesh(nx, ny, dc, nonperiodic_x, + nonperiodic_y, outFileName=None, + compareWithFileName=None, + format=None, engine=None): + """ + Builds an MPAS periodic, planar hexagonal mesh with the requested + dimensions, optionally saving it to a file, and returns it as an + ``xarray.Dataset``. + + Parameters + ---------- + nx : int + The number of cells in the x direction + + ny : even int + The number of cells in the y direction (must be an even number for + periodicity to work out) + + dc : float + The distance in meters between adjacent cell centers. + + nonperiodic_x, nonperiodic_y : bool + is the mesh non-periodic in x and y directions? + + outFileName : str, optional + The name of a file to save the mesh to. The mesh is not saved to a + file if no file name is supplied. + + compareWithFileName : str, optional + The name of a grid file to compare with to see if they are identical, + used for testing purposes + + format : {'NETCDF4', 'NETCDF4_CLASSIC', 'NETCDF3_64BIT', ' + NETCDF3_CLASSIC'}, optional + The NetCDF format to use for output + + engine : {'netcdf4', 'scipy', 'h5netcdf'}, optional + The library to use for NetCDF output + + Returns + ------- + mesh : xarray.Dataset + The mesh data set, available for further manipulation such as culling + cells or removing periodicity. + """ + + mesh = initial_setup(nx, ny, dc, nonperiodic_x, nonperiodic_y) + compute_indices_on_cell(mesh) + if nonperiodic_x: + mark_cull_cell_nonperiodic_x(mesh) + if nonperiodic_y: + mark_cull_cell_nonperiodic_y(mesh) + compute_indices_on_edge(mesh) + compute_indices_on_vertex(mesh) + compute_weights_on_edge(mesh) + compute_coordinates(mesh) + add_one_to_indices(mesh) + + # drop some arrays that aren't standard for MPAS but were used to compute + # the hex mesh + mesh = mesh.drop_vars(['cellIdx', 'cellRow', 'cellCol']) + + if outFileName is not None: + write_netcdf(mesh, outFileName, format=format, engine=engine) + + if compareWithFileName is not None: + # used to make sure results are exactly identical to periodic_hex + make_diff(mesh, compareWithFileName, 'diff.nc') + + return mesh
+ + +def initial_setup(nx, ny, dc, nonperiodic_x, nonperiodic_y): + """Setup the dimensions and add placeholders for some index variables""" + if ny % 2 != 0: + raise ValueError('ny must be divisible by 2 for the grid\'s ' + 'periodicity to work properly.') + + mesh = xarray.Dataset() + + if nonperiodic_x and nonperiodic_y: + mesh.attrs['is_periodic'] = 'NO' + else: + mesh.attrs['is_periodic'] = 'YES' + + if nonperiodic_x: + mesh.attrs['x_period'] = 0. + else: + mesh.attrs['x_period'] = nx * dc + if nonperiodic_y: + mesh.attrs['y_period'] = 0. + else: + mesh.attrs['y_period'] = ny * dc * numpy.sqrt(3.) / 2. + + mesh.attrs['dc'] = dc + mesh.attrs['nx'] = nx + mesh.attrs['ny'] = ny + mesh.attrs['on_a_sphere'] = 'NO' + mesh.attrs['sphere_radius'] = 0. + + if nonperiodic_x: + nx = nx + 2 + if nonperiodic_y: + ny = ny + 2 + + nCells = nx * ny + nEdges = 3 * nCells + nVertices = 2 * nCells + vertexDegree = 3 + maxEdges = 6 + + # add some basic arrays to get all the dimensions in place + indexToCellID = numpy.arange(nCells, dtype='i4') + indexToEdgeID = numpy.arange(nEdges, dtype='i4') + indexToVertexID = numpy.arange(nVertices, dtype='i4') + + cellIdx = indexToCellID.reshape(ny, nx) + cellCol, cellRow = numpy.meshgrid(numpy.arange(nx, dtype='i4'), + numpy.arange(ny, dtype='i4')) + + mesh['cellIdx'] = (('ny', 'nx'), cellIdx) + mesh['cellRow'] = (('nCells',), cellRow.ravel()) + mesh['cellCol'] = (('nCells',), cellCol.ravel()) + + mesh['indexToCellID'] = (('nCells',), indexToCellID) + mesh['indexToEdgeID'] = (('nEdges',), indexToEdgeID) + mesh['indexToVertexID'] = (('nVertices',), indexToVertexID) + + mesh['cullCell'] = (('nCells',), numpy.zeros(nCells, 'i4')) + + mesh['nEdgesOnCell'] = (('nCells',), 6 * numpy.ones((nCells,), 'i4')) + mesh['cellsOnCell'] = (('nCells', 'maxEdges'), + numpy.zeros((nCells, maxEdges), 'i4')) + mesh['edgesOnCell'] = (('nCells', 'maxEdges'), + numpy.zeros((nCells, maxEdges), 'i4')) + mesh['verticesOnCell'] = (('nCells', 'maxEdges'), + numpy.zeros((nCells, maxEdges), 'i4')) + + mesh['nEdgesOnEdge'] = (('nEdges',), 10 * numpy.ones((nEdges,), 'i4')) + mesh['cellsOnEdge'] = (('nEdges', 'TWO'), + numpy.zeros((nEdges, 2), 'i4')) + mesh['edgesOnEdge'] = (('nEdges', 'maxEdges2'), + -1 * numpy.ones((nEdges, 2 * maxEdges), 'i4')) + mesh['verticesOnEdge'] = (('nEdges', 'TWO'), + numpy.zeros((nEdges, 2), 'i4')) + + mesh['cellsOnVertex'] = (('nVertices', 'vertexDegree'), + numpy.zeros((nVertices, vertexDegree), 'i4')) + mesh['edgesOnVertex'] = (('nVertices', 'vertexDegree'), + numpy.zeros((nVertices, vertexDegree), 'i4')) + + return mesh + + +def mark_cull_cell_nonperiodic_y(mesh): + + cullCell = mesh.cullCell + nCells = mesh.sizes['nCells'] + nx = mesh.sizes['nx'] + cullCell[0:nx] = 1 + cullCell[nCells - nx:nCells + 1] = 1 + + +def mark_cull_cell_nonperiodic_x(mesh): + + cullCell = mesh.cullCell + nCells = mesh.sizes['nCells'] + nx = mesh.sizes['nx'] + cullCell[::nx] = 1 + cullCell[nx - 1:nCells + 1:nx] = 1 + + +def compute_indices_on_cell(mesh): + + cellIdx = mesh.cellIdx + cellRow = mesh.cellRow + cellCol = mesh.cellCol + + indexToCellID = mesh.indexToCellID + + nx = mesh.sizes['nx'] + ny = mesh.sizes['ny'] + + mx = numpy.mod(cellCol - 1, nx) + my = numpy.mod(cellRow - 1, ny) + px = numpy.mod(cellCol + 1, nx) + py = numpy.mod(cellRow + 1, ny) + + mask = numpy.mod(cellRow, 2) == 0 + + cellsOnCell = mesh.cellsOnCell + cellsOnCell[:, 0] = cellIdx[cellRow, mx] + cellsOnCell[:, 1] = cellIdx[my, mx].where(mask, cellIdx[my, cellCol]) + cellsOnCell[:, 2] = cellIdx[my, cellCol].where(mask, cellIdx[my, px]) + cellsOnCell[:, 3] = cellIdx[cellRow, px] + cellsOnCell[:, 4] = cellIdx[py, cellCol].where(mask, cellIdx[py, px]) + cellsOnCell[:, 5] = cellIdx[py, mx].where(mask, cellIdx[py, cellCol]) + + edgesOnCell = mesh.edgesOnCell + edgesOnCell[:, 0] = 3 * indexToCellID + edgesOnCell[:, 1] = 3 * indexToCellID + 1 + edgesOnCell[:, 2] = 3 * indexToCellID + 2 + edgesOnCell[:, 3] = 3 * cellsOnCell[:, 3] + edgesOnCell[:, 4] = 3 * cellsOnCell[:, 4] + 1 + edgesOnCell[:, 5] = 3 * cellsOnCell[:, 5] + 2 + + verticesOnCell = mesh.verticesOnCell + verticesOnCell[:, 0] = 2 * indexToCellID + verticesOnCell[:, 1] = 2 * indexToCellID + 1 + verticesOnCell[:, 2] = 2 * cellsOnCell[:, 2] + verticesOnCell[:, 3] = 2 * cellsOnCell[:, 3] + 1 + verticesOnCell[:, 4] = 2 * cellsOnCell[:, 3] + verticesOnCell[:, 5] = 2 * cellsOnCell[:, 4] + 1 + + +def compute_indices_on_edge(mesh): + edgesOnCell = mesh.edgesOnCell + verticesOnCell = mesh.verticesOnCell + indexToCellID = mesh.indexToCellID + + cellsOnEdge = mesh.cellsOnEdge + for j in range(3): + cellsOnEdge[edgesOnCell[:, j], 1] = indexToCellID + for j in range(3, 6): + cellsOnEdge[edgesOnCell[:, j], 0] = indexToCellID + + verticesOnEdge = mesh.verticesOnEdge + verticesOnEdge[edgesOnCell[:, 0], 0] = verticesOnCell[:, 1] + verticesOnEdge[edgesOnCell[:, 0], 1] = verticesOnCell[:, 0] + verticesOnEdge[edgesOnCell[:, 1], 0] = verticesOnCell[:, 2] + verticesOnEdge[edgesOnCell[:, 1], 1] = verticesOnCell[:, 1] + verticesOnEdge[edgesOnCell[:, 2], 0] = verticesOnCell[:, 3] + verticesOnEdge[edgesOnCell[:, 2], 1] = verticesOnCell[:, 2] + + edgesOnEdge = mesh.edgesOnEdge + edgesOnEdge[edgesOnCell[:, 3], 0] = edgesOnCell[:, 4] + edgesOnEdge[edgesOnCell[:, 3], 1] = edgesOnCell[:, 5] + edgesOnEdge[edgesOnCell[:, 3], 2] = edgesOnCell[:, 0] + edgesOnEdge[edgesOnCell[:, 3], 3] = edgesOnCell[:, 1] + edgesOnEdge[edgesOnCell[:, 3], 4] = edgesOnCell[:, 2] + + edgesOnEdge[edgesOnCell[:, 4], 0] = edgesOnCell[:, 5] + edgesOnEdge[edgesOnCell[:, 4], 1] = edgesOnCell[:, 0] + edgesOnEdge[edgesOnCell[:, 4], 2] = edgesOnCell[:, 1] + edgesOnEdge[edgesOnCell[:, 4], 3] = edgesOnCell[:, 2] + edgesOnEdge[edgesOnCell[:, 4], 4] = edgesOnCell[:, 3] + + edgesOnEdge[edgesOnCell[:, 5], 0] = edgesOnCell[:, 0] + edgesOnEdge[edgesOnCell[:, 5], 1] = edgesOnCell[:, 1] + edgesOnEdge[edgesOnCell[:, 5], 2] = edgesOnCell[:, 2] + edgesOnEdge[edgesOnCell[:, 5], 3] = edgesOnCell[:, 3] + edgesOnEdge[edgesOnCell[:, 5], 4] = edgesOnCell[:, 4] + + edgesOnEdge[edgesOnCell[:, 0], 5] = edgesOnCell[:, 1] + edgesOnEdge[edgesOnCell[:, 0], 6] = edgesOnCell[:, 2] + edgesOnEdge[edgesOnCell[:, 0], 7] = edgesOnCell[:, 3] + edgesOnEdge[edgesOnCell[:, 0], 8] = edgesOnCell[:, 4] + edgesOnEdge[edgesOnCell[:, 0], 9] = edgesOnCell[:, 5] + + edgesOnEdge[edgesOnCell[:, 1], 5] = edgesOnCell[:, 2] + edgesOnEdge[edgesOnCell[:, 1], 6] = edgesOnCell[:, 3] + edgesOnEdge[edgesOnCell[:, 1], 7] = edgesOnCell[:, 4] + edgesOnEdge[edgesOnCell[:, 1], 8] = edgesOnCell[:, 5] + edgesOnEdge[edgesOnCell[:, 1], 9] = edgesOnCell[:, 0] + + edgesOnEdge[edgesOnCell[:, 2], 5] = edgesOnCell[:, 3] + edgesOnEdge[edgesOnCell[:, 2], 6] = edgesOnCell[:, 4] + edgesOnEdge[edgesOnCell[:, 2], 7] = edgesOnCell[:, 5] + edgesOnEdge[edgesOnCell[:, 2], 8] = edgesOnCell[:, 0] + edgesOnEdge[edgesOnCell[:, 2], 9] = edgesOnCell[:, 1] + + +def compute_indices_on_vertex(mesh): + edgesOnCell = mesh.edgesOnCell + verticesOnCell = mesh.verticesOnCell + indexToCellID = mesh.indexToCellID + + cellsOnVertex = mesh.cellsOnVertex + cellsOnVertex[verticesOnCell[:, 1], 2] = indexToCellID + cellsOnVertex[verticesOnCell[:, 3], 0] = indexToCellID + cellsOnVertex[verticesOnCell[:, 5], 1] = indexToCellID + cellsOnVertex[verticesOnCell[:, 0], 0] = indexToCellID + cellsOnVertex[verticesOnCell[:, 2], 1] = indexToCellID + cellsOnVertex[verticesOnCell[:, 4], 2] = indexToCellID + + edgesOnVertex = mesh.edgesOnVertex + edgesOnVertex[verticesOnCell[:, 0], 0] = edgesOnCell[:, 0] + edgesOnVertex[verticesOnCell[:, 1], 0] = edgesOnCell[:, 0] + edgesOnVertex[verticesOnCell[:, 2], 2] = edgesOnCell[:, 1] + edgesOnVertex[verticesOnCell[:, 1], 2] = edgesOnCell[:, 1] + edgesOnVertex[verticesOnCell[:, 2], 1] = edgesOnCell[:, 2] + edgesOnVertex[verticesOnCell[:, 3], 1] = edgesOnCell[:, 2] + + +def compute_weights_on_edge(mesh): + edgesOnCell = mesh.edgesOnCell + + nEdges = mesh.sizes['nEdges'] + maxEdges2 = mesh.sizes['maxEdges2'] + mesh['weightsOnEdge'] = (('nEdges', 'maxEdges2'), + numpy.zeros((nEdges, maxEdges2), 'f8')) + weightsOnEdge = mesh.weightsOnEdge + + weights = (1. / numpy.sqrt(3.)) * numpy.array( + [[1. / 3., 1. / 6., 0., 1. / 6., 1. / 3.], + [1. / 3., -1. / 6., 0., 1. / 6., -1. / 3.], + [-1. / 3., -1. / 6., 0., -1. / 6., -1. / 3.]]) + for i in range(3): + for j in range(5): + weightsOnEdge[edgesOnCell[:, i + 3], j] = weights[i, j] + for i in range(3): + for j in range(5): + weightsOnEdge[edgesOnCell[:, i], j + 5] = weights[i, j] + + +def compute_coordinates(mesh): + + dc = mesh.attrs['dc'] + edgesOnCell = mesh.edgesOnCell + verticesOnCell = mesh.verticesOnCell + + nCells = mesh.sizes['nCells'] + nEdges = mesh.sizes['nEdges'] + nVertices = mesh.sizes['nVertices'] + vertexDegree = mesh.sizes['vertexDegree'] + + mesh['latCell'] = (('nCells',), numpy.zeros((nCells,), 'f8')) + mesh['lonCell'] = (('nCells',), numpy.zeros((nCells,), 'f8')) + + mesh['latEdge'] = (('nEdges',), numpy.zeros((nEdges,), 'f8')) + mesh['lonEdge'] = (('nEdges',), numpy.zeros((nEdges,), 'f8')) + + mesh['latVertex'] = (('nVertices',), numpy.zeros((nVertices,), 'f8')) + mesh['lonVertex'] = (('nVertices',), numpy.zeros((nVertices,), 'f8')) + + cellRow = mesh.cellRow + cellCol = mesh.cellCol + mask = numpy.mod(cellRow, 2) == 0 + + mesh['xCell'] = (dc * (cellCol + 0.5)).where(mask, dc * (cellCol + 1)) + mesh['yCell'] = dc * (cellRow + 1) * numpy.sqrt(3.) / 2. + mesh['zCell'] = (('nCells',), numpy.zeros((nCells,), 'f8')) + + mesh['xEdge'] = (('nEdges',), numpy.zeros((nEdges,), 'f8')) + mesh['yEdge'] = (('nEdges',), numpy.zeros((nEdges,), 'f8')) + mesh['zEdge'] = (('nEdges',), numpy.zeros((nEdges,), 'f8')) + + mesh.xEdge[edgesOnCell[:, 0]] = mesh.xCell - 0.5 * dc + mesh.yEdge[edgesOnCell[:, 0]] = mesh.yCell + + mesh.xEdge[edgesOnCell[:, 1]] = mesh.xCell - \ + 0.5 * dc * numpy.cos(numpy.pi / 3.) + mesh.yEdge[edgesOnCell[:, 1]] = mesh.yCell - \ + 0.5 * dc * numpy.sin(numpy.pi / 3.) + + mesh.xEdge[edgesOnCell[:, 2]] = mesh.xCell + \ + 0.5 * dc * numpy.cos(numpy.pi / 3.) + mesh.yEdge[edgesOnCell[:, 2]] = mesh.yCell - \ + 0.5 * dc * numpy.sin(numpy.pi / 3.) + + mesh['xVertex'] = (('nVertices',), numpy.zeros((nVertices,), 'f8')) + mesh['yVertex'] = (('nVertices',), numpy.zeros((nVertices,), 'f8')) + mesh['zVertex'] = (('nVertices',), numpy.zeros((nVertices,), 'f8')) + + mesh.xVertex[verticesOnCell[:, 0]] = mesh.xCell - 0.5 * dc + mesh.yVertex[verticesOnCell[:, 0]] = mesh.yCell + dc * numpy.sqrt(3.) / 6. + + mesh.xVertex[verticesOnCell[:, 1]] = mesh.xCell - 0.5 * dc + mesh.yVertex[verticesOnCell[:, 1]] = mesh.yCell - dc * numpy.sqrt(3.) / 6. + + mesh['angleEdge'] = (('nEdges',), numpy.zeros((nEdges,), 'f8')) + mesh.angleEdge[edgesOnCell[:, 1]] = numpy.pi / 3. + mesh.angleEdge[edgesOnCell[:, 2]] = 2. * numpy.pi / 3. + + mesh['dcEdge'] = (('nEdges',), dc * numpy.ones((nEdges,), 'f8')) + mesh['dvEdge'] = mesh.dcEdge * numpy.sqrt(3.) / 3. + + mesh['areaCell'] = \ + (('nCells',), dc**2 * numpy.sqrt(3.) / 2. * numpy.ones((nCells,), 'f8')) + + mesh['areaTriangle'] = \ + (('nVertices',), dc**2 * numpy.sqrt(3.) / + 4. * numpy.ones((nVertices,), 'f8')) + + mesh['kiteAreasOnVertex'] = \ + (('nVertices', 'vertexDegree'), + dc**2 * numpy.sqrt(3.) / 12. * numpy.ones((nVertices, vertexDegree), + 'f8')) + + mesh['meshDensity'] = (('nCells',), numpy.ones((nCells,), 'f8')) + + +def add_one_to_indices(mesh): + """Needed to adhere to Fortran indexing""" + indexVars = ['indexToCellID', 'indexToEdgeID', 'indexToVertexID', + 'cellsOnCell', 'edgesOnCell', 'verticesOnCell', + 'cellsOnEdge', 'edgesOnEdge', 'verticesOnEdge', + 'cellsOnVertex', 'edgesOnVertex'] + for var in indexVars: + mesh[var] = mesh[var] + 1 + + +def make_diff(mesh, refMeshFileName, diffFileName): + + refMesh = xarray.open_dataset(refMeshFileName) + diff = xarray.Dataset() + for variable in mesh.data_vars: + if variable in refMesh: + diff[variable] = mesh[variable] - refMesh[variable] + print(diff[variable].name, float(numpy.abs(diff[variable]).max())) + else: + print('mesh has extra variable {}'.format(mesh[variable].name)) + + for variable in refMesh.data_vars: + if variable not in mesh: + print('mesh mising variable {}'.format(refMesh[variable].name)) + + for attr in refMesh.attrs: + if attr not in mesh.attrs: + print('mesh mising attribute {}'.format(attr)) + + for attr in mesh.attrs: + if attr not in refMesh.attrs: + print('mesh has extra attribute {}'.format(attr)) + + write_netcdf(diff, diffFileName) + + +def main(): + + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('--nx', dest='nx', type=int, required=True, + help='Cells in x direction') + parser.add_argument('--ny', dest='ny', type=int, required=True, + help='Cells in y direction') + parser.add_argument('--dc', dest='dc', type=float, required=True, + help='Distance between cell centers in meters') + parser.add_argument('--npx', '--nonperiodic_x', dest='nonperiodic_x', + action="store_true", + help='non-periodic in x direction') + parser.add_argument('--npy', '--nonperiodic_y', dest='nonperiodic_y', + action="store_true", + help='non-periodic in y direction') + parser.add_argument('-o', '--outFileName', dest='outFileName', type=str, + required=False, default='grid.nc', + help='The name of the output file') + + args = parser.parse_args() + + make_planar_hex_mesh(args.nx, args.ny, args.dc, + args.nonperiodic_x, args.nonperiodic_y, + args.outFileName) + + +if __name__ == '__main__': + main() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/scrip/from_mpas.html b/0.22.0rc4/_modules/mpas_tools/scrip/from_mpas.html new file mode 100644 index 000000000..01ce4f226 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/scrip/from_mpas.html @@ -0,0 +1,318 @@ + + + + + + mpas_tools.scrip.from_mpas — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.scrip.from_mpas

+# Create a SCRIP file from an MPAS mesh.
+# See for details: http://www.earthsystemmodeling.org/esmf_releases/public/ESMF_5_2_0rp1/ESMF_refdoc/node3.html#SECTION03024000000000000000
+
+import sys
+import netCDF4
+import numpy as np
+
+from optparse import OptionParser
+from mpas_tools.cime.constants import constants
+
+
[docs]def scrip_from_mpas(mpasFile, scripFile, useLandIceMask=False): + """ + Create a SCRIP file from an MPAS mesh + + Parameters + ---------- + mpasFile : str + The path to a NetCDF file with the MPAS mesh + + scripFile : str + The path to the output SCRIP file + + useLandIceMask : bool + Whether to use the landIceMask field for masking + """ + if useLandIceMask: + print(" -- Landice Masks are enabled") + else: + print(" -- Landice Masks are disabled") + + # make a space in stdout before further output + print('') + fin = netCDF4.Dataset(mpasFile, 'r') + # This will clobber existing files + fout = netCDF4.Dataset(scripFile, 'w') + + # Get info from input file + latCell = fin.variables['latCell'][:] + lonCell = fin.variables['lonCell'][:] + latVertex = fin.variables['latVertex'][:] + lonVertex = fin.variables['lonVertex'][:] + verticesOnCell = fin.variables['verticesOnCell'][:] - 1 + nEdgesOnCell = fin.variables['nEdgesOnCell'][:] + nCells = len(fin.dimensions['nCells']) + maxVertices = len(fin.dimensions['maxEdges']) + areaCell = fin.variables['areaCell'][:] + sphereRadius = float(fin.sphere_radius) + on_a_sphere = str(fin.on_a_sphere) + + # check the longitude convention to use positive values [0 2pi] + if np.any(np.logical_or(lonCell < 0, lonCell > 2.0 * np.pi)): + raise ValueError("lonCell is not in the desired range (0, 2pi)") + + if np.any(np.logical_or(lonVertex < 0, lonVertex > 2.0 * np.pi)): + raise ValueError("lonVertex is not in the desired range (0, 2pi)") + + if sphereRadius <= 0: + sphereRadius = constants['SHR_CONST_REARTH'] + print(f" -- WARNING: sphereRadius<0 so setting sphereRadius = " + f"{constants['SHR_CONST_REARTH']}") + + if on_a_sphere == "NO": + print(" -- WARNING: 'on_a_sphere' attribute is 'NO', which means that " + "there may be some disagreement regarding area between the " + "planar (source) and spherical (target) mesh") + + if useLandIceMask: + landIceMask = fin.variables['landIceMask'][:] + else: + landIceMask = None + + # Write to output file + # Dimensions + fout.createDimension("grid_size", nCells) + fout.createDimension("grid_corners", maxVertices) + fout.createDimension("grid_rank", 1) + + # Variables + grid_center_lat = fout.createVariable('grid_center_lat', 'f8', + ('grid_size',)) + grid_center_lat.units = 'radians' + grid_center_lon = fout.createVariable('grid_center_lon', 'f8', + ('grid_size',)) + grid_center_lon.units = 'radians' + grid_corner_lat = fout.createVariable('grid_corner_lat', 'f8', + ('grid_size', 'grid_corners')) + grid_corner_lat.units = 'radians' + grid_corner_lon = fout.createVariable('grid_corner_lon', 'f8', + ('grid_size', 'grid_corners')) + grid_corner_lon.units = 'radians' + grid_area = fout.createVariable('grid_area', 'f8', ('grid_size',)) + grid_area.units = 'radian^2' + grid_imask = fout.createVariable('grid_imask', 'i4', ('grid_size',)) + grid_imask.units = 'unitless' + grid_dims = fout.createVariable('grid_dims', 'i4', ('grid_rank',)) + + grid_center_lat[:] = latCell[:] + grid_center_lon[:] = lonCell[:] + # SCRIP uses square radians + grid_area[:] = areaCell[:]/(sphereRadius**2) + grid_dims[:] = nCells + + # grid corners: + grid_corner_lon_local = np.zeros((nCells, maxVertices)) + grid_corner_lat_local = np.zeros((nCells, maxVertices)) + cellIndices = np.arange(nCells) + lastValidVertex = verticesOnCell[cellIndices, nEdgesOnCell-1] + for iVertex in range(maxVertices): + mask = iVertex < nEdgesOnCell + grid_corner_lat_local[mask, iVertex] = \ + latVertex[verticesOnCell[mask, iVertex]] + grid_corner_lon_local[mask, iVertex] = \ + lonVertex[verticesOnCell[mask, iVertex]] + + mask = iVertex >= nEdgesOnCell + grid_corner_lat_local[mask, iVertex] = latVertex[lastValidVertex[mask]] + grid_corner_lon_local[mask, iVertex] = lonVertex[lastValidVertex[mask]] + + if useLandIceMask: + # If useLandIceMask are enabled, mask out ocean under land ice. + grid_imask[:] = 1 - landIceMask[0, :] + else: + # If landiceMasks are not enabled, don't mask anything out. + grid_imask[:] = 1 + + grid_corner_lat[:] = grid_corner_lat_local[:] + grid_corner_lon[:] = grid_corner_lon_local[:] + + print("Input latCell min/max values (radians): {}, {}".format( + latCell[:].min(), latCell[:].max())) + print("Input lonCell min/max values (radians): {}, {}".format( + lonCell[:].min(), lonCell[:].max())) + print("Calculated grid_center_lat min/max values (radians): {}, {}".format( + grid_center_lat[:].min(), grid_center_lat[:].max())) + print("Calculated grid_center_lon min/max values (radians): {}, {}".format( + grid_center_lon[:].min(), grid_center_lon[:].max())) + print("Calculated grid_area min/max values (sq radians): {}, {}".format( + grid_area[:].min(), grid_area[:].max())) + + fin.close() + fout.close() + + print("Creation of SCRIP file is complete.")
+ + +def main(): + print("== Gathering information. (Invoke with --help for more details. All" + " arguments are optional)") + parser = OptionParser() + parser.description = "This script takes an MPAS grid file and generates " \ + "a SCRIP grid file." + parser.add_option("-m", "--mpas", dest="mpasFile", + help="MPAS grid file name used as input.", + default="grid.nc", metavar="FILENAME") + parser.add_option("-s", "--scrip", dest="scripFile", + help="SCRIP grid file to output.", default="scrip.nc", + metavar="FILENAME") + parser.add_option("-l", "--landice", dest="landiceMasks", + help="If flag is on, landice masks will be computed " + "and used.", + action="store_true") + for option in parser.option_list: + if option.default != ("NO", "DEFAULT"): + option.help += (" " if option.help else "") + "[default: %default]" + options, args = parser.parse_args() + + if not options.mpasFile: + sys.exit('Error: MPAS input grid file is required. Specify with -m ' + 'command line argument.') + if not options.scripFile: + sys.exit('Error: SCRIP output grid file is required. Specify with -s ' + 'command line argument.') + + if not options.landiceMasks: + options.landiceMasks = False + + scrip_from_mpas(options.mpasFile, options.scripFile, options.landiceMasks) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/seaice/mask.html b/0.22.0rc4/_modules/mpas_tools/seaice/mask.html new file mode 100644 index 000000000..42a73b798 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/seaice/mask.html @@ -0,0 +1,287 @@ + + + + + + mpas_tools.seaice.mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.seaice.mask

+from netCDF4 import Dataset
+import numpy as np
+import math
+
+from mpas_tools.cime.constants import constants
+
+
+
[docs]def extend_seaice_mask(filenameMesh, filenamePresence, extendDistance, + unitSphere=False): + """ + Add a field ``icePresenceExtended`` to ``filenamePresence`` if it doesn't + already exist. This field is the ``icePresence`` field extended by + a distance of ``extendDistance``. + + Parameters + ---------- + filenameMesh : str + The filename of the MPAS-Seaice mesh + + filenamePresence : str + A filename for a file containing an ``icePresence`` field to be + extended and to which a new ``icePresenceExtended`` will be added + + extendDistance : float + The distance in km to expand (no expansion is performed if + ``extendDistance=0.0``) + + unitSphere : bool, optional + Whether the mesh is provided on the unit sphere, rather than one with + the radius of the Earth + """ + + # mesh + print("Load mesh...") + fileMesh = Dataset(filenameMesh, "r") + + nCells = len(fileMesh.dimensions["nCells"]) + + nEdgesOnCell = fileMesh.variables["nEdgesOnCell"][:] + cellsOnCell = fileMesh.variables["cellsOnCell"][:] + + cellsOnCell[:] = cellsOnCell[:] - 1 + + xCell = fileMesh.variables["xCell"][:] + yCell = fileMesh.variables["yCell"][:] + zCell = fileMesh.variables["zCell"][:] + + fileMesh.close() + + # presence + print("Load ice presence...") + filePresence = Dataset(filenamePresence, "r") + + if "icePresenceExtended" in filePresence.variables: + # we're already done, probably from a previous call + filePresence.close() + return + + icePresence = filePresence.variables["icePresence"][:] + + filePresence.close() + + # ice edge cells + print("Get ice edge cells...") + iceEdgeCell = np.zeros(nCells, dtype="i") + + for iCell in range(0, nCells): + + # if (iCell % 100000 == 0): + # print(iCell, " of ", nCells, " cells...") + + for iCellOnCell in range(0, nEdgesOnCell[iCell]): + + iCell2 = cellsOnCell[iCell, iCellOnCell] + + if icePresence[iCell] == 1 and icePresence[iCell2] == 0: + iceEdgeCell[iCell] = 1 + + # only edge cells + nEdgeCells = np.sum(iceEdgeCell) + print("nEdgeCells: ", nEdgeCells) + + print("Get edge cell vector...") + iCellEdge = np.zeros(nEdgeCells, dtype="i") + + iEdgeCell = 0 + for iCell in range(0, nCells): + if iceEdgeCell[iCell] == 1: + iCellEdge[iEdgeCell] = iCell + iEdgeCell = iEdgeCell + 1 + + del iceEdgeCell + + # get edge positions + print("Get edge positions...") + xCellEdgeCell = np.zeros(nEdgeCells) + yCellEdgeCell = np.zeros(nEdgeCells) + zCellEdgeCell = np.zeros(nEdgeCells) + + for iEdgeCell in range(0, nEdgeCells): + iCell = iCellEdge[iEdgeCell] + xCellEdgeCell[iEdgeCell] = xCell[iCell] + yCellEdgeCell[iEdgeCell] = yCell[iCell] + zCellEdgeCell[iEdgeCell] = zCell[iCell] + + # find extended mask + print("Find new extended mask...") + + extendDistance = extendDistance * 1000.0 # convert from km to m + + if unitSphere: + earthRadius = constants['SHR_CONST_REARTH'] + extendDistance = extendDistance / earthRadius + + distanceLimit = math.pow(extendDistance, 2) + + icePresenceNew = icePresence.copy() + + if extendDistance > 0.0: + + distances = np.zeros(nEdgeCells) + + for iCell in range(0, nCells): + + if iCell % 100000 == 0: + print(iCell, " of ", nCells, " cells...") + + distances = np.multiply( + (xCell[iCell] - xCellEdgeCell), + (xCell[iCell] - xCellEdgeCell)) + np.multiply( + (yCell[iCell] - yCellEdgeCell), + (yCell[iCell] - yCellEdgeCell)) + np.multiply( + (zCell[iCell] - zCellEdgeCell), + (zCell[iCell] - zCellEdgeCell)) + + if distances[distances.argmin()] <= distanceLimit: + icePresenceNew[iCell] = 1 + + print("Load ice presence...") + filePresence = Dataset(filenamePresence, "a") + + icePresenceVar = filePresence.createVariable( + "icePresenceExtended", "d", dimensions=["nCells"]) + icePresenceVar[:] = icePresenceNew[:] + + filePresence.close()
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/seaice/mesh.html b/0.22.0rc4/_modules/mpas_tools/seaice/mesh.html new file mode 100644 index 000000000..d79003762 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/seaice/mesh.html @@ -0,0 +1,687 @@ + + + + + + mpas_tools.seaice.mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.seaice.mesh

+from netCDF4 import Dataset
+import numpy as np
+import math
+
+degreesToRadians = math.pi / 180.0
+radiansToDegrees = 180.0 / math.pi
+
+
+
[docs]def write_scrip_file(scripFilename, title, nCells, maxEdges, + latCell, lonCell, corner_lat, corner_lon, mask=None): + """ + A low-level function for writing a SCRIP file for the given MPAS-Seaice + mesh + + Parameters + ---------- + scripFilename : str + The name of the resulting SCRIP file + + title : str + A string to include as the ``title`` attribute in the SCRIP file + + nCells : int + The number of cells in the mesh + + maxEdges : int + The maximum number of edges/vertices on a cell in the mesh + + latCell : numpy.ndarray + The latitude (in radians) of cell centers + + lonCell : numpy.ndarray + The longitude (in radians) of cell centers + + corner_lat : numpy.ndarray + The latitude (in radians) of cell vertices + + corner_lon : numpy.ndarray + The longitude (in radians) of cell vertices + + mask : numpy.ndarray, optional + A mask of where cells are valid + """ + + # output mesh file + scripFile = Dataset(scripFilename, "w", format="NETCDF3_CLASSIC") + + scripFile.title = title.strip() + + scripFile.createDimension("grid_size", nCells) + scripFile.createDimension("grid_corners", maxEdges) + scripFile.createDimension("grid_rank", 1) + + grid_dims = scripFile.createVariable( + "grid_dims", "i", dimensions=["grid_rank"]) + grid_center_lat = scripFile.createVariable( + "grid_center_lat", "d", dimensions=["grid_size"]) + grid_center_lon = scripFile.createVariable( + "grid_center_lon", "d", dimensions=["grid_size"]) + grid_imask = scripFile.createVariable( + "grid_imask", "i", dimensions=["grid_size"]) + grid_corner_lat = scripFile.createVariable( + "grid_corner_lat", "d", dimensions=[ + "grid_size", "grid_corners"]) + grid_corner_lon = scripFile.createVariable( + "grid_corner_lon", "d", dimensions=[ + "grid_size", "grid_corners"]) + + grid_center_lat.units = "radians" + grid_center_lon.units = "radians" + grid_imask.units = "unitless" + grid_corner_lat.units = "radians" + grid_corner_lon.units = "radians" + + grid_dims[:] = [nCells] + grid_center_lat[:] = latCell + grid_center_lon[:] = lonCell + if mask is None: + grid_imask[:] = np.ones(nCells, dtype="i") + else: + grid_imask[:] = mask[:] + grid_corner_lat[:, :] = corner_lat[:, :] + grid_corner_lon[:, :] = corner_lon[:, :] + + scripFile.close()
+ +# ------------------------------------------------------------------------------------ + + +
[docs]def write_2D_scripfile(filenameScripOut, scripTitle, nColumns, nRows, + latsCentre, lonsCentre, latsVertex, lonsVertex, + degrees=False): + """ + Write a SCRIP file for the given 2D grid + + Parameters + ---------- + filenameScripOut : str + The name of the resulting SCRIP file + + scripTitle : str + A string to include as the ``title`` attribute in the SCRIP file + + nColumns : int + The number of columns in the grid + + nRows : int + The number of rows in the grid + + latsCentre : numpy.ndarray + The latitude (in radians) of cell centers + + lonsCentre : numpy.ndarray + The longitude (in radians) of cell centers + + latsVertex : numpy.ndarray + The latitude (in radians) of cell vertices + + lonsVertex : numpy.ndarray + The longitude (in radians) of cell vertices + + degrees : bool, optional + Whether the latitude and longitude variables are in degrees (as opposed + to radians) + """ + + if degrees: + scaling = np.pi / 180. + else: + scaling = 1.0 + + fileOut = Dataset(filenameScripOut, "w", format="NETCDF3_CLASSIC") + + fileOut.title = scripTitle + + grid_size = nRows * nColumns + grid_corners = 4 + grid_rank = 2 + + fileOut.createDimension("grid_size", grid_size) + fileOut.createDimension("grid_corners", grid_corners) + fileOut.createDimension("grid_rank", grid_rank) + + grid_dimsVar = fileOut.createVariable( + "grid_dims", "i", dimensions=("grid_rank",)) + grid_center_latVar = fileOut.createVariable( + "grid_center_lat", "d", dimensions=("grid_size",)) + grid_center_lonVar = fileOut.createVariable( + "grid_center_lon", "d", dimensions=("grid_size",)) + grid_imaskVar = fileOut.createVariable( + "grid_imask", "i", dimensions=("grid_size",)) + grid_corner_latVar = fileOut.createVariable( + "grid_corner_lat", "d", dimensions=( + "grid_size", "grid_corners")) + grid_corner_lonVar = fileOut.createVariable( + "grid_corner_lon", "d", dimensions=( + "grid_size", "grid_corners")) + + grid_dims = np.zeros(grid_rank, dtype="i") + grid_center_lat = np.zeros(grid_size, dtype="d") + grid_center_lon = np.zeros(grid_size, dtype="d") + grid_imask = np.zeros(grid_size, dtype="i") + grid_corner_lat = np.zeros((grid_size, grid_corners), dtype="d") + grid_corner_lon = np.zeros((grid_size, grid_corners), dtype="d") + + grid_dims[0] = nColumns + grid_dims[1] = nRows + + for iRow in range(0, nRows): + for iColumn in range(0, nColumns): + + i = iColumn + iRow * nColumns + + grid_center_lat[i] = latsCentre[iRow, iColumn] * scaling + grid_center_lon[i] = lonsCentre[iRow, iColumn] * scaling + + grid_imask[i] = 1 + + for iVertex in range(0, 4): + grid_corner_lat[i, iVertex] = \ + latsVertex[iRow, iColumn, iVertex] * scaling + grid_corner_lon[i, iVertex] = \ + lonsVertex[iRow, iColumn, iVertex] * scaling + + grid_dimsVar[:] = grid_dims + grid_center_latVar[:] = grid_center_lat + grid_center_lonVar[:] = grid_center_lon + grid_imaskVar[:] = grid_imask + grid_corner_latVar[:] = grid_corner_lat + grid_corner_lonVar[:] = grid_corner_lon + + grid_center_latVar.units = "radians" + grid_center_lonVar.units = "radians" + grid_imaskVar.units = "unitless" + grid_corner_latVar.units = "radians" + grid_corner_lonVar.units = "radians" + + fileOut.close()
+ +# --------------------------------------------------------------------- + + +
[docs]def make_mpas_scripfile_on_cells(meshFilename, scripFilename, title): + """ + Write a SCRIP file for cel quantities on the given MPAS-Seaice mesh + + Parameters + ---------- + meshFilename : str + The name of a file containing the MPAS-Seaice mesh + + scripFilename : str + The name of the resulting SCRIP file + + title : str + A string to include as the ``title`` attribute in the SCRIP file + """ + + # input mesh data + meshFile = Dataset(meshFilename, "r") + + nCells = len(meshFile.dimensions["nCells"]) + maxEdges = len(meshFile.dimensions["maxEdges"]) + + latCell = meshFile.variables["latCell"][:] + lonCell = meshFile.variables["lonCell"][:] + + latVertex = meshFile.variables["latVertex"][:] + lonVertex = meshFile.variables["lonVertex"][:] + + nEdgesOnCell = meshFile.variables["nEdgesOnCell"][:] + verticesOnCell = meshFile.variables["verticesOnCell"][:] + + meshFile.close() + + # make corner arrays + corner_lat = np.zeros((nCells, maxEdges), dtype="d") + corner_lon = np.zeros((nCells, maxEdges), dtype="d") + + for iCell in range(0, nCells): + + for iVertexOnCell in range(0, nEdgesOnCell[iCell]): + + iVertex = verticesOnCell[iCell, iVertexOnCell] - 1 + + corner_lat[iCell, iVertexOnCell] = latVertex[iVertex] + corner_lon[iCell, iVertexOnCell] = lonVertex[iVertex] + + for iVertexOnCell in range(nEdgesOnCell[iCell], maxEdges): + + corner_lat[iCell, + iVertexOnCell] = corner_lat[iCell, + nEdgesOnCell[iCell] - 1] + corner_lon[iCell, + iVertexOnCell] = corner_lon[iCell, + nEdgesOnCell[iCell] - 1] + + # create the scrip file + write_scrip_file( + scripFilename, + title, + nCells, + maxEdges, + latCell, + lonCell, + corner_lat, + corner_lon)
+ +# --------------------------------------------------------------------- + + +
[docs]def make_mpas_scripfile_on_vertices(meshFilename, scripFilename, title): + """ + Write a SCRIP file for vertex quantities on the given MPAS-Seaice mesh + + Parameters + ---------- + meshFilename : str + The name of a file containing the MPAS-Seaice mesh + + scripFilename : str + The name of the resulting SCRIP file + + title : str + A string to include as the ``title`` attribute in the SCRIP file + """ + + # input mesh data + meshFile = Dataset(meshFilename, "r") + + nVertices = len(meshFile.dimensions["nVertices"]) + vertexDegree = len(meshFile.dimensions["vertexDegree"]) + + latCell = meshFile.variables["latCell"][:] + lonCell = meshFile.variables["lonCell"][:] + + latVertex = meshFile.variables["latVertex"][:] + lonVertex = meshFile.variables["lonVertex"][:] + + cellsOnVertex = meshFile.variables["cellsOnVertex"][:] + + meshFile.close() + + # make corner arrays + corner_lat = np.zeros((nVertices, vertexDegree), dtype="d") + corner_lon = np.zeros((nVertices, vertexDegree), dtype="d") + + for iVertex in range(0, nVertices): + + for iCellOnVertex in range(0, vertexDegree): + + iCell = cellsOnVertex[iVertex, iCellOnVertex] - 1 + + if iCell != -1: + + corner_lat[iVertex, iCellOnVertex] = latCell[iCell] + corner_lon[iVertex, iCellOnVertex] = lonCell[iCell] + + else: + + corner_lat[iVertex, iCellOnVertex], \ + corner_lon[iVertex, iCellOnVertex] = \ + _estimate_missing_cell_latlon( + iVertex, iCellOnVertex, vertexDegree, cellsOnVertex, + latCell, lonCell, latVertex, lonVertex) + + # create the scrip file + write_scrip_file(scripFilename, title, nVertices, vertexDegree, + latVertex, lonVertex, corner_lat, corner_lon)
+ + +# --------------------------------------------------------------------- +# Private functions +# --------------------------------------------------------------------- + +def _rotate_about_vector(vectorToRotate, vectorAxis, rotationAngle): + """ + Rotate the given Cartesian vector around the given axis by the given + angle. + + Parameters + ---------- + vectorToRotate : numpy.ndarray + The 3-element vector to rotate + + vectorAxis : numpy.ndarray + The 3-element axis of rotation + + rotationAngle : float + The angle of rotation (in radians) + + Returns + ------- + rotatedVector : numpy.ndarray + The rotated vector + """ + + # http://ksuweb.kennesaw.edu/~plaval//math4490/rotgen.pdf + + r = vectorAxis / np.linalg.norm(vectorAxis) + + C = math.cos(rotationAngle) + S = math.sin(rotationAngle) + t = 1.0 - C + + rot = np.zeros((3, 3)) + + rot[0, 0] = t * r[0] * r[0] + C + rot[0, 1] = t * r[0] * r[1] - S * r[2] + rot[0, 2] = t * r[0] * r[2] + S * r[1] + + rot[1, 0] = t * r[0] * r[1] + S * r[2] + rot[1, 1] = t * r[1] * r[1] + C + rot[1, 2] = t * r[1] * r[2] - S * r[0] + + rot[2, 0] = t * r[0] * r[2] - S * r[1] + rot[2, 1] = t * r[1] * r[2] + S * r[0] + rot[2, 2] = t * r[2] * r[2] + C + + # get relative position of missing cell + rotatedVector = np.matmul(rot, vectorToRotate) + + return rotatedVector + + +def _wrap_index(i, n): + + return i % n + + +def _rotate_about_vertex(latCell, lonCell, latVertex, lonVertex, angle): + + vertexPosition = _get_position_from_lat_lon(latVertex, lonVertex) + cellPosition = _get_position_from_lat_lon(latCell, lonCell) + + vertexToCellVector = cellPosition - vertexPosition + + vertexToCellVectorMagnitude = _vector_magnitude(vertexToCellVector) + + vertexToCellVectorNormalized = _normalize_vector(vertexToCellVector) + + perpendicularVector = _cross_product(vertexPosition, vertexToCellVector) + + perpendicularVectorNormalized = _normalize_vector(perpendicularVector) + + rotatedVectorNormalized = \ + math.cos(angle * degreesToRadians) * vertexToCellVectorNormalized + \ + math.sin(angle * degreesToRadians) * perpendicularVectorNormalized + + rotatedVector = rotatedVectorNormalized * vertexToCellVectorMagnitude + + newPositionVector = vertexPosition + rotatedVector + + latRotated, lonRotated = _get_lat_lon_from_position(newPositionVector) + + return latRotated, lonRotated + + +def _estimate_missing_cell_latlon( + iVertex, iCellOnVertexNeeded, vertexDegree, cellsOnVertex, latCell, + lonCell, latVertex, lonVertex): + """ + Estimate the latitude and longitude of a "missing" neighbor cell that has + been culled from the MPAS-Seaice mesh + + Parameters + ---------- + iVertex : int + The index of the vertex with the missing neighbor + + iCellOnVertexNeeded : int + The local index on the vertex of the missing cell + + vertexDegree : int + The maximum number of cells neighboring each vertex + + cellsOnVertex : numpy.ndarray + The indices of cells neighboring each vertex in the mesh + + latCell : numpy.ndarray + The latitude (in radians) of cell centers + + lonCell : numpy.ndarray + The longitude (in radians) of cell centers + + latVertex : numpy.ndarray + The latitude (in radians) of vertices + + lonVertex : numpy.ndarray + The longitude (in radians) of vertices + + Returns + ------- + lat : float + The approximate latitude of the missing cell center + + lon : float + The approximate longitude of the missing cell center + + Raises + ------ + ValueError + If no reasonable location for the missing cell can be found + """ + + # firstly we find a cell on vertex that exists + nRotations = 0 + + for iCellOnVertex in range(0, vertexDegree): + + iCell = cellsOnVertex[iVertex, _wrap_index( + iCellOnVertexNeeded - iCellOnVertex - 1, vertexDegree)] - 1 + nRotations = nRotations + 1 + + if iCell != -1: + + # find relative vector to cell we have which needs to be rotated + cellPosition = _get_position_from_lat_lon( + latCell[iCell], lonCell[iCell]) + vertexPosition = _get_position_from_lat_lon( + latVertex[iVertex], lonVertex[iVertex]) + + cellVector = cellPosition - vertexPosition + + # rotate cell vector around vertex vector + theta = nRotations * ((2.0 * math.pi) / float(vertexDegree)) + missingCellVector = _rotate_about_vector( + cellVector, vertexPosition, theta) + + # get absolute position + missingCellPosition = vertexPosition + missingCellVector + + # get missing cell lat, lon + lat, lon = _get_lat_lon_from_position(missingCellPosition) + + return lat, lon + + raise ValueError("Can't find position!") + + +def _get_position_from_lat_lon(lat, lon): + + position = np.zeros(3) + + position[0] = math.cos(lat) * math.cos(lon) + position[1] = math.cos(lat) * math.sin(lon) + position[2] = math.sin(lat) + + return position + + +def _get_lat_lon_from_position(position): + + lat = math.asin(position[2]) + lon = math.atan2(position[1], position[0]) + + return lat, lon + + +def _vector_magnitude(vector): + + magnitude = math.sqrt(math.pow(vector[0], 2) + + math.pow(vector[1], 2) + + math.pow(vector[2], 2)) + + return magnitude + + +def _normalize_vector(vector): + + magnitude = _vector_magnitude(vector) + + normalizedVector = vector / magnitude + + return normalizedVector + + +def _cross_product(u, v): + + cp = np.zeros(3) + + cp[0] = u[1] * v[2] - u[2] * v[1] + cp[1] = u[2] * v[0] - u[0] * v[2] + cp[2] = u[0] * v[1] - u[1] * v[0] + + return cp +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/seaice/partition.html b/0.22.0rc4/_modules/mpas_tools/seaice/partition.html new file mode 100644 index 000000000..d1a4cabfa --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/seaice/partition.html @@ -0,0 +1,687 @@ + + + + + + mpas_tools.seaice.partition — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.seaice.partition

+from netCDF4 import Dataset
+import os
+import math
+import errno
+import numpy as np
+import subprocess
+import argparse
+import shutil
+import glob
+
+from .regrid import regrid_to_other_mesh
+from .mask import extend_seaice_mask
+from .regions import make_regions_file
+
+
+
[docs]def gen_seaice_mesh_partition(meshFilename, regionFilename, nProcsArray, + mpasCullerLocation, outputPrefix, plotting, + metis, cullEquatorialRegion): + """ + Generate graph partition(s) for the given MPAS-Seaice mesh and the given + number(s) of processors and a file defining regions that each processor + should own part of (typically a polar region and an equatorial region) + + Parameters + ---------- + meshFilename : str + The name of a file containing the MPAS-Seaice mesh + + regionFilename : str + The name of a file containing a ``region`` field defining different + regions that each processor should own part of + + nProcsArray : list or int + The number(s) of processors to create graph partitions for + + mpasCullerLocation : str or None + The directory for the ``MpasCellCuller.x`` tool or ``None`` to look in + the user's path + + outputPrefix : str + The prefix to prepend to each graph partition file + + plotting : bool + Whether to create a NetCDF file ``partition_diag.nc`` to use for + plotting the partitions + + metis : str + The exectable to use for partitioning in each region + + cullEquatorialRegion : bool + Whether to remove the equatorial region from the paritions + """ + + # arguments + meshToolsDir = mpasCullerLocation + if meshToolsDir is None: + culler = shutil.which("MpasCellCuller.x") + if culler is not None: + meshToolsDir = os.path.dirname(culler) + else: + # no directory was provided and none + this_dir = os.path.dirname(os.path.realpath(__file__)) + meshToolsDir = os.path.abspath(os.path.join( + this_dir, "..", "..", "..", "mesh_tools", + "mesh_conversion_tools")) + culler = os.path.join(meshToolsDir, "MpasCellCuller.x") + if not os.path.exists(culler): + raise FileNotFoundError( + "MpasCellCuller.x does not exist at the requested location.") + + plotFilename = "partition_diag.nc" + + # get regions + regionFile = Dataset(regionFilename, "r") + nRegions = regionFile.nRegions + region = regionFile.variables["region"][:] + regionFile.close() + + # diagnostics + if plotting: + shutil.copyfile(meshFilename, plotFilename) + + # load mesh file + mesh = Dataset(meshFilename, "r") + nCells = len(mesh.dimensions["nCells"]) + mesh.close() + + cellidsInRegion = [] + + for iRegion in range(0, nRegions): + + # tmp file basename + tmp = "%s_%2.2i_tmp" % (meshFilename, iRegion) + + # create precull file + tmpFilenamesPrecull = tmp + "_precull.nc" + shutil.copyfile(meshFilename, tmpFilenamesPrecull) + + # make cullCell variable + cullCell = np.ones(nCells) + + for iCell in range(0, nCells): + if region[iCell] == iRegion: + cullCell[iCell] = 0 + + # cull the mesh + tmpFilenamesPostcull = tmp + "_postcull.nc" + _cull_mesh(meshToolsDir, tmpFilenamesPrecull, tmpFilenamesPostcull, + cullCell) + + # get the cell IDs for this partition + cellid = _get_cell_ids(tmpFilenamesPostcull, meshFilename) + cellidsInRegion.append(cellid) + + # preserve the initial graph file + os.rename("culled_graph.info", f"culled_graph_{iRegion}_tmp.info") + + if not isinstance(nProcsArray, (list, tuple, set)): + # presumably, it's a single integer + nProcsArray = [nProcsArray] + + for nProcs in nProcsArray: + if cullEquatorialRegion: + nBlocks = nRegions * nProcs + else: + nBlocks = nProcs + + combinedGraph = np.zeros(nCells) + + for iRegion in range(0, nRegions): + + # partition the culled grid + try: + graphFilename = "culled_graph_%i_tmp.info" % iRegion + subprocess.call([metis, graphFilename, str(nProcs)]) + except OSError as e: + if e.errno == errno.ENOENT: + raise FileNotFoundError( + "metis program %s not found" % metis) + else: + print("metis error") + raise + + cellid = cellidsInRegion[iRegion] + + # load this partition + graph = _load_partition( + "culled_graph_%i_tmp.info.part.%i" % + (iRegion, nProcs)) + + # add this partition to the combined partition + for iCellPartition in range(0, len(graph)): + if cullEquatorialRegion: + combinedGraph[cellid[iCellPartition]] = \ + graph[iCellPartition] + nProcs * iRegion + else: + combinedGraph[cellid[iCellPartition]] = \ + graph[iCellPartition] + + # output the cell partition file + cellPartitionFile = open("%s.part.%i" % (outputPrefix, nBlocks), "w") + for iCell in range(0, nCells): + cellPartitionFile.write("%i\n" % (combinedGraph[iCell])) + cellPartitionFile.close() + + # output block partition file + if cullEquatorialRegion: + blockPartitionFile = open( + "%s.part.%i" % + (outputPrefix, nProcs), "w") + for iRegion in range(0, nRegions): + for iProc in range(0, nProcs): + blockPartitionFile.write("%i\n" % iProc) + blockPartitionFile.close() + + # diagnostics + if plotting: + plottingFile = Dataset(plotFilename, "a") + partitionVariable = plottingFile.createVariable( + "partition_%i" % nProcs, "i4", ("nCells",)) + partitionVariable[:] = combinedGraph + plottingFile.close() + + subprocess.run("rm *tmp*", shell=True)
+ + +
[docs]def prepare_partitions(): + """ + An entry point for performing preparatory work for making seaice partitions + """ + # parsing input + parser = argparse.ArgumentParser( + description="Perform preparatory work for making seaice partitions.") + + parser.add_argument("-i", "--inputmesh", dest="meshFilenameSrc", + required=True, + help="MPAS mesh file for source regridding mesh.") + parser.add_argument("-p", "--presence", dest="filenameData", + required=True, + help="Input ice presence file for source mesh.") + parser.add_argument("-m", "--outputmesh", dest="meshFilenameDst", + required=True, + help="MPAS mesh file for destination regridding mesh.") + parser.add_argument("-o", "--outputDir", dest="outputDir", + required=True, + help="Output directory for temporary files and " + "partition files.") + parser.add_argument("-w", "--weightsFilename", dest="weightsFilename", + required=False, + help="A mapping file between the input and output " + "MPAS meshes. One will be generated if it is " + "not supplied.") + + args = parser.parse_args() + + # Check if output directory exists + if not os.path.isdir(args.outputDir): + raise FileNotFoundError("ERROR: Output directory does not exist.") + + # 1) Regrid the ice presence from the input data mesh to the grid of choice + print("Regrid to desired mesh...") + filenameOut = args.outputDir + "/icePresent_regrid.nc" + + regrid_to_other_mesh( + meshFilenameSrc=args.meshFilenameSrc, + filenameData=args.filenameData, + meshFilenameDst=args.meshFilenameDst, + filenameOut=filenameOut, + generateWeights=(args.weightsFilename is None), + weightsFilename=args.weightsFilename) + + # 2) create icePresence variable + print("fix_regrid_output...") + + # check executable exists + if shutil.which("fix_regrid_output.exe") is not None: + # it's in the system path + executable = "fix_regrid_output.exe" + elif os.path.exists("./fix_regrid_output.exe"): + # found in local path + executable = "./fix_regrid_output.exe" + else: + raise FileNotFoundError("fix_regrid_output.exe could not be found.") + + inputFile = args.outputDir + "/icePresent_regrid.nc" + outputFile = args.outputDir + "/icePresent_regrid_modify.nc" + subprocess.call([executable, inputFile, args.meshFilenameDst, outputFile]) + + # 3) create variable icePresenceExtended + print("extend_seaice_mask...") + filenamePresence = args.outputDir + "/icePresent_regrid_modify.nc" + extend_seaice_mask(args.meshFilenameDst, filenamePresence, 0.0, False) + + # 4) Make the regions file from the icePresenceExtended variable + print("make_regions_file...") + filenameIcePresent = args.outputDir + "/icePresent_regrid_modify.nc" + filenameOut = args.outputDir + "/regions.nc" + make_regions_file(filenameIcePresent=filenameIcePresent, + filenameMesh=args.meshFilenameDst, + regionType="two_region_eq", + varname="icePresenceExtended", + limit=0.5, filenameOut=filenameOut)
+ + +
[docs]def create_partitions(): + """ + An entry point for creating sea-ice partitions + """ + + # parsing input + parser = argparse.ArgumentParser(description='Create sea-ice partitions.') + + parser.add_argument( + '-m', '--outputmesh', dest="meshFilename", required=True, + help='MPAS mesh file for destination regridding mesh.') + parser.add_argument( + '-o', '--outputDir', dest="outputDir", required=True, + help='Output directory for temporary files and partition files.') + parser.add_argument( + '-c', '--cullerDir', dest="mpasCullerLocation", required=False, + help='Location of MPAS MpasCellCuller.x executable.') + parser.add_argument( + '-p', '--prefix', dest="outputPrefix", required=False, + help='prefix for output partition filenames.', default="graph.info") + parser.add_argument( + '-x', '--plotting', dest="plotting", required=False, + help='create diagnostic plotting file of partitions', + action='store_true') + parser.add_argument( + '-g', '--metis', dest="metis", required=False, + help='name of metis utility', default="gpmetis") + parser.add_argument( + '-n', '--nProcs', dest="nProcsArray", nargs='*', required=False, + help='list of the number of processors to create partition for.', + type=int) + parser.add_argument( + '-f', '--nProcsFile', dest="nProcsFile", required=False, + help='number of processors to create partition for.') + + args = parser.parse_args() + + # number of processors + if args.nProcsArray is None and args.nProcsFile is None: + raise ValueError("Must specify nProcs or nProcsFile") + if args.nProcsArray is not None and args.nProcsFile is not None: + raise ValueError("Can't specify both nProcs or nProcsFile") + + if args.nProcsFile is not None: + with open(args.nProcsFile, "r") as fileNProcs: + nProcsLines = fileNProcs.readlines() + nProcsArray = [int(line) for line in nProcsLines + if line.split() != ''] + else: + nProcsArray = args.nProcsArray + + # create partitions + regionFilename = args.outputDir + "/regions.nc" + outputPrefix = args.outputDir + "/" + args.outputPrefix + + gen_seaice_mesh_partition(args.meshFilename, regionFilename, nProcsArray, + args.mpasCullerLocation, outputPrefix, + args.plotting, args.metis, + cullEquatorialRegion=False)
+ + +def simple_partitions(): + """ + An entry point for creating sea-ice partitions on LCRC (Anvil and + Chrysalis) + """ + + data_dir = '/lcrc/group/e3sm/public_html/mpas_standalonedata/' \ + 'mpas-seaice/partition' + + # parsing input + parser = argparse.ArgumentParser( + description='Create sea-ice partitions on LCRC.') + + parser.add_argument( + '-m', '--mesh', dest="meshFilename", required=True, + help='MPAS-Seaice mesh file.') + parser.add_argument( + '-p', '--prefix', dest="outputPrefix", required=True, + help='prefix for output partition filenames.') + parser.add_argument( + '-n', '--nprocs', dest="nProcsArray", nargs='*', required=True, + help='list of the number of processors to create partition for.', + type=int) + parser.add_argument( + '-d', '--datadir', dest="dataDir", required=False, + default=data_dir, + help='Directory with seaice_QU60km_polar.nc and ' + 'icePresent_QU60km_polar.nc.') + + args = parser.parse_args() + + meshFilenameDst = os.path.abspath(args.meshFilename) + + tmpdir = 'tmp_seaice_part_dir' + try: + shutil.rmtree(tmpdir) + except FileNotFoundError: + pass + + os.makedirs(tmpdir) + + cwd = os.getcwd() + + os.chdir(tmpdir) + + # make a local link to the mesh file + basename = os.path.basename(meshFilenameDst) + command = ['ln', '-s', meshFilenameDst, basename] + subprocess.run(command, check=True) + meshFilenameDst = basename + + # 1) Regrid the ice presence from the input data mesh to the grid of choice + print("Regrid to desired mesh...") + filenameOut = "icePresent_regrid.nc" + + meshFilenameSrc = os.path.join(data_dir, 'seaice_QU60km_polar.nc') + filenameData = os.path.join(data_dir, 'icePresent_QU60km_polar.nc') + + regrid_to_other_mesh( + meshFilenameSrc=meshFilenameSrc, + filenameData=filenameData, + meshFilenameDst=meshFilenameDst, + filenameOut=filenameOut, + generateWeights=True, + weightsFilename=None) + + # 2) create icePresence variable + print("fix_regrid_output...") + + inputFile = "icePresent_regrid.nc" + outputFile = "icePresent_regrid_modify.nc" + subprocess.call(["fix_regrid_output.exe", inputFile, meshFilenameDst, + outputFile]) + + # 3) create variable icePresenceExtended + print("extend_seaice_mask...") + filenamePresence = "icePresent_regrid_modify.nc" + extend_seaice_mask(meshFilenameDst, filenamePresence, 0.0, False) + + # 4) Make the regions file from the icePresenceExtended variable + print("make_regions_file...") + filenameIcePresent = "icePresent_regrid_modify.nc" + filenameOut = "regions.nc" + make_regions_file(filenameIcePresent=filenameIcePresent, + filenameMesh=meshFilenameDst, + regionType="two_region_eq", + varname="icePresenceExtended", + limit=0.5, + filenameOut=filenameOut) + + nProcsArray = args.nProcsArray + + # create partitions + regionFilename = "regions.nc" + outputPrefix = os.path.join(cwd, args.outputPrefix) + + gen_seaice_mesh_partition(meshFilename=meshFilenameDst, + regionFilename=regionFilename, + nProcsArray=nProcsArray, + mpasCullerLocation=None, + outputPrefix=outputPrefix, + plotting=False, + metis="gpmetis", + cullEquatorialRegion=False) + + for file in glob.glob(f'{outputPrefix}*'): + command = ['chmod', 'ug+rw', file] + subprocess.run(command, check=True) + command = ['chmod', 'o+r', file] + subprocess.run(command, check=True) + + os.chdir(cwd) + shutil.rmtree(tmpdir) + + +# --------------------------------------------------------------------- +# Private functions +# --------------------------------------------------------------------- + +def _degree_to_radian(degree): + + return (degree * math.pi) / 180.0 + + +def _add_cell_cull_array(filename, cullCell): + + mesh = Dataset(filename, "a") + + cullCellVariable = mesh.createVariable("cullCell", "i4", ("nCells",)) + + cullCellVariable[:] = cullCell + + mesh.close() + + +def _cull_mesh(meshToolsDir, filenameIn, filenameOut, cullCell): + + _add_cell_cull_array(filenameIn, cullCell) + executable = "MpasCellCuller.x" + if meshToolsDir is not None: + executable = os.path.join(meshToolsDir, executable) + + subprocess.run([executable, filenameIn, filenameOut, "-c"], check=True) + + +def _load_partition(graphFilename): + + graphFile = open(graphFilename, "r") + lines = graphFile.readlines() + graphFile.close() + + partition = [] + for line in lines: + partition.append(int(line)) + + return partition + + +def _get_cell_ids(culledFilename, originalFilename): + + culledFile = Dataset(culledFilename, "r") + nCellsCulled = len(culledFile.dimensions["nCells"]) + + originalFile = Dataset(originalFilename, "r") + nCellsOriginal = len(originalFile.dimensions["nCells"]) + + cellid = np.zeros(nCellsCulled, dtype=int) + + cellMapFile = open("cellMapForward.txt", "r") + cellMapLines = cellMapFile.readlines() + cellMapFile.close() + + iCellOriginal = 0 + for cellMapLine in cellMapLines: + + if iCellOriginal % 1000 == 0: + print(iCellOriginal, " of ", nCellsOriginal) + + try: + cellMap = int(cellMapLine) + except ValueError: + # There are blank lines to skip + continue + + if cellMap != -1: + + cellid[cellMap] = iCellOriginal + + iCellOriginal = iCellOriginal + 1 + + return cellid + + +def _get_cell_ids_orig(culledFilename, originalFilename): + + culledFile = Dataset(culledFilename, "r") + latCellCulled = culledFile.variables["latCell"][:] + lonCellCulled = culledFile.variables["lonCell"][:] + nCellsCulled = len(culledFile.dimensions["nCells"]) + + originalFile = Dataset(originalFilename, "r") + latCellOriginal = originalFile.variables["latCell"][:] + lonCellOriginal = originalFile.variables["lonCell"][:] + nCellsOriginal = len(originalFile.dimensions["nCells"]) + + cellid = np.zeros(nCellsCulled, dtype=int) + + for iCellCulled in range(0, nCellsCulled): + + if iCellCulled % 1000 == 0: + print("iCellCulled: ", iCellCulled, "of ", nCellsCulled) + + for iCellOriginal in range(0, nCellsOriginal): + + if (latCellCulled[iCellCulled] == latCellOriginal[iCellOriginal] and + lonCellCulled[iCellCulled] == lonCellOriginal[iCellOriginal]): + + cellid[iCellCulled] = iCellOriginal + break + + return cellid +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/seaice/regions.html b/0.22.0rc4/_modules/mpas_tools/seaice/regions.html new file mode 100644 index 000000000..9a48fbb19 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/seaice/regions.html @@ -0,0 +1,265 @@ + + + + + + mpas_tools.seaice.regions — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.seaice.regions

+from __future__ import print_function
+from netCDF4 import Dataset
+import numpy as np
+
+
+
[docs]def make_regions_file(filenameIcePresent, filenameMesh, + regionType, varname, limit, filenameOut): + """" + + Parameters + ---------- + filenameIcePresent : str + A filename for a file containing the field specified in ``varname`` + that determines where ice may be present + + filenameMesh : str + The name of a file containing the MPAS-Seaice mesh + + regionType : {"three_region", "two_region_eq", "three_region_eq", "five_region_eq"} + The type of regions to write + + varname : str + The name of the variable that determines where ice might be present + + limit : float + For ``regionType`` either ``three_region`` or ``five_region_eq``, + the value of the ``varname`` field above which ice is considered to + be present. For other ``regionType`` values, the limit is always 0.5 + and this parameter is ignored. + + filenameOut : str + The NetCDF filename to write the resulting ``region`` field to + """ + + # load ice presence + print(filenameIcePresent) + fileIcePresent = Dataset(filenameIcePresent, "r") + + icePresence = fileIcePresent.variables[varname][:] + + fileIcePresent.close() + + # load mesh data + fileMesh = Dataset(filenameMesh, "r") + + nCells = len(fileMesh.dimensions["nCells"]) + + latCell = fileMesh.variables["latCell"][:] + + fileMesh.close() + + # output region mask + region = np.zeros(nCells, dtype="i") + + # no equatorial removal + if regionType == "three_region": + + nRegions = 3 + + for iCell in range(0, nCells): + + if icePresence[iCell] > limit and latCell[iCell] < 0.0: + region[iCell] = 0 + elif icePresence[iCell] > limit and latCell[iCell] >= 0.0: + region[iCell] = 2 + else: + region[iCell] = 1 + + elif regionType == "two_region_eq": + + nRegions = 2 + + for iCell in range(0, nCells): + + if icePresence[iCell] > 0.5 and latCell[iCell] < 0.0: + region[iCell] = 0 + elif icePresence[iCell] > 0.5 and latCell[iCell] >= 0.0: + region[iCell] = 0 + else: + region[iCell] = 1 + + elif regionType == "three_region_eq": + + nRegions = 3 + + for iCell in range(0, nCells): + + if icePresence[iCell] > 0.5 and latCell[iCell] < 0.0: + region[iCell] = 0 + elif icePresence[iCell] > 0.5 and latCell[iCell] >= 0.0: + region[iCell] = 2 + else: + region[iCell] = 1 + + elif regionType == "five_region_eq": + + nRegions = 5 + + for iCell in range(0, nCells): + + if icePresence[iCell] > limit and latCell[iCell] >= 0.0: + region[iCell] = 4 + elif limit > icePresence[iCell] > 0.5 and latCell[iCell] >= 0.0: + region[iCell] = 3 + elif icePresence[iCell] > limit and latCell[iCell] < 0.0: + region[iCell] = 0 + elif limit > icePresence[iCell] > 0.5 and latCell[iCell] < 0.0: + region[iCell] = 1 + else: + region[iCell] = 2 + else: + raise ValueError(f'Unexpected regionType {regionType}') + + # output + fileOut = Dataset(filenameOut, "w", format="NETCDF3_CLASSIC") + + fileOut.nRegions = nRegions + + fileOut.createDimension("nCells", nCells) + + regionVar = fileOut.createVariable("region", "i", dimensions=["nCells"]) + regionVar[:] = region[:] + + fileOut.close()
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/seaice/regrid.html b/0.22.0rc4/_modules/mpas_tools/seaice/regrid.html new file mode 100644 index 000000000..a3f1d86f2 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/seaice/regrid.html @@ -0,0 +1,324 @@ + + + + + + mpas_tools.seaice.regrid — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.seaice.regrid

+import os
+from netCDF4 import Dataset
+import numpy as np
+import numpy.ma as ma
+import subprocess
+import hashlib
+
+from .mesh import make_mpas_scripfile_on_cells
+
+
+
[docs]def regrid_to_other_mesh(meshFilenameSrc, filenameData, + meshFilenameDst, filenameOut, + generateWeights=True, weightsFilename=None): + + # make scrip files + print("Make scrip files...") + SCRIPFilenameSrc = "scrip_src_tmp.nc" + SCRIPFilenameDst = "scrip_dst_tmp.nc" + + titleSrc = "MPAS grid src" + titleDst = "MPAS grid dst" + + make_mpas_scripfile_on_cells(meshFilenameSrc, SCRIPFilenameSrc, titleSrc) + make_mpas_scripfile_on_cells(meshFilenameDst, SCRIPFilenameDst, titleDst) + + if weightsFilename is None: + weightsFilename = os.getcwd() + "/weights_tmp.nc" + + if generateWeights: + # generate weights file + print("Generate weights...") + _generate_weights_file(SCRIPFilenameSrc, SCRIPFilenameDst, + weightsFilename, reuseWeights=False) + else: + assert os.path.exists(weightsFilename) + + # load output mesh + print("Load output mesh...") + meshFile = Dataset(meshFilenameDst, "r") + + nCells = len(meshFile.dimensions["nCells"]) + + cellsOnCell = meshFile.variables["cellsOnCell"][:] + cellsOnCell[:] = cellsOnCell[:] - 1 + + meshFile.close() + + # load data + print("Load input data...") + fileIn = Dataset(filenameData, "r") + + iceFractionIn = fileIn.variables["iceFraction"][:] + + fileIn.close() + + # regrid + print("Regrid array...") + iceFractionOut, iceFractionOutMask = _regrid_mpas_array( + weightsFilename, iceFractionIn) + + # output + print("Output...") + fileOut = Dataset(filenameOut, "w", format="NETCDF3_CLASSIC") + + fileOut.createDimension("nCells", nCells) + + iceFractionVar = fileOut.createVariable( + "iceFraction", "d", dimensions=["nCells"]) + iceFractionVar[:] = iceFractionOut[:] + + iceFractionMaskVar = fileOut.createVariable( + "iceFractionMask", "i", dimensions=["nCells"]) + iceFractionMaskVar[:] = iceFractionOutMask[:] + + fileOut.close()
+ + +# ------------------------------------------------------------------------------------ +# Private functions +# ------------------------------------------------------------------------------------ + +def _get_weights_filename(inputStrings): + + hashInput = "" + for inputString in inputStrings: + hashInput = hashInput + inputString + + hashOutput = hashlib.md5(hashInput).hexdigest() + weightFilename = "weights_%s.nc" % hashOutput + + return weightFilename + + +def _generate_weights_file( + SCRIPFilenameSrc, SCRIPFilenameDst, weightsFilename, reuseWeights): + + if not reuseWeights or not os.path.isfile(weightsFilename): + + args = ["ESMF_RegridWeightGen", + "--source", SCRIPFilenameSrc, + "--destination", SCRIPFilenameDst, + "--weight", weightsFilename, + "--src_regional", "--dst_regional", "--ignore_unmapped"] + + subprocess.run(args, check=True) + + +def _load_weights_file(weightsFilename): + + weights = {} + + weightsFile = Dataset(weightsFilename, "r") + + weights["n_s"] = len(weightsFile.dimensions["n_s"]) + + weights["col"] = weightsFile.variables["col"][:] + weights["row"] = weightsFile.variables["row"][:] + weights["S"] = weightsFile.variables["S"][:] + + dst_grid_dims = weightsFile.variables["dst_grid_dims"][:] + weights["nRows"] = dst_grid_dims[0] + weights["nColumns"] = dst_grid_dims[1] + + weightsFile.close() + + return weights + + +def _regrid_obs_array(obsArray, weights): + + n_s = weights["n_s"] + + col = weights["col"] + row = weights["row"] + S = weights["S"] + + nColumns = weights["nColumns"] + nRows = weights["nRows"] + + nRowsIn = obsArray.shape[0] + + # get two dimensional grid + obsArrayRegrid = ma.zeros((nRows, nColumns)) + + for i_s in range(0, n_s): + + iRow = (row[i_s] - 1) / nRows + iColumn = (row[i_s] - 1) % nRows + + iRowIn = (col[i_s] - 1) / nRowsIn + iColumnIn = (col[i_s] - 1) % nRowsIn + + obsArrayRegrid[iRow, iColumn] = obsArrayRegrid[iRow, + iColumn] + S[i_s] * obsArray[iRowIn, iColumnIn] + + return obsArrayRegrid + + +def _regrid_mpas_array(weightsFilename, mpasArrayIn): + + # load weights + print("Load weights...", weightsFilename) + weightsFile = Dataset(weightsFilename, "r") + + n_s = len(weightsFile.dimensions["n_s"]) + n_b = len(weightsFile.dimensions["n_b"]) + + col = weightsFile.variables["col"][:] + row = weightsFile.variables["row"][:] + S = weightsFile.variables["S"][:] + + weightsFile.close() + + # regrid + print("Regrid array...") + mpasArrayOut = np.zeros(n_b) + mpasArrayOutMask = np.zeros(n_b, dtype="i") + for i_s in range(0, n_s): + mpasArrayOut[row[i_s] - 1] = mpasArrayOut[row[i_s] - 1] + \ + S[i_s] * mpasArrayIn[col[i_s] - 1] + mpasArrayOutMask[row[i_s] - 1] = 1 + + return mpasArrayOut, mpasArrayOutMask +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/split_grids.html b/0.22.0rc4/_modules/mpas_tools/split_grids.html new file mode 100644 index 000000000..af221128e --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/split_grids.html @@ -0,0 +1,431 @@ + + + + + + mpas_tools.split_grids — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.split_grids

+#!/usr/bin/env python
+"""
+Tool to split 2 previously merged MPAS non-contiguous meshes into separate files.
+Typical usage is:
+    split_grids.py -1 outfile1.nc -2 outfile2.nc infile
+The optional arguments for nCells, nEdges, nVertices, and maxEdges should
+generally not be required as this information is saved in the combined mesh file
+as global attributes by the merge_grids.py script.
+"""
+
+import os
+import sys
+import json
+import argparse
+
+from datetime import datetime
+
+from netCDF4 import Dataset
+
+
+def parse_args(args=None):
+    parser = argparse.ArgumentParser(description=__doc__,
+                                     formatter_class=argparse.RawTextHelpFormatter)
+
+    parser.add_argument('infile', metavar='MESHFILE',
+                        help='Mesh file to split')
+
+    parser.add_argument('-1', '--outfile1', default='mesh1.nc', metavar='FILENAME',
+                        help='File name for first mesh output \n(default: %(default)s)')
+
+    parser.add_argument('-2', '--outfile2', default='mesh2.nc', metavar='FILENAME',
+                        help='File name for second mesh output \n(default: %(default)s)')
+
+    parser.add_argument('--nCells', type=int,
+                        help='The number of cells in the first mesh \n'
+                             '(default: the value specified in MESHFILE global '
+                             'attribute merge_point)')
+
+    parser.add_argument('--nEdges', type=int,
+                        help='The number of edges in the first mesh \n'
+                             '(default: the value specified in MESHFILE global '
+                             'attribute merge_point)')
+
+    parser.add_argument('--nVertices', type=int,
+                        help='The number of vertices in the first mesh \n'
+                             '(default: the value specified in MESHFILE global '
+                             'attribute merge_point)')
+
+    parser.add_argument('--maxEdges', type=int, nargs=2, metavar=('MAXEDGES1', 'MAXEDGES2'),
+                        help='The number of maxEdges in each mesh \n'
+                             '(default: the value specified in MESHFILE global '
+                             'attribute merge_point\n      OR: will use MESHFILE '
+                             'maxEdges dimension and assume same for both)')
+
+    return parser.parse_args(args)
+
+
+
[docs]def split_grids(infile=None, outfile1=None, outfile2=None, + nCells=None, nEdges=None, nVertices=None, maxEdges=None, runner=None): + """ + Split two previously merged MPAS non-contiguous meshes together into + separate files. Typical usage is: + + .. code:: python + + split_grids(infile='infile.nc', outfile1='outfile1.nc', outfile2='outfile2.nc') + + The optional arguments for ``nCells``, ``nEdges``, ``nVertices``, and ``maxEdges`` + should generally not be required as this information sould have been saved in + ``infiles``'s global attribute ``merge_point`` when created by + :func:`mpas_tools.merge_grids.merge_grids`. + + Parameters + ---------- + infile : str + The file name for the mesh to split + + outfile1 : str + The file name for the first split mesh + + outfile2 : str + The file name for the second split mesh + + nCells : int, optional + The number of cells in the first mesh (default: the value specified in + infile global attribute merge_point) + + nEdges : int, optional + The number of edges in the first mesh (default: the value specified in + infile global attribute merge_point + + nVertices : int, optional + The number of vertices in the first mesh (default: the value specified in + infile global attribute merge_point + + maxEdges : list[int, int], optional + A list of the number of max edges (int) in each mesh (default: the value + specified in infile global attribute merge_point OR will use infile + maxEdges dimension and assume same for both) + + runner : str, optional + The command to write into the global history attribute of the outfile + """ + now = datetime.now().strftime("%a %b %d %H:%M:%S %Y") + if not runner: + runner = '{}.split_grids(infile={}, outfile1={}, outfile2={}, nCells={},' \ + 'nEdges={}, nVertices={})'.format(os.path.splitext(__file__)[0], + infile, outfile1, outfile2, + nCells, nEdges, nVertices) + + merge_point_args_missing = (nCells is None, + nEdges is None, + nVertices is None) + + print('Opening {} to split'.format(infile)) + with Dataset(infile) as nc_in: + # NOTE: Because nCells, nEdges, and nVertices are optional arguments and + # the previous merge point can be specified in the mesh file, we + # need to do some complicated error handling. + merge_point_in_file = 'merge_point' in nc_in.ncattrs() + if not merge_point_in_file and any(merge_point_args_missing): + raise ValueError('ERROR: Previous merge point under specified!\n' + ' nCells, nEdges, and nVertices options must all ' + 'be given, or merge_point global attribute must exist ' + 'in {}'.format(infile)) + elif merge_point_in_file and not any(merge_point_args_missing): + print('Warning: command line arguments are overriding previous merge ' + 'point as specified in {} merge_point global' + ' attribute'.format(infile)) + elif merge_point_in_file: + if not all(merge_point_args_missing): + print('Warning: nCells, nEdges, and nVertices options must all ' + 'be given to override speification in {} merge_point global ' + 'attribute'.format(infile)) + try: + mp = json.loads(nc_in.merge_point) + except ValueError: + raise ValueError('ERROR: {} merge_point global attribute is not valid JSON.\n' + ' merge_point: {}'.format(infile, nc_in.merge_point)) + + mp_keyset = set(mp) + if {'nCells', 'nEdges', 'nVertices'} <= mp_keyset: + nCells = mp['nCells'] + nEdges = mp['nEdges'] + nVertices = mp['nVertices'] + else: + raise ValueError('ERROR: merge_point global attribute of {} must ' + 'contain nCells, nEdges, and nVertices.\n' + ' merge_point: {}'.format(infile, mp)) + if {'maxEdges1', 'maxEdges2'} <= mp_keyset: + maxEdges = [mp['maxEdges1'], mp['maxEdges2']] + + print('Creating the mesh files:\n {}\n {}'.format( + outfile1, outfile2)) + with Dataset(outfile1, 'w', format="NETCDF3_CLASSIC") as mesh1, \ + Dataset(outfile2, 'w', format="NETCDF3_CLASSIC") as mesh2: + mesh1.createDimension('nCells', nCells) + mesh1.createDimension('nEdges', nEdges) + mesh1.createDimension('nVertices', nVertices) + mesh1.createDimension('TWO', 2) + mesh1.createDimension('vertexDegree', + nc_in.dimensions['vertexDegree'].size) + + mesh2.createDimension('nCells', nc_in.dimensions['nCells'].size - nCells) + mesh2.createDimension('nEdges', nc_in.dimensions['nEdges'].size - nEdges) + mesh2.createDimension('nVertices', nc_in.dimensions['nVertices'].size - nVertices) + mesh2.createDimension('TWO', 2) + mesh2.createDimension('vertexDegree', + nc_in.dimensions['vertexDegree'].size) + + if 'StrLen' in nc_in.dimensions: + mesh1.createDimension('StrLen', nc_in.dimensions['StrLen'].size) + mesh2.createDimension('StrLen', nc_in.dimensions['StrLen'].size) + + if maxEdges is None: + maxEdges = [nc_in.dimensions['maxEdges'].size, + nc_in.dimensions['maxEdges'].size] + + mesh1.createDimension('maxEdges', maxEdges[0]) + mesh1.createDimension('maxEdges2', maxEdges[0] * 2) + + mesh2.createDimension('maxEdges', maxEdges[1]) + mesh2.createDimension('maxEdges2', maxEdges[1] * 2) + + mesh1.createDimension('nVertLevels', nc_in.dimensions['nVertLevels'].size) + mesh1.createDimension('nVertInterfaces', nc_in.dimensions['nVertInterfaces'].size) + mesh1.createDimension('Time', size=None) # make unlimited + + mesh2.createDimension('nVertLevels', nc_in.dimensions['nVertLevels'].size) + mesh2.createDimension('nVertInterfaces', nc_in.dimensions['nVertInterfaces'].size) + mesh2.createDimension('Time', size=None) # make unlimited + + print('Splitting variable:') + for var in nc_in.variables: + print(' {}'.format(var)) + var_in = nc_in.variables[var] + + var1 = mesh1.createVariable(var, var_in.dtype, var_in.dimensions) + var2 = mesh2.createVariable(var, var_in.dtype, var_in.dimensions) + + slice1, slice2 = var_slice(var_in.dimensions, nc_in, + nCells, nEdges, nVertices, maxEdges) + + var1[:] = nc_in.variables[var][slice1] + var2[:] = nc_in.variables[var][slice2] + + # Adjust the indexes + if var == 'indexToCellID': + var2[:] -= nCells + elif var == 'indexToEdgeID': + var2[:] -= nEdges + elif var == 'indexToVertexID': + var2[:] -= nVertices + elif var in ['cellsOnCell', 'cellsOnEdge', 'cellsOnVertex']: + tmp = var2[...] + tmp[tmp > 0] -= nCells + var2[:] = tmp + elif var in ['edgesOnCell', 'edgesOnEdge', 'edgesOnVertex']: + tmp = var2[...] + tmp[tmp > 0] -= nEdges + var2[:] = tmp + elif var in ['verticesOnCell', 'verticesOnEdge']: + tmp = var2[...] + tmp[tmp > 0] -= nVertices + var2[:] = tmp + + attr_to_copy = ("on_a_sphere", "sphere_radius", "is_periodic") + for attr in attr_to_copy: + if attr in nc_in.ncattrs(): + mesh1.setncattr(attr, nc_in.getncattr(attr)) + mesh2.setncattr(attr, nc_in.getncattr(attr)) + else: + print("Warning: '{0}' global attribute not present in input " + "file. '{0}' will not be added to the two output " + "files.".format(attr)) + + run_command = '{}: {} \n'.format(now, runner) + if 'history' in nc_in.ncattrs(): + mesh1.history = maybe_encode(run_command + nc_in.history) + mesh2.history = maybe_encode(run_command + nc_in.history) + else: + mesh1.history = maybe_encode(run_command) + mesh2.history = maybe_encode(run_command) + + print('Split complete! Mesh files:\n {}\n {}'.format(outfile1, outfile2))
+ + +def var_slice(dimensions, nc_in, nCells, nEdges, nVertices, maxEdges): + slice1 = () + slice2 = () + for dim in dimensions: + if dim == 'nCells': + slice1 += (slice(0, nCells),) + slice2 += (slice(nCells, nc_in.dimensions['nCells'].size),) + elif dim == 'nEdges': + slice1 += (slice(0, nEdges),) + slice2 += (slice(nEdges, nc_in.dimensions['nEdges'].size),) + elif dim == 'nVertices': + slice1 += (slice(0, nVertices),) + slice2 += (slice(nVertices, nc_in.dimensions['nVertices'].size),) + elif dim == 'maxEdges': + slice1 += (slice(0, maxEdges[0]),) + slice2 += (slice(0, maxEdges[1]),) + elif dim == 'maxEdges2': + slice1 += (slice(0, maxEdges[0]*2),) + slice2 += (slice(0, maxEdges[1]*2),) + else: + slice1 += (slice(None),) + slice2 += (slice(None),) + + return slice1, slice2 + + +# NOTE: Python 2 and 3 string fun conflicting with NC_CHAR vs NC_STRING, see: +# https://github.com/Unidata/netcdf4-python/issues/529 +def maybe_encode(string, encoding='ascii'): + try: + return string.encode(encoding) + except UnicodeEncodeError: + return string + + +def main(): + arguments = parse_args() + arguments.runner = ' '.join(sys.argv[:]) + split_grids(**vars(arguments)) + + +if __name__ == '__main__': + main() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/tests/test_cime_constants.html b/0.22.0rc4/_modules/mpas_tools/tests/test_cime_constants.html new file mode 100644 index 000000000..c14fa4b8e --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/tests/test_cime_constants.html @@ -0,0 +1,220 @@ + + + + + + mpas_tools.tests.test_cime_constants — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.tests.test_cime_constants

+from mpas_tools.cime.constants import constants
+import requests
+
+
+
[docs]def test_cime_constants(e3sm_tag='master'): + """ + Parse relevant constants from CIME + + Parameters + ---------- + e3sm_tag : str, optional + The E3SM tag to download constants from + """ + + resp = requests.get( + f'https://raw.githubusercontent.com/E3SM-Project/E3SM/{e3sm_tag}/' + f'share/util/shr_const_mod.F90') + + text = resp.text + + text = text.split('\n') + + found = {} + for constant in constants: + found[constant] = False + + for line in text: + constant, value = _parse_value(line) + if constant is None: + continue + print(f'line: {line}') + print(f'parsed: {constant} = {value}') + if constant in constants: + if isinstance(value, float): + print('verifying {}'.format(constant)) + assert value == constants[constant] + else: + print('skipping verification for {}'.format(constant)) + + found[constant] = True + else: + print('not in constants') + + print('') + + all_found = True + for constant in found: + if not found[constant]: + print('{} was not found!'.format(constant)) + all_found = False + + assert all_found
+ + +def _parse_value(line): + if '::' not in line or '=' not in line: + return None, None + + start = line.find('::') + 2 + end = line.find('=') + + key = line[start:end] + line = line[end+1:] + + if '!' in line: + line, _ = line.split('!', 1) + + line = line.replace('_R8', '').replace('_r8', '') + + try: + value = float(line) + except ValueError: + value = line.strip() + + return key.strip(), value + + +if __name__ == '__main__': + test_cime_constants() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/transects.html b/0.22.0rc4/_modules/mpas_tools/transects.html new file mode 100644 index 000000000..6081dcd0e --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/transects.html @@ -0,0 +1,385 @@ + + + + + + mpas_tools.transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.transects

+import numpy
+from shapely.geometry import LineString, Point
+
+from mpas_tools.vector import Vector
+
+
+
[docs]def subdivide_great_circle(x, y, z, maxRes, earthRadius): + """ + Subdivide each segment of the transect so the horizontal resolution + approximately matches the requested resolution + + Uses a formula for interpolating unit vectors on the sphere from + https://en.wikipedia.org/wiki/Slerp + + Parameters + ---------- + x : numpy.ndarray + The Cartesian x coordinate of a transect, where the number of segments + is ``len(x) - 1``. ``x``, ``y`` and ``z`` are of the same length. + y : numpy.ndarray + The Cartesian y coordinate of the transect + z : numpy.ndarray + The Cartesian z coordinate of the transect + + maxRes : float + The maximum allowed spacing in m after subdivision + + earthRadius : float + The radius of the Earth in m + + Returns + ------- + xOut : numpy.ndarray + The Cartesian x values of the transect subdivided into segments with + segment length at most ``maxRes``. All the points in ``x``, ``y`` and + ``z`` are guaranteed to be included. + + yOut : numpy.ndarray + The Cartesian y values of the subdivided transect + + zOut : numpy.ndarray + The Cartesian y values of the subdivided transect + + dIn : numpy.ndarray + The distance along the transect before subdivision + + dOut : numpy.ndarray + The distance along the transect after subdivision + + """ + + angularDistance = angular_distance(x=x, y=y, z=z) + + dx = angularDistance * earthRadius + + nSegments = numpy.maximum( + (dx / maxRes + 0.5).astype(int), 1) + + dIn = numpy.zeros(x.shape) + dIn[1:] = numpy.cumsum(dx) + + frac = [] + outIndices = [] + delta = [] + for index in range(len(dIn) - 1): + n = nSegments[index] + frac.extend(numpy.arange(0, n)/n) + outIndices.extend(index*numpy.ones(n, int)) + delta.extend(angularDistance[index]*numpy.ones(n)) + frac.append(1.) + outIndices.append(len(dIn) - 2) + delta.append(angularDistance[-1]) + + frac = numpy.array(frac) + delta = numpy.array(delta) + outIndices = numpy.array(outIndices) + + a = numpy.ones(delta.shape) + b = numpy.zeros(delta.shape) + mask = delta > 0. + denom = 1./numpy.sin(delta[mask]) + a[mask] = denom*numpy.sin((1.-frac[mask])*delta[mask]) + b[mask] = denom*numpy.sin(frac[mask]*delta[mask]) + + xOut = a*x[outIndices] + b*x[outIndices+1] + yOut = a*y[outIndices] + b*y[outIndices+1] + zOut = a*z[outIndices] + b*z[outIndices+1] + + dOut = (-frac + 1.)*dIn[outIndices] + frac*dIn[outIndices+1] + + return xOut, yOut, zOut, dIn, dOut
+ + +
[docs]def cartesian_to_great_circle_distance(x, y, z, earth_radius): + """ + Cartesian transect points to great-circle distance + + Parameters + ---------- + x : numpy.ndarray + The Cartesian x coordinate of a transect + y : numpy.ndarray + The Cartesian y coordinate of the transect + z : numpy.ndarray + The Cartesian z coordinate of the transect + + earth_radius : float + The radius of the earth + + Returns + ------- + distance : numpy.ndarray + The distance along the transect + """ + distance = numpy.zeros(x.shape) + for segIndex in range(len(x)-1): + transectv0 = Vector(x[segIndex], y[segIndex], z[segIndex]) + transectv1 = Vector(x[segIndex+1], y[segIndex+1], z[segIndex+1]) + + distance[segIndex+1] = distance[segIndex] + \ + earth_radius*transectv0.angular_distance(transectv1) + + return distance
+ + +
[docs]def subdivide_planar(x, y, maxRes): + """ + Subdivide each segment of the transect so the horizontal resolution + approximately matches the requested resolution + + Uses a formula for interpolating unit vectors on the sphere from + https://en.wikipedia.org/wiki/Slerp + + Parameters + ---------- + x : numpy.ndarray + The planar x coordinate of a transect, where the number of segments + is ``len(x) - 1`` + + y : numpy.ndarray + The planar y coordinates of the transect, the same length as ``x`` + + maxRes : float + The maximum allowed spacing in m after subdivision + + Returns + ------- + xOut : numpy.ndarray + The x coordinate of the transect, subdivided into segments with length + at most ``maxRes``. All the points in ``x`` are guaranteed to be + included. + + yOut : numpy.ndarray + The y coordinate of the transect. All the points in ``y`` are + guaranteed to be included. + + dIn : numpy.ndarray + The distance along the transect before subdivision + + dOut : numpy.ndarray + The distance along the transect after subdivision + """ + + dx = numpy.zeros(len(x)-1) + for index in range(len(x)-1): + start = Point(x[index], y[index]) + end = Point(x[index+1], y[index+1]) + segment = LineString([start, end]) + dx[index] = segment.length + + nSegments = numpy.maximum( + (dx / maxRes + 0.5).astype(int), 1) + + dIn = numpy.zeros(x.shape) + dIn[1:] = numpy.cumsum(dx) + + frac = [] + outIndices = [] + for index in range(len(dIn) - 1): + n = nSegments[index] + frac.extend(numpy.arange(0, n)/n) + outIndices.extend(index*numpy.ones(n, int)) + frac.append(1.) + outIndices.append(len(dIn) - 2) + + frac = numpy.array(frac) + outIndices = numpy.array(outIndices) + + xOut = (-frac + 1.)*x[outIndices] + frac*x[outIndices+1] + yOut = (-frac + 1.)*y[outIndices] + frac*y[outIndices+1] + dOut = (-frac + 1.)*dIn[outIndices] + frac*dIn[outIndices+1] + + return xOut, yOut, dIn, dOut
+ + +
[docs]def lon_lat_to_cartesian(lon, lat, earth_radius, degrees): + """Convert from lon/lat to Cartesian x, y, z""" + + if degrees: + lon = numpy.deg2rad(lon) + lat = numpy.deg2rad(lat) + x = earth_radius * numpy.cos(lat) * numpy.cos(lon) + y = earth_radius * numpy.cos(lat) * numpy.sin(lon) + z = earth_radius * numpy.sin(lat) + return x, y, z
+ + +
[docs]def cartesian_to_lon_lat(x, y, z, earth_radius, degrees): + """Convert from Cartesian x, y, z to lon/lat""" + lon = numpy.arctan2(y, x) + lat = numpy.arcsin(z/earth_radius) + if degrees: + lon = numpy.rad2deg(lon) + lat = numpy.rad2deg(lat) + return lon, lat
+ + +
[docs]def angular_distance(x, y, z): + """ + Compute angular distance between points on the sphere, following: + https://en.wikipedia.org/wiki/Great-circle_distance + + Parameters + ---------- + x : numpy.ndarray + The Cartesian x coordinate of a transect, where the number of segments + is ``len(x) - 1``. ``x``, ``y`` and ``z`` are of the same lengt. + + y : numpy.ndarray + The Cartesian y coordinate of the transect + + z : numpy.ndarray + The Cartesian z coordinate of the transect + + Returns + ------- + distance : numpy.ndarray + The angular distance (in radians) between segments of the transect. + """ + first = Vector(x[0:-1], y[0:-1], z[0:-1]) + second = Vector(x[1:], y[1:], z[1:]) + + distance = first.angular_distance(second) + return distance
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/translate.html b/0.22.0rc4/_modules/mpas_tools/translate.html new file mode 100644 index 000000000..a0c4c5e7c --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/translate.html @@ -0,0 +1,323 @@ + + + + + + mpas_tools.translate — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.translate

+#!/usr/bin/env python
+
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+from optparse import OptionParser
+
+import xarray
+
+from mpas_tools.io import write_netcdf
+
+
+
[docs]def translate(mesh, xOffset=0., yOffset=0.): + """ + Translates the coordinate system of the planar MPAS mesh by an arbitrary + shift in x and/or y + + Parameters + ---------- + mesh : xarray.Dataset + A planar mesh to translate + + xOffset : float, optional + user-specified shift in the x-direction + + yOffset : float, optional + user-specified shift in the y-direction + + """ + + mesh.xCell[:] += xOffset + mesh.yCell[:] += yOffset + mesh.xVertex[:] += xOffset + mesh.yVertex[:] += yOffset + mesh.xEdge[:] += xOffset + mesh.yEdge[:] += yOffset
+ + +
[docs]def center_on_mesh(mesh, otherMesh): + """ + Translates the coordinate system of the planar MPAS mesh by shifting the + origin to the center of the domain described in a separate mesh + + Parameters + ---------- + mesh : xarray.Dataset + A planar mesh to translate + + otherMesh : xarray.Dataset + Another planar mesh whose center will become the center of this mesh. + Uses xCell,yCell or, if those fields do not exist, will secondly try + x1,y1 fields + """ + + mpasXcenter, mpasYcenter = get_center(mesh) + + if 'xCell' in otherMesh and 'yCell' in otherMesh: + dataXcenter, dataYcenter = get_center(otherMesh, xVar='xCell', + yVar='yCell') + elif 'x1' in otherMesh and 'y1' in otherMesh: + dataXcenter, dataYcenter = get_center(otherMesh, xVar='x1', yVar='y1') + else: + raise ValueError('reference mesh has neither xCell/yCell nor x1/y1 ' + 'fields.') + + translate(mesh, dataXcenter-mpasXcenter, dataYcenter-mpasYcenter)
+ + +
[docs]def center(mesh): + """ + Translates the coordinate system of the planar MPAS mesh by shifting the + origin to the center of the domain + + Parameters + ---------- + mesh : xarray.Dataset + A planar mesh to translate + """ + mpasXcenter, mpasYcenter = get_center(mesh) + + translate(mesh, -mpasXcenter, -mpasYcenter)
+ + +def get_center(mesh, xVar='xCell', yVar='yCell'): + """ + Find the center of the mesh + """ + + xCenter = (mesh[xVar].min() + mesh[xVar].max()) * 0.5 + yCenter = (mesh[yVar].min() + mesh[yVar].max()) * 0.5 + + return xCenter, yCenter + + +def main(): + + print("== Gathering information. (Invoke with --help for more details. " + "All arguments are optional)") + parser = OptionParser() + parser.description = \ + "This script translates the coordinate system of the planar MPAS " \ + "mesh specified with the -f flag. \n" \ + "There are 3 possible methods to choose from:\n" \ + "1) shift the origin to the center of the domain\n" \ + "2) arbirary shift in x and/or y\n" \ + "3) shift to the center of the domain described in a separate file\n" + parser.add_option("-f", "--file", dest="fileInName", + help="MPAS planar grid file name.", default="grid.nc", + metavar="FILENAME") + parser.add_option("-d", "--datafile", dest="dataFileName", + help="data file name to which to match the domain " + "center of. Uses xCell,yCell or, if those fields " + "do not exist, will secondly try x1,y1 fields.", + metavar="FILENAME") + parser.add_option("-x", dest="xshift", + help="user-specified shift in the x-direction.", + type="float", default=0.0, metavar="SHIFT_VALUE") + parser.add_option("-y", dest="yshift", + help="user-specified shift in the y-direction.", + type="float", default=0.0, metavar="SHIFT_VALUE") + parser.add_option("-c", dest="center", + help="shift so origin is at center of domain", + action="store_true", default=False) + for option in parser.option_list: + if option.default != ("NO", "DEFAULT"): + option.help += (" " if option.help else "") + "[default: %default]" + options, args = parser.parse_args() + + print("Attempting to translate coordinates in file: {}".format( + options.fileInName)) + + if options.dataFileName is not None and \ + (options.xshift != 0. or options.yshift != 0.): + raise ValueError('Specifying a datafile AND one or both of x/y shift ' + 'is invalid. Please select one of those methods ' + 'only.') + + if options.center and (options.xshift != 0. or options.yshift != 0.): + raise ValueError('Specifying a shift to center AND one or both of x/y ' + 'shift is invalid. Please select one of those ' + 'methods only.') + + if options.dataFileName is not None and options.center: + raise ValueError('Specifying a datafile AND a shift to center is ' + 'invalid. Please select one of those methods only.') + + if not options.center and (options.xshift == 0.) and \ + (options.yshift == 0.) and options.dataFileName is None: + raise ValueError('No translation method was specified. Please select ' + 'one. Run with -h for more information.') + + mesh = xarray.open_dataset(options.fileInName) + if options.dataFileName is not None: + print(" Translating coordinates in {} so the domain center matches " + "the domain center in {}.\n\n".format(options.fileInName, + options.dataFileName)) + otherMesh = xarray.open_dataset(options.dataFileName) + center_on_mesh(mesh, otherMesh) + + if options.xshift != 0. or options.yshift != 0.: + print(" Translating coordinates in {} by user-specified values. " + "X-shift={:f}; Y-shift={:f}\n\n".format(options.fileInName, + options.xshift, + options.yshift)) + + translate(mesh, options.xshift, options.yshift) + + if options.center: + print(" Translating coordinates in %s so the origin is the center of " + "the domain.\n\n") + + center(mesh) + + # close the file so we can re-open it for writing + mesh.close() + write_netcdf(mesh, options.fileInName) + + print("Translation completed.") + + +if __name__ == '__main__': + main() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/vector.html b/0.22.0rc4/_modules/mpas_tools/vector.html new file mode 100644 index 000000000..9b5bff610 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/vector.html @@ -0,0 +1,375 @@ + + + + + + mpas_tools.vector — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.vector

+import numpy as np
+
+
+
[docs]class Vector: + """ + A class for representing Cartesian vectors with ``x``, ``y`` and ``z`` + components that are either ``float`` or ``numpy.array`` objects of + identical size. + + Attributes + ---------- + x : float or numpy.ndarray + The x component(s) + + y : float or numpy.ndarray + The y component(s) + + z : float or numpy.ndarray + The z component(s) + """ +
[docs] def __init__(self, x, y, z): + """ + A class for representing Cartesian vectors with ``x``, ``y`` and ``z`` + components that are either ``float`` or ``numpy.array`` objects of + identical size. + + Parameters + ---------- + x : float or numpy.ndarray + The x component(s) + + y : float or numpy.ndarray + The y component(s) + + z : float or numpy.ndarray + The z component(s) + """ + self.x = x + self.y = y + self.z = z
+ + def angular_distance(self, other): + """ + Compute angular distance between points on the sphere, following: + https://en.wikipedia.org/wiki/Great-circle_distance + + Parameters + ---------- + other : mpas_tools.vector.Vector + The vector to compute the angular distance to + + Returns + ------- + angularDistance : numpy.ndarray + The angular distance (in radians) between segments of the transect. + """ + angular_distance = np.arctan2(self.cross(other).mag(), self.dot(other)) + return angular_distance + + @staticmethod + def intersects(a1, a2, b1, b2): + """ + Based on https://stackoverflow.com/a/26669130/7728169 + Determine if the great circle arc from ``a1`` to ``a2`` intersects that + from ``b1`` to ``b2``. + + Parameters + ---------- + a1 : mpas_tools.vector.Vector + Cartesian coordinates of the end point of a great circle arc. + The types of the attributes ``x``, ``y``, and ``z`` must either be + ``numpy.arrays`` of identical size for all 4 vectors (in which case + intersections are found element-wise), or scalars for + at least one of either ``a1`` and ``a2`` or ``b1`` and ``b2``. + + a2 : mpas_tools.vector.Vector + Cartesian coordinates of the other end point of a great circle arc. + + b1 : mpas_tools.vector.Vector + Cartesian coordinates of an end point of a second great circle arc. + + b2 : mpas_tools.vector.Vector + Cartesian coordinates of the other end point of the second great + circle arc. + + Returns + ------- + intersect : numpy.ndarray + A boolean array of the same size as ``a1`` and ``a2`` or ``b1`` and + ``b2``, whichever is greater, indicating if the particular pair of + arcs intersects + """ + return np.logical_and(Vector.straddles(a1, a2, b1, b2), + Vector.straddles(b1, b2, a1, a2)) + + @staticmethod + def intersection(a1, a2, b1, b2): + """ + Based on https://stackoverflow.com/a/26669130/7728169 + Find the intersection point as a unit vector between great circle arc + from ``a1`` to ``a2`` and from ``b1`` to ``b2``. The arcs should have + already have been found to intersect by calling ``intersects()`` + + Parameters + ---------- + a1 : mpas_tools.vector.Vector + Cartesian coordinates of the end point of a great circle arc. + The types of the attributes ``x``, ``y``, and ``z`` must either be + ``numpy.arrays`` of identical size for all 4 vectors (in which case + intersections are found element-wise), or scalars for + at least one of either ``a1`` and ``a2`` or ``b1`` and ``b2``. + + a2 : mpas_tools.vector.Vector + Cartesian coordinates of the other end point of a great circle arc. + + b1 : mpas_tools.vector.Vector + Cartesian coordinates of an end point of a second great circle arc. + + b2 : mpas_tools.vector.Vector + Cartesian coordinates of the other end point of the second great + circle arc. + + Returns + ------- + points : mpas_tools.vector.Vector + An array of Cartesian points *on the unit sphere* indicating where + the arcs intersect + """ + points = (a1.cross(a2)).cross(b1.cross(b2)) + s = np.sign(Vector.det(a1, b1, b2))/points.mag() + points = Vector(s*points.x, s*points.y, s*points.z) + return points + + @staticmethod + def straddles(a1, a2, b1, b2): + """ + Based on https://stackoverflow.com/a/26669130/7728169 + Determines if the great circle segment determined by (a1, a2) + straddles the great circle determined by (b1, b2) + + Parameters + ---------- + a1: mpas_tools.vector.Vector + Cartesian coordinates of first end point of first great circle arc. + The types of the attributes ``x``, ``y``, and ``z`` must either be + ``numpy.arrays`` of identical size for all 4 vectors (in which case + intersections are found element-wise), or scalars for + at least one of either the ``a``s or the ``b``s. + + a2 : mpas_tools.vector.Vector + Second end point of first great circle arc. + + b1 : mpas_tools.vector.Vector + First end point of second great circle arc. + + b2 : mpas_tools.vector.Vector + Second end point of second great circle arc. + + Returns + ------- + straddle : numpy.ndarray + A boolean array of the same size as the ``a``s or the ``b``s, whichever + is greater, indicating if the great circle segment determined by + (a1, a2) straddles the great circle determined by (b1, b2) + """ + return Vector.det(a1, b1, b2) * Vector.det(a2, b1, b2) < 0 + + def dot(self, other): + """ + Compute the dot product between this vector and ``other``. + + Parameters + ---------- + other : mpas_tools.vector.Vector + The other vector + + Returns + ------- + dot_product : numpy.ndarray + The dot product + """ + return self.x * other.x + self.y * other.y + self.z * other.z + + def cross(self, other): + """ + Compute the dot product between this vector and ``other``. + + Parameters + ---------- + other : mpas_tools.vector.Vector + The other vector + + Returns + ------- + cross_product : mpas_tools.vector.Vector + The cross product + """ + return Vector(self.y * other.z - self.z * other.y, + self.z * other.x - self.x * other.z, + self.x * other.y - self.y * other.x) + + @staticmethod + def det(v1, v2, v3): + """ + The determinant of the matrix defined by the three ``Vector`` objects + + Parameters + ---------- + v1 : mpas_tools.vector.Vector + First row of the matrix + + v2 : mpas_tools.vector.Vector + Second row + + v3 : mpas_tools.vector.Vector + Third row + + Returns + ------- + determinant : numpy.ndarray + The determinant of the matrix + """ + return v1.dot(v2.cross(v3)) + + def mag(self): + """ + The magnitude of the vector + + Returns + ------- + magnitude : numpy.ndarray + The magnitude of the vector + """ + return np.sqrt(self.dot(self))
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/viz/colormaps.html b/0.22.0rc4/_modules/mpas_tools/viz/colormaps.html new file mode 100644 index 000000000..c9a7dcd01 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/viz/colormaps.html @@ -0,0 +1,192 @@ + + + + + + mpas_tools.viz.colormaps — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.viz.colormaps

+import xml.etree.ElementTree as ET
+try:
+    from importlib.resources import files as imp_res_files
+except ImportError:
+    # python<=3.8
+    from importlib_resources import files as imp_res_files
+from matplotlib.colors import LinearSegmentedColormap
+import matplotlib.pyplot as plt
+
+
+
[docs]def register_sci_viz_colormaps(): + """Register all SciVisColor colormaps with matplotlib""" + + for mapName in ['3wave-yellow-grey-blue', '3Wbgy5', + '4wave-grey-red-green-mgreen', '5wave-yellow-brown-blue', + 'blue-1', 'blue-3', 'blue-6', 'blue-8', 'blue-orange-div', + 'brown-2', 'brown-5', 'brown-8', 'green-1', 'green-4', + 'green-7', 'green-8', 'orange-5', 'orange-6', + 'orange-green-blue-gray', 'purple-7', 'purple-8', 'red-1', + 'red-3', 'red-4', 'yellow-1', 'yellow-7']: + xmlFile = str(imp_res_files('mpas_tools.viz.SciVisColorColormaps') / + f'{mapName}.xml') + _read_xml_colormap(xmlFile, mapName)
+ + +def _read_xml_colormap(xmlFile, mapName): + """Read in an XML colormap""" + + xml = ET.parse(xmlFile) + + root = xml.getroot() + colormap = root.findall('ColorMap') + if len(colormap) > 0: + colormap = colormap[0] + colorDict = {'red': [], 'green': [], 'blue': []} + for point in colormap.findall('Point'): + x = float(point.get('x')) + color = [float(point.get('r')), float(point.get('g')), + float(point.get('b'))] + colorDict['red'].append((x, color[0], color[0])) + colorDict['green'].append((x, color[1], color[1])) + colorDict['blue'].append((x, color[2], color[2])) + cmap = LinearSegmentedColormap(mapName, colorDict, 256) + + _register_colormap_and_reverse(mapName, cmap) + + +def _register_colormap_and_reverse(mapName, cmap): + if mapName not in plt.colormaps(): + plt.register_cmap(mapName, cmap) + plt.register_cmap('{}_r'.format(mapName), cmap.reversed()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/viz/mesh_to_triangles.html b/0.22.0rc4/_modules/mpas_tools/viz/mesh_to_triangles.html new file mode 100644 index 000000000..b794e5e72 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/viz/mesh_to_triangles.html @@ -0,0 +1,288 @@ + + + + + + mpas_tools.viz.mesh_to_triangles — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.viz.mesh_to_triangles

+import xarray
+import numpy
+
+
+
[docs]def mesh_to_triangles(dsMesh, periodicCopy=False): + """ + Construct a dataset in which each MPAS cell is divided into the triangles + connecting pairs of adjacent vertices to cell centers. + + Parameters + ---------- + dsMesh : xarray.Dataset + An MPAS mesh + + periodicCopy : bool, optional + Whether to make a periodic copy of triangles that cross -180/180 degrees + longitude. This is helpful when plotting triangles in a lon/lat space. + + Returns + ------- + dsTris : xarray.Dataset + A dataset that defines triangles connecting pairs of adjacent vertices + to cell centers as well as the cell index that each triangle is in and + cell indices and weights for interpolating data defined at cell centers + to triangle nodes. ``dsTris`` includes variables ``triCellIndices``, + the cell that each triangle is part of; ``nodeCellIndices`` and + ``nodeCellWeights``, the indices and weights used to interpolate from + MPAS cell centers to triangle nodes; Cartesian coordinates ``xNode``, + ``yNode``, and ``zNode``; and ``lonNode``` and ``latNode`` in radians. + ``lonNode`` is guaranteed to be within 180 degrees of the cell center + corresponding to ``triCellIndices``. Nodes always have a + counterclockwise winding. + + """ + nVerticesOnCell = dsMesh.nEdgesOnCell.values + verticesOnCell = dsMesh.verticesOnCell.values - 1 + cellsOnVertex = dsMesh.cellsOnVertex.values - 1 + + kiteAreasOnVertex = dsMesh.kiteAreasOnVertex.values + + nTriangles = numpy.sum(nVerticesOnCell) + + maxEdges = dsMesh.sizes['maxEdges'] + nCells = dsMesh.sizes['nCells'] + if dsMesh.sizes['vertexDegree'] != 3: + raise ValueError('mesh_to_triangles only supports meshes with ' + 'vertexDegree = 3') + + # find the third vertex for each triangle + nextVertex = -1*numpy.ones(verticesOnCell.shape, int) + for iVertex in range(maxEdges): + valid = iVertex < nVerticesOnCell + invalid = numpy.logical_not(valid) + verticesOnCell[invalid, iVertex] = -1 + nv = nVerticesOnCell[valid] + cellIndices = numpy.arange(0, nCells)[valid] + iNext = numpy.where(iVertex < nv - 1, iVertex + 1, 0) + nextVertex[:, iVertex][valid] = verticesOnCell[cellIndices, iNext] + + valid = verticesOnCell >= 0 + verticesOnCell = verticesOnCell[valid] + nextVertex = nextVertex[valid] + + # find the cell index for each triangle + triCellIndices, _ = numpy.meshgrid(numpy.arange(0, nCells), + numpy.arange(0, maxEdges), + indexing='ij') + triCellIndices = triCellIndices[valid] + + # find list of cells and weights for each triangle node + nodeCellIndices = -1*numpy.ones((nTriangles, 3, 3), int) + nodeCellWeights = numpy.zeros((nTriangles, 3, 3)) + + # the first node is at the cell center, so the value is just the one from + # that cell + nodeCellIndices[:, 0, 0] = triCellIndices + nodeCellWeights[:, 0, 0] = 1. + + # the other 2 nodes are associated with vertices + nodeCellIndices[:, 1, :] = cellsOnVertex[verticesOnCell, :] + nodeCellWeights[:, 1, :] = kiteAreasOnVertex[verticesOnCell, :] + nodeCellIndices[:, 2, :] = cellsOnVertex[nextVertex, :] + nodeCellWeights[:, 2, :] = kiteAreasOnVertex[nextVertex, :] + + weightSum = numpy.sum(nodeCellWeights, axis=2) + for iNode in range(3): + nodeCellWeights[:, :, iNode] = nodeCellWeights[:, :, iNode]/weightSum + + dsTris = xarray.Dataset() + dsTris['triCellIndices'] = ('nTriangles', triCellIndices) + dsTris['nodeCellIndices'] = (('nTriangles', 'nNodes', 'nInterp'), + nodeCellIndices) + dsTris['nodeCellWeights'] = (('nTriangles', 'nNodes', 'nInterp'), + nodeCellWeights) + + # get Cartesian and lon/lat coordinates of each node + for prefix in ['x', 'y', 'z', 'lat', 'lon']: + outVar = '{}Node'.format(prefix) + cellVar = '{}Cell'.format(prefix) + vertexVar = '{}Vertex'.format(prefix) + coord = numpy.zeros((nTriangles, 3)) + coord[:, 0] = dsMesh[cellVar].values[triCellIndices] + coord[:, 1] = dsMesh[vertexVar].values[verticesOnCell] + coord[:, 2] = dsMesh[vertexVar].values[nextVertex] + dsTris[outVar] = (('nTriangles', 'nNodes'), coord) + + # nothing obvious we can do about triangles containing the poles + + # make sure node longitudes are within 180 degrees of the cell center + lonNode = dsTris.lonNode.values + lonCell = lonNode[:, 0] + copyEast = numpy.zeros(lonCell.shape, bool) + copyWest = numpy.zeros(lonCell.shape, bool) + for iNode in [1, 2]: + mask = lonNode[:, iNode] - lonCell > numpy.pi + copyEast = numpy.logical_or(copyEast, mask) + lonNode[:, iNode][mask] = lonNode[:, iNode][mask] - 2*numpy.pi + mask = lonNode[:, iNode] - lonCell < -numpy.pi + copyWest = numpy.logical_or(copyWest, mask) + lonNode[:, iNode][mask] = lonNode[:, iNode][mask] + 2*numpy.pi + if periodicCopy: + dsNew = xarray.Dataset() + eastIndices = numpy.nonzero(copyEast)[0] + westIndices = numpy.nonzero(copyWest)[0] + triIndices = numpy.append(numpy.append(numpy.arange(0, nTriangles), + eastIndices), westIndices) + + dsNew['triCellIndices'] = ('nTriangles', triCellIndices[triIndices]) + dsNew['nodeCellIndices'] = (('nTriangles', 'nNodes', 'nInterp'), + nodeCellIndices[triIndices, :, :]) + dsNew['nodeCellWeights'] = (('nTriangles', 'nNodes', 'nInterp'), + nodeCellWeights[triIndices, :, :]) + for prefix in ['x', 'y', 'z', 'lat']: + outVar = '{}Node'.format(prefix) + coord = dsTris[outVar].values + dsNew[outVar] = (('nTriangles', 'nNodes'), coord[triIndices, :]) + + coord = dsTris['lonNode'].values[triIndices, :] + eastSlice = slice(nTriangles, nTriangles+len(eastIndices)) + coord[eastSlice, :] = coord[eastSlice, :] + 2*numpy.pi + westSlice = slice(nTriangles+len(eastIndices), + nTriangles + len(eastIndices) + len(westIndices)) + coord[westSlice, :] = coord[westSlice, :] - 2 * numpy.pi + dsNew['lonNode'] = (('nTriangles', 'nNodes'), coord) + dsTris = dsNew + + return dsTris
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/viz/paraview_extractor.html b/0.22.0rc4/_modules/mpas_tools/viz/paraview_extractor.html new file mode 100644 index 000000000..d12f9c2f5 --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/viz/paraview_extractor.html @@ -0,0 +1,2347 @@ + + + + + + mpas_tools.viz.paraview_extractor — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for mpas_tools.viz.paraview_extractor

+"""
+Extract a field from a time series of NetCDF files as VTK files for plotting in
+ParaView.
+
+It can extract a field across multiple files by passing in a regular expression
+for the filename patter. As an example, one can run the script using:
+
+    ./paraview_vtk_field_extractor.py -v areaCell,latVertex -f "hist.comp.*.nc"
+
+To extract a time series of areaCell,latVertex that spans multiple files.
+By default, time-independent fields on cells are written to a file
+vtk_files/staticFieldsOnCells.vtp
+and time-dependent fields on cells are written to
+vtk_files/timeDependentFieldsOnCells.pvd
+vtk_files/time_series/timeDependentFieldsOnCells.0.vtp
+vtk_files/time_series/timeDependentFieldsOnCells.1.vtp
+...
+and similarly for edges and vertices.  Time-independent fields can be
+included in each time step of the time-dependent fields for with
+the --combine flag.  This allows time-dependent and -independent fields
+to be combined in filters within ParaView at the expense of considerable
+additional storage space.
+
+Indices for extra dimensions can either be supplied at runtime at a prompt
+or through the -d flag.  For each extra dimension, the use can specify
+nothing (an empty string, meaning skip any fields with this dimension),
+a single index, or a comma-separated list of indices or a range of indices
+indices (separated by 1 or 2 colons).  For example,
+
+    -d maxEdges= nVertLeves=0:10:2 nParticles=0,2,4,6,8
+
+will ignore any fields with dimension maxEdges, extract every other layer from
+the first 10 vertical levels (each into its own field) and extract the five
+specified particles.
+
+An index array can also be specified in this way (and these can be mixed with
+integer indices in a comma-separated list but not in a colon-separated range):
+
+    -d nVertLeves=0,maxLevelCell
+
+will extract fields from the first vertical level and the vertical level with
+index given by maxLevelCell.
+
+The extractor includes optional support for extracting geometry appropriate
+for displaying variables at the depth of a topographic feature (typically the
+top or bottom of the domain) for MPAS components with a spatially variable
+top or bottom index (e.g. `maxLevelCell` in MPAS-Ocean).  This is accomplished
+with flags such as:
+
+    --topo_dim=nVertLevels --topo_cell_index=maxLevelCell
+
+Fields on cells are sampled at the topographic index and the geometry includes
+polygons corresponding to edges so that vertical faces between adjacent cells
+can be displayed.  Fields are extracted as normal except that they are sampled
+as point data rather than cell data, allowing computations in ParaView to
+display the topography.  A mask field is also included indicating which parts
+of edge polygons correspond to the boundary of the domain (boundaryMask == 1)
+and which parts of cell and edge polygons are interior (boundaryMask == 0).
+Together, this can be used to plot topography by using a calculator filter like
+the following:
+
+    coords*(1.0 + 100.0/mag(coords)*((1 - boundaryMask)*(-bottomDepth)
+                                     + 10.0*boundaryMask))
+
+If this is entered into a Calculator Filter in ParaView with the "coordinate
+result" box checked, the result will to display the MPAS-Ocean topography,
+exaggerated by a factor of 100, with a value equivalent to 10 m along boundary
+points of edge polygons (a "water-tight" surface).
+"""
+
+from __future__ import absolute_import, division, print_function, \
+    unicode_literals
+
+from pyevtk.vtk import VtkFile, VtkPolyData
+
+import sys
+import os
+import glob
+import numpy
+import argparse
+from datetime import datetime
+from netCDF4 import date2num
+
+from builtins import input
+
+from netCDF4 import Dataset as NetCDFFile
+
+import xarray
+import json
+from geometric_features import FeatureCollection
+import logging
+from io import StringIO
+
+from progressbar import ProgressBar, Percentage, Bar, ETA
+from mpas_tools.conversion import mask, cull
+from mpas_tools.io import write_netcdf
+from mpas_tools.logging import check_call
+
+
+
[docs]def extract_vtk(filename_pattern, variable_list='all', dimension_list=None, + mesh_filename=None, blocking=10000, output_32bit=False, + combine=False, append=False, out_dir='vtk_files', xtime='xtime', + lonlat=False, time=None, ignore_time=False, topo_dim=None, + topo_cell_index=None, include_mesh_vars=False, + fc_region_mask=None, temp_dir='./culled_region', + use_progress_bar=True): + """ + Extract fields from a time series of NetCDF files as VTK files for plotting + in ParaView. + + To extract fields across multiple files, passing in a regular expression + for the filename pattern, for example ``filename_pattern="hist.comp.*.nc"``. + + By default, time-independent fields on cells are written to a file + + .. code-block:: none + + vtk_files/staticFieldsOnCells.vtp + + and time-dependent fields on cells are written to + + .. code-block:: none + + vtk_files/timeDependentFieldsOnCells.pvd + vtk_files/time_series/timeDependentFieldsOnCells.0.vtp + vtk_files/time_series/timeDependentFieldsOnCells.1.vtp + ... + + and similarly for edges and vertices. Time-independent fields can be + included in each time step of the time-dependent fields for with + ``combine=True``. This allows time-dependent and -independent fields + to be combined in filters within ParaView at the expense of considerable + additional storage space. + + Indices for extra dimensions can either be supplied at runtime at a prompt + (if ``dimension_list=None``) or via a list of strings with the dimensions + and associated indices. For each extra dimension, you can specify + nothing for the indices (an empty string, meaning skip any fields with this + dimension), a single index, a comma-separated list of indices, or a range + of indices (separated by 1 or 2 colons). For example, + + .. code-block:: python + + dimension_list=['maxEdges=', 'nVertLeves=0:10:2', 'nParticles=0,2,4,6,8'] + + will ignore any fields with dimension ``maxEdges``, extract every other + layer from the first 10 vertical levels (each into its own field) and + extract the 5 specified particles. + + An index array can also be specified in this way (and these can be mixed + with integer indices in a comma-separated list but not in a colon-separated + range): + + .. code-block:: python + + dimension_list=['nVertLeves=0,maxLevelCell'] + + will extract fields from the first vertical level and the vertical level + with index given by ``maxLevelCell``. + + The extractor includes optional support for extracting geometry appropriate + for displaying variables at the depth of a topographic feature (typically + the top or bottom of the domain) for MPAS components with a spatially + variable top or bottom index (e.g. ``maxLevelCell`` in MPAS-Ocean). This is + accomplished with arguments such as: + + .. code-block:: python + + topo_dim='nVertLevels', topo_cell_index='maxLevelCell' + + Fields on cells are sampled at the topographic index and the geometry + includes polygons corresponding to edges so that vertical faces between + adjacent cells can be displayed. Fields are extracted as normal except + that they are sampled as point data rather than cell data, allowing + computations in ParaView to display the topography. A mask field is also + included indicating which parts of edge polygons correspond to the boundary + of the domain (``boundaryMask == 1``) and which parts of cell and edge + polygons are interior (``boundaryMask == 0``). Together, this can be used + to plot topography by using a calculator filter like the following: + + .. code-block:: none + + coords*(1.0 + 100.0/mag(coords)*((1 - boundaryMask)*(-bottomDepth) + + 10.0*boundaryMask)) + + If this is entered into a Calculator Filter in ParaView with the "coordinate + result" box checked, the result will to display the MPAS-Ocean topography, + exaggerated by a factor of 100, with a value equivalent to 10 m along + boundary points of edge polygons (a "water-tight" surface). + + Parameters + ---------- + filename_pattern : str + MPAS Filename pattern + + variable_list : list of str, optional + List of variables to extract ('all' for all variables, 'allOnCells' + for all variables on cells, etc.)" + + dimension_list : list of str, optional + A list of dimensions and associated indices + + mesh_filename : str, optional + MPAS Mesh filename. By default, the first file matching + ``filename_pattern`` will be used + + blocking : int, optional + Size of blocks when reading MPAS file + + output_32bit : bool, optional + Whether the vtk files will be written using 32bit floats + + combine : bool, optional + Whether time-independent fields are written to each file along with + time-dependent fields + + append : bool, optional + Whether only vtp files that do not already exist are written out + + out_dir : str, optional + The output directory + + xtime : str, optional" + The name of the xtime variable or 'none' to extract Time dim without + xtime + + lonlat : bool, optional + Whether the resulting points are in lon-lat space, not Cartesian + + time : str, optional + Indices for the time dimension + + ignore_time : bool, optional + Whether to ignore the Time dimension if it exists for files with a Time + dimension but no xtime variable (e.g. mesh file) + + topo_dim : str, optional + Dimension and range for topography dimension + + topo_cell_index : str, optional + Index array indicating the bottom of the domain (default is the + topo_dim-1 for all cells) + + include_mesh_vars : bool, optional + Whether to include mesh variables as well as time-series variables + in the extraction + + fc_region_mask : geometric_features.FeatureCollection, optional + A feature collection used to define a mask. The MPAS data is culled to + lie within the mask before conversion to VTK proceeds + + temp_dir : str, optional + If fc_region_mask is supplied, a temporary directory where the culled + mesh and time series files are stored + + use_progress_bar : bool, optional + Whether to display progress bars (problematic in logging to a file) + """ + + if ignore_time: + xtime = None + + (time_indices, time_file_names) = setup_time_indices( + filename_pattern, xtime, use_progress_bar) + + if time is not None: + time_indices, time_file_names = \ + parse_time_indices(time, time_indices, time_file_names) + + separate_mesh_file = True + if mesh_filename is None: + mesh_filename = time_file_names[0] + separate_mesh_file = False + + if fc_region_mask is not None: + mesh_filename, time_file_names = _cull_files( + fc_region_mask, temp_dir, mesh_filename, time_file_names, + separate_mesh_file, variable_list, include_mesh_vars, xtime, + use_progress_bar) + separate_mesh_file = True + + # Setting dimension values: + time_series_file = open_netcdf(time_file_names[0]) + if separate_mesh_file: + mesh_file = open_netcdf(mesh_filename) + else: + mesh_file = None + extra_dims, topo_cell_indices = \ + parse_extra_dims(dimension_list, time_series_file, + mesh_file, topo_dim=topo_dim, + topo_cell_index_name=topo_cell_index) + basic_dims = ['nCells', 'nEdges', 'nVertices', 'Time'] + if topo_dim is not None: + basic_dims.append(topo_dim) + + (all_dim_vals, cellVars, vertexVars, edgeVars) = \ + setup_dimension_values_and_sort_vars( + time_series_file, mesh_file, variable_list, extra_dims, + include_mesh_vars, basic_dims=basic_dims) + time_series_file.close() + if mesh_file is not None: + mesh_file.close() + + summarize_extraction(mesh_filename, time_indices, cellVars, + vertexVars, edgeVars) + + # Handle cell variables + if len(cellVars) > 0: + print(" -- Extracting cell fields --") + + mesh_file = open_netcdf(mesh_filename) + + # Build cell geometry + if topo_dim is None: + (vertices, connectivity, offsets, valid_mask) = \ + build_cell_geom_lists(mesh_file, output_32bit, lonlat) + cell_to_point_map = None + boundary_mask = None + else: + (vertices, connectivity, offsets, valid_mask, cell_to_point_map, + boundary_mask) = build_topo_point_and_polygon_lists( + mesh_file, output_32bit, lonlat, use_progress_bar) + + if not separate_mesh_file: + mesh_file.close() + mesh_file = None + + build_field_time_series(time_indices, time_file_names, mesh_file, + out_dir, blocking, all_dim_vals, + 'nCells', cellVars, vertices, connectivity, + offsets, valid_mask, output_32bit, + combine, append, xtime, use_progress_bar, + topo_dim=topo_dim, + topo_cell_indices=topo_cell_indices, + cell_to_point_map=cell_to_point_map, + boundary_mask=boundary_mask) + if separate_mesh_file: + mesh_file.close() + + print("") + + if len(vertexVars) > 0: + print(" -- Extracting vertex fields --") + + mesh_file = open_netcdf(mesh_filename) + + # Build vertex geometry + (vertices, connectivity, offsets, valid_mask) = \ + build_vertex_geom_lists(mesh_file, output_32bit, lonlat) + + if not separate_mesh_file: + mesh_file.close() + mesh_file = None + + build_field_time_series(time_indices, time_file_names, mesh_file, + out_dir, blocking, all_dim_vals, + 'nVertices', vertexVars, vertices, + connectivity, offsets, valid_mask, output_32bit, + combine, append, xtime, use_progress_bar) + + if separate_mesh_file: + mesh_file.close() + + print("") + + if len(edgeVars) > 0: + print(" -- Extracting edge fields --") + + mesh_file = open_netcdf(mesh_filename) + + # Build cell list + (vertices, connectivity, offsets, valid_mask) = \ + build_edge_geom_lists(mesh_file, output_32bit, lonlat) + + if not separate_mesh_file: + mesh_file.close() + mesh_file = None + + build_field_time_series(time_indices, time_file_names, mesh_file, + out_dir, blocking, all_dim_vals, + 'nEdges', edgeVars, vertices, connectivity, + offsets, valid_mask, output_32bit, + combine, append, xtime, use_progress_bar) + + if separate_mesh_file: + mesh_file.close()
+ + +def main(): + parser = \ + argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-f", "--file_pattern", dest="filename_pattern", + help="MPAS Filename pattern.", metavar="FILE", + required=True) + parser.add_argument("-m", "--mesh_file", dest="mesh_filename", + help="MPAS Mesh filename. If not set, it will use the " + "first file in the -f flag as the mesh file.") + parser.add_argument("-b", "--blocking", dest="blocking", type=int, + help="Size of blocks when reading MPAS file", + metavar="BLK", default=32000) + parser.add_argument("-v", "--variable_list", dest="variable_list", + help="List of variables to extract ('all' for all " + "variables, 'allOnCells' for all variables on " + "cells, etc.)", metavar="VAR", required=True) + parser.add_argument("-3", "--32bit", dest="output_32bit", + help="If set, the vtk files will be written using " + "32bit floats.", action="store_true") + parser.add_argument("-c", "--combine", dest="combine_output", + help="If set, time-independent fields are written to " + "each file along with time-dependent fields.", + action="store_true") + parser.add_argument("-a", "--append", dest="append", + help="If set, only vtp files that do not already " + "exist are written out.", action="store_true") + parser.add_argument("-d", "--dim_list", dest="dimension_list", nargs="+", + help="A list of dimensions and associated indices.", + metavar="DIM") + parser.add_argument("-o", "--out_dir", dest="out_dir", + help="the output directory.", default='vtk_files', + metavar="DIR") + parser.add_argument("-x", "--xtime", dest="xtime", default='xtime', + metavar="XTIME", + help="the name of the xtime variable or 'none' to " + "extract Time dim without xtime") + parser.add_argument("-l", "--lonlat", dest="lonlat", + help="If set, the resulting points are in lon-lat " + "space, not Cartesian.", action="store_true") + parser.add_argument("-t", "--time", dest="time", + help="Indices for the time dimension", metavar="TIME", + required=False) + parser.add_argument("--ignore_time", dest="ignore_time", required=False, + action="store_true", + help="ignore the Time dimension if it exists " + "for files with a Time dimension but no xtime" + "variable (e.g. mesh file)") + parser.add_argument("--topo_dim", dest="topo_dim", required=False, + help="Dimension and range for topography dimension") + parser.add_argument("--topo_cell_index", dest="topo_cell_index", + required=False, + help="Index array indicating the bottom of the domain " + "(default is the topo_dim-1 for all cells)") + parser.add_argument("--include_mesh_vars", dest="include_mesh_vars", + action="store_true", + help="Whether to extract mesh variables as well as" + "time-series variables") + parser.add_argument("--region_mask", dest="region_mask", required=False, + help="A geojson file defining a region that the data" + "should be masked to before extraction. Make one" + "easily at https://goejson.io") + parser.add_argument("--temp_dir", dest="temp_dir", required=False, + default="./culled_region", + help="If --region_mask is provided, a temporary " + "directory for the culled files") + args = parser.parse_args() + + if args.region_mask is not None: + fc_region_mask = FeatureCollection() + with open(args.region_mask) as f: + featuresDict = json.load(f) + defaults = {'component': 'ocean', + 'name': 'mask', + 'object': 'region'} + for feature in featuresDict['features']: + if feature['geometry']['type'] not in ['Polygon', + 'MultiPolygon']: + raise ValueError('All masking features must be regions ' + '(Polygons or MultiPolygons)') + # assign the default values if they're not already present + for key, value in defaults.items(): + if key not in feature['properties']: + feature['properties'][key] = value + fc_region_mask.add_feature(feature) + else: + fc_region_mask = None + + extract_vtk(filename_pattern=args.filename_pattern, + variable_list=args.variable_list, + dimension_list=args.dimension_list, + mesh_filename=args.mesh_filename, + blocking=args.blocking, + output_32bit=args.output_32bit, + combine=args.combine_output, + append=args.append, + out_dir=args.out_dir, + xtime=args.xtime, + lonlat=args.lonlat, + time=args.time, + ignore_time=args.ignore_time, + topo_dim=args.topo_dim, + topo_cell_index=args.topo_cell_index, + include_mesh_vars=args.include_mesh_vars, + fc_region_mask=fc_region_mask, + temp_dir=args.temp_dir) + + +def build_field_time_series(local_time_indices, file_names, mesh_file, + out_dir, blocking, all_dim_vals, blockDimName, + variable_list, vertices, connectivity, offsets, + valid_mask, output_32bit, combine_output, append, + xtimeName, use_progress_bar, topo_dim=None, + topo_cell_indices=None, cell_to_point_map=None, + boundary_mask=None): # {{{ + + if len(variable_list) == 0: + return + + if output_32bit: + outType = 'float32' + else: + outType = 'float64' + + # Get dimension info to allocate the size of Colors + time_series_file = open_netcdf(file_names[0]) + + if mesh_file is not None: + # blockDim may not exist in time series file + blockDim = len(mesh_file.dimensions[blockDimName]) + else: + blockDim = len(time_series_file.dimensions[blockDimName]) + + if boundary_mask is not None: + variable_list.append('boundaryMask') + all_dim_vals['boundaryMask'] = None + pointData = True + cellData = False + else: + pointData = False + cellData = True + + # Pre-compute the number of blocks + nBlocks = int(numpy.ceil(blockDim / blocking)) + + nPolygons = len(offsets) + nPoints = len(vertices[0]) + nTimes = len(local_time_indices) + nVars = len(variable_list) + + var_has_time_dim = numpy.zeros(nVars, bool) + nHyperSlabs = 0 + for iVar in range(nVars): + var_name = variable_list[iVar] + if boundary_mask is not None and var_name == 'boundaryMask': + var_has_time_dim[iVar] = False + elif xtimeName is not None: + if var_name in time_series_file.variables: + var_has_time_dim[iVar] = \ + 'Time' in time_series_file.variables[var_name].dimensions + else: + # we can't support time dependence in the mesh file + assert('Time' not in mesh_file.variables[var_name].dimensions) + var_has_time_dim[iVar] = False + + extra_dim_vals = all_dim_vals[var_name] + if (extra_dim_vals is None) or (len(extra_dim_vals) == 0): + nHyperSlabs += 1 + else: + nHyperSlabs += len(extra_dim_vals) + + any_var_has_time_dim = numpy.any(var_has_time_dim) + + if topo_dim is not None: + if (mesh_file is not None) and (topo_dim in mesh_file.dimensions): + nTopoLevels = len(mesh_file.dimensions[topo_dim]) + else: + nTopoLevels = len(time_series_file.dimensions[topo_dim]) + else: + nTopoLevels = None + + time_series_file.close() + + try: + os.makedirs(out_dir) + except OSError: + pass + + if any_var_has_time_dim: + try: + os.makedirs('{}/time_series'.format(out_dir)) + except OSError: + pass + else: + # there is no point in combining output if no fields have Time dim + combine_output = False + nTimes = 1 + + # Output time series + if use_progress_bar: + widgets = ['Writing time series: ', Percentage(), ' ', Bar(), ' ', + ETA()] + field_bar = ProgressBar(widgets=widgets, + maxval=nTimes*nHyperSlabs).start() + else: + print("Writing time series....") + + suffix = blockDimName[1:] + if any_var_has_time_dim: + if combine_output or numpy.all(var_has_time_dim): + out_prefix = "fieldsOn{}".format(suffix) + else: + out_prefix = "timeDependentFieldsOn{}".format(suffix) + # start the pvd file + pvd_file = write_pvd_header(out_dir, out_prefix) + pvd_file.write('<Collection>\n') + + if not combine_output and not numpy.all(var_has_time_dim): + static_prefix = "staticFieldsOn{}".format(suffix) + varIndices = numpy.arange(nVars)[numpy.logical_not(var_has_time_dim)] + timeIndependentFile = write_vtp_header(out_dir, + static_prefix, + varIndices[0], + varIndices, + variable_list, + all_dim_vals, + vertices, + connectivity, + offsets, + nPoints, + nPolygons, + outType, + cellData=cellData, + pointData=pointData, + xtime=None) + + prev_file = "" + for time_index in range(nTimes): + + if prev_file != file_names[time_index]: + if prev_file != "": + time_series_file.close() + time_series_file = open_netcdf(file_names[time_index]) + prev_file = file_names[time_index] + + if any_var_has_time_dim: + if xtimeName is None: + xtime = None + years = float(time_index) + else: + if xtimeName == 'none': + xtime = '{}'.format(time_index) + years = float(time_index) + else: + if xtimeName not in time_series_file.variables: + raise ValueError("xtime variable name {} not found in " + "{}".format(xtimeName, + time_series_file)) + var = time_series_file.variables[xtimeName] + if len(var.shape) == 2: + xtime = var[local_time_indices[time_index], :] + xtime = xtime.tostring().decode('utf-8').strip().strip( + '\x00') + date = datetime(int(xtime[0:4]), int(xtime[5:7]), + int(xtime[8:10]), int(xtime[11:13]), + int(xtime[14:16]), int(xtime[17:19])) + years = date2num(date, units='days since 0000-01-01', + calendar='noleap')/365. + else: + xtime = var[local_time_indices[time_index]] + years = xtime/365. + xtime = str(xtime) + + # write the header for the vtp file + vtp_file_prefix = "time_series/{}.{:d}".format(out_prefix, + time_index) + file_name = '{}/{}.vtp'.format(out_dir, vtp_file_prefix) + if append and os.path.exists(file_name): + pvd_file.write('<DataSet timestep="{:.16f}" group="" ' + 'part="0"\n'.format(years)) + pvd_file.write('\tfile="{}.vtp"/>\n'.format(vtp_file_prefix)) + continue + + if combine_output: + varIndices = numpy.arange(nVars) + else: + varIndices = numpy.arange(nVars)[var_has_time_dim] + timeDependentFile = write_vtp_header(out_dir, + vtp_file_prefix, + varIndices[0], + varIndices, + variable_list, + all_dim_vals, + vertices, + connectivity, + offsets, + nPoints, + nPolygons, + outType, + cellData=cellData, + pointData=pointData, + xtime=xtime) + + # add time step to pdv file + pvd_file.write('<DataSet timestep="{:.16f}" group="" ' + 'part="0"\n'.format(years)) + pvd_file.write('\tfile="{}.vtp"/>\n'.format(vtp_file_prefix)) + + if time_index == 0 or combine_output: + varIndices = numpy.arange(nVars) + else: + # only the time-dependent variables + varIndices = numpy.arange(nVars)[var_has_time_dim] + + iHyperSlabProgress = 0 + for iVar in varIndices: + has_time = var_has_time_dim[iVar] + + var_name = variable_list[iVar] + (out_var_names, dim_list) = \ + get_hyperslab_name_and_dims(var_name, all_dim_vals[var_name]) + if has_time or combine_output: + vtkFile = timeDependentFile + else: + vtkFile = timeIndependentFile + for iHyperSlab in range(len(out_var_names)): + if dim_list is not None: + dim_vals = dim_list[iHyperSlab] + else: + dim_vals = None + + if boundary_mask is not None and var_name == 'boundaryMask': + field = numpy.array(boundary_mask, dtype=outType) + else: + field = numpy.zeros(blockDim, dtype=outType) + + for iBlock in numpy.arange(0, nBlocks): + blockStart = iBlock * blocking + blockEnd = min((iBlock + 1) * blocking, blockDim) + block_indices = numpy.arange(blockStart, blockEnd) + if topo_cell_indices is None: + block_topo_cell_indices = None + else: + block_topo_cell_indices = \ + topo_cell_indices[block_indices] + field_block = read_field( + var_name, mesh_file, time_series_file, + dim_vals, local_time_indices[time_index], + block_indices, outType, topo_dim=topo_dim, + topo_cell_indices=block_topo_cell_indices, + nTopoLevels=nTopoLevels) + + field[blockStart:blockEnd] = field_block + + field = field[valid_mask] + + if cell_to_point_map is not None: + # map field from cells to points + field = field[cell_to_point_map] + + vtkFile.appendData(field) + + if use_progress_bar: + field_bar.update(time_index*nHyperSlabs + + iHyperSlabProgress) + iHyperSlabProgress += 1 + + del field + + if any_var_has_time_dim: + timeDependentFile.save() + del timeDependentFile + + if time_index == 0 and not combine_output and not \ + numpy.all(var_has_time_dim): + timeIndependentFile.save() + del timeIndependentFile + + time_series_file.close() + if use_progress_bar: + field_bar.finish() + + if any_var_has_time_dim: + # finish the pdv file + pvd_file.write('</Collection>\n') + pvd_file.write('</VTKFile>\n') + pvd_file.close() # }}} + + +def open_netcdf(file_name): + nc_file = NetCDFFile(file_name, 'r') + # turn off auto mask (if applicable) + try: + nc_file.set_auto_mask(False) + except AttributeError: + pass + return nc_file + + +def is_valid_mesh_var(mesh_file, variable_name): # {{{ + if mesh_file is None: + return False + + if variable_name not in mesh_file.variables: + return False + + return 'Time' not in mesh_file.variables[variable_name].dimensions # }}} + + +def get_var(variable_name, mesh_file, time_series_file): # {{{ + if is_valid_mesh_var(mesh_file, variable_name): + return mesh_file.variables[variable_name] + else: + return time_series_file.variables[variable_name] # }}} + + +def setup_time_indices(fn_pattern, xtimeName, use_progress_bar): # {{{ + """ + This function finds a list of NetCDF files containing time-dependent + MPAS data and extracts the time indices in each file. The routine + insures that each time is unique. + """ + # Build file list and time indices + if ';' in fn_pattern: + file_list = [] + for pattern in fn_pattern.split(';'): + file_list.extend(glob.glob(pattern)) + else: + file_list = glob.glob(fn_pattern) + file_list.sort() + + local_indices = [] + file_names = [] + all_times = [] + + if len(file_list) == 0: + print("No files to process.") + print("Exiting...") + sys.exit(0) + + if use_progress_bar: + widgets = ['Build time indices: ', Percentage(), ' ', Bar(), ' ', + ETA()] + time_bar = ProgressBar(widgets=widgets, maxval=len(file_list)).start() + else: + print("Build time indices...") + + i_file = 0 + allTIndex = 0 + for file_name in file_list: + try: + nc_file = open_netcdf(file_name) + except IOError: + print("Warning: could not open {}".format(file_name)) + continue + + if 'Time' not in nc_file.dimensions or xtimeName is None: + local_times = ['0'] + else: + local_times = [] + if xtimeName == 'none': + # no xtime variable so just use integers converted to strings + for index in range(len(nc_file.dimensions['Time'])): + local_times.append(allTIndex) + allTIndex += 1 + else: + if xtimeName not in nc_file.variables: + raise ValueError("xtime variable name {} not found in " + "{}".format(xtimeName, file_name)) + xtime = nc_file.variables[xtimeName] + if len(xtime.shape) == 2: + xtime = xtime[:, :] + for index in range(xtime.shape[0]): + local_times.append(xtime[index, :].tostring()) + else: + local_times = xtime[:] + + if len(local_times) == 0: + local_times = ['0'] + + nTime = len(local_times) + + for time_idx in range(nTime): + if local_times[time_idx] not in all_times: + local_indices.append(time_idx) + file_names.append(file_name) + all_times.append(local_times[time_idx]) + + i_file = i_file + 1 + nc_file.close() + if use_progress_bar: + time_bar.update(i_file) + + if use_progress_bar: + time_bar.finish() + + return local_indices, file_names # }}} + + +def parse_extra_dim(dim_name, index_string, time_series_file, mesh_file): + # {{{ + """ + Parses the indices to be extracted along a given dimension. + The index_string can be fomatted as follows: + <blank> -- no indices are to be extracted + n -- the index n is to be extracted + m,n,p -- the list of indices is to be extracted + m:n -- all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) + m:n:s -- all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) with + stride s between indices + + Parameters + ---------- + dim_name : str + The name of the dimension to be indexed + + index_string : str + An index string indicating with indices are to be extracted + + time_series_file : NetCDF4.Dataset + The name of a time series file that can be used to determine the size + of the dimension if ``mesh_file=None``. + + mesh_file : NetCDF4.Dataset + The name of a mesh file that can be used to determine the size + of the dimension, or ``None`` if the time series file should be used + + Returns + ------- + indices : list of str + Indices into the given dimension formatted as zero-padded strings + (if indices are numerical, as opposed to the name of an index variable) + """ + if index_string == '': + return [] + + if (mesh_file is not None) and (dim_name in mesh_file.dimensions): + nc_file = mesh_file + else: + nc_file = time_series_file + + dim_size = len(nc_file.dimensions[dim_name]) + + indices, numerical_indices = parse_index_string(index_string, dim_size) + + # zero-pad integer indices + if len(numerical_indices) > 0: + max_index = numpy.amax(numerical_indices) + pad = int(numpy.log10(max(max_index, 1)))+1 + template = '%%0%dd' % pad + for i in range(len(indices)): + try: + val = int(indices[i]) + except ValueError: + continue + indices[i] = template % (val) + + return indices + +# }}} + + +def parse_time_indices(index_string, time_indices, time_file_names): # {{{ + """ + Parses the indices to be extracted along the Time dimension. + The index_string can be formatted as follows: + <blank> -- no indices are to be extracted + n -- the index n is to be extracted + m,n,p -- the list of indices is to be extracted + m:n -- all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) + m:n:s -- all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) with + stride s between indices + + Parameters + ---------- + index_string : str or list of int + An index string indicating with indices are to be extracted + + time_indices : list of int + The local time indices in each input NetCDF file + + time_file_names : list of str + The name of the file associated with each time index + + Returns + ------- + time_indices : list of int + The local time indices in each input NetCDF file after reindexing + + time_file_names : list of str + The name of the file associated with each time index after reindexing + + """ + dim_size = len(time_indices) + _, numerical_indices = parse_index_string(index_string, dim_size) + + time_indices = [time_indices[index] for index in numerical_indices] + time_file_names = [time_file_names[index] for index in numerical_indices] + return time_indices, time_file_names # }}} + + +def parse_index_string(index_string, dim_size): # {{{ + """ + Parses an index string into a list of indices. + The index_string can be fomatted as follows: + <blank> -- no indices are to be extracted + n -- the index n is to be extracted + m,n,p -- the list of indices is to be extracted + m:n -- all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) + m:n:s -- all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) with + stride s between indices + + Parameters + ---------- + index_string : str or list of int + An index string indicating with indices are to be extracted + + dim_size : int + The size of the dimension + + Returns + ------- + indices : list of int + The indices corresponding to the given index string. + """ + if not isinstance(index_string, str): + numerical_indices = index_string + indices = [] + for index in numerical_indices: + if index < 0 or index >= dim_size: + raise ValueError("Index (or indices) out of bounds 0 <= " + "index < {}: {}".format(dim_size, + index_string)) + indices.append('{}'.format(index)) + else: + if index_string == '': + return [], [] + + if ',' in index_string: + indices = [index for index in index_string.split(',')] + elif ':' in index_string: + index_list = index_string.split(':') + if len(index_list) not in [2, 3]: + raise ValueError("Improperly formatted index string: " + "{}".format(index_string)) + if index_list[0] == '': + first = 0 + else: + first = int(index_list[0]) + if index_list[1] == '': + last = dim_size + else: + last = int(index_list[1]) + if (len(index_list) == 2) or (index_list[2] == ''): + step = 1 + else: + step = int(index_list[2]) + indices = [str(index) for index in numpy.arange(first, last, step)] + else: + indices = [index_string] + + numerical_indices = [] + for index in indices: + try: + val = int(index) + except ValueError: + continue + + if val < 0 or val >= dim_size: + raise ValueError("Index (or indices) out of bounds 0 <= " + "index < {}: {}".format(dim_size, + index_string)) + + numerical_indices.append(val) + + return indices, numerical_indices # }}} + + +def parse_extra_dims(dimension_list, time_series_file, mesh_file, + topo_dim=None, topo_cell_index_name=None, + max_index_count=None): + # {{{ + """ + Parses a list of dimensions and corresponding indices separated by equals + signs. Optionally, a max_index_count (typically 1) can be provided, + indicating that indices beyond max_index_count-1 will be ignored in each + dimension. Optionally, topo_dim contains the name of a dimension associated + with the surface or bottom topography (e.g. nVertLevels for MPAS-Ocean) + If topo_dim is provided, topo_cell_index_name can optionally be either + a constant value for the vertical index to the topography or the name of a + field with dimension nCells that contains the vertical index of the + topography. + """ + + extra_dims = {} + topo_cell_indices = None + + if dimension_list is not None: + for dim_item in dimension_list: + print(dim_item) + (dimName, index_string) = dim_item.split('=') + indices = parse_extra_dim(dimName, index_string, time_series_file, + mesh_file) + if indices is not None: + if max_index_count is None or len(indices) <= max_index_count: + extra_dims[dimName] = indices + else: + extra_dims[dimName] = indices[0:max_index_count] + + if topo_dim is not None: + if topo_cell_index_name is not None: + if (mesh_file is not None) and \ + (topo_cell_index_name in mesh_file.variables): + topo_cell_indices = \ + mesh_file.variables[topo_cell_index_name][:]-1 + else: + topo_cell_indices = \ + time_series_file.variables[topo_cell_index_name][:]-1 + else: + index = len(mesh_file.dimensions[topo_dim])-1 + nCells = len(mesh_file.dimensions['nCells']) + topo_cell_indices = index*numpy.ones(nCells, int) + + return extra_dims, topo_cell_indices +# }}} + + +def setup_dimension_values_and_sort_vars( + time_series_file, mesh_file, variable_list, extra_dims, + include_mesh_vars, basic_dims=('nCells', 'nEdges', 'nVertices', 'Time'), + include_dims=('nCells', 'nEdges', 'nVertices')): # {{{ + """ + Creates a list of variables names to be extracted. Prompts for indices + of any extra dimensions that were not specified on the command line. + extra_dims should be a dictionary of indices along extra dimensions (as + opposed to "basic" dimensions). basic_dims is a list of dimension names + that should be excluded from extra_dims. include_dims is a list of + possible dimensions, one of which must be in each vairable to be extracted + (used in expanding command line placeholders "all", "allOnCells", etc.) + """ + + time_series_variables = time_series_file.variables + if mesh_file is None or not include_mesh_vars: + mesh_variables = None + else: + mesh_variables = mesh_file.variables + variable_names = _expand_variable_list(variable_list, time_series_variables, + mesh_variables, include_dims) + + all_dim_vals = {} + cellVars = [] + vertexVars = [] + edgeVars = [] + + promptDimNames = [] + display_prompt = True + for variable_name in variable_names: + if is_valid_mesh_var(mesh_file, variable_name): + nc_file = mesh_file + else: + nc_file = time_series_file + field_dims = nc_file.variables[variable_name].dimensions + for dim in field_dims: + if ((dim in basic_dims) or (dim in extra_dims) + or (dim in promptDimNames)): + # this dimension has already been accounted for + continue + promptDimNames.append(str(dim)) + + if display_prompt: + print("") + print("Need to define additional dimension values") + display_prompt = False + + dim_size = len(nc_file.dimensions[dim]) + valid = False + while not valid: + print("Valid range for dimension {} between 0 and {}" + "".format(dim, dim_size-1)) + index_string = input("Enter a value for dimension {}: " + "".format(dim)) + indices = parse_extra_dim(str(dim), index_string, + time_series_file, mesh_file) + valid = indices is not None + if valid: + extra_dims[str(dim)] = indices + else: + print(" -- Invalid value, please re-enter --") + + empty_dims = [] + for dim in extra_dims: + if len(extra_dims[dim]) == 0: + empty_dims.append(dim) + + for variable_name in variable_names: + + field_dims = get_var(variable_name, mesh_file, + time_series_file).dimensions + skip = False + for dim in field_dims: + if dim in empty_dims: + skip = True + break + if skip: + continue + + # Setting dimension values: + indices = [] + for dim in field_dims: + if dim not in basic_dims: + indices.append(extra_dims[dim]) + if len(indices) == 0: + dim_vals = None + elif len(indices) == 1: + dim_vals = [] + for index0 in indices[0]: + dim_vals.append([index0]) + elif len(indices) == 2: + dim_vals = [] + for index0 in indices[0]: + for index1 in indices[1]: + dim_vals.append([index0, index1]) + elif len(indices) == 3: + dim_vals = [] + for index0 in indices[0]: + for index1 in indices[1]: + for index2 in indices[2]: + dim_vals.append([index0, index1, index2]) + else: + print("variable {} has too many extra dimensions and will be " + "skipped.".format(variable_name)) + continue + + if "nCells" in field_dims: + cellVars.append(variable_name) + elif "nVertices" in field_dims: + vertexVars.append(variable_name) + elif "nEdges" in field_dims: + edgeVars.append(variable_name) + + all_dim_vals[variable_name] = dim_vals + del dim_vals + + return all_dim_vals, cellVars, vertexVars, edgeVars +# }}} + + +def summarize_extraction(mesh_file, time_indices, cellVars, vertexVars, + edgeVars, transects_file=None): # {{{ + """ + print a summary of the time levels, mesh file, transects file (optional) + and variables to be extracted. + """ + + print("") + print("Extracting a total of {} time levels.".format(len(time_indices))) + print("Using file '{}' as the mesh file for this extraction." + "".format(mesh_file)) + if transects_file is not None: + print("Using file '{}' as the transects file.".format(transects_file)) + print("") + print("") + print("The following variables will be extracted from the input file(s).") + print("") + + if len(cellVars) > 0: + print(" Variables with 'nCells' as a dimension:") + for variable_name in cellVars: + print(" name: {}".format(variable_name)) + + if len(vertexVars) > 0: + print(" Variables with 'nVertices' as a dimension:") + for variable_name in vertexVars: + print(" name: {}".format(variable_name)) + + if len(edgeVars) > 0: + print(" Variables with 'nEdges' as adimension:") + for variable_name in edgeVars: + print(" name: {}".format(variable_name)) + + print("") +# }}} + + +def write_pvd_header(path, prefix): # {{{ + pvd_file = open('{}/{}.pvd'.format(path, prefix), 'w') + pvd_file.write('<?xml version="1.0"?>\n') + pvd_file.write('<VTKFile type="Collection" version="0.1"\n') + pvd_file.write('\tbyte_order="LittleEndian"\n') + pvd_file.write('\tcompressor="vtkZLibDataCompressor">\n') + return pvd_file # }}} + + +def get_hyperslab_name_and_dims(var_name, extra_dim_vals): # {{{ + if extra_dim_vals is None: + return [var_name], None + if len(extra_dim_vals) == 0: + return [], None + out_var_names = [] + for hyper_slab in extra_dim_vals: + pieces = [var_name] + pieces.extend(hyper_slab) + out_var_names.append('_'.join(pieces)) + return out_var_names, extra_dim_vals +# }}} + + +def write_vtp_header(path, prefix, active_var_index, var_indices, + variable_list, all_dim_vals, vertices, connectivity, + offsets, nPoints, nPolygons, outType, cellData=True, + pointData=False, xtime=None): # {{{ + vtkFile = VtkFile("{}/{}".format(path, prefix), VtkPolyData) + + if xtime is not None: + vtkFile.openElement(str("metadata")) + vtkFile.openElement(str("xtime")) + vtkFile.xml.addText(str(xtime)) + vtkFile.closeElement(str("xtime")) + vtkFile.closeElement(str("metadata")) + + vtkFile.openElement(vtkFile.ftype.name) + vtkFile.openPiece(npoints=nPoints, npolys=nPolygons) + + vtkFile.openElement(str("Points")) + vtkFile.addData(str("points"), vertices) + vtkFile.closeElement(str("Points")) + + vtkFile.openElement(str("Polys")) + vtkFile.addData(str("connectivity"), connectivity) + vtkFile.addData(str("offsets"), offsets) + vtkFile.closeElement(str("Polys")) + + if cellData: + vtkFile.openData(str("Cell"), + scalars=variable_list[active_var_index]) + for iVar in var_indices: + var_name = variable_list[iVar] + (out_var_names, dim_list) = \ + get_hyperslab_name_and_dims(var_name, all_dim_vals[var_name]) + for out_var_name in out_var_names: + vtkFile.addHeader(str(out_var_name), outType, nPolygons, 1) + vtkFile.closeData(str("Cell")) + if pointData: + vtkFile.openData(str("Point"), + scalars=variable_list[active_var_index]) + for iVar in var_indices: + var_name = variable_list[iVar] + (out_var_names, dim_list) = \ + get_hyperslab_name_and_dims(var_name, all_dim_vals[var_name]) + for out_var_name in out_var_names: + vtkFile.addHeader(str(out_var_name), outType, nPoints, 1) + vtkFile.closeData(str("Point")) + + vtkFile.closePiece() + vtkFile.closeElement(vtkFile.ftype.name) + + vtkFile.appendData(vertices) + vtkFile.appendData(connectivity) + vtkFile.appendData(offsets) + + return vtkFile # }}} + + +def build_topo_point_and_polygon_lists(nc_file, output_32bit, lonlat, + use_progress_bar): # {{{ + + if output_32bit: + dtype = 'f4' + else: + dtype = 'f8' + + xVertex, yVertex, zVertex = \ + _build_location_list_xyz(nc_file, 'Vertex', output_32bit, lonlat) + + nCells = len(nc_file.dimensions['nCells']) + nEdges = len(nc_file.dimensions['nEdges']) + maxEdges = len(nc_file.dimensions['maxEdges']) + + nEdgesOnCell = nc_file.variables['nEdgesOnCell'][:] + verticesOnCell = nc_file.variables['verticesOnCell'][:, :]-1 + edgesOnCell = nc_file.variables['edgesOnCell'][:, :]-1 + verticesOnEdge = nc_file.variables['verticesOnEdge'][:] - 1 + cellsOnEdge = nc_file.variables['cellsOnEdge'][:] - 1 + + # 4 points for each edge face + nPoints = 4*nEdges + # 1 polygon for each edge and cell + nPolygons = nEdges + nCells + + X = numpy.zeros(nPoints, dtype) + Y = numpy.zeros(nPoints, dtype) + Z = numpy.zeros(nPoints, dtype) + + # The points on an edge are vertex 0, 1, 1, 0 on that edge, making a + # vertical rectangle if the points are offset + iEdges, voe = numpy.meshgrid(numpy.arange(nEdges), [0, 1, 1, 0], + indexing='ij') + iVerts = verticesOnEdge[iEdges, voe].ravel() + X[:] = xVertex[iVerts] + Y[:] = yVertex[iVerts] + Z[:] = zVertex[iVerts] + vertices = (X, Y, Z) + + verticesOnPolygon = -1*numpy.ones((nPolygons, maxEdges), int) + verticesOnPolygon[0:nEdges, 0:4] = \ + numpy.arange(4*nEdges).reshape(nEdges, 4) + + # Build cells + if use_progress_bar: + widgets = ['Build cell connectivity: ', Percentage(), ' ', Bar(), ' ', + ETA()] + bar = ProgressBar(widgets=widgets, maxval=nCells).start() + else: + print("Build cell connectivity...") + + outIndex = nEdges + + for iCell in range(nCells): + neoc = nEdgesOnCell[iCell] + eocs = edgesOnCell[iCell, 0:neoc] + vocs = verticesOnCell[iCell, 0:neoc] + for index in range(neoc): + iVert = vocs[index] + iEdge = eocs[index] + # which vertex on the edge corresponds to iVert? + coes = cellsOnEdge[iEdge, :] + voes = verticesOnEdge[iEdge, :] + + if coes[0] == iCell: + if voes[0] == iVert: + voe = 0 + else: + voe = 1 + else: + if voes[0] == iVert: + voe = 3 + else: + voe = 2 + + verticesOnPolygon[nEdges+iCell, index] = 4*iEdge + voe + + outIndex += neoc + + if use_progress_bar: + bar.update(iCell) + + if use_progress_bar: + bar.finish() + + validVerts = verticesOnPolygon >= 0 + + if lonlat: + lonEdge = numpy.rad2deg(nc_file.variables['lonEdge'][:]) + latEdge = numpy.rad2deg(nc_file.variables['latEdge'][:]) + lonCell = numpy.rad2deg(nc_file.variables['lonCell'][:]) + latCell = numpy.rad2deg(nc_file.variables['latCell'][:]) + lonPolygon = numpy.append(lonEdge, lonCell) + latPolygon = numpy.append(latEdge, latCell) + + vertices, verticesOnPolygon = _fix_lon_lat_vertices(vertices, + verticesOnPolygon, + validVerts, + lonPolygon) + + if nc_file.on_a_sphere.strip() == 'NO' and \ + nc_file.is_periodic.strip() == 'YES': + if lonlat: + xcoord = lonPolygon + ycoord = latPolygon + else: + xEdge = numpy.rad2deg(nc_file.variables['xEdge'][:]) + yEdge = numpy.rad2deg(nc_file.variables['yEdge'][:]) + xCell = numpy.rad2deg(nc_file.variables['xCell'][:]) + yCell = numpy.rad2deg(nc_file.variables['yCell'][:]) + xcoord = numpy.append(xEdge, xCell) + ycoord = numpy.append(yEdge, yCell) + + vertices, verticesOnPolygon = _fix_periodic_vertices(vertices, + verticesOnPolygon, + validVerts, + xcoord, ycoord, + nc_file.x_period, + nc_file.y_period) + + nPoints = len(vertices[0]) + + # we want to know the cells corresponding to each point. The first two + # points correspond to the first cell, the second two to the second cell + # (if any). + cell_to_point_map = -1*numpy.ones((nPoints,), int) + boundary_mask = numpy.zeros((nPoints,), bool) + + # first cell on edge always exists + coe = cellsOnEdge[:, 0].copy() + for index in range(2): + voe = verticesOnPolygon[0:nEdges, index] + cell_to_point_map[voe] = coe + boundary_mask[voe] = False + + # second cell on edge may not exist + coe = cellsOnEdge[:, 1].copy() + mask = coe == -1 + # use the first cell if the second doesn't exist + coe[mask] = cellsOnEdge[:, 0][mask] + for index in range(2, 4): + voe = verticesOnPolygon[0:nEdges, index] + cell_to_point_map[voe] = coe + boundary_mask[voe] = mask + + # for good measure, make sure vertices on cell are also accounted for + for index in range(maxEdges): + iCells = numpy.arange(nCells) + voc = verticesOnPolygon[nEdges:nEdges+nCells, index] + mask = index < nEdgesOnCell + cell_to_point_map[voc[mask]] = iCells[mask] + boundary_mask[voc[mask]] = False + + connectivity = verticesOnPolygon[validVerts] + validCount = numpy.sum(numpy.array(validVerts, int), axis=1) + offsets = numpy.cumsum(validCount, dtype=int) + valid_mask = numpy.ones(nCells, bool) + + return vertices, connectivity, offsets, valid_mask, \ + cell_to_point_map, boundary_mask.ravel() # }}} + + +def build_cell_geom_lists(nc_file, output_32bit, lonlat): # {{{ + + print("Build geometry for fields on cells...") + + vertices = _build_location_list_xyz(nc_file, 'Vertex', output_32bit, + lonlat) + + if lonlat: + lonCell = numpy.rad2deg(nc_file.variables['lonCell'][:]) + latCell = numpy.rad2deg(nc_file.variables['latCell'][:]) + + nCells = len(nc_file.dimensions['nCells']) + + nEdgesOnCell = nc_file.variables['nEdgesOnCell'][:] + verticesOnCell = nc_file.variables['verticesOnCell'][:, :] - 1 + # MPAS-O sets non-masked values to total number of vertices instead of 0 + # (as produced in mesh workflow) + verticesOnCell[numpy.where(verticesOnCell == len(vertices[0]))] = 0 + + validVertices = numpy.zeros(verticesOnCell.shape, bool) + for vIndex in range(validVertices.shape[1]): + validVertices[:, vIndex] = vIndex < nEdgesOnCell + + if lonlat: + vertices, verticesOnCell = _fix_lon_lat_vertices(vertices, + verticesOnCell, + validVertices, + lonCell) + + if nc_file.on_a_sphere.strip() == 'NO' and \ + nc_file.is_periodic.strip() == 'YES': + if lonlat: + xcoord = lonCell + ycoord = latCell + else: + xcoord = nc_file.variables['xCell'][:] + ycoord = nc_file.variables['yCell'][:] + vertices, verticesOnCell = _fix_periodic_vertices(vertices, + verticesOnCell, + validVertices, + xcoord, ycoord, + nc_file.x_period, + nc_file.y_period) + + connectivity = numpy.array(verticesOnCell[validVertices], int) + offsets = numpy.cumsum(nEdgesOnCell, dtype=int) + valid_mask = numpy.ones(nCells, bool) + + return vertices, connectivity, offsets, valid_mask # }}} + + +def build_vertex_geom_lists(nc_file, output_32bit, lonlat): # {{{ + print("Build geometry for fields on vertices....") + + vertices = _build_location_list_xyz(nc_file, 'Cell', output_32bit, lonlat) + + if lonlat: + lonVertex = numpy.rad2deg(nc_file.variables['lonVertex'][:]) + latVertex = numpy.rad2deg(nc_file.variables['latVertex'][:]) + + vertexDegree = len(nc_file.dimensions['vertexDegree']) + + cellsOnVertex = nc_file.variables['cellsOnVertex'][:, :] - 1 + + valid_mask = numpy.all(cellsOnVertex >= 0, axis=1) + + cellsOnVertex = cellsOnVertex[valid_mask, :] + + if lonlat: + # all remaining entries in cellsOnVertex are valid + validVertices = numpy.ones(cellsOnVertex.shape, bool) + vertices, cellsOnVertex = _fix_lon_lat_vertices(vertices, + cellsOnVertex, + validVertices, + lonVertex[valid_mask]) + + if nc_file.on_a_sphere.strip() == 'NO' and \ + nc_file.is_periodic.strip() == 'YES': + # all remaining entries in cellsOnVertex are valid + validVertices = numpy.ones(cellsOnVertex.shape, bool) + if lonlat: + xcoord = lonVertex[valid_mask] + ycoord = latVertex[valid_mask] + else: + xcoord = nc_file.variables['xVertex'][valid_mask] + ycoord = nc_file.variables['yVertex'][valid_mask] + vertices, cellsOnVertex = _fix_periodic_vertices(vertices, + cellsOnVertex, + validVertices, + xcoord, ycoord, + nc_file.x_period, + nc_file.y_period) + + connectivity = numpy.array(cellsOnVertex.ravel(), int) + validCount = cellsOnVertex.shape[0] + offsets = numpy.array(vertexDegree*numpy.arange(1, validCount+1), int) + + return vertices, connectivity, offsets, valid_mask # }}} + + +def build_edge_geom_lists(nc_file, output_32bit, lonlat): # {{{ + (xCell, yCell, zCell) = \ + _build_location_list_xyz(nc_file, 'Cell', output_32bit, lonlat) + (xVertex, yVertex, zVertex) = \ + _build_location_list_xyz(nc_file, 'Vertex', output_32bit, lonlat) + + vertices = (numpy.append(xCell, xVertex), + numpy.append(yCell, yVertex), + numpy.append(zCell, zVertex)) + + if lonlat: + lonEdge = numpy.rad2deg(nc_file.variables['lonEdge'][:]) + latEdge = numpy.rad2deg(nc_file.variables['latEdge'][:]) + + nEdges = len(nc_file.dimensions['nEdges']) + nCells = len(nc_file.dimensions['nCells']) + + cellsOnEdge = nc_file.variables['cellsOnEdge'][:] - 1 + verticesOnEdge = nc_file.variables['verticesOnEdge'][:] - 1 + + vertsOnCell = -1*numpy.ones((nEdges, 4), int) + vertsOnCell[:, 0] = cellsOnEdge[:, 0] + vertsOnCell[:, 1] = verticesOnEdge[:, 0] + vertsOnCell[:, 2] = cellsOnEdge[:, 1] + vertsOnCell[:, 3] = verticesOnEdge[:, 1] + + validVerts = vertsOnCell >= 0 + + vertsOnCell[:, 1] += nCells + vertsOnCell[:, 3] += nCells + + validCount = numpy.sum(numpy.array(validVerts, int), axis=1) + + # exclude any isolated points or lines -- we need only triangles or quads + valid_mask = validCount >= 3 + + vertsOnCell = vertsOnCell[valid_mask, :] + validVerts = validVerts[valid_mask, :] + + if lonlat: + vertices, vertsOnCell = _fix_lon_lat_vertices(vertices, + vertsOnCell, + validVerts, + lonEdge[valid_mask]) + if nc_file.on_a_sphere.strip() == 'NO' and \ + nc_file.is_periodic.strip() == 'YES': + if lonlat: + xcoord = lonEdge[valid_mask] + ycoord = latEdge[valid_mask] + else: + xcoord = nc_file.variables['xEdge'][valid_mask] + ycoord = nc_file.variables['yEdge'][valid_mask] + + vertices, vertsOnCell = _fix_periodic_vertices(vertices, + vertsOnCell, + validVerts, + xcoord, ycoord, + nc_file.x_period, + nc_file.y_period) + + connectivity = numpy.array(vertsOnCell[validVerts], int) + validCount = numpy.sum(numpy.array(validVerts, int), axis=1) + offsets = numpy.cumsum(validCount, dtype=int) + + return vertices, connectivity, offsets, valid_mask # }}} + + +def get_field_sign(field_name): + if field_name[0] == '-': + field_name = field_name[1:] + sign = -1 + else: + sign = 1 + + return field_name, sign + + +def read_field(var_name, mesh_file, time_series_file, extra_dim_vals, + time_index, block_indices, outType, sign=1, + topo_dim=None, topo_cell_indices=None, nTopoLevels=None): # {{{ + + def read_field_with_dims(field_var, dim_vals, temp_shape, outType, + index_arrays): # {{{ + temp_field = numpy.zeros(temp_shape, dtype=outType) + inDims = len(dim_vals) + if inDims <= 0 or inDims > 5: + print('reading field {} with {} dimensions not supported.' + ''.format(var_name, inDims)) + sys.exit(1) + + if inDims == 1: + temp_field = numpy.array(field_var[dim_vals[0]], dtype=outType) + elif inDims == 2: + temp_field = numpy.array(field_var[dim_vals[0], dim_vals[1]], + dtype=outType) + elif inDims == 3: + temp_field = numpy.array(field_var[dim_vals[0], dim_vals[1], + dim_vals[2]], + dtype=outType) + elif inDims == 4: + temp_field = numpy.array(field_var[dim_vals[0], dim_vals[1], + dim_vals[2], dim_vals[3]], + dtype=outType) + elif inDims == 5: + temp_field = numpy.array(field_var[dim_vals[0], dim_vals[1], + dim_vals[2], dim_vals[3], + dim_vals[4]], + dtype=outType) + + if topo_dim is not None and topo_dim in field_var.dimensions: + if len(temp_field.shape) != 2: + raise ValueError('Field with dimensions {} not supported in ' + 'topography extraction mode.'.format( + field_var.dimensions)) + # sample the depth-dependent field at the index of the topography + temp_field = temp_field[numpy.arange(temp_field.shape[0]), + topo_cell_indices] + + outDims = len(temp_field.shape) + + if outDims <= 0 or outDims > 4: + print('something went wrong reading field {}, resulting in a temp ' + 'array with {} dimensions.'.format(var_name, outDims)) + sys.exit(1) + block_indices = numpy.arange(temp_field.shape[0]) + if outDims == 1: + field = temp_field + elif outDims == 2: + field = temp_field[block_indices, index_arrays[0]] + elif outDims == 3: + field = temp_field[block_indices, index_arrays[0], index_arrays[1]] + elif outDims == 4: + field = temp_field[block_indices, index_arrays[0], index_arrays[1], + index_arrays[2]] + + return field # }}} + + field_var = get_var(var_name, mesh_file, time_series_file) + if 'missing_value' in field_var.ncattrs(): + missing_val = field_var.missing_value + elif '_FillValue' in field_var.ncattrs(): + missing_val = field_var._FillValue + else: + missing_val = None + + dim_vals = [] + extra_dim_index = 0 + shape = field_var.shape + temp_shape = () + + index_arrays = [] + + for i in range(field_var.ndim): + dim = field_var.dimensions[i] + if dim == 'Time': + dim_vals.append(time_index) + elif dim in ['nCells', 'nEdges', 'nVertices']: + dim_vals.append(block_indices) + temp_shape = temp_shape + (len(block_indices),) + elif topo_dim is not None and dim == topo_dim: + dim_vals.append(numpy.arange(nTopoLevels)) + else: + extra_dim_val = extra_dim_vals[extra_dim_index] + try: + index = int(extra_dim_val) + dim_vals.append(index) + except ValueError: + # we have an index array so we need to read the whole range + # first and then sample the result + dim_vals.append(numpy.arange(shape[i])) + temp_shape = temp_shape + (shape[i],) + + index_array_var = get_var(extra_dim_val, mesh_file, + time_series_file) + + # read the appropriate indices from the index_array_var + index_array = numpy.maximum(0, numpy.minimum( + shape[i]-1, index_array_var[block_indices]-1)) + + index_arrays.append(index_array) + + extra_dim_index += 1 + + field = read_field_with_dims(field_var, dim_vals, temp_shape, outType, + index_arrays) + + if missing_val is not None: + field[field == missing_val] = numpy.nan + + return sign*field # }}} + + +def compute_zInterface(minLevelCell, maxLevelCell, layerThicknessCell, + zMinCell, zMaxCell, dtype, cellsOnEdge=None): + # {{{ + + (nCells, nLevels) = layerThicknessCell.shape + + cellMask = numpy.ones((nCells, nLevels), bool) + for iLevel in range(nLevels): + if minLevelCell is not None: + cellMask[:, iLevel] = numpy.logical_and(cellMask[:, iLevel], + iLevel >= minLevelCell) + if maxLevelCell is not None: + cellMask[:, iLevel] = numpy.logical_and(cellMask[:, iLevel], + iLevel <= maxLevelCell) + + zInterfaceCell = numpy.zeros((nCells, nLevels+1), dtype=dtype) + for iLevel in range(nLevels): + zInterfaceCell[:, iLevel+1] = \ + zInterfaceCell[:, iLevel] \ + + cellMask[:, iLevel]*layerThicknessCell[:, iLevel] + + if zMinCell is not None: + minLevel = minLevelCell.copy() + minLevel[minLevel < 0] = nLevels-1 + zOffsetCell = zMinCell - zInterfaceCell[numpy.arange(0, nCells), + minLevel] + else: + zOffsetCell = zMaxCell - zInterfaceCell[numpy.arange(0, nCells), + maxLevelCell+1] + + for iLevel in range(nLevels+1): + zInterfaceCell[:, iLevel] += zOffsetCell + + if cellsOnEdge is None: + return zInterfaceCell + else: + nEdges = cellsOnEdge.shape[0] + zInterfaceEdge = numpy.zeros((nEdges, nLevels+1), dtype=dtype) + + # Get a list of valid cells on edges and a mask of which are valid + cellsOnEdgeMask = numpy.logical_and(cellsOnEdge >= 0, + cellsOnEdge < nCells) + cellIndicesOnEdge = list() + cellIndicesOnEdge.append(cellsOnEdge[cellsOnEdgeMask[:, 0], 0]) + cellIndicesOnEdge.append(cellsOnEdge[cellsOnEdgeMask[:, 1], 1]) + + for iLevel in range(nLevels): + edgeMask = numpy.zeros(nEdges, bool) + layerThicknessEdge = numpy.zeros(nEdges, float) + denom = numpy.zeros(nEdges, float) + for index in range(2): + mask = cellsOnEdgeMask[:, index] + cellIndices = cellIndicesOnEdge[index] + cellMaskLocal = cellMask[cellIndices, iLevel] + + edgeMask[mask] = numpy.logical_or(edgeMask[mask], + cellMaskLocal) + + layerThicknessEdge[mask] += \ + cellMaskLocal*layerThicknessCell[cellIndices, iLevel] + denom[mask] += 1.0*cellMaskLocal + + layerThicknessEdge[edgeMask] /= denom[edgeMask] + + zInterfaceEdge[:, iLevel+1] = (zInterfaceEdge[:, iLevel] + + edgeMask*layerThicknessEdge) + + if zMinCell is not None: + refLevelEdge = numpy.zeros(nEdges, int) + for index in range(2): + mask = cellsOnEdgeMask[:, index] + cellIndices = cellIndicesOnEdge[index] + refLevelEdge[mask] = numpy.maximum(refLevelEdge[mask], + minLevel[cellIndices]) + else: + refLevelEdge = (nLevels-1)*numpy.ones(nEdges, int) + for index in range(2): + mask = cellsOnEdgeMask[:, index] + cellIndices = cellIndicesOnEdge[index] + refLevelEdge[mask] = numpy.minimum(refLevelEdge[mask], + maxLevelCell[cellIndices]+1) + + zOffsetEdge = numpy.zeros(nEdges, float) + # add the average of zInterfaceCell at each adjacent cell + denom = numpy.zeros(nEdges, float) + for index in range(2): + mask = cellsOnEdgeMask[:, index] + cellIndices = cellIndicesOnEdge[index] + zOffsetEdge[mask] += zInterfaceCell[cellIndices, + refLevelEdge[mask]] + denom[mask] += 1.0 + + mask = denom > 0. + zOffsetEdge[mask] /= denom[mask] + + # subtract the depth of zInterfaceEdge at the level of the bottom + zOffsetEdge -= zInterfaceEdge[numpy.arange(nEdges), refLevelEdge] + + for iLevel in range(nLevels+1): + zInterfaceEdge[:, iLevel] += zOffsetEdge + + return zInterfaceCell, zInterfaceEdge # }}} + + +def _build_location_list_xyz(nc_file, suffix, output_32bit, lonlat): # {{{ + + if lonlat: + X = numpy.rad2deg(nc_file.variables['lon{}'.format(suffix)][:]) + Y = numpy.rad2deg(nc_file.variables['lat{}'.format(suffix)][:]) + Z = numpy.zeros(X.shape) + else: + X = nc_file.variables['x{}'.format(suffix)][:] + Y = nc_file.variables['y{}'.format(suffix)][:] + Z = nc_file.variables['z{}'.format(suffix)][:] + if output_32bit: + X = numpy.array(X, 'f4') + Y = numpy.array(Y, 'f4') + Z = numpy.array(Z, 'f4') + return X, Y, Z + +# }}} + + +def _fix_lon_lat_vertices(vertices, verticesOnCell, validVertices, + lonCell): # {{{ + + nCells = verticesOnCell.shape[0] + nVertices = len(vertices[0]) + + xVertex = vertices[0] + xDiff = xVertex[verticesOnCell] - lonCell.reshape(nCells, 1) + + # which cells have vertices that are out of range? + outOfRange = numpy.logical_and(validVertices, + numpy.logical_or(xDiff >= 180., + xDiff < -180.)) + + cellsOutOfRange = numpy.any(outOfRange, axis=1) + + valid = validVertices[cellsOutOfRange, :] + + verticesToChange = numpy.zeros(verticesOnCell.shape, bool) + verticesToChange[cellsOutOfRange, :] = valid + + xDiff = xDiff[cellsOutOfRange, :][valid] + voc = verticesOnCell[cellsOutOfRange, :][valid] + nVerticesToAdd = numpy.count_nonzero(valid) + verticesToAdd = numpy.arange(nVerticesToAdd) + nVertices + xv = xVertex[voc] + verticesOnCell[verticesToChange] = verticesToAdd + + # where the lon. difference between the cell center and the vertex + # is out of range (presumably because of the periodic boundary), + # move it to be within 180 degrees. + mask = xDiff >= 180. + xv[mask] -= 360. + mask = xDiff < -180. + xv[mask] += 360. + + vertices = (numpy.append(xVertex, xv), + numpy.append(vertices[1], vertices[1][voc]), + numpy.append(vertices[2], vertices[2][voc])) + + return vertices, verticesOnCell # }}} + + +def _fix_periodic_vertices(vertices, verticesOnCell, validVertices, + xCell, yCell, xperiod, yperiod): # {{{ + + vertices, verticesOnCell = _fix_periodic_vertices_1D( + vertices, verticesOnCell, validVertices, xCell, xperiod, dim=0) + vertices, verticesOnCell = _fix_periodic_vertices_1D( + vertices, verticesOnCell, validVertices, yCell, yperiod, dim=1) + + return vertices, verticesOnCell # }}} + + +def _fix_periodic_vertices_1D(vertices, verticesOnCell, validVertices, + coordCell, coordPeriod, dim): # {{{ + + nCells = verticesOnCell.shape[0] + nVertices = len(vertices[0]) + + coordVertex = vertices[dim] + + coordDiff = coordVertex[verticesOnCell] - coordCell.reshape(nCells, 1) + + # which cells have vertices that are out of range? + coordOutOfRange = numpy.logical_and( + validVertices, + numpy.logical_or(coordDiff > coordPeriod / 2.0, + coordDiff < -coordPeriod / 2.0)) + + coordCellsOutOfRange = numpy.any(coordOutOfRange, axis=1) + + coordValid = validVertices[coordCellsOutOfRange, :] + + coordVerticesToChange = numpy.zeros(verticesOnCell.shape, bool) + coordVerticesToChange[coordCellsOutOfRange, :] = coordValid + + coordDiff = coordDiff[coordCellsOutOfRange, :][coordValid] + coordVOC = verticesOnCell[coordCellsOutOfRange, :][coordValid] + + coordNVerticesToAdd = numpy.count_nonzero(coordValid) + + coordVerticesToAdd = numpy.arange(coordNVerticesToAdd) + nVertices + coordV = coordVertex[coordVOC] + verticesOnCell[coordVerticesToChange] = coordVerticesToAdd + + # need to shift points outside periodic domain (assumes that mesh is only + # within one period) can use mod if this is not the case in general + coordMask = coordDiff > coordPeriod / 2.0 + coordV[coordMask] -= coordPeriod + coordMask = coordDiff < -coordPeriod / 2.0 + coordV[coordMask] += coordPeriod + + outVertices = [] + for outDim in range(3): + if outDim == dim: + outVertices.append(numpy.append(vertices[outDim], coordV)) + else: + outVertices.append(numpy.append(vertices[outDim], + vertices[outDim][coordVOC])) + + return tuple(outVertices), verticesOnCell # }}} + + +def _expand_variable_list(variable_list, time_series_variables, + mesh_variables, include_dims): + + + if variable_list == 'all': + variable_names = [] + exclude_dims = ['Time'] + for variable_name in time_series_variables: + _add_var(time_series_variables, str(variable_name), + include_dims, variable_names, exc_dims=None) + if mesh_variables is not None: + for variable_name in mesh_variables: + _add_var(mesh_variables, str(variable_name), include_dims, + variable_names, exclude_dims) + elif isinstance(variable_list, str): + variable_names = variable_list.split(',') + else: + variable_names = variable_list + + for suffix in ['Cells', 'Edges', 'Vertices']: + include_dim = 'n{}'.format(suffix) + all_on = 'allOn{}'.format(suffix) + if (all_on in variable_names) and (include_dim in include_dims): + variable_names.remove(all_on) + exclude_dims = ['Time'] + for variable_name in time_series_variables: + _add_var(time_series_variables, str(variable_name), + inc_dims=[include_dim], variable_names=variable_names, + exc_dims=None) + if mesh_variables is not None: + for variable_name in mesh_variables: + _add_var(mesh_variables, str(variable_name), + inc_dims=[include_dim], + variable_names=variable_names, + exc_dims=exclude_dims) + + variable_names.sort() + return variable_names + + +def _add_var(variables, var_name, inc_dims, variable_names, exc_dims=None): + if var_name in variable_names: + return + + dims = variables[var_name].dimensions + supported = False + for d in inc_dims: + if d in dims: + supported = True + if exc_dims is not None: + for d in exc_dims: + if d in dims: + supported = False + if supported: + variable_names.append(var_name) + + +def _cull_files(fc_region_mask, temp_dir, mesh_filename, time_file_names, + separate_mesh_file, variable_list, include_mesh_vars, xtime, + use_progress_bar): + + mesh_vars = [ + 'areaCell', 'cellsOnCell', 'edgesOnCell', 'indexToCellID', + 'latCell', 'lonCell', 'nEdgesOnCell', 'verticesOnCell', + 'xCell', 'yCell', 'zCell', 'angleEdge', 'cellsOnEdge', 'dcEdge', + 'dvEdge', 'edgesOnEdge', 'indexToEdgeID', 'latEdge', + 'lonEdge', 'nEdgesOnCell', 'nEdgesOnEdge', 'verticesOnEdge', + 'xEdge', 'yEdge', 'zEdge', 'areaTriangle', + 'cellsOnVertex', 'edgesOnVertex', 'indexToVertexID', + 'kiteAreasOnVertex', 'latVertex', 'lonVertex', 'xVertex', 'yVertex', + 'zVertex', 'weightsOnEdge'] + + try: + os.makedirs(temp_dir) + except OSError: + pass + + log_stream = StringIO() + logger = logging.getLogger('_cull_files') + for handler in logger.handlers: + logger.removeHandler(handler) + handler = logging.StreamHandler(log_stream) + logger.addHandler(handler) + handler.setLevel(logging.INFO) + + # Figure out the variable names we want to extract + with open_netcdf(time_file_names[0]) as time_series_file: + time_series_variables = time_series_file.variables + if separate_mesh_file and include_mesh_vars: + mesh_file = open_netcdf(mesh_filename) + mesh_variables = mesh_file.variables + else: + mesh_file = None + mesh_variables = None + + include_dims = ('nCells', 'nEdges', 'nVertices') + variable_names = _expand_variable_list(variable_list, + time_series_variables, + mesh_variables, include_dims) + + if mesh_file is not None: + mesh_file.close() + + print('Including variables: {}'.format(', '.join(variable_names))) + + with xarray.open_dataset(mesh_filename) as ds_mesh: + ds_mesh = ds_mesh[mesh_vars] + print('Making a region mask file') + ds_mask = mask(dsMesh=ds_mesh, fcMask=fc_region_mask, logger=logger, + dir=temp_dir) + write_netcdf(ds_mask, f'{temp_dir}/mask.nc') + print('Cropping mesh to region') + out_mesh_filename = '{}/mesh.nc'.format(temp_dir) + args = ['MpasCellCuller.x', + mesh_filename, + out_mesh_filename, + '-i', f'{temp_dir}/mask.nc'] + check_call(args=args, logger=logger) + + region_masks = dict() + cell_mask = ds_mask.regionCellMasks.sum(dim='nRegions') > 0 + region_masks['nCells'] = cell_mask + region_masks['nVertices'] = \ + ds_mask.regionVertexMasks.sum(dim='nRegions') > 0 + coe = ds_mesh.cellsOnEdge - 1 + valid_cell_on_edge = numpy.logical_and(coe >= 0, cell_mask[coe]) + region_masks['nEdges'] = numpy.logical_or( + valid_cell_on_edge.isel(TWO=0), + valid_cell_on_edge.isel(TWO=1)) + + if use_progress_bar: + widgets = ['Cropping time series to region: ', Percentage(), ' ', + Bar(), ' ', ETA()] + bar = ProgressBar(widgets=widgets, maxval=len(time_file_names)).start() + else: + print('Cropping time series to region') + bar = None + + out_time_file_names = [] + already_culled = [] + for index, filename in enumerate(time_file_names): + file_index = len(already_culled) + out_filename = f'{temp_dir}/time_series{file_index:04d}.nc' + out_time_file_names.append(out_filename) + if filename in already_culled: + continue + ds_in = xarray.open_dataset(filename) + ds_out = xarray.Dataset() + if xtime is None: + ds_in = ds_in[variable_names] + else: + ds_in = ds_in[variable_names + [xtime]] + ds_out[xtime] = ds_in[xtime] + for var in ds_in.data_vars: + for dim in region_masks: + if dim in ds_in[var].dims: + ds_out[var] = ds_in[var].where(region_masks[dim], drop=True) + write_netcdf(ds_out, out_filename) + already_culled.append(filename) + if use_progress_bar: + bar.update(index+1) + bar.finish() + + logger.removeHandler(handler) + handler.close() + + return out_mesh_filename, out_time_file_names +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_modules/mpas_tools/viz/transects.html b/0.22.0rc4/_modules/mpas_tools/viz/transects.html new file mode 100644 index 000000000..ae73d572d --- /dev/null +++ b/0.22.0rc4/_modules/mpas_tools/viz/transects.html @@ -0,0 +1,867 @@ + + + + + + mpas_tools.viz.transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for mpas_tools.viz.transects

+import numpy
+import xarray
+
+from scipy.spatial import cKDTree
+from shapely.geometry import LineString, Point
+
+from mpas_tools.transects import (
+    cartesian_to_lon_lat,
+    lon_lat_to_cartesian,
+    subdivide_great_circle,
+    subdivide_planar
+)
+from mpas_tools.vector import Vector
+
+
+
[docs]def make_triangle_tree(dsTris): + """ + Make a KD-Tree for finding triangle edges that are near enough to transect + segments that they might intersect + + Parameters + ---------- + dsTris : xarray.Dataset + A dataset that defines triangles, the results of calling + :py:fun:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()` + + Returns + ------- + tree : scipy.spatial.cKDTree + A tree of edge centers from triangles making up an MPAS mesh + """ + + nTriangles = dsTris.sizes['nTriangles'] + nNodes = dsTris.sizes['nNodes'] + nodeCoords = numpy.zeros((nTriangles*nNodes, 3)) + nodeCoords[:, 0] = dsTris.xNode.values.ravel() + nodeCoords[:, 1] = dsTris.yNode.values.ravel() + nodeCoords[:, 2] = dsTris.zNode.values.ravel() + + nextTri, nextNode = numpy.meshgrid( + numpy.arange(nTriangles), numpy.mod(numpy.arange(nNodes) + 1, 3), + indexing='ij') + nextIndices = nNodes*nextTri.ravel() + nextNode.ravel() + + # edge centers are half way between adjacent nodes (ignoring great-circle + # distance) + edgeCoords = 0.5*(nodeCoords + nodeCoords[nextIndices, :]) + + tree = cKDTree(data=edgeCoords, copy_data=True) + return tree
+ + +
[docs]def find_transect_cells_and_weights(lonTransect, latTransect, dsTris, dsMesh, + tree, degrees=True, subdivisionRes=10e3): + """ + Find "nodes" where the transect intersects the edges of the triangles + that make up MPAS cells. + + Parameters + ---------- + lonTransect : xarray.DataArray + The longitude of segments making up the transect + + latTransect : xarray.DataArray + The latitude of segments making up the transect + + dsTris : xarray.Dataset + A dataset that defines triangles, the results of calling + :py:fun:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()` + + dsMesh : xarray.Dataset + A data set with the full MPAS mesh. + + tree : scipy.spatial.cKDTree + A tree of edge centers from triangles making up an MPAS mesh, the return + value from ``make_triangle_tree()`` + + degrees : bool, optional + Whether ``lonTransect`` and ``latTransect`` are in degrees (as opposed + to radians). + + subdivisionRes : float, optional + Resolution in m to use to subdivide the transect when looking for + intersection candidates. Should be small enough that curvature is + small. + + Returns + ------- + dsOut : xarray.Dataset + A dataset that contains "nodes" where the transect intersects the + edges of the triangles in ``dsTris``. The nodes also includes the two + end points of the transect, which typically lie within triangles. Each + internal node (that is, not including the end points) is purposefully + repeated twice, once for each triangle that node touches. This allows + for discontinuous fields between triangles (e.g. if one wishes to plot + constant values on each MPAS cell). The Cartesian and lon/lat + coordinates of these nodes are ``xCartNode``, ``yCartNode``, + ``zCartNode``, ``lonNode`` and ``latNode``. The distance along the + transect of each intersection is ``dNode``. The index of the triangle + and the first triangle node in ``dsTris`` associated with each + intersection node are given by ``horizTriangleIndices`` and + ``horizTriangleNodeIndices``, respectively. The second node on the + triangle for the edge associated with the intersection is given by + ``numpy.mod(horizTriangleNodeIndices + 1, 3)``. + + The MPAS cell that a given node belongs to is given by + ``horizCellIndices``. Each node also has an associated set of 6 + ``interpHorizCellIndices`` and ``interpHorizCellWeights`` that can be + used to interpolate from MPAS cell centers to nodes first with + area-weighted averaging to MPAS vertices and then linear interpolation + along triangle edges. Some of the weights may be zero, in which case + the associated ``interpHorizCellIndices`` will be -1. + + Finally, ``lonTransect`` and ``latTransect`` are included in the + dataset, along with Cartesian coordinates ``xCartTransect``, + ``yCartTransect``, `zCartTransect``, and ``dTransect``, the great-circle + distance along the transect of each original transect point. In order + to interpolate values (e.g. observations) from the original transect + points to the intersection nodes, linear interpolation indices + ``transectIndicesOnHorizNode`` and weights + ``transectWeightsOnHorizNode`` are provided. The values at nodes are + found by:: + + nodeValues = ((transectValues[transectIndicesOnHorizNode] * + transectWeightsOnHorizNode) + + (transectValues[transectIndicesOnHorizNode+1] * + (1.0 - transectWeightsOnHorizNode)) + """ + earth_radius = dsMesh.attrs['sphere_radius'] + buffer = numpy.maximum(numpy.amax(dsMesh.dvEdge.values), + numpy.amax(dsMesh.dcEdge.values)) + + x, y, z = lon_lat_to_cartesian(lonTransect, latTransect, earth_radius, + degrees) + + nNodes = dsTris.sizes['nNodes'] + nodeCellWeights = dsTris.nodeCellWeights.values + nodeCellIndices = dsTris.nodeCellIndices.values + + xNode = dsTris.xNode.values.ravel() + yNode = dsTris.yNode.values.ravel() + zNode = dsTris.zNode.values.ravel() + + dTransect = numpy.zeros(lonTransect.shape) + + dNode = None + xOut = None + yOut = None + zOut = None + tris = None + nodes = None + interpCells = None + cellWeights = None + + nHorizWeights = 6 + + first = True + + dStart = 0. + for segIndex in range(len(x)-1): + transectv0 = Vector(x[segIndex].values, + y[segIndex].values, + z[segIndex].values) + transectv1 = Vector(x[segIndex+1].values, + y[segIndex+1].values, + z[segIndex+1].values) + + subSlice = slice(segIndex, segIndex+2) + xSub, ySub, zSub, _, _ = subdivide_great_circle( + x[subSlice].values, y[subSlice].values, z[subSlice].values, + subdivisionRes, earth_radius) + + coords = numpy.zeros((len(xSub), 3)) + coords[:, 0] = xSub + coords[:, 1] = ySub + coords[:, 2] = zSub + radius = buffer + subdivisionRes + + indexList = tree.query_ball_point(x=coords, r=radius) + + uniqueIndices = set() + for indices in indexList: + uniqueIndices.update(indices) + + n0IndicesCand = numpy.array(list(uniqueIndices)) + + if len(n0IndicesCand) == 0: + continue + + trisCand = n0IndicesCand//nNodes + nextNodeIndex = numpy.mod(n0IndicesCand + 1, nNodes) + n1IndicesCand = nNodes * trisCand + nextNodeIndex + + n0Cand = Vector(xNode[n0IndicesCand], + yNode[n0IndicesCand], + zNode[n0IndicesCand]) + n1Cand = Vector(xNode[n1IndicesCand], + yNode[n1IndicesCand], + zNode[n1IndicesCand]) + + intersect = Vector.intersects(n0Cand, n1Cand, transectv0, + transectv1) + + n0Inter = Vector(n0Cand.x[intersect], + n0Cand.y[intersect], + n0Cand.z[intersect]) + n1Inter = Vector(n1Cand.x[intersect], + n1Cand.y[intersect], + n1Cand.z[intersect]) + + trisInter = trisCand[intersect] + n0IndicesInter = n0IndicesCand[intersect] + n1IndicesInter = n1IndicesCand[intersect] + + intersections = Vector.intersection(n0Inter, n1Inter, transectv0, + transectv1) + intersections = Vector(earth_radius*intersections.x, + earth_radius*intersections.y, + earth_radius*intersections.z) + + angularDistance = transectv0.angular_distance(intersections) + + dNodeLocal = dStart + earth_radius * angularDistance + + dStart += earth_radius*transectv0.angular_distance(transectv1) + + node0Inter = numpy.mod(n0IndicesInter, nNodes) + node1Inter = numpy.mod(n1IndicesInter, nNodes) + + nodeWeights = (intersections.angular_distance(n1Inter) / + n0Inter.angular_distance(n1Inter)) + + weights = numpy.zeros((len(trisInter), nHorizWeights)) + cellIndices = numpy.zeros((len(trisInter), nHorizWeights), int) + for index in range(3): + weights[:, index] = (nodeWeights * + nodeCellWeights[trisInter, node0Inter, index]) + cellIndices[:, index] = \ + nodeCellIndices[trisInter, node0Inter, index] + weights[:, index+3] = ((1.0 - nodeWeights) * + nodeCellWeights[trisInter, node1Inter, index]) + cellIndices[:, index+3] = \ + nodeCellIndices[trisInter, node1Inter, index] + + if first: + xOut = intersections.x + yOut = intersections.y + zOut = intersections.z + dNode = dNodeLocal + + tris = trisInter + nodes = node0Inter + interpCells = cellIndices + cellWeights = weights + first = False + else: + xOut = numpy.append(xOut, intersections.x) + yOut = numpy.append(yOut, intersections.y) + zOut = numpy.append(zOut, intersections.z) + dNode = numpy.append(dNode, dNodeLocal) + + tris = numpy.concatenate((tris, trisInter)) + nodes = numpy.concatenate((nodes, node0Inter)) + interpCells = numpy.concatenate((interpCells, cellIndices), axis=0) + cellWeights = numpy.concatenate((cellWeights, weights), axis=0) + + dTransect[segIndex + 1] = dStart + + epsilon = 1e-6*subdivisionRes + dNode, xOut, yOut, zOut, tris, nodes, interpCells, cellWeights = \ + _sort_intersections(dNode, tris, nodes, xOut, yOut, zOut, interpCells, + cellWeights, epsilon) + + dNode, xOut, yOut, zOut, tris, nodes, interpCells, cellWeights = \ + _update_start_end_triangles(tris, nodes, interpCells, cellWeights, + dNode, xOut, yOut, zOut, dStart, x, y, z) + + lonOut, latOut = cartesian_to_lon_lat(xOut, yOut, zOut, earth_radius, + degrees) + + nSegments = len(xOut)//2 + nBounds = 2 + + cellIndices = dsTris.triCellIndices.values[tris] + nodes = nodes.reshape((nSegments, nBounds)) + dNode = dNode.reshape((nSegments, nBounds)) + + dsOut = xarray.Dataset() + dsOut['xCartNode'] = (('nSegments', 'nBounds'), + xOut.reshape((nSegments, nBounds))) + dsOut['yCartNode'] = (('nSegments', 'nBounds'), + yOut.reshape((nSegments, nBounds))) + dsOut['zCartNode'] = (('nSegments', 'nBounds'), + zOut.reshape((nSegments, nBounds))) + dsOut['dNode'] = (('nSegments', 'nBounds'), dNode) + dsOut['lonNode'] = (('nSegments', 'nBounds'), + lonOut.reshape((nSegments, nBounds))) + dsOut['latNode'] = (('nSegments', 'nBounds'), + latOut.reshape((nSegments, nBounds))) + + dsOut['horizTriangleIndices'] = ('nSegments', tris) + dsOut['horizCellIndices'] = ('nSegments', cellIndices) + dsOut['horizTriangleNodeIndices'] = (('nSegments', 'nBounds'), nodes) + dsOut['interpHorizCellIndices'] = \ + (('nSegments', 'nBounds', 'nHorizWeights'), + interpCells.reshape((nSegments, nBounds, nHorizWeights))) + dsOut['interpHorizCellWeights'] = \ + (('nSegments', 'nBounds', 'nHorizWeights'), + cellWeights.reshape((nSegments, nBounds, nHorizWeights))) + + transectIndicesOnHorizNode = numpy.zeros(dNode.shape, int) + transectWeightsOnHorizNode = numpy.zeros(dNode.shape) + for segIndex in range(len(dTransect)-1): + d0 = dTransect[segIndex] + d1 = dTransect[segIndex+1] + mask = numpy.logical_and(dNode >= d0, dNode < d1) + transectIndicesOnHorizNode[mask] = segIndex + transectWeightsOnHorizNode[mask] = (d1 - dNode[mask])/(d1 - d0) + # last index will get missed by the mask and needs to be handled as a + # special case + transectIndicesOnHorizNode[-1, 1] = len(dTransect)-2 + transectWeightsOnHorizNode[-1, 1] = 0.0 + + dsOut['lonTransect'] = lonTransect + dsOut['latTransect'] = latTransect + dsOut['xCartTransect'] = x + dsOut['yCartTransect'] = y + dsOut['zCartTransect'] = z + dsOut['dTransect'] = (lonTransect.dims, dTransect) + dsOut['transectIndicesOnHorizNode'] = (('nSegments', 'nBounds'), + transectIndicesOnHorizNode) + dsOut['transectWeightsOnHorizNode'] = (('nSegments', 'nBounds'), + transectWeightsOnHorizNode) + + return dsOut
+ + +
[docs]def find_planar_transect_cells_and_weights(xTransect, yTransect, dsTris, dsMesh, + tree, subdivisionRes=10e3): + """ + Find "nodes" where the transect intersects the edges of the triangles + that make up MPAS cells. + + Parameters + ---------- + xTransect : xarray.DataArray + The x points defining segments making up the transect + + yTransect : xarray.DataArray + The y points defining segments making up the transect + + dsTris : xarray.Dataset + A dataset that defines triangles, the results of calling + `:py:fun:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()` + + dsMesh : xarray.Dataset + A data set with the full MPAS mesh. + + tree : scipy.spatial.cKDTree + A tree of edge centers from triangles making up an MPAS mesh, the return + value from ``make_triangle_tree()`` + + subdivisionRes : float, optional + Resolution in m to use to subdivide the transect when looking for + intersection candidates. Should be small enough that curvature is + small. + + Returns + ------- + dsOut : xarray.Dataset + A dataset that contains "nodes" where the transect intersects the + edges of the triangles in ``dsTris``. The nodes also include the two + end points of the transect, which typically lie within triangles. Each + internal node (that is, not including the end points) is purposefully + repeated twice, once for each triangle that node touches. This allows + for discontinuous fields between triangles (e.g. if one wishes to plot + constant values on each MPAS cell). The planar coordinates of these + nodes are ``xNode`` and ``yNode``. The distance along the transect of + each intersection is ``dNode``. The index of the triangle and the first + triangle node in ``dsTris`` associated with each intersection node are + given by ``horizTriangleIndices`` and ``horizTriangleNodeIndices``, + respectively. The second node on the triangle for the edge associated + with the intersection is given by + ``numpy.mod(horizTriangleNodeIndices + 1, 3)``. + + The MPAS cell that a given node belongs to is given by + ``horizCellIndices``. Each node also has an associated set of 6 + ``interpHorizCellIndices`` and ``interpHorizCellWeights`` that can be + used to interpolate from MPAS cell centers to nodes first with + area-weighted averaging to MPAS vertices and then linear interpolation + along triangle edges. Some of the weights may be zero, in which case + the associated ``interpHorizCellIndices`` will be -1. + + Finally, ``xTransect`` and ``yTransect`` are included in the + dataset, along with ``dTransect``, the distance along the transect of + each original transect point. In order to interpolate values (e.g. + observations) from the original transect points to the intersection + nodes, linear interpolation indices ``transectIndicesOnHorizNode`` and + weights ``transectWeightsOnHorizNode`` are provided. The values at + nodes are found by:: + + nodeValues = ((transectValues[transectIndicesOnHorizNode] * + transectWeightsOnHorizNode) + + (transectValues[transectIndicesOnHorizNode+1] * + (1.0 - transectWeightsOnHorizNode)) + """ + buffer = numpy.maximum(numpy.amax(dsMesh.dvEdge.values), + numpy.amax(dsMesh.dcEdge.values)) + + nNodes = dsTris.sizes['nNodes'] + nodeCellWeights = dsTris.nodeCellWeights.values + nodeCellIndices = dsTris.nodeCellIndices.values + + x = xTransect + y = yTransect + + xNode = dsTris.xNode.values.ravel() + yNode = dsTris.yNode.values.ravel() + + coordNode = numpy.zeros((len(xNode), 2)) + coordNode[:, 0] = xNode + coordNode[:, 1] = yNode + + dTransect = numpy.zeros(xTransect.shape) + + dNode = None + xOut = None + yOut = None + tris = None + nodes = None + interpCells = None + cellWeights = None + + nHorizWeights = 6 + + first = True + + dStart = 0. + for segIndex in range(len(x)-1): + + subSlice = slice(segIndex, segIndex+2) + xSub, ySub, _, _ = subdivide_planar( + x[subSlice].values, y[subSlice].values, subdivisionRes) + + startPoint = Point(xTransect[segIndex].values, + yTransect[segIndex].values) + endPoint = Point(xTransect[segIndex+1].values, + yTransect[segIndex+1].values) + + segment = LineString([startPoint, endPoint]) + + coords = numpy.zeros((len(xSub), 3)) + coords[:, 0] = xSub + coords[:, 1] = ySub + radius = buffer + subdivisionRes + + indexList = tree.query_ball_point(x=coords, r=radius) + + uniqueIndices = set() + for indices in indexList: + uniqueIndices.update(indices) + + startIndices = numpy.array(list(uniqueIndices)) + + if len(startIndices) == 0: + continue + + trisCand = startIndices//nNodes + nextNodeIndex = numpy.mod(startIndices + 1, nNodes) + endIndices = nNodes * trisCand + nextNodeIndex + + intersectingNodes = list() + trisInter = list() + xIntersection = list() + yIntersection = list() + nodeWeights = list() + node0Inter = list() + node1Inter = list() + distances = list() + + for index in range(len(startIndices)): + start = startIndices[index] + end = endIndices[index] + + node0 = Point(coordNode[start, 0], coordNode[start, 1]) + node1 = Point(coordNode[end, 0], coordNode[end, 1]) + + edge = LineString([node0, node1]) + if segment.intersects(edge): + point = segment.intersection(edge) + intersectingNodes.append((node0, node1, start, end, edge)) + + if isinstance(point, LineString): + raise ValueError('A triangle edge exactly coincides with a ' + 'transect segment and I can\'t handle ' + 'that case. Try moving the transect a ' + 'tiny bit.') + elif not isinstance(point, Point): + raise ValueError(f'Unexpected intersection type {point}') + + xIntersection.append(point.x) + yIntersection.append(point.y) + + startToIntersection = LineString([startPoint, point]) + + weight = (LineString([point, node1]).length / + LineString([node0, node1]).length) + + nodeWeights.append(weight) + node0Inter.append(numpy.mod(start, nNodes)) + node1Inter.append(numpy.mod(end, nNodes)) + distances.append(startToIntersection.length) + trisInter.append(trisCand[index]) + + distances = numpy.array(distances) + xIntersection = numpy.array(xIntersection) + yIntersection = numpy.array(yIntersection) + nodeWeights = numpy.array(nodeWeights) + node0Inter = numpy.array(node0Inter) + node1Inter = numpy.array(node1Inter) + trisInter = numpy.array(trisInter) + + dNodeLocal = dStart + distances + + dStart += segment.length + + weights = numpy.zeros((len(trisInter), nHorizWeights)) + cellIndices = numpy.zeros((len(trisInter), nHorizWeights), int) + for index in range(3): + weights[:, index] = (nodeWeights * + nodeCellWeights[trisInter, node0Inter, index]) + cellIndices[:, index] = \ + nodeCellIndices[trisInter, node0Inter, index] + weights[:, index+3] = ((1.0 - nodeWeights) * + nodeCellWeights[trisInter, node1Inter, index]) + cellIndices[:, index+3] = \ + nodeCellIndices[trisInter, node1Inter, index] + + if first: + xOut = xIntersection + yOut = yIntersection + dNode = dNodeLocal + + tris = trisInter + nodes = node0Inter + interpCells = cellIndices + cellWeights = weights + first = False + else: + xOut = numpy.append(xOut, xIntersection) + yOut = numpy.append(yOut, yIntersection) + dNode = numpy.append(dNode, dNodeLocal) + + tris = numpy.concatenate((tris, trisInter)) + nodes = numpy.concatenate((nodes, node0Inter)) + interpCells = numpy.concatenate((interpCells, cellIndices), axis=0) + cellWeights = numpy.concatenate((cellWeights, weights), axis=0) + + dTransect[segIndex + 1] = dStart + + zOut = numpy.zeros(xOut.shape) + z = xarray.zeros_like(x) + + epsilon = 1e-6*subdivisionRes + dNode, xOut, yOut, zOut, tris, nodes, interpCells, cellWeights = \ + _sort_intersections(dNode, tris, nodes, xOut, yOut, zOut, interpCells, + cellWeights, epsilon) + + dNode, xOut, yOut, zOut, tris, nodes, interpCells, cellWeights = \ + _update_start_end_triangles(tris, nodes, interpCells, cellWeights, + dNode, xOut, yOut, zOut, dStart, x, y, z) + + nSegments = len(xOut)//2 + nBounds = 2 + + cellIndices = dsTris.triCellIndices.values[tris] + nodes = nodes.reshape((nSegments, nBounds)) + dNode = dNode.reshape((nSegments, nBounds)) + + dsOut = xarray.Dataset() + dsOut['xNode'] = (('nSegments', 'nBounds'), + xOut.reshape((nSegments, nBounds))) + dsOut['yNode'] = (('nSegments', 'nBounds'), + yOut.reshape((nSegments, nBounds))) + dsOut['dNode'] = (('nSegments', 'nBounds'), dNode) + + dsOut['horizTriangleIndices'] = ('nSegments', tris) + dsOut['horizCellIndices'] = ('nSegments', cellIndices) + dsOut['horizTriangleNodeIndices'] = (('nSegments', 'nBounds'), nodes) + dsOut['interpHorizCellIndices'] = \ + (('nSegments', 'nBounds', 'nHorizWeights'), + interpCells.reshape((nSegments, nBounds, nHorizWeights))) + dsOut['interpHorizCellWeights'] = \ + (('nSegments', 'nBounds', 'nHorizWeights'), + cellWeights.reshape((nSegments, nBounds, nHorizWeights))) + + transectIndicesOnHorizNode = numpy.zeros(dNode.shape, int) + transectWeightsOnHorizNode = numpy.zeros(dNode.shape) + for segIndex in range(len(dTransect)-1): + d0 = dTransect[segIndex] + d1 = dTransect[segIndex+1] + mask = numpy.logical_and(dNode >= d0, dNode < d1) + transectIndicesOnHorizNode[mask] = segIndex + transectWeightsOnHorizNode[mask] = (d1 - dNode[mask])/(d1 - d0) + # last index will get missed by the mask and needs to be handled as a + # special case + transectIndicesOnHorizNode[-1, 1] = len(dTransect)-2 + transectWeightsOnHorizNode[-1, 1] = 0.0 + + dsOut['xTransect'] = x + dsOut['yTransect'] = y + dsOut['dTransect'] = (xTransect.dims, dTransect) + dsOut['transectIndicesOnHorizNode'] = (('nSegments', 'nBounds'), + transectIndicesOnHorizNode) + dsOut['transectWeightsOnHorizNode'] = (('nSegments', 'nBounds'), + transectWeightsOnHorizNode) + + return dsOut
+ + +def _sort_intersections(dNode, tris, nodes, xOut, yOut, zOut, interpCells, + cellWeights, epsilon): + """ sort nodes by distance """ + + sortIndices = numpy.argsort(dNode) + dSorted = dNode[sortIndices] + trisSorted = tris[sortIndices] + + nodesAreSame = numpy.abs(dSorted[1:] - dSorted[:-1]) < epsilon + if nodesAreSame[0]: + # the first two nodes are the same, so the first transect point is in a + # triangle, and we need to figure out which + if trisSorted[1] == trisSorted[2] or trisSorted[1] == trisSorted[3]: + # the first transect point is in trisSorted[0], so the first two + # nodes are in the right order + indices = [0, 1] + elif trisSorted[0] == trisSorted[2] or trisSorted[0] == trisSorted[3]: + # the first transect point is in trisSorted[1], so the first two + # nodes need to be swapped + indices = [1, 0] + else: + raise ValueError('Couldn\'t find an order for the first two nodes') + else: + # the first transect point is outside of an MPAS cell + indices = [0] + + while len(indices) < len(sortIndices): + index = len(indices) + currentTri = trisSorted[indices[-1]] + if index < len(nodesAreSame) and nodesAreSame[index]: + # the next two nodes are the same, so we need to know which + # corresponds to the current triangle + if trisSorted[index] == currentTri: + # the first node is in the current triangle, so add the next + # two nodes in the current order + indices.extend([index, index+1]) + elif trisSorted[index+1] == currentTri: + # the second node is in the current triangle, so add the next + # two nodes in swapped order + indices.extend([index+1, index]) + else: + print(trisSorted[index:index+2], currentTri) + raise ValueError('Couldn\'t find an order for nodes {} and ' + '{}'.format(index, index+1)) + else: + # the next node is a boundary of the MPAS domain, so there is no + # ambiguity about order and we just add it + indices.extend([index]) + + indices = sortIndices[indices] + + dNode = dNode[indices] + xOut = xOut[indices] + yOut = yOut[indices] + zOut = zOut[indices] + + tris = tris[indices] + nodes = nodes[indices] + interpCells = interpCells[indices, :] + cellWeights = cellWeights[indices, :] + + return dNode, xOut, yOut, zOut, tris, nodes, interpCells, cellWeights + + +def _update_start_end_triangles(tris, nodes, interpCells, cellWeights, dNode, + xOut, yOut, zOut, dStart, x, y, z): + """ + figure out if the end points of the transect are in a triangle and add tris, + nodes, interpCells and cellWeights if so + """ + + if len(tris) >= 2 and tris[0] != tris[1]: + # the starting point is in a triangle so we need to duplicate the first + # entry in several fields to handle this + tris = numpy.concatenate((tris[0:1], tris)) + nodes = numpy.concatenate((nodes[0:1], nodes)) + interpCells = numpy.concatenate((interpCells[0:1, :], interpCells), + axis=0) + cellWeights = numpy.concatenate((cellWeights[0:1, :], cellWeights), + axis=0) + + dNode = numpy.append(numpy.array([0.]), dNode) + xOut = numpy.append(x[0].values, xOut) + yOut = numpy.append(y[0].values, yOut) + zOut = numpy.append(z[0].values, zOut) + + if len(tris) >= 2 and tris[-1] != tris[-2]: + # the end point is in a triangle so we need to add final entries or + # duplicate the last entry in several fields to handle this + tris = numpy.concatenate((tris, tris[-1:])) + nodes = numpy.concatenate((nodes, nodes[-1:])) + interpCells = numpy.concatenate((interpCells, interpCells[-1:, :]), + axis=0) + cellWeights = numpy.concatenate((cellWeights, cellWeights[-1:, :]), + axis=0) + + dNode = numpy.append(dNode, dStart) + xOut = numpy.append(xOut, x[-1].values) + yOut = numpy.append(yOut, y[-1].values) + zOut = numpy.append(zOut, z[-1].values) + + assert(numpy.all(tris[0::2] == tris[1::2])) + + tris = tris[0::2] + + return dNode, xOut, yOut, zOut, tris, nodes, interpCells, cellWeights +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/_sources/api.rst.txt b/0.22.0rc4/_sources/api.rst.txt new file mode 100644 index 000000000..c5c89144a --- /dev/null +++ b/0.22.0rc4/_sources/api.rst.txt @@ -0,0 +1,361 @@ +############# +API reference +############# + +This page provides an auto-generated summary of the MPAS mesh-tools API. For +more details and examples, refer to the relevant chapters in the main part of +the documentation. + +MPAS mesh tools +=============== + +Mesh creation +------------- + +.. currentmodule:: mpas_tools.planar_hex + +.. autosummary:: + :toctree: generated/ + + make_planar_hex_mesh + +.. currentmodule:: mpas_tools.mesh.creation + +.. autosummary:: + :toctree: generated/ + + build_mesh + build_mesh.build_spherical_mesh + build_mesh.build_planar_mesh + jigsaw_driver.jigsaw_driver + jigsaw_to_netcdf.jigsaw_to_netcdf + mesh_definition_tools + mesh_definition_tools.mergeCellWidthVsLat + mesh_definition_tools.EC_CellWidthVsLat + mesh_definition_tools.RRS_CellWidthVsLat + mesh_definition_tools.AtlanticPacificGrid + mpas_to_triangle.mpas_to_triangle + signed_distance + signed_distance.signed_distance_from_geojson + signed_distance.mask_from_geojson + signed_distance.distance_from_geojson + triangle_to_netcdf.triangle_to_netcdf + +Mesh conversion +--------------- + +.. currentmodule:: mpas_tools.mesh.conversion + +.. autosummary:: + :toctree: generated/ + + convert + cull + mask + +.. currentmodule:: mpas_tools.mesh.mask + +.. autosummary:: + :toctree: generated/ + + compute_mpas_region_masks + compute_mpas_transect_masks + compute_mpas_flood_fill_mask + compute_lon_lat_region_masks + +.. currentmodule:: mpas_tools.merge_grids + +.. autosummary:: + :toctree: generated/ + + merge_grids + +.. currentmodule:: mpas_tools.split_grids + +.. autosummary:: + :toctree: generated/ + + split_grids + +.. currentmodule:: mpas_tools.translate + +.. autosummary:: + :toctree: generated/ + + translate + center + center_on_mesh + +.. currentmodule:: mpas_tools.scrip.from_mpas + +.. autosummary:: + :toctree: generated/ + + scrip_from_mpas + +Config +------ + +.. currentmodule:: mpas_tools.config + +.. autosummary:: + :toctree: generated/ + + MpasConfigParser + MpasConfigParser.add_user_config + MpasConfigParser.add_from_file + MpasConfigParser.add_from_package + MpasConfigParser.get + MpasConfigParser.getint + MpasConfigParser.getfloat + MpasConfigParser.getboolean + MpasConfigParser.getlist + MpasConfigParser.getexpression + MpasConfigParser.has_section + MpasConfigParser.has_option + MpasConfigParser.set + MpasConfigParser.write + MpasConfigParser.copy + MpasConfigParser.__getitem__ + +I/O +--- + +.. currentmodule:: mpas_tools.io + +.. autosummary:: + :toctree: generated/ + + write_netcdf + +Parallelism +----------- + +.. currentmodule:: mpas_tools.parallel + +.. autosummary:: + :toctree: generated/ + + create_pool + +Interpolation +------------- + +.. currentmodule:: mpas_tools.mesh.interpolation + +.. autosummary:: + :toctree: generated/ + + interp_bilin + +CIME constants +-------------- + +.. currentmodule:: mpas_tools.cime + +.. autosummary:: + :toctree: generated/ + + constants + +Ocean Tools +=========== + +.. currentmodule:: mpas_tools.ocean + +.. autosummary:: + :toctree: generated/ + + coastline_alteration + coastline_alteration.add_critical_land_blockages + coastline_alteration.widen_transect_edge_masks + coastline_alteration.add_land_locked_cells_to_mask + + moc + moc.make_moc_basins_and_transects + moc.add_moc_southern_boundary_transects + + build_mesh + build_mesh.build_spherical_mesh + build_mesh.build_planar_mesh + + coastal_tools + coastal_tools.coastal_refined_mesh + coastal_tools.create_background_mesh + coastal_tools.extract_coastlines + coastal_tools.distance_to_coast + coastal_tools.compute_cell_width + coastal_tools.save_matfile + coastal_tools.CPP_projection + coastal_tools.smooth_coastline + coastal_tools.get_data_inside_box + coastal_tools.get_indices_inside_quad + coastal_tools.get_convex_hull_coordinates + coastal_tools.plot_coarse_coast + coastal_tools.plot_region_box + + depth.add_depth + depth.add_zmid + depth.write_time_varying_zmid + depth.compute_depth + depth.compute_zmid + +.. currentmodule:: mpas_tools.ocean.inject_bathymetry + +.. autosummary:: + :toctree: generated/ + + inject_bathymetry + +.. currentmodule:: mpas_tools.ocean.inject_meshDensity + +.. autosummary:: + :toctree: generated/ + + inject_meshDensity_from_file + inject_spherical_meshDensity + inject_planar_meshDensity + +.. currentmodule:: mpas_tools.ocean.inject_preserve_floodplain + +.. autosummary:: + :toctree: generated/ + + inject_preserve_floodplain + + +.. currentmodule:: mpas_tools.ocean.transects + +.. autosummary:: + :toctree: generated/ + + find_transect_levels_and_weights + interp_mpas_to_transect_triangles + interp_mpas_to_transect_triangle_nodes + interp_transect_grid_to_transect_triangle_nodes + get_outline_segments + +.. currentmodule:: mpas_tools.ocean.viz + +.. autosummary:: + :toctree: generated/ + + plot_ocean_transects + add_inset + +Sea-ice Tools +============= + +.. currentmodule:: mpas_tools.seaice.mask + +.. autosummary:: + :toctree: generated/ + + extend_seaice_mask + +.. currentmodule:: mpas_tools.seaice.mesh + +.. autosummary:: + :toctree: generated/ + + write_scrip_file + write_2D_scripfile + make_mpas_scripfile_on_cells + make_mpas_scripfile_on_vertices + +.. currentmodule:: mpas_tools.seaice.partition + +.. autosummary:: + :toctree: generated/ + + gen_seaice_mesh_partition + prepare_partitions + create_partitions + +.. currentmodule:: mpas_tools.seaice.regions + +.. autosummary:: + :toctree: generated/ + + make_regions_file + +.. currentmodule:: mpas_tools.seaice.regrid + +.. autosummary:: + :toctree: generated/ + + regrid_to_other_mesh + +Logging +======= + +.. currentmodule:: mpas_tools.logging + +.. autosummary:: + :toctree: generated/ + + check_call + LoggingContext + +Transects +========= + +.. currentmodule:: mpas_tools.transects + +.. autosummary:: + :toctree: generated/ + + subdivide_great_circle + cartesian_to_great_circle_distance + subdivide_planar + lon_lat_to_cartesian + cartesian_to_lon_lat + angular_distance + intersects + intersection + Vector + + +Visualization +============= + +.. currentmodule:: mpas_tools.viz.paraview_extractor + +.. autosummary:: + :toctree: generated/ + + extract_vtk + +.. currentmodule:: mpas_tools.viz.mesh_to_triangles + +.. autosummary:: + :toctree: generated/ + + mesh_to_triangles + +.. currentmodule:: mpas_tools.viz.transects + +.. autosummary:: + :toctree: generated/ + + make_triangle_tree + find_transect_cells_and_weights + find_planar_transect_cells_and_weights + +.. currentmodule:: mpas_tools.viz.colormaps + +.. autosummary:: + :toctree: generated/ + + register_sci_viz_colormaps + +Tests +===== + +.. currentmodule:: mpas_tools.tests.test_cime_constants + +.. autosummary:: + :toctree: generated/ + + test_cime_constants + diff --git a/0.22.0rc4/_sources/authors.rst.txt b/0.22.0rc4/_sources/authors.rst.txt new file mode 100644 index 000000000..13e64be2a --- /dev/null +++ b/0.22.0rc4/_sources/authors.rst.txt @@ -0,0 +1,27 @@ +Main Authors +============ +* Xylar Asay-Davis +* Michael Duda +* Matthew Hoffman +* Douglas Jacobsen + +Contributors +============ +* Riley X. Brady +* Miles Curry +* Amrapalli Garanaik +* Dom Heinzeller +* Trevor Hillebrand +* Joseph Kennedy +* William Lipscomb +* Mark Petersen +* Stephen Price +* Todd Ringler +* Juan Saenz +* Adrian Turner +* Luke Van Roekel +* Phillip J. Wolfram +* Tong Zhang + +For a list of all the contributions: +https://github.com/MPAS-Dev/MPAS-Tools/graphs/contributors diff --git a/0.22.0rc4/_sources/building_docs.rst.txt b/0.22.0rc4/_sources/building_docs.rst.txt new file mode 100644 index 000000000..189014ba7 --- /dev/null +++ b/0.22.0rc4/_sources/building_docs.rst.txt @@ -0,0 +1,18 @@ +.. _dev_building_docs: + +************************** +Building the Documentation +************************** + +To make a local test build of the documentation, it is easiest to follow the +:ref:`dev_testing_changes` procedure for how to make a local build of the +``mpas_tools`` package. The development environment includes the packages +needed to build the documentation. Simply run: + +code-block:: + + export DOCS_VERSION="test" + cd conda_package/docs + make html + +Then, you can view the documentation by opening ``_build/html/index.html``. diff --git a/0.22.0rc4/_sources/cime.rst.txt b/0.22.0rc4/_sources/cime.rst.txt new file mode 100644 index 000000000..30a525dd5 --- /dev/null +++ b/0.22.0rc4/_sources/cime.rst.txt @@ -0,0 +1,27 @@ +.. _cime_mod: + +CIME Constants +============== + +The module :py:mod:`mpas_tools.cime.constants` contains constants that are in +sync with `CIME `_, which provides infrastructure +and utilities for Earth System Models such at E3SM. Currently, we sync only +those constants given numerical values in CIME, not those that are derivied +from other constants. Constants are checked against their values on CIME's +master branch during tests of the conda build. See +:py:func:`mpas_tools.tests.test_cime_constants.test_cime_constants`. + +Some of the constants most likely to be useful in MPAS-Tools, COMPASS and other +related projects are: + +* ``SHR_CONST_CDAY`` - sec in calendar day (s) +* ``SHR_CONST_REARTH`` - radius of Earth (m) +* ``SHR_CONST_G`` - acceleration of gravity (m/s^2) +* ``SHR_CONST_RHOFW`` - density of fresh water (kg/m^3) +* ``SHR_CONST_RHOSW`` - density of sea water (kg/m^3) +* ``SHR_CONST_RHOICE`` - density of ice (kg/m^3) +* ``SHR_CONST_CPFW`` - specific heat of fresh water (J/kg/K) +* ``SHR_CONST_CPSW`` - specific heat of sea water (J/kg/K) +* ``SHR_CONST_CPICE`` - specific heat of fresh ice (J/kg/K) +* ``SHR_CONST_LATICE`` - latent heat of fusion (J/kg) +* ``SHR_CONST_LATVAP`` - latent heat of evaporation (J/kg) diff --git a/0.22.0rc4/_sources/config.rst.txt b/0.22.0rc4/_sources/config.rst.txt new file mode 100644 index 000000000..06f1d36e1 --- /dev/null +++ b/0.22.0rc4/_sources/config.rst.txt @@ -0,0 +1,93 @@ +.. _config_mod: + +Config files +============ + +The ``mpas_tools.config`` module includes the +:py:class:`mpas_tools.config.MpasConfigParser` class reading, getting, setting, +and writing config options and config files. + +The :py:meth:`mpas_tools.config.MpasConfigParser.add_from_package()` method can +be used to add the contents of a config file within a package to the config +options. + +Here is an example from `compass `_ +.. code-block:: python + + self.config.add_from_package( + 'compass.ocean.tests.global_ocean.make_diagnostics_files', + 'make_diagnostics_files.cfg', exception=True) + +The first and second arguments are the name of a package containing the config +file and the name of the config file itself, respectively. You can see that +the file is in the path ``compass/ocean/tests/global_ocean/make_diagnostics_files`` +(replacing the ``.`` in the module name with ``/``). In this case, we know +that the config file should always exist, so we would like the code to raise +an exception (``exception=True``) if the file is not found. This is the +default behavior. In some cases, you would like the code to add the config +options if the config file exists and do nothing if it does not +(``exception=False``). + +Ihe ``MpasConfigParser`` class also includes methods for adding a user +config file, :py:meth:`mpas_tools.config.MpasConfigParser.add_user_config()`, +and other config files by file name, +:py:meth:`mpas_tools.config.MpasConfigParser.add_from_file()`. + +The :py:meth:`mpas_tools.config.MpasConfigParser.copy()` method can be used to +make a deep copy of the config parser. This is useful in cases where config +options should be added or modified without affecting the original config +object. For example, this feature is used in MPAS-Analysis to set a reference +year as the start year in some analysis without affecting the start year in +other analysis. + +The :py:meth:`mpas_tools.config.MpasConfigParser.set()` method has some +optional arguments not present in :py:class:`configparser.ConfigParser.set()`. +The ``comment`` argument can be used to add a comment that will be written +out above the config option. The comment can cover multiple lines by including +a ``\n`` character. The comment should not include the ``#`` comment +character, as this is added automatically. The argument ``user=True`` can be +used to set "user" config options similar to reading a user config file with +:py:meth:`mpas_tools.config.MpasConfigParser.add_user_config()`. + +Other methods for the ``MpasConfigParser`` are similar to those for +:py:class:`configparser.ConfigParser`. In addition to ``get()``, +``getinteger()``, ``getfloat()`` and ``getboolean()`` methods, this class +implements :py:meth:`mpas_tools.config.MpasConfigParser.getlist()`, which +can be used to parse a config value separated by spaces and/or commas into +a list of strings, floats, integers, booleans, etc. Another useful method +is :py:meth:`mpas_tools.config.MpasConfigParser.getexpression()`, which can +be used to get python dictionaries, lists and tuples as well as a small set +of functions (``range()``, :py:meth:`numpy.linspace()`, +:py:meth:`numpy.arange()`, and :py:meth:`numpy.array()`) + +Currently, ``MpasConfigParser`` supports accessing a config section using +section names as keys, e.g.: + +.. code-block:: python + + section = self.config['enthalpy_benchmark_viz'] + display_image = section.getboolean('display_image') + ... + +But it does not allow assignment of a section or many of the other +dictionary-like features supported by :py:class:`configparser.ConfigParser`. + +.. _config_comments: + +Comments in config files +------------------------ + +One of the main advantages of :py:class:`mpas_tools.config.MpasConfigParser` +over :py:class:`configparser.ConfigParser` is that it keeps track of comments +that are associated with config sections and options. There are a few "rules" +that make this possible. + +Comments must begin with the ``#`` character. They must be placed *before* the +config section or option in question (preferably without blank lines between). +The comments can be any number of lines. + +.. note:: + + Inline comments (after a config option on the same line) are not allowed + and will be parsed as part of the config option itself. + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.cime.constants.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.cime.constants.rst.txt new file mode 100644 index 000000000..730e02aa5 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.cime.constants.rst.txt @@ -0,0 +1,23 @@ +mpas\_tools.cime.constants +========================== + +.. automodule:: mpas_tools.cime.constants + + + + + + + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.__getitem__.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.__getitem__.rst.txt new file mode 100644 index 000000000..56cbe8b63 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.__getitem__.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.\_\_getitem\_\_ +=================================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.__getitem__ \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_from_file.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_from_file.rst.txt new file mode 100644 index 000000000..c453d1575 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_from_file.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.add\_from\_file +=================================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.add_from_file \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_from_package.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_from_package.rst.txt new file mode 100644 index 000000000..bc46913e7 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_from_package.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.add\_from\_package +====================================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.add_from_package \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_user_config.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_user_config.rst.txt new file mode 100644 index 000000000..3214495b7 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.add_user_config.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.add\_user\_config +===================================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.add_user_config \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.copy.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.copy.rst.txt new file mode 100644 index 000000000..bd82b04da --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.copy.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.copy +======================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.copy \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.get.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.get.rst.txt new file mode 100644 index 000000000..6502bbb08 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.get.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.get +======================================= + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.get \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getboolean.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getboolean.rst.txt new file mode 100644 index 000000000..b548576da --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getboolean.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.getboolean +============================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.getboolean \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getexpression.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getexpression.rst.txt new file mode 100644 index 000000000..ce32579c3 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getexpression.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.getexpression +================================================= + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.getexpression \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getfloat.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getfloat.rst.txt new file mode 100644 index 000000000..f41a22132 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getfloat.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.getfloat +============================================ + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.getfloat \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getint.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getint.rst.txt new file mode 100644 index 000000000..f8b0641b3 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getint.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.getint +========================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.getint \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getlist.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getlist.rst.txt new file mode 100644 index 000000000..8e48b659b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.getlist.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.getlist +=========================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.getlist \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.has_option.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.has_option.rst.txt new file mode 100644 index 000000000..321083a3d --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.has_option.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.has\_option +=============================================== + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.has_option \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.has_section.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.has_section.rst.txt new file mode 100644 index 000000000..909ebd774 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.has_section.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.has\_section +================================================ + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.has_section \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.rst.txt new file mode 100644 index 000000000..6bb26766f --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.rst.txt @@ -0,0 +1,38 @@ +mpas\_tools.config.MpasConfigParser +=================================== + +.. currentmodule:: mpas_tools.config + +.. autoclass:: MpasConfigParser + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~MpasConfigParser.__init__ + ~MpasConfigParser.add_from_file + ~MpasConfigParser.add_from_package + ~MpasConfigParser.add_user_config + ~MpasConfigParser.combine + ~MpasConfigParser.copy + ~MpasConfigParser.get + ~MpasConfigParser.getboolean + ~MpasConfigParser.getexpression + ~MpasConfigParser.getfloat + ~MpasConfigParser.getint + ~MpasConfigParser.getlist + ~MpasConfigParser.has_option + ~MpasConfigParser.has_section + ~MpasConfigParser.list_files + ~MpasConfigParser.set + ~MpasConfigParser.write + + + + + + \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.set.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.set.rst.txt new file mode 100644 index 000000000..2c4c88ecd --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.set.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.set +======================================= + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.set \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.write.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.write.rst.txt new file mode 100644 index 000000000..6620868d2 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.config.MpasConfigParser.write.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.config.MpasConfigParser.write +========================================= + +.. currentmodule:: mpas_tools.config + +.. automethod:: MpasConfigParser.write \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.io.write_netcdf.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.io.write_netcdf.rst.txt new file mode 100644 index 000000000..013e691ad --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.io.write_netcdf.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.io.write\_netcdf +============================ + +.. currentmodule:: mpas_tools.io + +.. autofunction:: write_netcdf \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.logging.LoggingContext.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.logging.LoggingContext.rst.txt new file mode 100644 index 000000000..8bd95ef54 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.logging.LoggingContext.rst.txt @@ -0,0 +1,22 @@ +mpas\_tools.logging.LoggingContext +================================== + +.. currentmodule:: mpas_tools.logging + +.. autoclass:: LoggingContext + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~LoggingContext.__init__ + + + + + + \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.logging.check_call.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.logging.check_call.rst.txt new file mode 100644 index 000000000..98f0dad1c --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.logging.check_call.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.logging.check\_call +=============================== + +.. currentmodule:: mpas_tools.logging + +.. autofunction:: check_call \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.merge_grids.merge_grids.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.merge_grids.merge_grids.rst.txt new file mode 100644 index 000000000..cab5842c8 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.merge_grids.merge_grids.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.merge\_grids.merge\_grids +===================================== + +.. currentmodule:: mpas_tools.merge_grids + +.. autofunction:: merge_grids \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.convert.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.convert.rst.txt new file mode 100644 index 000000000..2f75e735e --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.convert.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.conversion.convert +=================================== + +.. currentmodule:: mpas_tools.mesh.conversion + +.. autofunction:: convert \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.cull.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.cull.rst.txt new file mode 100644 index 000000000..dbbb6fa5a --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.cull.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.conversion.cull +================================ + +.. currentmodule:: mpas_tools.mesh.conversion + +.. autofunction:: cull \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.mask.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.mask.rst.txt new file mode 100644 index 000000000..0e30e57ec --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.conversion.mask.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.conversion.mask +================================ + +.. currentmodule:: mpas_tools.mesh.conversion + +.. autofunction:: mask \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.rst.txt new file mode 100644 index 000000000..b06f64000 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.build\_mesh.build\_planar\_mesh +========================================================= + +.. currentmodule:: mpas_tools.mesh.creation.build_mesh + +.. autofunction:: build_planar_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.rst.txt new file mode 100644 index 000000000..2e85a2250 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.build\_mesh.build\_spherical\_mesh +============================================================ + +.. currentmodule:: mpas_tools.mesh.creation.build_mesh + +.. autofunction:: build_spherical_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.rst.txt new file mode 100644 index 000000000..b1ef21526 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.build_mesh.rst.txt @@ -0,0 +1,30 @@ +mpas\_tools.mesh.creation.build\_mesh +===================================== + +.. automodule:: mpas_tools.mesh.creation.build_mesh + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + build_planar_mesh + build_spherical_mesh + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.rst.txt new file mode 100644 index 000000000..a5f548bac --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.jigsaw\_driver.jigsaw\_driver +======================================================= + +.. currentmodule:: mpas_tools.mesh.creation.jigsaw_driver + +.. autofunction:: jigsaw_driver \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.rst.txt new file mode 100644 index 000000000..db2ae509a --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.jigsaw\_to\_netcdf.jigsaw\_to\_netcdf +=============================================================== + +.. currentmodule:: mpas_tools.mesh.creation.jigsaw_to_netcdf + +.. autofunction:: jigsaw_to_netcdf \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.rst.txt new file mode 100644 index 000000000..645172ff7 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.mesh\_definition\_tools.AtlanticPacificGrid +===================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.mesh_definition_tools + +.. autofunction:: AtlanticPacificGrid \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.rst.txt new file mode 100644 index 000000000..d69e40140 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.mesh\_definition\_tools.EC\_CellWidthVsLat +==================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.mesh_definition_tools + +.. autofunction:: EC_CellWidthVsLat \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.rst.txt new file mode 100644 index 000000000..1a7e3b6f4 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.mesh\_definition\_tools.RRS\_CellWidthVsLat +===================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.mesh_definition_tools + +.. autofunction:: RRS_CellWidthVsLat \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.rst.txt new file mode 100644 index 000000000..37df6d6e3 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.mesh\_definition\_tools.mergeCellWidthVsLat +===================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.mesh_definition_tools + +.. autofunction:: mergeCellWidthVsLat \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.rst.txt new file mode 100644 index 000000000..464b747cf --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mesh_definition_tools.rst.txt @@ -0,0 +1,32 @@ +mpas\_tools.mesh.creation.mesh\_definition\_tools +================================================= + +.. automodule:: mpas_tools.mesh.creation.mesh_definition_tools + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + AtlanticPacificGrid + EC_CellWidthVsLat + RRS_CellWidthVsLat + mergeCellWidthVsLat + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.rst.txt new file mode 100644 index 000000000..6a211a7e8 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.mpas\_to\_triangle.mpas\_to\_triangle +=============================================================== + +.. currentmodule:: mpas_tools.mesh.creation.mpas_to_triangle + +.. autofunction:: mpas_to_triangle \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.rst.txt new file mode 100644 index 000000000..9a5f3366e --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.signed\_distance.distance\_from\_geojson +================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.signed_distance + +.. autofunction:: distance_from_geojson \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.rst.txt new file mode 100644 index 000000000..25b61c128 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.signed\_distance.mask\_from\_geojson +============================================================== + +.. currentmodule:: mpas_tools.mesh.creation.signed_distance + +.. autofunction:: mask_from_geojson \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.rst.txt new file mode 100644 index 000000000..2fec23182 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.rst.txt @@ -0,0 +1,31 @@ +mpas\_tools.mesh.creation.signed\_distance +========================================== + +.. automodule:: mpas_tools.mesh.creation.signed_distance + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + distance_from_geojson + mask_from_geojson + signed_distance_from_geojson + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.rst.txt new file mode 100644 index 000000000..96a32904c --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.signed\_distance.signed\_distance\_from\_geojson +========================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.signed_distance + +.. autofunction:: signed_distance_from_geojson \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.rst.txt new file mode 100644 index 000000000..63d3cf5da --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.creation.triangle\_to\_netcdf.triangle\_to\_netcdf +=================================================================== + +.. currentmodule:: mpas_tools.mesh.creation.triangle_to_netcdf + +.. autofunction:: triangle_to_netcdf \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.interpolation.interp_bilin.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.interpolation.interp_bilin.rst.txt new file mode 100644 index 000000000..5fc6d7cad --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.interpolation.interp_bilin.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.interpolation.interp\_bilin +============================================ + +.. currentmodule:: mpas_tools.mesh.interpolation + +.. autofunction:: interp_bilin \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.rst.txt new file mode 100644 index 000000000..dce2071e5 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.mask.compute\_lon\_lat\_region\_masks +====================================================== + +.. currentmodule:: mpas_tools.mesh.mask + +.. autofunction:: compute_lon_lat_region_masks \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.rst.txt new file mode 100644 index 000000000..b1bb27fb8 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.mask.compute\_mpas\_flood\_fill\_mask +====================================================== + +.. currentmodule:: mpas_tools.mesh.mask + +.. autofunction:: compute_mpas_flood_fill_mask \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_region_masks.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_region_masks.rst.txt new file mode 100644 index 000000000..699467f9b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_region_masks.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.mask.compute\_mpas\_region\_masks +================================================== + +.. currentmodule:: mpas_tools.mesh.mask + +.. autofunction:: compute_mpas_region_masks \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.rst.txt new file mode 100644 index 000000000..c4d4506bf --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.mesh.mask.compute\_mpas\_transect\_masks +==================================================== + +.. currentmodule:: mpas_tools.mesh.mask + +.. autofunction:: compute_mpas_transect_masks \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.build_planar_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.build_planar_mesh.rst.txt new file mode 100644 index 000000000..a143306b0 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.build_planar_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.build\_mesh.build\_planar\_mesh +================================================= + +.. currentmodule:: mpas_tools.ocean.build_mesh + +.. autofunction:: build_planar_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.rst.txt new file mode 100644 index 000000000..7e8006c01 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.build\_mesh.build\_spherical\_mesh +==================================================== + +.. currentmodule:: mpas_tools.ocean.build_mesh + +.. autofunction:: build_spherical_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.rst.txt new file mode 100644 index 000000000..74e962d42 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.build_mesh.rst.txt @@ -0,0 +1,30 @@ +mpas\_tools.ocean.build\_mesh +============================= + +.. automodule:: mpas_tools.ocean.build_mesh + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + build_planar_mesh + build_spherical_mesh + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.CPP_projection.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.CPP_projection.rst.txt new file mode 100644 index 000000000..b07539e89 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.CPP_projection.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.CPP\_projection +================================================ + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: CPP_projection \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.rst.txt new file mode 100644 index 000000000..f6383751f --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.coastal\_refined\_mesh +======================================================= + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: coastal_refined_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.compute_cell_width.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.compute_cell_width.rst.txt new file mode 100644 index 000000000..77953fc30 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.compute_cell_width.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.compute\_cell\_width +===================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: compute_cell_width \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.create_background_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.create_background_mesh.rst.txt new file mode 100644 index 000000000..29a73a83a --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.create_background_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.create\_background\_mesh +========================================================= + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: create_background_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.distance_to_coast.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.distance_to_coast.rst.txt new file mode 100644 index 000000000..462a0052b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.distance_to_coast.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.distance\_to\_coast +==================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: distance_to_coast \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.extract_coastlines.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.extract_coastlines.rst.txt new file mode 100644 index 000000000..02d209342 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.extract_coastlines.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.extract\_coastlines +==================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: extract_coastlines \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.rst.txt new file mode 100644 index 000000000..921cb0f58 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.get\_convex\_hull\_coordinates +=============================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: get_convex_hull_coordinates \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.rst.txt new file mode 100644 index 000000000..7ee09b49b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.get\_data\_inside\_box +======================================================= + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: get_data_inside_box \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.rst.txt new file mode 100644 index 000000000..f1119b1f6 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.get\_indices\_inside\_quad +=========================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: get_indices_inside_quad \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.rst.txt new file mode 100644 index 000000000..fd5dff857 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.plot\_coarse\_coast +==================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: plot_coarse_coast \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.plot_region_box.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.plot_region_box.rst.txt new file mode 100644 index 000000000..eeadae391 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.plot_region_box.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.plot\_region\_box +================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: plot_region_box \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.rst.txt new file mode 100644 index 000000000..a8d685fee --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.rst.txt @@ -0,0 +1,42 @@ +mpas\_tools.ocean.coastal\_tools +================================ + +.. automodule:: mpas_tools.ocean.coastal_tools + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + CPP_projection + coastal_refined_mesh + compute_cell_width + create_background_mesh + distance_to_coast + extract_coastlines + flag_wrap + get_convex_hull_coordinates + get_data_inside_box + get_indices_inside_quad + plot_coarse_coast + plot_region_box + save_matfile + smooth_coastline + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.save_matfile.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.save_matfile.rst.txt new file mode 100644 index 000000000..56afb08e2 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.save_matfile.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.save\_matfile +============================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: save_matfile \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.smooth_coastline.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.smooth_coastline.rst.txt new file mode 100644 index 000000000..291e7c1d9 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastal_tools.smooth_coastline.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastal\_tools.smooth\_coastline +================================================== + +.. currentmodule:: mpas_tools.ocean.coastal_tools + +.. autofunction:: smooth_coastline \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.rst.txt new file mode 100644 index 000000000..1e9fa9a34 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastline\_alteration.add\_critical\_land\_blockages +====================================================================== + +.. currentmodule:: mpas_tools.ocean.coastline_alteration + +.. autofunction:: add_critical_land_blockages \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.rst.txt new file mode 100644 index 000000000..3da90899f --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastline\_alteration.add\_land\_locked\_cells\_to\_mask +========================================================================== + +.. currentmodule:: mpas_tools.ocean.coastline_alteration + +.. autofunction:: add_land_locked_cells_to_mask \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.rst.txt new file mode 100644 index 000000000..384c58f02 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.rst.txt @@ -0,0 +1,31 @@ +mpas\_tools.ocean.coastline\_alteration +======================================= + +.. automodule:: mpas_tools.ocean.coastline_alteration + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + add_critical_land_blockages + add_land_locked_cells_to_mask + widen_transect_edge_masks + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.rst.txt new file mode 100644 index 000000000..034ca0373 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.coastline\_alteration.widen\_transect\_edge\_masks +==================================================================== + +.. currentmodule:: mpas_tools.ocean.coastline_alteration + +.. autofunction:: widen_transect_edge_masks \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.add_depth.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.add_depth.rst.txt new file mode 100644 index 000000000..5fac8927b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.add_depth.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.depth.add\_depth +================================== + +.. currentmodule:: mpas_tools.ocean.depth + +.. autofunction:: add_depth \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.add_zmid.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.add_zmid.rst.txt new file mode 100644 index 000000000..f74b7c293 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.add_zmid.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.depth.add\_zmid +================================= + +.. currentmodule:: mpas_tools.ocean.depth + +.. autofunction:: add_zmid \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.compute_depth.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.compute_depth.rst.txt new file mode 100644 index 000000000..e7f653c98 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.compute_depth.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.depth.compute\_depth +====================================== + +.. currentmodule:: mpas_tools.ocean.depth + +.. autofunction:: compute_depth \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.compute_zmid.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.compute_zmid.rst.txt new file mode 100644 index 000000000..ccb80d794 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.compute_zmid.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.depth.compute\_zmid +===================================== + +.. currentmodule:: mpas_tools.ocean.depth + +.. autofunction:: compute_zmid \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.write_time_varying_zmid.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.write_time_varying_zmid.rst.txt new file mode 100644 index 000000000..c3e3b6651 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.depth.write_time_varying_zmid.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.depth.write\_time\_varying\_zmid +================================================== + +.. currentmodule:: mpas_tools.ocean.depth + +.. autofunction:: write_time_varying_zmid \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.rst.txt new file mode 100644 index 000000000..78c26036d --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.inject\_bathymetry.inject\_bathymetry +======================================================= + +.. currentmodule:: mpas_tools.ocean.inject_bathymetry + +.. autofunction:: inject_bathymetry \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.rst.txt new file mode 100644 index 000000000..59bbcd80e --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.inject\_meshDensity.inject\_meshDensity\_from\_file +===================================================================== + +.. currentmodule:: mpas_tools.ocean.inject_meshDensity + +.. autofunction:: inject_meshDensity_from_file \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.rst.txt new file mode 100644 index 000000000..607bac3f6 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.inject\_meshDensity.inject\_planar\_meshDensity +================================================================= + +.. currentmodule:: mpas_tools.ocean.inject_meshDensity + +.. autofunction:: inject_planar_meshDensity \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.rst.txt new file mode 100644 index 000000000..2bdc09716 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.inject\_meshDensity.inject\_spherical\_meshDensity +==================================================================== + +.. currentmodule:: mpas_tools.ocean.inject_meshDensity + +.. autofunction:: inject_spherical_meshDensity \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.rst.txt new file mode 100644 index 000000000..580c2cb29 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.inject\_preserve\_floodplain.inject\_preserve\_floodplain +=========================================================================== + +.. currentmodule:: mpas_tools.ocean.inject_preserve_floodplain + +.. autofunction:: inject_preserve_floodplain \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.rst.txt new file mode 100644 index 000000000..d94e31d21 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.moc.add\_moc\_southern\_boundary\_transects +============================================================= + +.. currentmodule:: mpas_tools.ocean.moc + +.. autofunction:: add_moc_southern_boundary_transects \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.rst.txt new file mode 100644 index 000000000..abd583cee --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.moc.make\_moc\_basins\_and\_transects +======================================================= + +.. currentmodule:: mpas_tools.ocean.moc + +.. autofunction:: make_moc_basins_and_transects \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.rst.txt new file mode 100644 index 000000000..b6d6269fe --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.moc.rst.txt @@ -0,0 +1,30 @@ +mpas\_tools.ocean.moc +===================== + +.. automodule:: mpas_tools.ocean.moc + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + add_moc_southern_boundary_transects + make_moc_basins_and_transects + + + + + + + + + + + + + diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.rst.txt new file mode 100644 index 000000000..1c4b5dc59 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.transects.find\_transect\_levels\_and\_weights +================================================================ + +.. currentmodule:: mpas_tools.ocean.transects + +.. autofunction:: find_transect_levels_and_weights \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.get_outline_segments.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.get_outline_segments.rst.txt new file mode 100644 index 000000000..e66a2a486 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.get_outline_segments.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.transects.get\_outline\_segments +================================================== + +.. currentmodule:: mpas_tools.ocean.transects + +.. autofunction:: get_outline_segments \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.rst.txt new file mode 100644 index 000000000..9113d8921 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.transects.interp\_mpas\_to\_transect\_triangle\_nodes +======================================================================= + +.. currentmodule:: mpas_tools.ocean.transects + +.. autofunction:: interp_mpas_to_transect_triangle_nodes \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.rst.txt new file mode 100644 index 000000000..1f2797626 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.transects.interp\_mpas\_to\_transect\_triangles +================================================================= + +.. currentmodule:: mpas_tools.ocean.transects + +.. autofunction:: interp_mpas_to_transect_triangles \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.rst.txt new file mode 100644 index 000000000..f3352a6a8 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.transects.interp\_transect\_grid\_to\_transect\_triangle\_nodes +================================================================================= + +.. currentmodule:: mpas_tools.ocean.transects + +.. autofunction:: interp_transect_grid_to_transect_triangle_nodes \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.viz.add_inset.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.viz.add_inset.rst.txt new file mode 100644 index 000000000..3609d556b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.viz.add_inset.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.viz.add\_inset +================================ + +.. currentmodule:: mpas_tools.ocean.viz + +.. autofunction:: add_inset \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.ocean.viz.plot_ocean_transects.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.ocean.viz.plot_ocean_transects.rst.txt new file mode 100644 index 000000000..54c14ef21 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.ocean.viz.plot_ocean_transects.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.ocean.viz.plot\_ocean\_transects +============================================ + +.. currentmodule:: mpas_tools.ocean.viz + +.. autofunction:: plot_ocean_transects \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.parallel.create_pool.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.parallel.create_pool.rst.txt new file mode 100644 index 000000000..38025bdc7 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.parallel.create_pool.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.parallel.create\_pool +================================= + +.. currentmodule:: mpas_tools.parallel + +.. autofunction:: create_pool \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.planar_hex.make_planar_hex_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.planar_hex.make_planar_hex_mesh.rst.txt new file mode 100644 index 000000000..4de31db63 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.planar_hex.make_planar_hex_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.planar\_hex.make\_planar\_hex\_mesh +=============================================== + +.. currentmodule:: mpas_tools.planar_hex + +.. autofunction:: make_planar_hex_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.rst.txt new file mode 100644 index 000000000..24e9d46ff --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.scrip.from\_mpas.scrip\_from\_mpas +============================================== + +.. currentmodule:: mpas_tools.scrip.from_mpas + +.. autofunction:: scrip_from_mpas \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.mask.extend_seaice_mask.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mask.extend_seaice_mask.rst.txt new file mode 100644 index 000000000..3f3f89c7b --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mask.extend_seaice_mask.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.mask.extend\_seaice\_mask +============================================ + +.. currentmodule:: mpas_tools.seaice.mask + +.. autofunction:: extend_seaice_mask \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.rst.txt new file mode 100644 index 000000000..3e7f26b9c --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.mesh.make\_mpas\_scripfile\_on\_cells +======================================================== + +.. currentmodule:: mpas_tools.seaice.mesh + +.. autofunction:: make_mpas_scripfile_on_cells \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.rst.txt new file mode 100644 index 000000000..86f470b09 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.mesh.make\_mpas\_scripfile\_on\_vertices +=========================================================== + +.. currentmodule:: mpas_tools.seaice.mesh + +.. autofunction:: make_mpas_scripfile_on_vertices \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.write_2D_scripfile.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.write_2D_scripfile.rst.txt new file mode 100644 index 000000000..0cde5258d --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.write_2D_scripfile.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.mesh.write\_2D\_scripfile +============================================ + +.. currentmodule:: mpas_tools.seaice.mesh + +.. autofunction:: write_2D_scripfile \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.write_scrip_file.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.write_scrip_file.rst.txt new file mode 100644 index 000000000..58fa74c7a --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.mesh.write_scrip_file.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.mesh.write\_scrip\_file +========================================== + +.. currentmodule:: mpas_tools.seaice.mesh + +.. autofunction:: write_scrip_file \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.create_partitions.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.create_partitions.rst.txt new file mode 100644 index 000000000..6c43fda73 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.create_partitions.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.partition.create\_partitions +=============================================== + +.. currentmodule:: mpas_tools.seaice.partition + +.. autofunction:: create_partitions \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.rst.txt new file mode 100644 index 000000000..4a42b8869 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.partition.gen\_seaice\_mesh\_partition +========================================================= + +.. currentmodule:: mpas_tools.seaice.partition + +.. autofunction:: gen_seaice_mesh_partition \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.prepare_partitions.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.prepare_partitions.rst.txt new file mode 100644 index 000000000..05a6afd7a --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.partition.prepare_partitions.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.partition.prepare\_partitions +================================================ + +.. currentmodule:: mpas_tools.seaice.partition + +.. autofunction:: prepare_partitions \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.regions.make_regions_file.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.regions.make_regions_file.rst.txt new file mode 100644 index 000000000..6dafd7a9e --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.regions.make_regions_file.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.regions.make\_regions\_file +============================================== + +.. currentmodule:: mpas_tools.seaice.regions + +.. autofunction:: make_regions_file \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.rst.txt new file mode 100644 index 000000000..481529e1c --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.seaice.regrid.regrid\_to\_other\_mesh +================================================= + +.. currentmodule:: mpas_tools.seaice.regrid + +.. autofunction:: regrid_to_other_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.split_grids.split_grids.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.split_grids.split_grids.rst.txt new file mode 100644 index 000000000..88a91bb7e --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.split_grids.split_grids.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.split\_grids.split\_grids +===================================== + +.. currentmodule:: mpas_tools.split_grids + +.. autofunction:: split_grids \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.tests.test_cime_constants.test_cime_constants.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.tests.test_cime_constants.test_cime_constants.rst.txt new file mode 100644 index 000000000..5ed307a08 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.tests.test_cime_constants.test_cime_constants.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.tests.test\_cime\_constants.test\_cime\_constants +============================================================= + +.. currentmodule:: mpas_tools.tests.test_cime_constants + +.. autofunction:: test_cime_constants \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.Vector.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.Vector.rst.txt new file mode 100644 index 000000000..b84c029ce --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.Vector.rst.txt @@ -0,0 +1,30 @@ +mpas\_tools.transects.Vector +============================ + +.. currentmodule:: mpas_tools.transects + +.. autoclass:: Vector + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Vector.__init__ + ~Vector.angular_distance + ~Vector.cross + ~Vector.det + ~Vector.dot + ~Vector.intersection + ~Vector.intersects + ~Vector.mag + ~Vector.straddles + + + + + + \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.angular_distance.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.angular_distance.rst.txt new file mode 100644 index 000000000..5397f6acd --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.angular_distance.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.transects.angular\_distance +======================================= + +.. currentmodule:: mpas_tools.transects + +.. autofunction:: angular_distance \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.cartesian_to_great_circle_distance.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.cartesian_to_great_circle_distance.rst.txt new file mode 100644 index 000000000..a3d3ec947 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.cartesian_to_great_circle_distance.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.transects.cartesian\_to\_great\_circle\_distance +============================================================ + +.. currentmodule:: mpas_tools.transects + +.. autofunction:: cartesian_to_great_circle_distance \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.cartesian_to_lon_lat.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.cartesian_to_lon_lat.rst.txt new file mode 100644 index 000000000..cf69d2ad0 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.cartesian_to_lon_lat.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.transects.cartesian\_to\_lon\_lat +============================================= + +.. currentmodule:: mpas_tools.transects + +.. autofunction:: cartesian_to_lon_lat \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.lon_lat_to_cartesian.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.lon_lat_to_cartesian.rst.txt new file mode 100644 index 000000000..52139e37a --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.lon_lat_to_cartesian.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.transects.lon\_lat\_to\_cartesian +============================================= + +.. currentmodule:: mpas_tools.transects + +.. autofunction:: lon_lat_to_cartesian \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.subdivide_great_circle.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.subdivide_great_circle.rst.txt new file mode 100644 index 000000000..b78a99134 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.subdivide_great_circle.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.transects.subdivide\_great\_circle +============================================== + +.. currentmodule:: mpas_tools.transects + +.. autofunction:: subdivide_great_circle \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.transects.subdivide_planar.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.transects.subdivide_planar.rst.txt new file mode 100644 index 000000000..ccc2278c8 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.transects.subdivide_planar.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.transects.subdivide\_planar +======================================= + +.. currentmodule:: mpas_tools.transects + +.. autofunction:: subdivide_planar \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.translate.center.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.translate.center.rst.txt new file mode 100644 index 000000000..4749af4a6 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.translate.center.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.translate.center +============================ + +.. currentmodule:: mpas_tools.translate + +.. autofunction:: center \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.translate.center_on_mesh.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.translate.center_on_mesh.rst.txt new file mode 100644 index 000000000..3e98d1933 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.translate.center_on_mesh.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.translate.center\_on\_mesh +====================================== + +.. currentmodule:: mpas_tools.translate + +.. autofunction:: center_on_mesh \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.translate.translate.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.translate.translate.rst.txt new file mode 100644 index 000000000..7a35c037d --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.translate.translate.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.translate.translate +=============================== + +.. currentmodule:: mpas_tools.translate + +.. autofunction:: translate \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.rst.txt new file mode 100644 index 000000000..38af19d8e --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.viz.colormaps.register\_sci\_viz\_colormaps +======================================================= + +.. currentmodule:: mpas_tools.viz.colormaps + +.. autofunction:: register_sci_viz_colormaps \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.rst.txt new file mode 100644 index 000000000..960197bbc --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.viz.mesh\_to\_triangles.mesh\_to\_triangles +======================================================= + +.. currentmodule:: mpas_tools.viz.mesh_to_triangles + +.. autofunction:: mesh_to_triangles \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.viz.paraview_extractor.extract_vtk.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.viz.paraview_extractor.extract_vtk.rst.txt new file mode 100644 index 000000000..dc8e932bc --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.viz.paraview_extractor.extract_vtk.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.viz.paraview\_extractor.extract\_vtk +================================================ + +.. currentmodule:: mpas_tools.viz.paraview_extractor + +.. autofunction:: extract_vtk \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.rst.txt new file mode 100644 index 000000000..ced980029 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.viz.transects.find\_planar\_transect\_cells\_and\_weights +===================================================================== + +.. currentmodule:: mpas_tools.viz.transects + +.. autofunction:: find_planar_transect_cells_and_weights \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.find_transect_cells_and_weights.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.find_transect_cells_and_weights.rst.txt new file mode 100644 index 000000000..82c9c39d2 --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.find_transect_cells_and_weights.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.viz.transects.find\_transect\_cells\_and\_weights +============================================================= + +.. currentmodule:: mpas_tools.viz.transects + +.. autofunction:: find_transect_cells_and_weights \ No newline at end of file diff --git a/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.make_triangle_tree.rst.txt b/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.make_triangle_tree.rst.txt new file mode 100644 index 000000000..8c050ecbd --- /dev/null +++ b/0.22.0rc4/_sources/generated/mpas_tools.viz.transects.make_triangle_tree.rst.txt @@ -0,0 +1,6 @@ +mpas\_tools.viz.transects.make\_triangle\_tree +============================================== + +.. currentmodule:: mpas_tools.viz.transects + +.. autofunction:: make_triangle_tree \ No newline at end of file diff --git a/0.22.0rc4/_sources/index.rst.txt b/0.22.0rc4/_sources/index.rst.txt new file mode 100644 index 000000000..0e8ec2cc0 --- /dev/null +++ b/0.22.0rc4/_sources/index.rst.txt @@ -0,0 +1,81 @@ +MPAS-Tools +========== + +.. image:: images/so60to10.png + :width: 500 px + :align: center + +MPAS-Tools includes a python package, compiled Fortran, C and C++ tools, and +scripts for supporting initialization, visualization and analysis of Model for +Prediction Across Scales (MPAS) components. These tools are used by the +`COMPASS `_ +(Configuring of MPAS Setups) framework within +`MPAS-Model `_ used to create +ocean and land-ice test cases, +the `MPAS-Analysis `_ package for +analyzing simulations, and in other MPAS-related workflows. + +.. toctree:: + :caption: User's Guide + :maxdepth: 2 + + mesh_creation + mesh_conversion + interpolation + + cime + + config + + logging + + transects + + visualization + +.. toctree:: + :caption: Ocean Tools + :maxdepth: 2 + + ocean/mesh_creation + ocean/coastal_tools + ocean/coastline_alteration + ocean/moc + ocean/depth + +.. toctree:: + :caption: Sea-ice Tools + :maxdepth: 2 + + seaice/mask + seaice/mesh + seaice/partition + seaice/regions + seaice/regrid + +.. toctree:: + :caption: Developer's Guide + :maxdepth: 2 + + making_changes + testing_changes + building_docs + + api + +Indices and tables +================== + +* :ref:`genindex` + +.. toctree:: + :caption: Authors + :maxdepth: 1 + + authors + +.. toctree:: + :caption: Versions + :maxdepth: 1 + + versions diff --git a/0.22.0rc4/_sources/interpolation.rst.txt b/0.22.0rc4/_sources/interpolation.rst.txt new file mode 100644 index 000000000..c6fa90529 --- /dev/null +++ b/0.22.0rc4/_sources/interpolation.rst.txt @@ -0,0 +1,48 @@ +.. _mesh_interpolation: + +.. |---| unicode:: U+2014 .. em dash, trimming surrounding whitespace + :trim: + +************* +Interpolation +************* + +Previously, various tools in this package used ``scipy`` for interpolation. +However, the interpolation routines in ``scipy`` are not well suited to +interpolation from regular grids to MPAS meshes---they are slow and very memory +intensive, particularly for large meshes. + +For bilinear interpolation from a tensor lon/lat grid to an MPAS mesh, it will +be faster to use the function +:py:func:`mpas_tools.mesh.interpolation.interp_bilin()` +Here is an example where we define cell width for an EC mesh (see +:ref:`ec_mesh`), read in longitude and latitude from an MPAS mesh, and +interpolate the cell widths to cell centers on the MPAS mesh. + +.. code-block:: python + + import numpy as np + import netCDF4 as nc4 + from mpas_tools.mesh.interpolation import interp_bilin + + dlon = 1. + dlat = dlon + earth_radius = constants['SHR_CONST_REARTH'] + nlon = int(360./dlon) + 1 + nlat = int(180./dlat) + 1 + lon = np.linspace(-180., 180., nlon) + lat = np.linspace(-90., 90., nlat) + + cellWidth = mdt.EC_CellWidthVsLat(lat) + + # broadcast cellWidth to 2D + _, cellWidth = np.meshgrid(lon, cellWidthVsLat) + + ds = nc4.Dataset('base_mesh.nc', 'r+') + lonCell = ds.variables['lonCell'][:] + latCell = ds.variables['latCell'][:] + + lonCell = np.mod(np.rad2deg(lonCell) + 180., 360.) - 180. + latCell = np.rad2deg(latCell) + + cellWidthOnMpas = interp_bilin(lon, lat, cellWidth, lonCell, latCell) diff --git a/0.22.0rc4/_sources/logging.rst.txt b/0.22.0rc4/_sources/logging.rst.txt new file mode 100644 index 000000000..13c197bda --- /dev/null +++ b/0.22.0rc4/_sources/logging.rst.txt @@ -0,0 +1,110 @@ +.. _logging: + +******* +Logging +******* + +MPAS-Tools includes capabilities for logging output from many of its function +calls to either ``stdout``/``stderr`` or to a log file. + +Using logging +============= + +Logging is performed by creating a +:py:class:`mpas_tools.logging.LoggingContext` object inside a ``with`` +statement: + +.. code-block:: python + + with LoggingContext(__name__) as logger: + + ... + logger.info('Step 1. Generate mesh with JIGSAW') + ... + logger.info('Step 2. Convert triangles from jigsaw format to netcdf') + ... + logger.info('Step 3. Convert from triangles to MPAS mesh') + ... + +A ``LoggingContext`` is given a unique name (typically the name of the module, +``__name__``). If no other arguments are supplied, the logger will write to +``stdout`` with calls to ``logger.info()`` and ``logger.debug()``, and to +``stderr`` for calls to ``logger.error()``. + +It is convenient to create this kind of a ``logger`` in contexts where logging +might be to a file or might be to ``stdout``/``stderr``, depending on the +calling code. + +Often, a function should support output to a ``logger`` but you do not +necessarily want the calling code to have to crate one if the calling code just +wants output to ``stdout``/``stderr``. In such contexts, the function can take +``logger=None`` as an optional argument. Then, in the function itself, a new +``LoggingContext`` can be created that will just use the existing ``logger`` +if there is one or create a new ong for ``stdout``/``stderr`` if none is +provided. As an example, here is a snippet from +:py:func:`mpas_tools.mesh.creation.build_mesh.build_spherical_mesh()`: + +.. code-block:: python + + def build_spherical_mesh(cellWidth, lon, lat, earth_radius, + out_filename='base_mesh.nc', plot_cellWidth=True, + dir='./', logger=None): + ... + with LoggingContext(__name__, logger=logger) as logger: + + ... + logger.info('Step 1. Generate mesh with JIGSAW') + jigsaw_driver(cellWidth, lon, lat, on_sphere=True, + earth_radius=earth_radius, logger=logger) + + logger.info('Step 2. Convert triangles from jigsaw format to netcdf') + jigsaw_to_netcdf(msh_filename='mesh-MESH.msh', + output_name='mesh_triangles.nc', on_sphere=True, + sphere_radius=earth_radius) + + logger.info('Step 3. Convert from triangles to MPAS mesh') + write_netcdf(convert(xarray.open_dataset('mesh_triangles.nc'), dir=dir, + logger=logger), + out_filename) + +The optional argument ``logger`` is passed to a new ``LoggingContext``. That +way ``logger`` is guaranteed not to be ``None`` (so calls to ``logger.info`` +work properly). The ``logger`` is also passed on to +:py:func:`mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver()` and +:py:func:`mpas_tools.io.write_netcdf()` for output from those functions. + +To log to a new log file, simply pass a file name to the ``log_filename`` +argument: + +.. code-block:: python + + with LoggingContext(name=__name__, log_filename='output.log') as logger: + ... + logger.info('Step 1. Generate mesh with JIGSAW') + + +If both the ``logger`` and ``log_filename`` arguments are not ``None``, the +``log_filename`` is ignored and the existing ``logger`` is simply used for +logging. + +Logging subprocess calls +======================== + +You can also run subprocesses and capture the output to a ``logger``. This is +accomplished with the function :py:func:`mpas_tools.logging.check_call`, which +acts a lot like :py:func:`subprocess.check_call()` but with output going to +the logger, as in this example from +:py:func:`mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver()` + +.. code-block:: python + + from mpas_tools.logging import check_call + + + def jigsaw_driver(cellWidth, x, y, on_sphere=True, earth_radius=6371.0e3, + geom_points=None, geom_edges=None, logger=None): + + ... + opts.jcfg_file = 'mesh.jig' + ... + check_call(['jigsaw', opts.jcfg_file], logger=logger) diff --git a/0.22.0rc4/_sources/making_changes.rst.txt b/0.22.0rc4/_sources/making_changes.rst.txt new file mode 100644 index 000000000..cdce554b1 --- /dev/null +++ b/0.22.0rc4/_sources/making_changes.rst.txt @@ -0,0 +1,137 @@ +.. _dev_making_changes: + +**************************** +Making Changes to mpas_tools +**************************** + +New python functions and modules (``.py`` files) can be added within the +``conda_package/mpas_tools``. These will automatically be part of the +``mpas_tools`` package. New directories with python modules should include an +``__init__.py`` file (which can be empty) to indicate that they are also part of +the package. + +Entry Points +============ + +The best way to add new "scripts" to the package is to add a function without +any arguments somewhere in the package, and then to add it as an "entry point" +both in ``conda_package/setup.py`` and ``conda_package/recipe/meta.yaml``. + +As an example, the entry point ``planar_hex`` is defined in ``setup.py`` as: + +.. code-block:: python + + setup(name='mpas_tools', + ... + entry_points={'console_scripts': + ['planar_hex = mpas_tools.planar_hex:main', + ... + +and in ``meta.yaml`` as: + +.. code-block:: + + build: + number: 0 + entry_points: + - planar_hex = mpas_tools.planar_hex:main + +When the package is installed in a conda environment, a stub script +``planar_hex`` will be in the user's path that will call the function ``main()`` +in the module ``mpas_tools.planar_hex``: + +.. code-block:: python + + def main(): + + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('--nx', dest='nx', type=int, required=True, + help='Cells in x direction') + ... + args = parser.parse_args() + + make_planar_hex_mesh(args.nx, args.ny, args.dc, + args.nonperiodic_x, args.nonperiodic_y, + args.outFileName) + +As you can see, the function pointed to by the entry point can used to parse +command-line arguments, just as a "normal" python script would do + +By convention, entry points do not typically include the ``.py`` extension. + +Dependencies +============ + +If you changes introduce new dependencies, these need to be added to both +the recipe for the conda package in ``conda_package/recipe/meta.yaml`` and +to the text file describing the development environment, +``conda_package/dev-spec.txt``. + +In ``meta.yaml``, add these changes in alphabetical order to the ``run`` +section of ``requirements``: + +.. code-block:: yaml + + requirements: + ... + run: + - python + - affine + ... + +These requirements *must* be on the ``conda-forge`` anaconda channel. If you +need help with this, please contact the developers. + +Add the new dependencies in alphabetical order to ``dev-speck.txt`` +under the ``# Base`` comment: + +.. code-block:: none + + ... + # This file may be used to create an environment using: + # $ conda create --name --file + + # Base + python>=3.8 + cartopy + ... + +Updating the Version +==================== + +Before a release of the package, the version of ``mpas_tools`` needs to be +updated in 3 places. First, in ``conda_package/mpas_tools/__init__.py``: + +.. code-block:: python + + __version_info__ = (0, 6, 0) + __version__ = '.'.join(str(vi) for vi in __version_info__) + +Increment ``__version_info__`` (major, minor or micro version, depending on +what makes sense). + +Second, the version in the conda recipe (``conda_package/recipe/meta.yaml``) +needs to match: + +.. code-block:: + + {% set name = "mpas_tools" %} + {% set version = "0.6.0" %} + +Third, Add the new version to the :ref:`versions` in the documentation. + +.. code-block:: + + `v0.6.0`_ `0.6.0`_ + ================ =============== + + ... + + .. _`v0.6.0`: ../0.6.0/index.html + .. _`0.6.0`: https://github.com/MPAS-Dev/MPAS-Analysis/tree/0.6.0 + + +The new links won't be valid until a new release is made and Azure Pipelines +has generated the associated documentation. Eventually, it should be possible +to do this automatically but that has not yet been implemented. diff --git a/0.22.0rc4/_sources/mesh_conversion.rst.txt b/0.22.0rc4/_sources/mesh_conversion.rst.txt new file mode 100644 index 000000000..7affcd53d --- /dev/null +++ b/0.22.0rc4/_sources/mesh_conversion.rst.txt @@ -0,0 +1,776 @@ +.. _mesh_conversion: + +*************** +Mesh Conversion +*************** + +.. _mesh_converter: + +Mesh Converter +============== + +The command-line tool ``MpasMeshConverter.x`` and the corresponding wrapper +function :py:func:`mpas_tools.mesh.conversion.convert` are used to convert a +dataset describing cell locations, vertex locations, and connectivity between +cells and vertices into a valid MPAS mesh following the `MPAS mesh specification +`_. + +Example call to the command-line tool: + +.. code-block:: + + $ planar_hex --nx 4 --ny 4 --dc 10e3 -o base_mesh.nc + $ MpasMeshConverter.x base_mesh.nc mesh.nc + +This example uses the ``planar_hex`` tool to generate a small, doubly periodic +MPAS mesh with 10-km cells, then uses the MPAS mesh converter to make sure the +resulting mesh adheres to the mesh specification. ``MpasMeshConverter.x`` takes +two arguments, the input and output mesh files, and will prompt the user for +file names if these arguments are not supplied. + +The same example in a python script can be accomplished with: + +.. code-block:: python + + from mpas_tools.planar_hex import make_planar_hex_mesh + from mpas_tools.mesh.conversion import convert + from mpas_tools.io import write_netcdf + + ds = make_planar_hex_mesh(nx=4, ny=4, dc=10e3, nonperiodic_x=False, + nonperiodic_y=False) + ds = convert(ds) + write_netcdf(ds, 'mesh.nc') + +Regardless of which of these methods is used, the input mesh must define the +following dimensions, variables and global attributes (not the dimension sizes +are merely examples from the mesh generated in the previous examples): + +.. code-block:: + + netcdf mesh { + dimensions: + nCells = 16 ; + nVertices = 32 ; + vertexDegree = 3 ; + variables: + double xCell(nCells) ; + double yCell(nCells) ; + double zCell(nCells) ; + double xVertex(nVertices) ; + double yVertex(nVertices) ; + double zVertex(nVertices) ; + int cellsOnVertex(nVertices, vertexDegree) ; + double meshDensity(nCells) ; + + // global attributes: + :on_a_sphere = "NO" ; + :sphere_radius = 0. ; + :is_periodic = "YES" ; + +The variable ``meshDensity`` is required for historical reasons and is passed +unchanged to the resulting mesh. It can contain all ones (or zeros), the +resolution of the mesh in kilometers, or whatever field the user wishes. + +The following global attributes are optional but will be passed on to the +resulting mesh: + +.. code-block:: + + // global attributes: + :x_period = 40000. ; + :y_period = 34641.0161513775 ; + :history = "Tue May 26 20:58:10 2020: /home/xylar/miniconda3/envs/mpas/bin/planar_hex --nx 4 --ny 4 --dc 10e3 -o base_mesh.nc" ; + +The ``file_id`` global attribute is also optional and is preserved in the +resulting mesh as ``parent_id``. A new ``file_id`` (a random hash tag) is +generated by the mesh converter. + +The resulting dataset has all the dimensions and variables required for an MPAS +mesh. + +The mesh converter also generates a file called ``graph.info`` that is used to +create graph partitions from tools like `Metis +`_. This file is not stored by +default when the python ``cull`` function is used but can be specified with +the ``graphInfoFileName`` argument. The python function also takes a ``logger`` +that can be used to capture the output that would otherwise go to the screen +via ``stdout`` and ``stderr``. + +.. _cell_culler: + +Cell Culler +=========== + +The command-line tool ``MpasCellCuller.x`` and the corresponding wrapper +function :py:func:`mpas_tools.mesh.conversion.cull` are used to cull cells from +a mesh based on the ``cullCell`` field in the input dataset and/or the provided +masks. The contents of the ``cullCell`` field is merge with the mask(s) from a +masking dataset and the inverse of the mask(s) from an inverse-masking dataset. +Then, a preserve-masking dataset is used to determine where cells should *not* +be culled. + +Example call to the command-line tool, assuming you start with a spherical mesh +called ``base_mesh.nc`` (not the doubly periodic planar mesh from the examples +above): + +.. code-block:: + + $ merge_features -c natural_earth -b region -n "Land Coverage" -o land.geojson + $ MpasMaskCreator.x base_mesh.nc land.nc -f land.geojson + $ MpasCellCuller.x base_mesh.nc culled_mesh.nc -m land.nc + +This example uses the ``merge_features`` tool from the ``geometric_features`` +conda package to get a geojson file containing land coverage. Then, it uses +the mask creator (see the next section) to create a mask on the MPAS mesh that +is one inside this region and zero outside. Finally, it culls the base mesh +to only those cells where the mask is zero (i.e. the mask indicates which cells +are to be removed). + +The same example in a python script can be accomplished with: + +.. code-block:: python + + import xarray + from geometric_features import GeometricFeatures + from mpas_tools.mesh.conversion import mask, cull + + gf = GeometricFeatures() + + fcLandCoverage = gf.read(componentName='natural_earth', objectType='region', + featureNames=['Land Coverage']) + + dsBaseMesh = xarray.open_dataset('base_mesh.nc') + dsLandMask = mask(dsBaseMesh, fcMask=fcLandCoverage) + dsCulledMesh = conversion.cull(dsBaseMesh, dsMask=dsLandMask) + write_netcdf(dsCulledMesh, 'culled_mesh.nc') + +Here is the full usage of ``MpasCellCuller.x``: + +.. code-block:: + + MpasCellCuller.x [input_name] [output_name] [[-m/-i/-p] masks_name] [-c] + + input_name: + This argument specifies the input MPAS mesh. + output_name: + This argument specifies the output culled MPAS mesh. + If not specified, it defaults to culled_mesh.nc, but + it is required if additional arguments are specified. + -m/-i/-p: + These arguments control how a set of masks is used when + culling a mesh. + The -m argument applies a mask to cull based on (i.e. + where the mask is 1, the mesh will be culled). + The -i argument applies the inverse mask to cull based + on (i.e. where the mask is 0, the mesh will be + culled). + The -p argument forces any marked cells to not be + culled. + If this argument is specified, the masks_name argument + is required + -c: + Output the mapping from old to new mesh (cellMap) in + cellMapForward.txt, + and output the reverse mapping from new to old mesh in + cellMapBackward.txt. + +.. _mask_creator: + +Mask Creator +============ + +The command-line tool ``MpasMaskCreator.x`` and the corresponding wrapper +function :py:func:`mpas_tools.mesh.conversion.mask` are used to create a set of +region masks either from mask features or from seed points to be used to flood +fill a contiguous block of cells. + +Examples usage of the mask creator can be found above under the Cell Culler. + +Here is the full usage of ``MpasMaskCreator.x``: + +.. code-block:: + + MpasMaskCreator.x in_file out_file [ [-f/-s] file.geojson ] [--positive_lon] + in_file: This argument defines the input file that masks will be created for. + out_file: This argument defines the file that masks will be written to. + -s file.geojson: This argument pair defines a set of points (from the geojson point definition) + that will be used as seed points in a flood fill algorithim. This is useful when trying to remove isolated cells from a mesh. + -f file.geojson: This argument pair defines a set of geojson features (regions, transects, or points) + that will be converted into masks / lists. + --positive_lon: It is unlikely that you want this argument. In rare cases when using a non-standard geojson + file where the logitude ranges from 0 to 360 degrees (with the prime meridian at 0 degrees), use this flag. + If this flag is not set, the logitude range is -180-180 with 0 degrees being the prime meridian, which is the + case for standar geojson files including all features from the geometric_feature repo. + The fact that longitudes in the input MPAS mesh range from 0 to 360 is not relevant to this flag, + as latitude and longitude are recomputed internally from Cartesian coordinates. + Whether this flag is passed in or not, any longitudes written are in the 0-360 range. + +.. _py_mask_creation: + +Mask Creation with Python Multiprocessing +========================================= + +The Mask Creator is a serial code, and the algorithms it uses to find points in +a region or cells, edges and vertices along a transect are not particularly +efficient or sophisticated. + +To provide better efficiency and to enable more sophisticated algorithms (now +and in the future), a set of related python functions has been developed to +provide much (but not all) of the functionality of the C++ Mask Creator +described above. + +Computing MPAS Region Masks +--------------------------- + +The function :py:func:`mpas_tools.mesh.mask.compute_mpas_region_masks()` +or the ``compute_mpas_region_masks`` command-line tool can +be used to create region masks on cells, edges and/or vertices given an MPAS +mesh :py:class:`xarray.Dataset` ``dsMesh`` and a +:py:class:`geometric_features.FeatureCollection` ``fcMask`` containing regions. +The resulting masks, in the variable ``regionCellMasks``, are 1 where the center +of the polygon corresponding to the cell, edge or vertex (see the +`MPAS Mesh Specification `_) +are inside the given region and 0 where they are outside. This function is +far more useful if the user provides a :py:class:`multiprocessing.Pool` in the +``pool`` argument. ``pool`` should be created at the beginning of the calling +code (when memory usage is small), possibly with +:py:func:`mpas_tools.parallel.create_pool()`, and terminated +(:py:meth:`multiprocessing.Pool.terminate`) before the code has finished. +The same pool can be used in multiple calls to this and the other Python-based +masking functions. If ``pool = None`` (the default), the masks are computed in +serial, which will likely be frustratingly slow. + +The ``chunkSize`` argument can be used to control how much work (how many cells, +edges or vertices) each process computes on at one time. A very small +``chunkSize`` will incur a high overhead, while a very large ``chunkSize`` will +lead to poor load balancing and infrequent progress updates (if +``showProgress = True``). The default ``chunkSize`` of 1000 seems to perform +well across a wide variety of mesh sizes and processor counts. + +It is a good idea to provide a ``logger`` (see :ref:`logging`) to get some +output as the mask creation is progressing. + +For efficiency, large shapes (e.g. the global coastline) are divided into +smaller "tiles". This subdivision is controlled with ``subdivisionThreshold``, +which should be set to a minimum size in degrees (latitude or longitude). If +a shape is larger than this, it will be divided into tiles. The underlying +algorithm first check bounding boxes of the resulting shapes against points +before performing the more time-consuming step of determining if the point is +inside the shape. The default value of 30 degrees performs much better than +no subdivision for large shapes (again, such as the global coastline), but +alternative values have not yet been explored. + +The resulting variables are: + + - ``regionCellMasks(nCells, nRegions)`` - a cell mask (1 for inside and 0 for + outside the region) for each region + - ``regionEdgeMasks(nEdges, nRegions)`` - an edge mask for each region + - ``regionVertexMasks(nVertices, nRegions)`` - a vertex mask for each region + - ``regionNames(nRegions, string64)`` - the names of the regions + +NetCDF fill values are used for invalid mask values, so ``nCellsInRegion``, +etc. are not produced. + +The command-line tool takes the following arguments: + +.. code-block:: + + $ compute_mpas_region_masks --help + usage: compute_mpas_region_masks [-h] -m MESH_FILE_NAME -g GEOJSON_FILE_NAME + -o MASK_FILE_NAME + [-t MASK_TYPES [MASK_TYPES ...]] + [-c CHUNK_SIZE] [--show_progress] + [-s SUBDIVISION] + [--process_count PROCESS_COUNT] + [--multiprocessing_method MULTIPROCESSING_METHOD] + + optional arguments: + -h, --help show this help message and exit + -m MESH_FILE_NAME, --mesh_file_name MESH_FILE_NAME + An MPAS mesh file + -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME + An Geojson file containing mask regions + -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME + An output MPAS region masks file + -t MASK_TYPES [MASK_TYPES ...], --mask_types MASK_TYPES [MASK_TYPES ...] + Which type(s) of masks to make: cell, edge or vertex. + Default is cell and vertex. + -c CHUNK_SIZE, --chunk_size CHUNK_SIZE + The number of cells, vertices or edges that are + processed in one operation + --show_progress Whether to show a progress bar + -s SUBDIVISION, --subdivision SUBDIVISION + A threshold in degrees (lon or lat) above which the + mask region will be subdivided into smaller polygons + for faster intersection checking + --process_count PROCESS_COUNT + The number of processes to use to compute masks. The + default is to use all available cores + --multiprocessing_method MULTIPROCESSING_METHOD + The multiprocessing method use for python mask + creation ('fork', 'spawn' or 'forkserver') + + +Computing Transect Masks +------------------------ + +The function :py:func:`mpas_tools.mesh.mask.compute_mpas_transect_masks()` +and the ``compute_mpas_transect_masks`` command-line tool +are similar to the function for computing region masks. The function takes a +:py:class:`geometric_features.FeatureCollection` ``fcMask`` that is made up of +transects, rather than regions. One mask is produced for each feature in the +collection, indicating where the transect +intersects the cell, edge or vertex polygons (see the +`MPAS Mesh Specification `_). + +The arguments ``logger``, ``pool``, ``chunkSize`` and ``showProgress`` are the +same as for region-mask creation above. + +The argument ``subdivisionResolution`` is a length in meters, above which +segments of the transect are subdivided to provide a better representation of +the spherical path in longitude/latitude space. The default value of 10 km is +typically good enough to capture distortion at typical MPAS mesh resolutions. + +The algorithm perform intersections in longitude/latitude space using the +``shapely`` library. Because ``shapely`` is designed for 2D shapes in a +Cartesian plane, it is not designed for spherical coordinates. Care has been +taken to handle periodicity at the dateline (antimeridian) but there may be +issues with MPAS mesh polygons containing the north or south pole. If a user +needs to handle a transect that is very close to the pole, it is likely worth +contacting the developers to request modifications to the code to support this +case. + +The resulting variables are: + + - ``transectCellMasks(nCells, nTransects)`` - a cell mask (1 if the transect + intersects the cell and 0 if not) for each transect + - ``transectEdgeMasks(nEdges, nTransects)`` - an edge mask for each transect + - ``transectVertexMasks(nVertices, nTransects)`` - a vertex mask for each + transect + - ``transectNames(nTransects, string64)`` - the names of the transects + +We don't currently provide cell, edge or vertex indices (e.g. +``transectCellGlobalIDs``) for path along a transect. This is, in part, +because the algorithm doesn't keep track of the relative order of points along +a transect. This could be updated in the future if there is sufficient demand. + +The edge sign (``transectEdgeMaskSigns``) is computed only if +``addEdgeSign=True``, since this takes extra time to compute and isn't always +needed. + +.. note:: + + While the default ``subdivisionResolution`` is 10 km for + :py:func:`mpas_tools.mesh.mask.compute_mpas_transect_masks()`, the default + behavior in the command-line tool ``compute_mpas_transect_masks`` is no + subdivision because there is otherwise not a good way to specify at the + command line that no subdivision is desired. Typically, users will want + to request subdivision with something like ``-s 10e3`` + +The command-line tool takes the following arguments: + +.. code-block:: + + $ compute_mpas_transect_masks --help + usage: compute_mpas_transect_masks [-h] -m MESH_FILE_NAME -g GEOJSON_FILE_NAME + -o MASK_FILE_NAME + [-t MASK_TYPES [MASK_TYPES ...]] + [-c CHUNK_SIZE] [--show_progress] + [-s SUBDIVISION] + [--process_count PROCESS_COUNT] + [--multiprocessing_method MULTIPROCESSING_METHOD] + + optional arguments: + -h, --help show this help message and exit + -m MESH_FILE_NAME, --mesh_file_name MESH_FILE_NAME + An MPAS mesh file + -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME + An Geojson file containing transects + -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME + An output MPAS transect masks file + -t MASK_TYPES [MASK_TYPES ...], --mask_types MASK_TYPES [MASK_TYPES ...] + Which type(s) of masks to make: cell, edge or vertex. + Default is cell, edge and vertex. + -c CHUNK_SIZE, --chunk_size CHUNK_SIZE + The number of cells, vertices or edges that are + processed in one operation + --show_progress Whether to show a progress bar + -s SUBDIVISION, --subdivision SUBDIVISION + The maximum resolution (in meters) of segments in a + transect. If a transect is too coarse, it will be + subdivided. Default is no subdivision. + --process_count PROCESS_COUNT + The number of processes to use to compute masks. The + default is to use all available cores + --multiprocessing_method MULTIPROCESSING_METHOD + The multiprocessing method use for python mask + creation ('fork', 'spawn' or 'forkserver') + --add_edge_sign Whether to add the transectEdgeMaskSigns variable + + +Computing a Flood-fill Mask +--------------------------- + +The function :py:func:`mpas_tools.mesh.mask.compute_mpas_flood_fill_mask()` +and the command-line tool ``compute_mpas_flood_fill_mask`` +fill in a mask, starting with the ocean points closest to the seed points +given in :py:class:`geometric_features.FeatureCollection` ``fcSeed``. This +algorithm runs in serial, and will be more efficient the more seed points +are provided and the more widely scattered over the ocean they are. + +The resulting dataset contains a single variable: + + - ``cellSeedMask(nCells)`` - a cell mask that is 1 where the flood fill + (following ``cellsOnCell``) propagated starting from the seed points and 0 + elsewhere + +The command-line tool takes the following arguments: + +.. code-block:: + + $ compute_mpas_flood_fill_mask --help + usage: compute_mpas_flood_fill_mask [-h] -m MESH_FILE_NAME -g + GEOJSON_FILE_NAME -o MASK_FILE_NAME + + optional arguments: + -h, --help show this help message and exit + -m MESH_FILE_NAME, --mesh_file_name MESH_FILE_NAME + An MPAS mesh file + -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME + An Geojson file containing points at which to start + the flood fill + -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME + An output MPAS region masks file + + +Computing Lon/Lat Region Masks +------------------------------ + +The function :py:func:`mpas_tools.mesh.mask.compute_lon_lat_region_masks()` +or the ``compute_lon_lat_region_masks`` command-line tool compute region masks +on a longitude/latitude grid but are otherwise functionally very similar to +the corresponding tools for compute MPAS region masks. The major difference is +that 1D arrays of longitude and latitude are provided instead of an MPAS mesh +dataset. There is no argument equivalent to the mask type for MPAS meshes. +Instead, mask values are given at each point on the 2D longitude/latitude grid. +All other arguments serve the same purpose as for the MPAS region mask creation +described above. + +The command-line tool takes the following arguments: + +.. code-block:: + + $ compute_lon_lat_region_masks --help + usage: compute_lon_lat_region_masks [-h] -i GRID_FILE_NAME [--lon LON] + [--lat LAT] -g GEOJSON_FILE_NAME -o + MASK_FILE_NAME [-c CHUNK_SIZE] + [--show_progress] [-s SUBDIVISION] + [--process_count PROCESS_COUNT] + [--multiprocessing_method MULTIPROCESSING_METHOD] + + optional arguments: + -h, --help show this help message and exit + -i GRID_FILE_NAME, --grid_file_name GRID_FILE_NAME + An input lon/lat grid file + --lon LON The name of the longitude coordinate + --lat LAT The name of the latitude coordinate + -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME + An Geojson file containing mask regions + -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME + An output MPAS region masks file + -c CHUNK_SIZE, --chunk_size CHUNK_SIZE + The number of grid points that are processed in one + operation + --show_progress Whether to show a progress bar + -s SUBDIVISION, --subdivision SUBDIVISION + A threshold in degrees (lon or lat) above which the + mask region will be subdivided into smaller polygons + for faster intersection checking + --process_count PROCESS_COUNT + The number of processes to use to compute masks. The + default is to use all available cores + --multiprocessing_method MULTIPROCESSING_METHOD + The multiprocessing method use for python mask + creation ('fork', 'spawn' or 'forkserver') + + +.. _merge_split: + +Merging and Splitting +===================== + +In order to support running +`MPAS-Albany Land Ice (MALI) `_ +with both Greenland and Antarctica at the same time, tools have been added to +support merging and splitting MPAS meshes. + +Merging two meshes can be accomplished with +:py:func:`mpas_tools.merge_grids.merge_grids()`: + +.. code-block:: python + + from mpas_tools.translate import translate + from mpas_tools.merge_grids import merge_grids + from mpas_tools.planar_hex import make_planar_hex_mesh + from mpas_tools.io import write_netcdf + + + dsMesh1 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True, + nonperiodic_y=True) + + dsMesh2 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True, + nonperiodic_y=True) + + translate(dsMesh2, xOffset=20000., yOffset=0.) + + write_netcdf(dsMesh1, 'mesh1.nc') + write_netcdf(dsMesh2, 'mesh2.nc') + + merge_grids(infile1='mesh1.nc', infile2='mesh2.nc', + outfile='merged_mesh.nc') + +Typically, it will only make sense to merge non-periodic meshes in this way. + +Later, perhaps during analysis or visualization, it can be useful to split +apart the merged meshes. This can be done with +:py:func:`mpas_tools.split_grids.split_grids()` + +.. code-block:: python + + from mpas_tools.translate import translate + from mpas_tools.split_grids import split_grids + from mpas_tools.planar_hex import make_planar_hex_mesh + from mpas_tools.io import write_netcdf + + + dsMesh1 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True, + nonperiodic_y=True) + + dsMesh2 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True, + nonperiodic_y=True) + + translate(dsMesh2, xOffset=20000., yOffset=0.) + + write_netcdf(dsMesh1, 'mesh1.nc') + write_netcdf(dsMesh2, 'mesh2.nc') + + + split_grids(infile='merged_mesh.nc', outfile1='split_mesh1.nc', + outfile='split_mesh2.nc') + +Merging meshes can also be accomplished with the ``merge_grids`` command-line +tool: + +.. code-block:: none + + $ merge_grids --help + + usage: merge_grids [-h] [-o FILENAME] FILENAME1 FILENAME2 + + Tool to merge 2 MPAS non-contiguous meshes together into a single file + + positional arguments: + FILENAME1 File name for first mesh to merge + FILENAME2 File name for second mesh to merge + + optional arguments: + -h, --help show this help message and exit + -o FILENAME The merged mesh file + +Similarly, ``split_grids`` can be used to to split meshes: + +.. code-block:: none + + $ split_grids --help + + usage: split_grids [-h] [-1 FILENAME] [-2 FILENAME] [--nCells NCELLS] + [--nEdges NEDGES] [--nVertices NVERTICES] + [--maxEdges MAXEDGES1 MAXEDGES2] + MESHFILE + + Tool to split 2 previously merged MPAS non-contiguous meshes into separate files. + Typical usage is: + split_grids.py -1 outfile1.nc -2 outfile2.nc infile + The optional arguments for nCells, nEdges, nVertices, and maxEdges should + generally not be required as this information is saved in the combined mesh file + as global attributes by the merge_grids.py script. + + positional arguments: + MESHFILE Mesh file to split + + optional arguments: + -h, --help show this help message and exit + -1 FILENAME, --outfile1 FILENAME + File name for first mesh output + (default: mesh1.nc) + -2 FILENAME, --outfile2 FILENAME + File name for second mesh output + (default: mesh2.nc) + --nCells NCELLS The number of cells in the first mesh + (default: the value specified in MESHFILE global attribute merge_point) + --nEdges NEDGES The number of edges in the first mesh + (default: the value specified in MESHFILE global attribute merge_point) + --nVertices NVERTICES + The number of vertices in the first mesh + (default: the value specified in MESHFILE global attribute merge_point) + --maxEdges MAXEDGES1 MAXEDGES2 + The number of maxEdges in each mesh + (default: the value specified in MESHFILE global attribute merge_point + OR: will use MESHFILE maxEdges dimension and assume same for both) + + +.. _mesh_translation: + +Translation +=========== + +A planar mesh can be translated in x, y or both by calling +:py:func:`mpas_tools.translate.translate()`: + +.. code-block:: python + + from mpas_tools.translate import translate + from mpas_tools.planar_hex import make_planar_hex_mesh + + dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False, + nonperiodic_y=False) + + translate(dsMesh, xOffset=1000., yOffset=2000.) + +This creates a periodic, planar mesh and then translates it by 1 km in x and +2 km in y. + +.. note:: + + All the functions in the ``mpas_tools.translate`` module modify the mesh + inplace, rather than returning a new ``xarray.Dataset`` object. This is + in contrast to typical ``xarray`` functions and methods. + + +A mesh can be translated so that its center is at ``x = 0.``, ``y = 0.`` with +the function :py:func:`mpas_tools.translate.center()`: + +.. code-block:: python + + from mpas_tools.translate import center + from mpas_tools.planar_hex import make_planar_hex_mesh + + dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False, + nonperiodic_y=False) + + center(dsMesh) + +A mesh can be translated so its center matches the center of another mesh by +using :py:func:`mpas_tools.translate.center_on_mesh()`: + +.. code-block:: python + + from mpas_tools.translate import center_on_mesh + from mpas_tools.planar_hex import make_planar_hex_mesh + + dsMesh1 = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False, + nonperiodic_y=False) + + dsMesh2 = make_planar_hex_mesh(nx=20, ny=40, dc=2000., nonperiodic_x=False, + nonperiodic_y=False) + + center_on_mesh(dsMesh2, dsMesh1) + +In this example, the coordinates of ``dsMesh2`` are altered so its center +matches that of ``dsMesh1``. + +The functionality of all three of these functions is also available via the +``translate_planar_grid`` command-line tool: + +.. code-block:: none + + $ translate_planar_grid --help + + == Gathering information. (Invoke with --help for more details. All arguments are optional) + Usage: translate_planar_grid [options] + + This script translates the coordinate system of the planar MPAS mesh specified + with the -f flag. There are 3 possible methods to choose from: 1) shift the + origin to the center of the domain 2) arbirary shift in x and/or y 3) shift to + the center of the domain described in a separate file + + Options: + -h, --help show this help message and exit + -f FILENAME, --file=FILENAME + MPAS planar grid file name. [default: grid.nc] + -d FILENAME, --datafile=FILENAME + data file name to which to match the domain center of. + Uses xCell,yCell or, if those fields do not exist, + will secondly try x1,y1 fields. + -x SHIFT_VALUE user-specified shift in the x-direction. [default: + 0.0] + -y SHIFT_VALUE user-specified shift in the y-direction. [default: + 0.0] + -c shift so origin is at center of domain [default: + False] + + +Converting Between Mesh Formats +=============================== + +MSH to MPAS NetCDF +------------------ + +``jigsawpy`` produces meshes in ``.msh`` format that need to be converted to +`NetCDF `_ files for use by MPAS +components. A utility function +:py:func:`mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf()` or the +command-line utility ``jigsaw_to_netcdf`` are used for this purpose. + +In addition to the input ``.msh`` and output ``.nc`` files, the user must +specify whether this is a spherical or planar mesh and, if it is spherical, +provide the radius of the Earth in meters. + +Triangle to MPAS NetCDF +----------------------- + +Meshes in `Triangle `_ format +can be converted to MPAS NetCDF format using +:py:func:`mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf()` or +the ``triangle_to_netcdf`` command-line tool. + +The user supplies the names of input ``.node`` and ``.ele`` files and the +name of an output MPAS mesh file. + +MPAS NetCDF to Triangle +----------------------- + +MPAS meshes in NetCDF format can be converted to ``Triangle`` format using +:py:func:`mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle()` or +the ``mpas_to_triangle`` command-line tool. + +The user supplies the name of an input MPAS mesh file and the output prefix +for the resulting Triangle ``.node`` and ``.ele`` files. + +MPAS NetCDF to SCRIP +-------------------- + +The function :py:func:`mpas_tools.scrip.from_mpas.scrip_from_mpas()` can be +used to convert an MPAS mesh file in NetCDF format to +`SCRIP `_ +format. SCRIP files are typically used to create mapping files used to +interpolate between meshes. + +A command-line tools is also available for this purpose: + +.. code-block:: none + + $ scrip_from_mpas --help + == Gathering information. (Invoke with --help for more details. All arguments are optional) + Usage: scrip_from_mpas [options] + + This script takes an MPAS grid file and generates a SCRIP grid file. + + Options: + -h, --help show this help message and exit + -m FILENAME, --mpas=FILENAME + MPAS grid file name used as input. [default: grid.nc] + -s FILENAME, --scrip=FILENAME + SCRIP grid file to output. [default: scrip.nc] + -l, --landice If flag is on, landice masks will be computed and + used. diff --git a/0.22.0rc4/_sources/mesh_creation.rst.txt b/0.22.0rc4/_sources/mesh_creation.rst.txt new file mode 100644 index 000000000..5aa8cbd06 --- /dev/null +++ b/0.22.0rc4/_sources/mesh_creation.rst.txt @@ -0,0 +1,473 @@ +.. _mesh_creation: + +.. |---| unicode:: U+2014 .. em dash, trimming surrounding whitespace + :trim: + +************* +Mesh Creation +************* + +Uniform, Planar Meshes +====================== + +The most basic tool for creating an MPAS mesh is the function +:py:func:`mpas_tools.planar_hex.make_planar_hex_mesh()` or the associated +command-line tool ``planar_hex``. These tools create a uniform, planar mesh +of hexagons that may optionally be periodic in either or both of the x and +y directions. A typical call to ``make_planar_hex_mesh()`` might look like +the following: + +.. code-block:: python + + from mpas_tools.planar_hex import make_planar_hex_mesh + + dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False, + nonperiodic_y=False) + +This creates a periodic mesh in both x and y that is 10 grid cells by 20 grid +cells in size with 1-km resolution. The mesh is not save to a file in this +example but is instead returned as an ``xarray.Dataset`` object. + +The command-line approach for generating the same mesh would be: + +.. code-block:: none + + $ planar_hex --nx=10 --ny=20 --dc=1000. \ + --outFileName=periodic_mesh_10x20_1km.nc + +In this case, the resulting mesh is written to a file. + +The default is to make a periodic mesh (awkwardly, it's "not non-periodic"). If +you want a mesh that is not periodic in one or both directions, you first need +to create a mesh and then cull the cells along the periodic boundary. It +doesn't hurt to run the mesh converter as well, just to be sure the mesh +conforms correctly to the MPAS mesh specification: + +.. code-block:: python + + from mpas_tools.planar_hex import make_planar_hex_mesh + from mpas_tools.mesh.conversion import cull, convert + + dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=True, + nonperiodic_y=True) + + dsMesh = cull(dsMesh) + dsMesh = convert(dsMesh) + +On the command line, this looks like: + +.. code-block:: none + + $ planar_hex --nx=10 --ny=20 --dc=1000. --npx --npy \ + --outFileName=mesh_to_cull.nc + + $ MpasCellCuller.x mesh_to_cull.nc culled_mesh.nc + + $ MpasMeshConverter.x culled_mesh.nc nonperiodic_mesh_10x20_1km.nc + + +Building a JIGSAW Mesh +====================== + +The :py:mod:`mpas_tools.mesh.creation.build_mesh` module is used +create an MPAS mesh using the `JIGSAW `_ +and `JIGSAW-Python (jigsawpy) `_ +packages. + + +Spherical Meshes +---------------- + +Spherical meshes are constructed with the function +:py:func:`mpas_tools.mesh.creation.build_mesh.build_spherical_mesh()`. +The user provides a 2D array ``cellWidth`` of cell sizes in kilometers along +1D arrays for the longitude and latitude (the cell widths must be on a lon/lat +tensor grid) and the radius of the earth in meters. + +The result is an MPAS mesh file, called ``base_mesh.nc`` by default, as well as +several intermediate files: ``mesh.log``, ``mesh-HFUN.msh``, ``mesh.jig``, +``mesh-MESH.msh``, ``mesh.msh``, and ``mesh_triangles.nc``. + +Here is a simple example script for creating a uniform MPAS mesh with 240-km +resolution: + +.. code-block:: python + + #!/usr/bin/env python + import numpy as np + from mpas_tools.ocean import build_spherical_mesh + + + def cellWidthVsLatLon(): + """ + Create cell width array for this mesh on a regular latitude-longitude grid. + Returns + ------- + cellWidth : ndarray + m x n array of cell width in km + lon : ndarray + longitude in degrees (length n and between -180 and 180) + lat : ndarray + longitude in degrees (length m and between -90 and 90) + """ + dlat = 10 + dlon = 10 + constantCellWidth = 240 + + nlat = int(180/dlat) + 1 + nlon = int(360/dlon) + 1 + + lat = np.linspace(-90., 90., nlat) + lon = np.linspace(-180., 180., nlon) + + cellWidth = constantCellWidth * np.ones((lat.size, lon.size)) + return cellWidth, lon, lat + + + def main(): + cellWidth, lon, lat = cellWidthVsLatLon() + build_spherical_mesh(cellWidth, lon, lat, out_filename='base_mesh.nc') + + + if __name__ == '__main__': + main() + +We define the resolution on a coarse (10 degree by 10 degree) grid because it +is uniform. Meshes with more complex variation may require higher resolution +grids to cell widths. + +Planar Meshes +------------- + +Planar meshes can be constructed with the function +:py:func:`mpas_tools.mesh.creation.build_mesh.build_planar_mesh()`. Provide +this function with a 2D array ``cellWidth`` of cell sizes in kilometers and +1D arrays for x and y (the cell widths must be on a 2D tensor grid). Planar +meshes also require ``geom_points``, a list of point coordinates for bounding +polygon for the planar mesh, and ``geom_edges``, a list of edges between points +in ``geom_points`` that define the bounding polygon. + +As for spehrical meshes, the result is an MPAS mesh file, called +``base_mesh.nc`` by default, as well as several intermediate files: +``mesh.log``, ``mesh-HFUN.msh``, ``mesh.jig``, ``mesh-MESH.msh``, ``mesh.msh``, +and ``mesh_triangles.nc``. + + +JIGSAW Driver +------------- + +Underlying both spherical and planar mesh creation is the JIGSAW driver +function :py:func:`mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver()`. This +function is used to setup data structures and then build a JIGSAW mesh using +``jigsawpy``. + +Mesh Definition Tools +===================== + +The :py:mod:`mpas_tools.mesh.creation.mesh_definition_tools` module includes +several tools for defining the ``cellWidth`` variable. + +Merging Cell Widths +------------------- +The function +:py:func:`mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat()` +is used to combine two cell-width distributions that are functions of latitude +only and which asymptote to different constant values north and south of a given +transition latitude with a ``tanh`` function of a given characteristic width. + +For example, the following code snippet will produce cell widths as a function +of latitude of about 30 km south of the Arctic Circle and 10 km north of that +latitude, transitioning over a characteristic "distance" of about 5 degrees. + +.. code-block:: python + + import numpy + from mpas_tools.mesh.creation.mesh_definition_tools import \ + mergeCellWidthVsLat + + + lat = numpy.linspace(-90., 90., 181) + cellWidthInSouth = 30. + cellWidthInNorth = 10. + latTransition = 66.5 + latWidthTransition = 5. + + cellWidths = mergeCellWidthVsLat(lat, cellWidthInSouth, cellWidthInNorth, + latTransition, latWidthTransition) + +.. _ec_mesh: + +Defining an Eddy-closure Mesh +----------------------------- + +One of the commonly used flavor of MPAS-Ocean and MPAS-Seaice meshes is designed +with relatively coarse resolution in mind (requiring parameterization of ocean +eddies with an "eddy closure"). This flavor of mesh has resolution that is +purely a function of latitude, with 5 regions of relatively uniform resolution +(north polar, northern mid-latitudes, equatorial, southern mid-latitudes and +south polar) with smooth (``tanh``) transitions between these resolutions. + +The default EC mesh has resolutions of 35 km at the poles, 60 km at +mid-latitudes and 30 km at the equator. Transitions between equatorial and +mid-latitude regions are at 15 degrees N/S latitude and transitions between +mid-latitude and polar regions are at 73 degrees N/S latitude. The +transition near the equator is somewhat more abrupt (~6 degrees) than near the +poles (~9 degrees). The switch between the transitional ``tanh`` functions is +made at 40 degrees N/S latitude, where the resolution is nearly constant and no +appreciable discontinuity arises. The default EC mesh can be obtained with the +function +:py:func:`mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat()`: + +.. code-block:: python + + import numpy + from mpas_tools.mesh.creation.mesh_definition_tools import \ + EC_CellWidthVsLat + + lat = numpy.linspace(-90., 90., 181) + cellWidths = EC_CellWidthVsLat(lat) + +.. _rrs_mesh: + +Defining a Rossby-radius Mesh +----------------------------- + +Another common flavor of MPAS-Ocean and MPAS-Seaice meshes is designed for +higher resolutions, where the Rossby radius of deformation can be (at least +partially) resolved. These meshes approximately scale their resolution in +proportion to the Rossby radius. + +A typical Rossby Radius Scaling (RRS) mesh has a resolution at the poles that is +three times finer than the resolution at the equator. For example, the RRS mesh +used in E3SMv1 high resolution simulations would be defined, using the function +:py:func:`mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat()` +by: + +.. code-block:: python + + import numpy + from mpas_tools.mesh.creation.mesh_definition_tools import \ + RRS_CellWidthVsLat + + lat = numpy.linspace(-90., 90., 181) + cellWidths = RRS_CellWidthVsLat(lat, cellWidthEq=18., cellWidthPole=6.) + +Defining an Atlantic/Pacific Mesh +--------------------------------- + +The function +:py:func:`mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid()` +can be used to define a mesh that has two different, constant resolutions in the +Atlantic and Pacific Oceans. + + +Signed Distance Functions +========================= + +The :py:mod:`mpas_tools.mesh.creation.signed_distance` module includes several +functions for creating ``cellWidth`` variables based on the signed distance from +a boundary curve on the sphere. A signed distance function is positive outside +the bounding shape and negative inside, with a value proportional to the +distance to the nearest point on the curve (so the function is equal to zero on +the curve). Signed distance functions provide a useful way ot define +transitions in resolution based on complex shapes that can be defined using +`geojson `_ files. These files can be created by hand, +e.g. at `geojson.io `_ or in python using libraries like +`shapely `_. + +Calls to the functions in this module require a +`FeatureCollection `_ +object from the +`geometric_features `_ +package. The ``FeatureColleciton`` must define one or more regions on the +sphere from which the distance, mask, or signed distance will be computed. +The ``FeatureColleciton`` could come from the predefined features included in +``geometric_features``, could be read in from a ``geojson`` file (see +`Reading in Features `_), +or could be created as part of a python script with ``shapely`` or other tools. + +In this example, we first define a base resolution using the default EC mesh +(see :ref:`ec_mesh`) and then use +:py:func:`mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson()` +to create a signed distance function from a ``FeatureCollection`` read in from +`this geojson file `_. +The signed distance function is used to define a region of high resolution (12 +km) around Antarctica. + +.. code-block:: python + + import numpy as np + import mpas_tools.mesh.creation.mesh_definition_tools as mdt + from mpas_tools.mesh.creation.signed_distance import \ + signed_distance_from_geojson + from geometric_features import read_feature_collection + from mpas_tools.cime.constants import constants + + + dlon = 0.1 + dlat = dlon + earth_radius = constants['SHR_CONST_REARTH'] + nlon = int(360./dlon) + 1 + nlat = int(180./dlat) + 1 + lon = np.linspace(-180., 180., nlon) + lat = np.linspace(-90., 90., nlat) + + cellWidth = mdt.EC_CellWidthVsLat(lat) + + # broadcast cellWidth to 2D + _, cellWidth = np.meshgrid(lon, cellWidthVsLat) + + # now, add the high-res region + fc = read_feature_collection('high_res_region.geojson') + + so_signed_distance = signed_distance_from_geojson(fc, lon, lat, + earth_radius, + max_length=0.25) + + # Equivalent to 20 degrees latitude + trans_width = 1600e3 + trans_start = -500e3 + dx_min = 12. + + weights = 0.5 * (1 + np.tanh((so_signed_distance - trans_start) / + trans_width)) + + cellWidth = dx_min * (1 - weights) + cellWidth * weights + +Sometimes it can be useful to extract just the mask of the region of interest +(defined as ``0`` outside the the region and ``1`` inside it) or the unsigned +distance. For these purposes, use the functions +:py:func:`mpas_tools.mesh.creation.signed_distance.mask_from_geojson()` +and +:py:func:`mpas_tools.mesh.creation.signed_distance.distance_from_geojson()`, +respectively. + +The grid does not necessarily have to be uniform in resolution. Here is a +relatively complicated example where the highest resolution (1/100 degree) of +the lon/lat grid is concentrated within +/- 10 degrees of 0 degrees longitude +and 0 degrees latitude and the resolution is ~2 degrees elsewhere. The shape +``test.geojson`` is given below, and is in the high-res region: + +.. code-block:: python + + import numpy + import matplotlib.pyplot as plt + + from geometric_features import read_feature_collection + + from mpas_tools.cime.constants import constants + from mpas_tools.mesh.creation.signed_distance import \ + distance_from_geojson, mask_from_geojson, signed_distance_from_geojson + + + def gaussian(dcoarse, dfine, cmin, cmax, center, width, iter_count=10): + def get_res(xval): + res = dcoarse + \ + (dfine - dcoarse) * numpy.exp(-(xval - center) ** 2 / + (2. * width**2)) + return res + + x = [cmin] + while x[-1] < cmax: + d = get_res(x[-1]) + for index in range(iter_count): + x_mid = x[-1] + 0.5*d + d = get_res(x_mid) + x.append(x[-1] + d) + + x = numpy.array(x) + factor = (cmax - cmin)/(x[-1] - x[0]) + x = cmin + factor*(x - x[0]) + return x + + + def main(): + dcoarse = 2. + dfine = 0.01 + width = 10. + + lon = gaussian(dcoarse=dcoarse, dfine=dfine, cmin=-180., cmax=180., + center=0., width=width) + + lat = gaussian(dcoarse=dcoarse, dfine=dfine, cmin=-90., cmax=90., + center=0., width=width) + + earth_radius = constants['SHR_CONST_REARTH'] + + fc = read_feature_collection('test.geojson') + + distance = distance_from_geojson(fc, lon, lat, earth_radius, + max_length=dfine) + + mask = mask_from_geojson(fc, lon, lat, max_length=dfine) + + signed_distance = signed_distance_from_geojson(fc, lon, lat, earth_radius, + max_length=dfine) + + +Here is ``test.geojson``: + +.. code-block:: python + + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "weird shape", + "component": "ocean", + "object": "region", + "author": "Xylar Asay-Davis" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 3.8232421875000173, + 3.283113991917228 + ], + [ + 1.5600585937500142, + 3.8752158957336085 + ], + [ + 0.9448242187500171, + 1.8453839885731744 + ], + [ + -0.3186035156249841, + 0.8239462091017558 + ], + [ + 0.6372070312500188, + -0.37353251022881745 + ], + [ + 2.3181152343750147, + 0.03295898255728466 + ], + [ + 3.636474609375017, + -0.3405741662837591 + ], + [ + 4.163818359375015, + 1.5159363834516735 + ], + [ + 2.9443359375000164, + 1.9771465537125645 + ], + [ + 3.8232421875000173, + 3.283113991917228 + ] + ] + ] + } + } + ] + } + diff --git a/0.22.0rc4/_sources/ocean/coastal_tools.rst.txt b/0.22.0rc4/_sources/ocean/coastal_tools.rst.txt new file mode 100644 index 000000000..5a17a59d7 --- /dev/null +++ b/0.22.0rc4/_sources/ocean/coastal_tools.rst.txt @@ -0,0 +1,369 @@ +.. _ocean_coastal_tools: + +.. |---| unicode:: U+2014 .. em dash, trimming surrounding whitespace + :trim: + +Coastal Tools +============= + +The :py:mod:`mpas_tools.ocean.coastal_tools` module contains several functions +that aid in the construction of meshes refined around coastlines. + +.. _coastal_tools_refine_mesh: + +Refining a Mesh +--------------- + +The main driver of coastal tools is the function +:py:func:`mpas_tools.ocean.coastal_tools.coastal_refined_mesh()`. This function +is called repeatedly with different dictionaries of ``params`` to add refinement +in different locations, starting from a background mesh (see +:ref:`coastal_tools_background_mesh`). + +``coastal_tools`` provides the following dictionary of default parameters as +a starting point for ``params``: + +.. code-block:: python + + default_params = { + + # Path to bathymetry data and name of file + "nc_file": "./earth_relief_15s.nc", + "nc_vars": ["lon","lat","z"], + + # Bounding box of coastal refinement region + "region_box": Continental_US, + "origin": np.array([-100, 40]), + "restrict_box": Empty, + + # Coastline extraction parameters + "z_contour": 0.0, + "n_longest": 10, + "smooth_coastline": 0, + "point_list": None, + + # Global mesh parameters + "grd_box": Entire_Globe, + "ddeg": .1, + # 'EC' (defaults to 60to30), 'QU' (uses dx_max_global), + # 'RRS' (uses dx_max_global and dx_min_global) + "mesh_type": 'EC', + "dx_max_global": 30.0 * km, + "dx_min_global": 10.0 * km, + + # Coastal mesh parameters + "dx_min_coastal": 10.0 * km, + "trans_width": 600.0 * km, + "trans_start": 400.0 * km, + + # Bounding box of plotting region + "plot_box": North_America, + + # Options + "nn_search": "kdtree", + "plot_option": True + + } + +A coastal mesh is defined by: + +1. :ref:`coastal_tools_background_mesh` +2. :ref:`coastal_tools_extract` +3. :ref:`coastal_tools_distance` +4. :ref:`coastal_tools_cell_width` + +Steps 2-4 can be repeated with several different regions to add more refinement. + +The first time ``coastal_refined_mesh()`` is called, no cell width, latitude or +longitude coordinates are supplied. In this case, a background mesh resolution +is defined through a call to +:py:func:`mpas_tools.ocean.coastal_tools.create_background_mesh()`. The +following entries in ``params`` are used as arguments: + +* ``'grd_box'`` - the bounds of the grid defining the mesh resolution +* ``'ddeg'`` - the resolution in longitude and latitude in degrees +* ``'mesh_type'`` - one of {``'QU'``, ``'EC'`` or ``'RRS'``} indicating the + type of mesh +* ``'dx_min_global'`` - the resolution for a ``QU`` mesh, the minimum resolution + for an ``RRS`` mesh, ignored for ``EC`` meshes. +* ``'dx_max_global'`` - the maximum resolution for an ``RRS`` mesh, ignored for + ``QU`` and ``EC`` meshes. +* ``'plot_option'`` - whether to plot the results and save it to a PNG file. +* ``'plot_box'`` - If ``plot_option`` is ``True``, the bounds of the plot in + longitude and latitude. + +After the background field of cell widths has been created or using the +cell widths passed in as function arguments, ``coastal_refined_mesh()`` then +adds a region of refinement. + +First, a set of coastline contours is extracted by calling +:py:func:`mpas_tools.ocean.coastal_tools.extract_coastlines()` with the +following values from ``params``: + +* ``'nc_file'`` - A bathymetry dataset on a lon/lat grid in NetCDF format +* ``'nc_vars'`` - The names of the lon, lat and bathymetry variables in a list +* ``'region_box'`` - see :ref:`coastal_tools_regions` +* ``'z_contour'`` - A contour level from the bathymetry dataset to extract as a + region boundary +* ``'n_longest'`` - The maximum number of contours to retain (sorted from + longest to shortest). +* ``'point_list'`` - An optional list of points to add to the coastline +* ``'plot_option'`` - Whether to plot the extracted coastline. +* ``'plot_box'`` - If ``plot_option`` is ``True``, the bounds of the plot in + longitude and latitude. + +Next, the distance to the coastal contours is computed using +:py:func:`mpas_tools.ocean.coastal_tools.distance_to_coast()` with the +following values from ``params``: + +* ``'nn_search'`` - currently, only the ``'kdtree'`` algorithm is supported +* ``'smooth_coastline'`` - The number of neighboring cells along the coastline + over which to average locations to smooth the coastline +* ``'plot_option'`` - Whether to plot the distance function. +* ``'plot_box'`` - If ``plot_option`` is ``True``, the bounds of the plot in + longitude and latitude. + +Finally, the distance function is used to blend the background and refined +regions using +:py:func:`mpas_tools.ocean.coastal_tools.compute_cell_width()` with the +following values from ``params``: + +* ``'dx_min_coastal'`` - the resolution in meters of the refined region +* ``'trans_start'`` - the distance in meters from the coast at which the + transition in resolution begins---the center of the transition is half a + ``trans_width`` farther from the coastline +* ``'trans_width'`` - the distance in meters over which the transition occurs +* ``'restrict_box'`` - A region of made up of quadrilaterals to ``include`` and + ``exclude`` that defines where resolution may be altered. Outside of the + ``restrict_box``, the resolution remains unchanged. See + :ref:`coastal_tools_regions`. +* ``'plot_option'`` - Whether to plot the cell widths and transition function. +* ``'plot_box'`` - If ``plot_option`` is ``True``, the bounds of the plot in + longitude and latitude. + +Here is an example of multiple calls to ``coastal_refined_mesh()`` in action, +taken from the +`hurricane/USDEQU120at30cr10rr2 `_ +test case from +`COMPASS `_. +This workflow refines a background uniform mesh with 120-km resolution with +successively higher and higher resolution down to the Delaware Bay at 2-km +resolution. + +.. code-block:: python + + import mpas_tools.ocean.coastal_tools as ct + + + km = 1000.0 + + params = ct.default_params + + print("****QU 120 background mesh and enhanced Atlantic (30km)****") + params["mesh_type"] = "QU" + params["dx_max_global"] = 120.0 * km + params["region_box"] = ct.Atlantic + params["restrict_box"] = ct.Atlantic_restrict + params["plot_box"] = ct.Western_Atlantic + params["dx_min_coastal"] = 30.0 * km + params["trans_width"] = 5000.0 * km + params["trans_start"] = 500.0 * km + + cell_width, lon, lat = ct.coastal_refined_mesh(params) + + print("****Northeast refinement (10km)***") + params["region_box"] = ct.Delaware_Bay + params["plot_box"] = ct.Western_Atlantic + params["dx_min_coastal"] = 10.0 * km + params["trans_width"] = 600.0 * km + params["trans_start"] = 400.0 * km + + cell_width, lon, lat = ct.coastal_refined_mesh( + params, cell_width, lon, lat) + + print("****Delaware regional refinement (5km)****") + params["region_box"] = ct.Delaware_Region + params["plot_box"] = ct.Delaware + params["dx_min_coastal"] = 5.0 * km + params["trans_width"] = 175.0 * km + params["trans_start"] = 75.0 * km + + cell_width, lon, lat = ct.coastal_refined_mesh( + params, cell_width, lon, lat) + + print("****Delaware Bay high-resolution (2km)****") + params["region_box"] = ct.Delaware_Bay + params["plot_box"] = ct.Delaware + params["restrict_box"] = ct.Delaware_restrict + params["dx_min_coastal"] = 2.0 * km + params["trans_width"] = 100.0 * km + params["trans_start"] = 17.0 * km + + cell_width, lon, lat = ct.coastal_refined_mesh( + params, cell_width, lon, lat) + +.. _coastal_tools_background_mesh: + +Creating a Background Mesh +-------------------------- + +A background mesh is typically created by calling +:py:func:`mpas_tools.ocean.coastal_tools.coastal_refined_mesh()` without +providing an input mesh but can also be created by calling +:py:func:`mpas_tools.ocean.coastal_tools.create_background_mesh()` directly. + +The user must define the bounds of the grid in longitude and latitude (typically +-180 to 180 and -90 to 90, respectively) and the resolution in degrees. The +mesh can be any of three types: {``'QU'``, ``'EC'`` or ``'RRS'``}. For +Quasi-Uniform (QU) meshes, the resulting cell width will be a constant equal to +``dx_min_global``. For Eddy-Closure (EC) meshes, the default parameters are +always used (see :ref:`ec_mesh`). For Rossby-Radius Scaled (RRS) meshes, +``dx_min_global`` is the resolution at the poles while ``dx_max_global`` is the +resolution at the equator (see :ref:`rrs_mesh`). + +.. _coastal_tools_extract: + +Extracting Coastlines +--------------------- + +``coastal_tools`` extracts points along a coastline using +:py:func:`mpas_tools.ocean.coastal_tools.extract_coastlines()`. The default +parameters are set up to use the +`earth_relief_15s.nc dataset `_, +but any bathymetry data set on a lon/lat grid could be used as long as +``params['nc_file']`` is modified to point to the new name of the dataset and +``params['nc_vars']`` is set to the appropriate variable names. + +By default, the coastline is extracted using the ``z = 0.0`` contour of the +bathyemtry but other values can be selected (e.g. to use distance from the +continental shelf break) by defining ``params['z_contour']``. +By default, only the 10 longest contours are retained to reduce computational +cost but more (or fewer) contours can be retained by setting +``params['n_longest']`` to another number. + +Optionally, the results can be plotted withing the given "plot box" and saved +to a file. + +.. _coastal_tools_distance: + +Computing Distance to Coast +--------------------------- + +A key ingredient in defining resolution in coastal meshes is a field containing +the distance from each location in the field to the nearest point on the +coastline. This distance field ``D`` is computed with +:py:func:`mpas_tools.ocean.coastal_tools.distance_to_coast()` +The user could previouly control the search algorithm used via +``params['nn_search']`` but ``'kdtree'`` is now the only option. +They can also decide to smooth the coastline as long as there is +a single coastline contour---with multiple contours, the current algorithm will +average the end of one contour with the start fo the next---by specifying an +integer number of neighbors as ``params['smooth_coastline']``. The default is +no smoothing (``0`` neighbors). + +.. _coastal_tools_cell_width: + +Blending Cell Widths +-------------------- + +The final step in each iteration of coastal refinement is to blend the new, +refined resolution into the previous grid of cell widths with the function +:py:func:`mpas_tools.ocean.coastal_tools.compute_cell_width()`. + +The most important parameters to set are ``params['dx_min_coastal']``, the +resolution in meters of the refined region; ``params['trans_start']``, the +distance from the coast in meters where the transition in resolution should +start; and ``params['trans_width']``, the width of the transition itself in +meters. + +The resolution refinement can be confined to a region using +``params['restrict_box']`` to supply a region of made up of quadrilaterals to +``include`` and ``exclude`` from the restricted region. ``include`` boxes +specify regions where the distance-based coastal refinement function should be +used to update the desired cell width values. ``exclude`` boxes eliminate areas +within the ``include`` regions so they are not affected by the coastal +refinement function. This is useful for preventing resolution from appearing on +one side of a narrow piece of land. For example, coastal refinement in the Gulf +of Mexico should not appear on the other Pacific Ocean side of Central America. +The ``params['restrict_box']`` regions can be used to enforce this. + +Here is an example of a restriction box for the region around Delaware, used in +the example above: + +.. code-block:: python + + Delaware_restrict = {"include": [np.array([[-75.853, 39.732], + [-74.939, 36.678], + [-71.519, 40.156], + [-75.153, 40.077]]), + np.array([[-76.024, 37.188], + [-75.214, 36.756], + [-74.512, 37.925], + [-75.274, 38.318]])], + "exclude": []} + + +.. _coastal_tools_regions: + +Regions +------- + +:ref:`coastal_tools_extract` requires a set of bounding regions to be defined. +These regions are made up of a list of quadrilaterals to ``include`` and another +list to ``exclude``. The quadrilaterals are either bounding rectangles +(min lon, max lon, min lat, max lat) or lists of 4 (lon, lat) points numbered +counter clockwise. + +``include`` boxes specify areas where coastline contours will be extracted from +the underlying bathymetry dataset. ``exclude`` boxes can be used to select +regions within ``include`` regions where coastline extraction should not be +done. For example, a large include box covering the U.S. East Coast may contain +small islands in the Atlantic, which may need to be ignored when placing coastal +refinement. In this case, ``exclude`` boxes can be specified to eliminate the +small coastlines. + +An example of such a region is: + +.. code-block:: python + + Greenland = {"include":[np.array([-81.5, -12.5, 60, 85])], + "exclude":[np.array([[-87.6, 58.7], + [-51.9, 56.6], + [-68.9, 75.5], + [-107.0, 73.3]]), + np.array([[-119.0, 74.5], + [-92.7, 75.9], + [-52.84, 83.25], + [-100.8, 84.0]]), + np.array([[-101.3, 68.5], + [-82.4, 72.3], + [-68.7, 81.24], + [-117.29, 77.75]]), + np.array([-25.0, -10.0, 62.5, 67.5])]} + +.. note:: + + This example includes both bounding rectangles (e.g. + ``np.array([-81.5, -12.5, 60, 85])``) and more general quadrilaterals (e.g. + ``np.array([[-101.3, 68.5], [-82.4, 72.3],...``) + +``coastal_tools`` defines 16 regions via dictionaries of this type. The defined +regions are: + +* Delaware_Bay +* Galveston_Bay +* Delaware_Region +* US_East_Coast +* US_Gulf_Coast +* Caribbean +* US_West_Coast +* Hawaii +* Alaska +* Bering_Sea_E +* Bering_Sea_W +* Aleutian_Islands_E +* Aleutian_Islands_W +* Greenland +* CONUS +* Continental_US + diff --git a/0.22.0rc4/_sources/ocean/coastline_alteration.rst.txt b/0.22.0rc4/_sources/ocean/coastline_alteration.rst.txt new file mode 100644 index 000000000..5a9385ecb --- /dev/null +++ b/0.22.0rc4/_sources/ocean/coastline_alteration.rst.txt @@ -0,0 +1,152 @@ +.. _ocean_coastline_alteration: + +Coastline Alteration +==================== + +The :py:mod:`mpas_tools.ocean.coastline_alteration` module contains several +functions for modifying the coastline in MPAS cells. This is accomplished by +modifying the land mask that indicates which MPAS cells are ocean vs. land +(or grounded ice). + +.. _coastline_land_blockages: + +Adding Land Blockages +--------------------- + +The function +:py:func:`mpas_tools.ocean.coastline_alteration.add_critical_land_blockages()` +add the masks associated with one or more transects to the land mask. This is +useful if there are land features (typically peninsulas or narrow land bridges) +that must block the ocean flow even if they are too narrow to be resolved in +the MPAS mesh. + +An example of the typical workflow that uses this function would be: + +.. code-block:: python + + import xarray + + from geometric_features import GeometricFeatures + from mpas_tools.mesh import conversion + from mpas_tools.ocean.coastline_alteration import add_critical_land_blockages + + + # an object used to read feature collections from the geometric_features + # package + gf = GeometricFeatures() + + # get geometry of the land coverage from Natural Earth + fcLandCoverage = gf.read(componentName='natural_earth', objectType='region', + featureNames=['Land Coverage']) + + # read in the base mesh + dsBaseMesh = xarray.open_dataset('base_mesh.nc') + # create a mask on the base mesh that is ones for land or grounded ice and + # zeros for ocean + dsLandMask = conversion.mask(dsBaseMesh, fcMask=fcLandCoverage) + + # get a collection of features from geometric_features that are meant for + # use as critical land blockages + fcCritBlockages = gf.read(componentName='ocean', objectType='transect', + tags=['Critical_Land_Blockage']) + + # make masks from the transects + dsCritBlockMask = conversion.mask(dsBaseMesh, fcMask=fcCritBlockages) + + # add the masks to the "land" mask + dsLandMask = add_critical_land_blockages(dsLandMask, dsCritBlockMask) + +.. _coastline_mask_land_locked: + +Masking Land-locked Cells +------------------------- + +By default, the land mask produced by the MPAS :ref:`mask_creator` can produce +ocean cells with vertices that are all on the land-ocean boundary. MPAS-Seaice +uses a so-called +`Arakawa B-grid `_, +meaning that velocities are located at vertices of the MPAS mesh. This means +that sea-ice flow into or out of a given cell is not possible if all vertices +of that cell are boundary vertices (where the velocity is, by definition, zero). +This problem is alleviated by calling +:py:func:`mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask()`. +Any "land-locked" cells with only boundary vertices are removed from the mesh. +Land-locked cells are only removed poleward of a threshold latitude (43 degrees +by default). The user can specify the number of iterations (``nSweeps``) of +land-locked cell removal, since removing land-locked cells can produce new +land-locked cells. + +Here is an example workflow that removes land-locked cells: + +.. code-block:: python + + import xarray + + from geometric_features import GeometricFeatures + from mpas_tools.mesh import conversion + from mpas_tools.ocean.coastline_alteration import \ + add_land_locked_cells_to_mask + + + # an object used to read feature collections from the geometric_features + # package + gf = GeometricFeatures() + + # get geometry of the land coverage from Natural Earth + fcLandCoverage = gf.read(componentName='natural_earth', objectType='region', + featureNames=['Land Coverage']) + + # read in the base mesh + dsBaseMesh = xarray.open_dataset('base_mesh.nc') + # create a mask on the base mesh that is ones for land or grounded ice and + # zeros for ocean + dsLandMask = conversion.mask(dsBaseMesh, fcMask=fcLandCoverage) + + # Find ocean cells that are land-locked, and alter the cell mask so that + # they are counted as land cells + dsLandMask = add_land_locked_cells_to_mask(dsLandMask, dsBaseMesh, + latitude_threshold=43.0, + nSweeps=20) + +.. _coastline_widen_transects: + +Widening Transects +------------------ + +Similarly to :ref:`coastline_mask_land_locked`, if critical passages in polar +regions are too narrow, they can become blocked by sea ice that cannot be +advected. Sea-ice flow is not possible unless channels are at least 2 cells +wide. This widening is accomplished with +:py:func:`mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks()`. +Channels are only widened poleward of a threshold latitude (43 degrees by +default). + +An example workflow that includes transect-widening is: + +.. code-block:: python + + import xarray + + from geometric_features import GeometricFeatures + from mpas_tools.mesh import conversion + from mpas_tools.ocean.coastline_alteration import widen_transect_edge_masks + + # an object used to read feature collections from the geometric_features + # package + gf = GeometricFeatures() + + # read in the base mesh + dsBaseMesh = xarray.open_dataset('base_mesh.nc') + + # merge transects for critical passages into critical_passages.geojson + fcCritPassages = gf.read(componentName='ocean', objectType='transect', + tags=['Critical_Passage']) + + # create masks from the transects + dsCritPassMask = conversion.mask(dsBaseMesh, fcMask=fcCritPassages) + + # Alter critical passages to be at least two cells wide, to avoid sea ice + # blockage. + dsCritPassMask = widen_transect_edge_masks(dsCritPassMask, dsBaseMesh, + latitude_threshold=43.0) + diff --git a/0.22.0rc4/_sources/ocean/depth.rst.txt b/0.22.0rc4/_sources/ocean/depth.rst.txt new file mode 100644 index 000000000..e0c0b05d1 --- /dev/null +++ b/0.22.0rc4/_sources/ocean/depth.rst.txt @@ -0,0 +1,52 @@ +.. _ocean_depth: + +Adding a Depth Coordinate +========================= + +Adding a 1D depth coordinate +---------------------------- + +The function :py:func:`mpas_tools.ocean.depth.add_depth()` can be used to add +a 1D ``depth`` coordinate that is appropriate for runs with a z-star MPAS-Ocean +mesh. The coordinate is only approximately correct but is useful for +visualization. + +Internally, the depth is computed with +:py:func:`mpas_tools.ocean.depth.compute_depth()`, which could also be called +directly if one has a suitable ``refBottomDepth`` data array indicating the +reference depth of the bottom of each layer in a 1D coordinate that is +independent of both time and horizontal coordinate. + + +Adding a 3D zMid coordinate +--------------------------- + +The function :py:func:`mpas_tools.ocean.depth.add_zmid()` can be used to add +a time-independent, 3D ``zMid`` coordinate that is appropriate for runs with +any MPAS-Ocean vertical coordinate that is not a significant function of time. +This is appropriate for both z-star simulations and those with ice-shelf +cavities, which have a more complex vertical coordinate. The coordinate is only +approximately correct because MPAS-Ocean coordinates vary at least slightly +in time (with the undulation of the sea surface). The time-independent ``zMid`` +is appropriate for visualization an analysis that does not need to account for +this time variability. + +Internally, the ``zMid`` is computed with +:py:func:`mpas_tools.ocean.depth.compute_zmid()`, which could also be called +directly if one has a suitable ``bottomDepth``, ``maxLevelCell``, +and (reference) ``layerThickness`` data arrays. + + +Writing a time-dependent, 3D zMid variable +------------------------------------------ + +The function :py:func:`mpas_tools.ocean.depth.write_time_varying_zmid()` can be +used to write out a time-dependent, 3D ``zMid`` variable to its own file. +This is the "true" MPAS-Ocean vertical coordinate, in contrast to the 1D and +3D time-independent coordinates mentioned above. However, it requires a +significant amount of disk space so may not be desirable in many contexts. + +Internally, the ``zMid`` is computed with +:py:func:`mpas_tools.ocean.depth.compute_zmid()` using the time-dependent +``layerThickness`` variable, where ```` is a prefix such as +``'timeMonthly_avg_'`` or an empty string (``''``) for no prefix. diff --git a/0.22.0rc4/_sources/ocean/mesh_creation.rst.txt b/0.22.0rc4/_sources/ocean/mesh_creation.rst.txt new file mode 100644 index 000000000..555dcd7e6 --- /dev/null +++ b/0.22.0rc4/_sources/ocean/mesh_creation.rst.txt @@ -0,0 +1,41 @@ +.. _ocean_mesh_creation: + +Ocean Mesh Creation +=================== + +The :py:mod:`mpas_tools.ocean.build_mesh` module is used create +ocean-specific MPAS meshes using the +:py:mod:`mpas_tools.mesh.creation.build_mesh` module. + +Spherical meshes are constructed with the function +:py:func:`mpas_tools.ocean.build_mesh.build_spherical_mesh()`. The basic +arguments are the same as those to +:py:func:`mpas_tools.mesh.creation.build_mesh.build_spherical_mesh()`. + +Similarly, planar meshes can be constructed with the function +:py:func:`mpas_tools.ocean.build_mesh.build_planar_mesh()`, which has the +same basic arguments as +:py:func:`mpas_tools.mesh.creation.build_mesh.build_planar_mesh()`. + +Each of these functions has additional, optional arguments that allow users to: + + * specify a directory for extracting VTK geometry for viewing in + `ParaVeiw `_. + The :py:func:`mpas_tools.viz.paraview_extractor.extract_vtk` function is + used to produce a VTK file in this directory, named ``base_mesh_vtk`` + by default. + + * Specify whether to preserve a region of the mesh above sea level as a + floodplain, and the elevation up to which this regions should remain part + of the mesh. This feature is used in coastal simulations that support + wetting and drying. A field, ``cellSeedMask``, is added to the mesh file + that can later be used preserve the floodplain. + See :py:func:`mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain`. + + + * Whether to add a default bathymetry data set to the mesh. A field, + ``bottomDepthObserved``, is added to the mesh file with bathymetry data + from one of two topography files: ``earth_relief_15s.nc`` or ``topo.msh``. + If bathymetry should be added to the mesh, a local link with one of these + file names must exist. + See :py:func:`mpas_tools.ocean.inject_bathymetry.inject_bathymetry`. diff --git a/0.22.0rc4/_sources/ocean/moc.rst.txt b/0.22.0rc4/_sources/ocean/moc.rst.txt new file mode 100644 index 000000000..06759a939 --- /dev/null +++ b/0.22.0rc4/_sources/ocean/moc.rst.txt @@ -0,0 +1,150 @@ +.. _ocean_moc: + +Meridional Overturning Circulation +================================== + +The :py:mod:`mpas_tools.ocean.moc` module contains tools for setting up masks +used by both +`MPAS-Ocean `_ and +`MPAS-Analysis `_ for +computing the global and basin-wide Meridional Overturning Circulation (MOC). + +.. _moc_basins: + +Building MOC Basins +------------------- + +The :py:func:`mpas_tools.ocean.moc.build_moc_basins()` function can be used to +merge a large number of individual seas from the +`geometric_features ` +package into 5 larger features defining the MOC basins: + +* Global +* Atlantic +* Indian +* Pacific +* Indo-pacific + +A call to this function returns a +`FeatureCollection `_ +with these 5 basins. + +A typical workflow calling this function would look like: + +.. code-block:: python + + from geometric_features import GeometricFeatures + from mpas_tools.ocean.moc import build_moc_basins + + + gf = GeometricFeatures() + fcMOC = build_moc_basins(gf) + +.. _moc_southern_transects: + +Adding Southern Transects +------------------------- + +Typically, the basins on their own are not particularly useful. For all but +the global MOC, a southern transect is needed to determine the flow into or +out of the basin from the south. The function +:py:func:`mpas_tools.ocean.mocadd_moc_southern_boundary_transects()` can be +used to add masks for all the edges associated with the southern boundary of +each MOC basin. + +A typical workflow calling this function would look like: + +.. code-block:: python + + import xarray + from geometric_features import GeometricFeatures + from mpas_tools.ocean.moc import build_moc_basins + + + mesh_filename = 'mesh.nc' + + gf = GeometricFeatures() + fcMOC = build_moc_basins(gf) + + dsMesh = xarray.open_dataset(mesh_filename) + dsMasks = mpas_tools.mesh.conversion.mask(dsMesh=dsMesh, fcMask=fcMOC) + + dsMasksAndTransects = add_moc_southern_boundary_transects(dsMasks, dsMesh) + +In this example, only the ``mesh.nc`` file is required as an input. The +resulting ``xarray.Dataset`` contains both the basin and southern-transect +masks. + +A command-line tool ``moc_southern_boundary_extractor.py`` is also available +for this purpose: + +.. code-block:: none + + $ moc_southern_boundary_extractor.py --help + + usage: moc_southern_boundary_extractor.py [-h] -f IN_FILE -m MESH_FILE -o + OUT_FILE + + This script takes a mesh file (-m flag) and a file with MOC regions masks + (-f flag) produce by the MPAS mask creator. The script produces a copy of + the contents of the MOC mask file, adding transects that mark the southern + boundary of each region in a file indicated with the -o flag. The transect + is applied only to vertices and edges, not cells, because the need for southern + boundary transect data on cells is not foreseen. + + Author: Xylar Asay-Davis + last modified: 5/22/2018 + + optional arguments: + -h, --help show this help message and exit + -f IN_FILE, --in_file IN_FILE + Input file with MOC masks + -m MESH_FILE, --mesh_file MESH_FILE + Input mesh file + -o OUT_FILE, --out_file OUT_FILE + Output file for MOC masks and southern-boundary transects + +The command-line tool is largely intended for backwards compatibility and the +python function is the preferred way of building a workflow with this +functionality. + +.. _moc_basins_and_transects: + +Building MOC Basins and Transects Together +------------------------------------------ + +Typically, a workflow can be made more efficient by using the function +:py:func:`mpas_tools.ocean.moc.make_moc_basins_and_transects()` takes care of +both :ref:`moc_basins` and :ref:`moc_southern_transects` as well as writing out +the results to files. + +A typical workflow calling this function would look like: + +.. code-block:: python + + from geometric_features import GeometricFeatures + from mpas_tools.ocean.moc import make_moc_basins_and_transects + + + mesh_filename = 'mesh.nc' + mesh_name = 'EC30to60kmL60E3SMv2r03' + + mask_filename = '{}_moc_masks.nc'.format(mesh_name) + mask_and_transect_filename = '{}_moc_masks_and_transects.nc'.format( + mesh_name) + + geojson_filename = 'moc_basins.geojson' + + gf = GeometricFeatures() + + make_moc_basins_and_transects(gf, mesh_filename, mask_and_transect_filename, + geojson_filename=geojson_filename, + mask_filename=mask_filename) + +In this example, only the ``mesh.nc`` file is required as an input. The basin +and transect masks are written to ``mask_and_transect_filename``, and we also +request that the intermediate data sets get written out for, perhaps for +purposes of debugging or provenance. The MOC feature collection from +:ref:`moc_basins` will be written to ``geojson_filename``, while the basin +masks (without the associate transect masks) will be written to +``mask_filename``. diff --git a/0.22.0rc4/_sources/ocean/visualization.rst.txt b/0.22.0rc4/_sources/ocean/visualization.rst.txt new file mode 100644 index 000000000..a2490398c --- /dev/null +++ b/0.22.0rc4/_sources/ocean/visualization.rst.txt @@ -0,0 +1,109 @@ +.. _ocean_visualization: + +************* +Visualization +************* + +.. _ocean_viz_transects: + +Plotting Ocean Transects +======================== + +.. image:: ../images/south_atlantic_temperature_transect.png + :width: 500 px + :align: center + +The function :py:func:`mpas_tools.ocean.viz.plot_ocean_transects()` and the +associated ``plot_ocean_transects`` command-line tool can be used to plot +transects of various MPAS-Ocean variables. The arguments to the command-line +tool are: + +.. code-block:: none + + $ plot_ocean_transects --help + usage: plot_ocean_transects [-h] -g GEOJSON_FILENAME [-m MESH_FILENAME] -f + FILENAME [-v VARIABLE_LIST [VARIABLE_LIST ...]] + [-c COLORMAP] [--flip] + + options: + -h, --help show this help message and exit + -g GEOJSON_FILENAME, --geojson GEOJSON_FILENAME + A geojson file with transects to plot + -m MESH_FILENAME, --mesh MESH_FILENAME + An MPAS-Ocean mesh file. If not specified, the MPAS-Ocean data file must contain the mesh. + -f FILENAME, --file FILENAME + An MPAS-Ocean data file + -v VARIABLE_LIST [VARIABLE_LIST ...], --variable_list VARIABLE_LIST [VARIABLE_LIST ...] + List of variables to plot. All variables on cells in the data file is the default. + -c COLORMAP, --colormap COLORMAP + A colormap to use for the plots, default depends on the field name. + --flip Flip the x axis for all transects + +See `transects `_ +from ``geometric_features`` for a examples of what a geojson transect might +look like: + +.. code-block:: json + + { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "Drake Passage", + "object": "transect", + "component": "ocean", + "author": "Mark Petersen, Xylar Asay-Davis, Milena Veneziani", + }, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -63.02, + -65.46 + ], + [ + -63.81, + -63.8 + ], + [ + -64.42, + -62.02 + ], + [ + -65.04, + -60.25 + ], + [ + -65.74, + -58.28 + ], + [ + -66.37, + -56.39 + ], + [ + -67.02, + -54.44 + ] + ] + } + } + ] + } + +Add more features to the ``features`` list to plot multiple transects at the +same time. + +The MPAS-Ocean mesh file must including not just the horizontal mesh variables +but also the vertical mesh variables (``minLevelCell``, ``maxLevelCell``, +``layerThickness``, etc.) + +If you don't specify the list of variables to plot, all variables with +dimensions ``nCells`` and ``nVertLevels`` will be plotted. + +One way of customizing these visualizaitons is to make your own copy of +`transects.py ` +and change ``_plot_transect()`` to suite your needs, (changing figure size, dpi, +colorbar, etc.) diff --git a/0.22.0rc4/_sources/seaice/mask.rst.txt b/0.22.0rc4/_sources/seaice/mask.rst.txt new file mode 100644 index 000000000..d065febed --- /dev/null +++ b/0.22.0rc4/_sources/seaice/mask.rst.txt @@ -0,0 +1,17 @@ +.. _seaice_mask: + +Mask +==== + +The :py:mod:`mpas_tools.seaice.mask` module contains a function for +manipulating sea-ice region masks. + +.. _seaice_mask_extend_seaice_mask: + +Extending a Mask +---------------- + +The function :py:func:`mpas_tools.seaice.mask.extend_seaice_mask()` is used to +extend a sea-ice "presence" mask that covers the area where sea-ice is present +by a given distance. This is useful as part of creating a sea-ice +:ref:`seaice_partition`. diff --git a/0.22.0rc4/_sources/seaice/mesh.rst.txt b/0.22.0rc4/_sources/seaice/mesh.rst.txt new file mode 100644 index 000000000..9aa7cf80e --- /dev/null +++ b/0.22.0rc4/_sources/seaice/mesh.rst.txt @@ -0,0 +1,28 @@ +.. _seaice_mesh: + +Mesh +==== + +The :py:mod:`mpas_tools.seaice.mesh` module contains several functions for +creating scrip files for sea-ice meshes and regular grids. + +.. _seaice_mesh_mpas_scrip: + +MPAS-Seaice SCRIP files +----------------------- + +The functions :py:func:`mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells()` +and :py:func:`mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices()` are for +creating scrip files for fields on cells and vertices, respectively. + +These are both created using a lower-level function +:py:func:`mpas_tools.seaice.mesh.write_scrip_file()`. + + +.. _seaice_mesh_2d_scrip: + +SCRIP files for 2D grids +------------------------ + +The function :py:func:`mpas_tools.seaice.mesh.write_2D_scripfile()` is for +creating scrip files for a regular, 2D latitude/longitude grid. diff --git a/0.22.0rc4/_sources/seaice/partition.rst.txt b/0.22.0rc4/_sources/seaice/partition.rst.txt new file mode 100644 index 000000000..f36458741 --- /dev/null +++ b/0.22.0rc4/_sources/seaice/partition.rst.txt @@ -0,0 +1,207 @@ +.. _seaice_partitions: + +Graph partitioning +================== + +The :py:mod:`mpas_tools.seaice.partition` module contains a function for +creating graph partition files for MPAS-Seaice that are better balanced than +those created from Metis tools directly. + +.. _seaice_partitions_: + +Running from compass +-------------------- + +One way to run the tools is from compass using the +`files_for_e3sm `_ +test case. + +This has the advantage that it can run with a version of ESMF that has been +compiled with system compilers for compass. Compass also automatically +downloads and links the files needed for determining the regions of sea-ice +coverage. However, if you are unfamiliar with compass, there may be a learning +curve involved in setting up and running the test case. + +Conda environment +----------------- + +The other preferred way to use the sea ice partitioning tool is through the +mpas_tools conda package. To install it, first install +`Mambaforge `_ +(if you don't already have Miniconda3): + +To activate it, run: + +.. code-block:: bash + + source ~/mambaforge/etc/profile.d/conda.sh + source ~/mambaforge/etc/profile.d/mamba.sh + +To create a new conda environment for ``mpas_tools``, run: + +.. code-block:: bash + + mamba activate + mamba create -y -n mpas_tools python=3.11 mpas_tools "esmf=*=nompi*" + +This will create a new conda environment called ``mpas_tools`` that contains +the ``mpas_tools`` package and also the version of ESMF without MPI support. +This is necessary because the version with MPI support (the default) doesn't +typically work on HPC. + +Each time you want to run the sea-ice partitioning tools, run: + +.. code-block:: bash + + source ~/mambaforge/etc/profile.d/conda.sh + source ~/mambaforge/etc/profile.d/mamba.sh + mamba activate mpas_tools + +All the tools (including ``fix_regrid_output.exe`` built from the Fortran code) +are part of the ``mpas_tools`` conda package. + +You will also need an MPAS mesh file to partition. You do not need to pass +a location for the MPAS cell culler (``-c``) or Metis (``-g``) because theses +will be found automatically in the conda package + + +Graph partition tools +--------------------- +The tools ``prepare_seaice_partitions`` and ``create_seaice_partitions`` are +used to create MPAS-Seaice graph partitions that are better balanced so that +each processor "owns" cells from both polar and equatorial regions. + +.. code-block:: none + + $ prepare_seaice_partitions --help + usage: prepare_seaice_partitions [-h] -i MESHFILENAMESRC -p FILENAMEDATA -m + MESHFILENAMEDST -o OUTPUTDIR + + Perform preparatory work for making seaice partitions. + + options: + -h, --help show this help message and exit + -i MESHFILENAMESRC, --inputmesh MESHFILENAMESRC + MPAS mesh file for source regridding mesh. + -p FILENAMEDATA, --presence FILENAMEDATA + Input ice presence file for source mesh. + -m MESHFILENAMEDST, --outputmesh MESHFILENAMEDST + MPAS mesh file for destination regridding mesh. + -o OUTPUTDIR, --outputDir OUTPUTDIR + Output direct + +The input mesh file contains the MPAS-Seaice mesh fields for the mesh used to +create the "presence" file. The "presence" file itself contains an +``icePresence`` field that indicates where sea ice might be present. We +typically use a +`60-km mesh file `_ +and the corresponding +`presence file `_. +The presence file will be regridded to the given output MPAS-Seaice mesh. Here the ice +presence was determined as any cell in the mesh to have had ice present at any time +during a 50 year MPAS-Seaice standalone simulation with the above 60-km mesh file. +The output directory is often the current directory. + +After this preprocessing has finished, the ``create_seaice_partitions`` tool +can be run one or more times. It is significantly more efficient to provide +a list of processor numbers than to call the tool for each processor number +separately. + +.. code-block:: none + + $ create_seaice_partitions --help + usage: create_seaice_partitions [-h] -m MESHFILENAME -o OUTPUTDIR + [-c MPASCULLERLOCATION] [-p OUTPUTPREFIX] [-x] + [-g METIS] [-n NPROCS] [-f NPROCSFILE] + + Create sea-ice partitions. + + options: + -h, --help show this help message and exit + -m MESHFILENAME, --outputmesh MESHFILENAME + MPAS mesh file for destination regridding mesh. + -o OUTPUTDIR, --outputDir OUTPUTDIR + Output directory for temporary files and partition + files. + -c MPASCULLERLOCATION, --cullerDir MPASCULLERLOCATION + Location of MPAS MpasCellCuller.x executable. + -p OUTPUTPREFIX, --prefix OUTPUTPREFIX + prefix for output partition filenames. + -x, --plotting create diagnostic plotting file of partitions + -g METIS, --metis METIS + name of metis utility + -n NPROCS, --nProcs NPROCS + number of processors to create partition for. + -f NPROCSFILE, --nProcsFile NPROCSFILE + number of processors to create partition for. + +The mesh filename provides the desired MPAS-Seaice mesh, the same as the +destination mesh for ``prepare_seaice_partitions``. The output directory +is often the current directory. A directory containing the +``MpasCellCuller.x`` tool can be provided but by default it will be found in +your path as part of the ``mpas_tools`` conda package. The output prefix will +be prepended onto each graph partition file, and defaults to ``graph.info``. +The Metis tool is nearly always ``gpmetis``, the default, and must be available +in your path (which is the case if you use ``mpas_tools`` conda package). +One graph partition file is created for each number of processors (one or more +integers) provided. Alternatively, these can be listed, one value on each +line, in a file. You can optionally save a NetCDF file with partition +information ``partition_diag.nc``, which will contain a ``partition_{nProcs}`` +field for each number of processors requested. + +A simplified tool, primarily intended for use on LCRC machines Anvil and +Chrysalis, has only a few arguments: + +.. code-block:: none + + $ simple_seaice_partitions --help + usage: simple_seaice_partitions [-h] -m MESHFILENAME -p OUTPUTPREFIX -n + [NPROCSARRAY ...] [-d DATADIR] + + Create sea-ice partitions on LCRC. + + options: + -h, --help show this help message and exit + -m MESHFILENAME, --mesh MESHFILENAME + MPAS-Seaice mesh file. + -p OUTPUTPREFIX, --prefix OUTPUTPREFIX + prefix for output partition filenames. + -n [NPROCSARRAY ...], --nprocs [NPROCSARRAY ...] + list of the number of processors to create partition + for. + -d DATADIR, --datadir DATADIR + Directory with seaice_QU60km_polar.nc and + icePresent_QU60km_polar.nc. + +The mesh file is any file that contains the MPAS-Seaice mesh. Some meshes +are available in `inputdata/share/meshes/mpas/sea-ice` and also each +MPAS-Seaice initial condition in `inputdata/ice/mpas-seaice/` +contains the MPAS mesh. Which specific initial condition you choose should +not matter because the mesh should be identical. + +The output prefix can be an absolute or relative path prefix for the graph +partition file to be created. Typically, this will be something like +``partitions/mpas-seaice.graph.info.230313``. It should end in a date that +matches other existing partition files (i.e. it can't typically be today's +date or E3SM won't find the new partition file) and should not contain the +``.part.`` suffix. + +You can provide several task counts with ``-n`` for efficiency. There is a +significant overhead in calling the tool multiple times for different task +counts. + +Here is an example: + +.. code-block:: bash + + cd /lcrc/group/e3sm/public_html/inputdata/ice/mpas-seaice/WC14to60E2r3 + simple_seaice_partitions -m seaice.WC14to60E2r3.210210.nc -p partitions/mpas-seaice.graph.info.230313 -n 468 + + +Graph partition function +------------------------ + +A helper function :py:func:`mpas_tools.seaice.partition.gen_seaice_mesh_partition()` +is used within ``create_seaice_partitions``. It can also be called directly +but must already have the files resulting from ``prepare_seaice_partitions`` +available in the output directory. diff --git a/0.22.0rc4/_sources/seaice/regions.rst.txt b/0.22.0rc4/_sources/seaice/regions.rst.txt new file mode 100644 index 000000000..3bd472d25 --- /dev/null +++ b/0.22.0rc4/_sources/seaice/regions.rst.txt @@ -0,0 +1,16 @@ +.. _seaice_regions: + +Region masks +============ + +The :py:mod:`mpas_tools.seaice.regions` module contains a function for +creating masks to help with graph partitioning. + +.. _seaice_regions_make_regions_file: + +Make a region mask for partitioning +----------------------------------- + +The function :py:func:`mpas_tools.seaice.regions.make_regions_file()` is used +to create a ``region`` field with different integer values for different +regions that are used as part of creating a sea-ice :ref:`seaice_partition`. diff --git a/0.22.0rc4/_sources/seaice/regrid.rst.txt b/0.22.0rc4/_sources/seaice/regrid.rst.txt new file mode 100644 index 000000000..5041eae00 --- /dev/null +++ b/0.22.0rc4/_sources/seaice/regrid.rst.txt @@ -0,0 +1,16 @@ +.. _seaice_regrid: + +Regrid +====== + +The :py:mod:`mpas_tools.seaice.regrid` module contains a function for +regridding between MPAS-Seaice meshes. + +.. _seaice_regrid_regrid_to_other_mesh: + +Regridding between MPAS-Seaice meshes +------------------------------------- + +The function :py:func:`mpas_tools.seaice.regrid.regrid_to_other_mesh()` is used +to regrid between MPAS-Seaice meshes, used as part of preparing for sea-ice +:ref:`seaice_partition`. diff --git a/0.22.0rc4/_sources/testing_changes.rst.txt b/0.22.0rc4/_sources/testing_changes.rst.txt new file mode 100644 index 000000000..a9aa5e83c --- /dev/null +++ b/0.22.0rc4/_sources/testing_changes.rst.txt @@ -0,0 +1,61 @@ +.. _dev_testing_changes: + +***************************** +Testing Changes to mpas_tools +***************************** + +Here, we describe the workflow for creating a development conda environment +that points to ``mpas_tools`` in a branch from a local clone of the repo. +This approach works both for calling functions from the package within a python +script or another python package and for calling the "entry points" +(command-line tools; see :ref:`dev_making_changes`). + +Basic instructions on how to install `Miniconda `_ +are beyond the scope of this documentation. Make sure the conda-forge channel +is added and that channel priority is "strict", meaning packages will +definitely come from conda-forge if they are available there. + +.. code-block:: bash + + conda config --add channels conda-forge + conda config --set channel_priority strict + +To make a conda environment and install the current `mpas_tools` in a way that +it will be used out of the repo directly (i.e. it will notice changes as you +make them in your branch), run: + +.. code-block:: bash + + cd conda_package + conda env create -y -n mpas_tools_dev --file dev-spec.txt + conda activate mpas_tools_dev + python -m pip install -e . + +You should now find that ``mpas_tools`` can be imported in python codes and the +various scripts and entry points are available in the path. + +If you have already created the ``mpas_tools_dev`` environment, it may be best +to remove it (see below) and create it again. If you are in a rush, you can +use: + +.. code-block:: bash + + conda env update -f ./dev_environment + conda activate mpas_tools_dev + python -m pip install -e . + +to update the existing environment and make sure ``mpas_tools`` in the +environment points to your current branch. + +There is no need to build a conda package, as previous instructions had +suggested. + +Removing the test environment +***************************** + +If you're done with testing, you can remove the test environment + +.. code-block:: + + conda deactivate + conda remove --all -n mpas_tools_dev diff --git a/0.22.0rc4/_sources/transects.rst.txt b/0.22.0rc4/_sources/transects.rst.txt new file mode 100644 index 000000000..c0dce4099 --- /dev/null +++ b/0.22.0rc4/_sources/transects.rst.txt @@ -0,0 +1,44 @@ +.. _transects: + +********* +Transects +********* + +The :py:mod:`mpas_tools.transects` module contains functions used to define +transects through MPAS meshes. These transects can be used to create masks +of the cells, edges or dual-mesh cells (in some sense "vertices") that +intersect the transect. They can also be used for visualization such as +plotting vertical cross-sections of MPAS data along the transect. + +.. _subdividing_transects: + +Subdividing transects +===================== + +For both visualization and intersection detection, it is often useful to +subdivide a transect into smaller segments. This is performed with the +function :py:func:`mpas_tools.transects.subdivide_great_circle()` for spherical +meshes and with :py:func:`mpas_tools.transects.subdivide_planar()` for planar +meshes. + +For spherical meshes, subdivision is performed in Cartesian coordinates. Since +transects are typically provided as a sequence of longitude/latitude points, +it is typically necessary to convert to Cartesian coordinates using +:py:func:`mpas_tools.transects.lon_lat_to_cartesian()` and then back to +longitude/latitude coordinates using +:py:func:`mpas_tools.transects.cartesian_to_lon_lat()`. + + +Low-level functions +=================== + +The module also shares some lower-level functions used elsewhere in the +package. + +The arc length (in radians) along a transect can be found with +:py:func:`mpas_tools.transects.angular_distance()`. + +The function :py:func:`mpas_tools.transects.intersects()` can be used to +determine if 2 arcs on the sphere intersect one another and +:py:func:`mpas_tools.transects.intersection()` can be used to find the +intersection point of 2 intersecting arcs. diff --git a/0.22.0rc4/_sources/versions.rst.txt b/0.22.0rc4/_sources/versions.rst.txt new file mode 100644 index 000000000..975203982 --- /dev/null +++ b/0.22.0rc4/_sources/versions.rst.txt @@ -0,0 +1,94 @@ +.. _versions: + +Versions +======== + +================ =============== +Documentation On GitHub +================ =============== +`stable`_ `master`_ +`v0.0.11`_ `0.0.11`_ +`v0.0.12`_ `0.0.12`_ +`v0.0.13`_ `0.0.13`_ +`v0.0.14`_ `0.0.14`_ +`v0.0.15`_ `0.0.15`_ +`v0.1.0`_ `0.1.0`_ +`v0.2.0`_ `0.2.0`_ +`v0.2.1`_ `0.2.1`_ +`v0.3.0`_ `0.3.0`_ +`v0.4.0`_ `0.4.0`_ +`v0.5.0`_ `0.5.0`_ +`v0.6.0`_ `0.6.0`_ +`v0.7.0`_ `0.7.0`_ +`v0.8.0`_ `0.8.0`_ +`v0.9.0`_ `0.9.0`_ +`v0.10.0`_ `0.10.0`_ +`v0.11.0`_ `0.11.0`_ +`v0.12.0`_ `0.12.0`_ +`v0.13.0`_ `0.13.0`_ +`v0.14.0`_ `0.14.0`_ +`v0.15.0`_ `0.15.0`_ +`v0.16.0`_ `0.16.0`_ +`v0.17.0`_ `0.17.0`_ +`v0.18.0`_ `0.18.0`_ +`v0.19.0`_ `0.19.0`_ +`v0.20.0`_ `0.20.0`_ +`v0.21.0`_ `0.21.0`_ +================ =============== + +.. _`stable`: ../stable/index.html +.. _`master`: https://github.com/MPAS-Dev/MPAS-Tools/tree/master +.. _`v0.0.11`: ../0.0.11/index.html +.. _`0.0.11`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.0.11 +.. _`v0.0.12`: ../0.0.12/index.html +.. _`0.0.12`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.0.12 +.. _`v0.0.13`: ../0.0.13/index.html +.. _`0.0.13`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.0.13 +.. _`v0.0.14`: ../0.0.14/index.html +.. _`0.0.14`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.0.14 +.. _`v0.0.15`: ../0.0.15/index.html +.. _`0.0.15`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.0.15 +.. _`v0.1.0`: ../0.1.0/index.html +.. _`0.1.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.1.0 +.. _`v0.2.0`: ../0.2.0/index.html +.. _`0.2.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.2.0 +.. _`v0.2.1`: ../0.2.1/index.html +.. _`0.2.1`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.2.1 +.. _`v0.3.0`: ../0.3.0/index.html +.. _`0.3.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.3.0 +.. _`v0.4.0`: ../0.4.0/index.html +.. _`0.4.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.4.0 +.. _`v0.5.0`: ../0.5.0/index.html +.. _`0.5.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.5.0 +.. _`v0.6.0`: ../0.6.0/index.html +.. _`0.6.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.6.0 +.. _`v0.7.0`: ../0.7.0/index.html +.. _`0.7.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.7.0 +.. _`v0.8.0`: ../0.8.0/index.html +.. _`0.8.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.8.0 +.. _`v0.9.0`: ../0.9.0/index.html +.. _`0.9.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.9.0 +.. _`v0.10.0`: ../0.10.0/index.html +.. _`0.10.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.10.0 +.. _`v0.11.0`: ../0.11.0/index.html +.. _`0.11.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.11.0 +.. _`v0.12.0`: ../0.12.0/index.html +.. _`0.12.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.12.0 +.. _`v0.13.0`: ../0.13.0/index.html +.. _`0.13.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.13.0 +.. _`v0.14.0`: ../0.14.0/index.html +.. _`0.14.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.14.0 +.. _`v0.15.0`: ../0.15.0/index.html +.. _`0.15.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.15.0 +.. _`v0.16.0`: ../0.16.0/index.html +.. _`0.16.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.16.0 +.. _`v0.17.0`: ../0.17.0/index.html +.. _`0.17.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.17.0 +.. _`v0.18.0`: ../0.18.0/index.html +.. _`0.18.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.18.0 +.. _`v0.19.0`: ../0.19.0/index.html +.. _`0.19.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.19.0 +.. _`v0.20.0`: ../0.20.0/index.html +.. _`0.20.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.20.0 +.. _`v0.21.0`: ../0.21.0/index.html +.. _`0.21.0`: https://github.com/MPAS-Dev/MPAS-Tools/tree/0.21.0 diff --git a/0.22.0rc4/_sources/visualization.rst.txt b/0.22.0rc4/_sources/visualization.rst.txt new file mode 100644 index 000000000..1675bf8aa --- /dev/null +++ b/0.22.0rc4/_sources/visualization.rst.txt @@ -0,0 +1,624 @@ +.. _visualization: + +************* +Visualization +************* + +MPAS-Tools has kind of a hodge-podge of unrelated visualization tools. This is +largely because MPAS-Tools is conceived of primarily as a repository for tools +for manipulating MPAS meshes during their construction and initialization. + +.. _viz_paraview_extractor: + +ParaView VTK Extractor +====================== + +Data on MPAS meshes can be viewed directly in +`ParaView `_. However, those of us who work with +output from MPAS components on a regular basis have found that the built-in +capability has a number of significant limitations. These include: + +* ParaView visualizes data on MPAS cell centers by connecting them to form + triangles. The data is linearly interpolated within each triangle and + geometry associated with the parts of MPAS cells that are adjacent to + boundaries (e.g. land in the ocean and sea-ice components) are not visualized. +* MPAS output may not contain the mesh information needed by ParaView. This is + typical of monthly output files, which do not include the mesh data for + more efficient file storage. +* MPAS output files may contain significantly more data that is desired for + visualization. The data may contain full 3D fields, whereas a few slices at + different depths may suffice for visualization. There may also be many more + variables in the output than are of interest. This may be a problem if the + datasets are quite large and therefore prohibitive to transfer to another + machine where visualization may be more practical. + +For these reasons and more, we created a Python tool for extracting data on +MPAS meshes in files in `VTK `_ format that can be read in by +ParaView. The VTK files provide the data as "cell", rather than "point" data in +ParaVeiw, meaning each cell has the correct polygonal geometry and will be +visualized with a single, constant value for a given field. The extractor, +which is available either through the +:py:func:`mpas_tools.viz.paraview_extractor.extract_vtk()` function or the +``paraview_vtk_field_extractor.py`` command-line interface, can also be used to +visualize data on MPAS vertices (visualized on triangles) and edges (visualized +on quadrilaterals). + +The extractor also allows the user to select a subset of the indices along +dimensions other than ``Time``, ``nCells``, ``nVertices`` and ``nEdges``. This +can be useful for selecting, for example, only the top layer of a 3D field. +This capability can also be used to ignore fields with a given dimension by +selecting no indices along that dimension. + +By default, time-independent fields on cells are written to a file + +.. code-block:: none + + vtk_files/staticFieldsOnCells.vtp + +and time-dependent fields on cells are written to a series of files + +.. code-block:: none + + vtk_files/timeDependentFieldsOnCells.pvd + vtk_files/time_series/timeDependentFieldsOnCells.0.vtp + vtk_files/time_series/timeDependentFieldsOnCells.1.vtp + ... + +and similarly for edges and vertices. Time-independent fields can be +included in each time step of the time-dependent fields for with +``combine=True``. This allows time-dependent and -independent fields +to be combined in filters within Paraview at the expense of considerable +additional storage space. + +Since the extractor is fairly complex with a lot of possible use cases, we will +describe its functionality in several examples. + +.. _extract_temperature: + +Extracting a Temperature Time-series +------------------------------------ + +To extract fields across multiple files, passing in a regular expression +for the filename pattern, for example +``filename_pattern="hist.mpaso.timeSeriesStatsMonthly.*.nc"``. Since the mesh +data is often excluded from time series output, you may need to supply a +different file with mesh information, such as an initial condition or a restart +file: ``mesh_filename='mpaso.rst.0001-02-01_00000.nc'``. + +In the following example, we extract the temperature field from a time series +of daily output from the MPAS-Ocean model: + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list='timeDaily_avg_activeTracers_temperature', + dimension_list=['nVertLevels=0'], mesh_filename='init.nc', + out_dir='vtk_files', xtime='xtime_startDaily') + +The top index (``nVertLevels=0``) is extracted from the temperature time series. +The output directory is ``'vtk_files'``. MPAS output typically includes time +information in string format in a variable called ``xtime``. In this instance, +we have time-averaged data and the output instead includes a start time +``xtime_startDaily`` that we need to supply instead. (We could also supply the +end time ``xtime_endDaily`` if that were preferred for some reason.) + +The result is: + +.. code-block:: none + + vtk_files/fieldsOnCells.pvd + vtk_files/time_series/fieldsOnCells.0.vtp + ... + +These files can be opened in ParaView with: + +.. code-block:: none + + $ paraview vtk_files/fieldsOnCells.pvd + +This will open all of the files in the ``vtk_files/time_series`` directory as +they are requested within ParaView. See :ref:`paraview_macros` for some tips +on filling in the continents and displaying the current date in ParaView. + +The same extraction could be accomplished with the command-line tool as follows: + +.. code-block:: none + + $ paraview_vtk_field_extractor.py \ + -f "analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc" \ + -v timeDaily_avg_activeTracers_temperature -d nVertLevels=0 \ + -m init.nc -o vtk_files --xtime=xtime_startDaily + +Extracting Multiple Fields +-------------------------- + +In this next example, we will extract ``areaCell`` in addition to temperature. +First, we will extract it into a separate VTK file for time-independent +variables, then we will demonstrate combining it with the time-dependent data. + +In the first instance, we add ``areaCell`` to the ``variable_list`` and +explicitly include ``combine=False``, the default, to indicate that we want to +keep time-independent and time-dependent variables separate: + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list=['timeDaily_avg_activeTracers_temperature', 'areaCell'], + dimension_list=['nVertLevels=0'], mesh_filename='init.nc', + combine=False, out_dir='vtk_files2', xtime='xtime_startDaily') + + +The result is: + +.. code-block:: none + + vtk_files2/staticFieldsOnCells.vtp + vtk_files2/timeDependentFieldsOnCells.pvd + vtk_files2/time_series/timeDependentFieldsOnCells.0.vtp + ... + +We can open both ``vtk_files/staticFieldsOnCells.vtp`` and +``vtk_files/timeDependentFieldsOnCells.pvd`` in the same ParaVeiw sesson and +plot them as we like. But we cannot perform calculations involving both +temperature and cell area very easily. If this were a necessity, it might be +convenient to combine them into the same files: + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list=['timeDaily_avg_activeTracers_temperature', 'areaCell'], + dimension_list=['nVertLevels=0'], mesh_filename='init.nc', + combine=True, out_dir='vtk_files3', xtime='xtime_startDaily') + + +Now, the result is that ``areaCell`` is included in the time-series files + +.. code-block:: none + + vtk_files3/fieldsOnCells.pvd + vtk_files3/time_series/fieldsOnCells.0.vtp + ... + +Extracting "All" Fields +----------------------- + +Sometimes, you want all of the fields from your input files to be extracted. +For this purpose there is a special "variable" called ``'all'`` that gets +translated into the full list of available variables. More often, you want to +extract all the variables on cells, edges or vertices, so there are special +"variables" for this, too: ``'allOnCells'``, ``'allOnEdges'``, and +``'allOnVertices'``. By default, only variables from the files found by +``filename_pattern`` are expanded by these special variables. If you also want +to include variables from the mesh file, you need to specify +``include_mesh_vars=True``. + +The following example extracts all the variables on cells for both the +time-series and the mesh data. It specifies ``maxEdges=`` so that variables +(such as ``edgesOnCell`` and ``cellsOnCell``) that include this dimension are +excluded: + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list=['allOnCells'], + dimension_list=['nVertLevels=0', 'nVertLevelsP1=0', 'maxEdges='], + mesh_filename='init.nc', combine=True, include_mesh_vars=True, + out_dir='vtk_files4', xtime='xtime_startDaily') + + +Indexing Dimensions +------------------- + +In the previous examples, we saw a basic example of indexing the "extra" +dimensions (i.e. dimensions other than ``Time``, ``nCells``, ``nVertices`` and +``nEdges``) from MPAS output. Here, we show some slightly more involved +examples. + +Indices for extra dimensions can either be supplied at runtime at a prompt (if +``dimension_list=None``) or via a list of strings with the dimensions and +associated indices. For each extra dimension, you can specify nothing for the +indices (an empty string, meaning skip any fields with this dimension), a single +index, a comma-separated list of indices, or a range of indices (separated by 1 +or 2 colons). For example, + +.. code-block:: python + + dimension_list=['maxEdges=', 'nVertLeves=0:10:2', 'nParticles=0,2,4,6,8'] + +will ignore any fields with dimension ``maxEdges``, extract every other +layer from the first 10 vertical levels (each into its own field) and +extract the 5 specified particles. + +An index array can also be specified in this way (and these can be mixed +with integer indices in a comma-separated list but not in a colon-separated +range): + +.. code-block:: python + + dimension_list=['nVertLeves=0,maxLevelCell'] + +This will extract fields from the first vertical level and the vertical level +with index given by ``maxLevelCell`` (the deepest layer in each ocean column). + +Here is a more complete example that extracts the temperature, salinity and +layer thickness at the sea surface and seafloor. + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list=['timeDaily_avg_activeTracers_temperature', + 'timeDaily_avg_activeTracers_salinity', + 'timeDaily_avg_layerThickness'], + dimension_list=['nVertLevels=0,maxLevelCell'], mesh_filename='init.nc', + out_dir='vtk_files5', xtime='xtime_startDaily') + +The resulting fields are named: + +.. code-block:: none + + timeDaily_avg_activeTracers_temperature_0 + timeDaily_avg_activeTracers_temperature_maxLevelCell + timeDaily_avg_activeTracers_salinity_0 + timeDaily_avg_activeTracers_salinity_maxLevelCell + timeDaily_avg_layerThickness_0 + timeDaily_avg_layerThickness_maxLevelCell + +Indexing Time +------------- + +Time can also be indexed like the other dimensions, but it is not passed to the +``dimension_list`` argument but instead to the ``time`` argument. The time +index string can have any of the following formats: + +* ``''`` - no times are to be extracted (probably not useful for ``time``) +* ``'n'`` - the index n is to be extracted +* ``'m,n,p'`` - the list of indices is to be extracted +* ``'m:n'`` - all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) +* ``'m:n:s'`` - all indices from m to n are to be extracted (including m but + excluding n, in the typical python indexing convention) with stride s between + indices + +In this example, we extract every 6 days from the daily data set starting with +the beginning fo the data set and continuing to the end (by not specifying the +end index ``n``): + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list=['timeDaily_avg_activeTracers_temperature'], + dimension_list=['nVertLevels=0'], mesh_filename='init.nc', + time='0::6', out_dir='vtk_files6', xtime='xtime_startDaily') + +Ignoring Time +------------- + +Some MPAS files, for example mesh files and initial conditions, contain a +``Time`` dimension but no ``xtime`` variable. The extractor will complain about +this unless you specify ``ignore_time=True``. In this case, only the first time +index is used and all fields are considered to be time-independent, ending +up in ``staticFieldsOnCells.vtp``, etc. + +Lon/Lat Coordinates +------------------- + +The extractor can produce files in lon/lat coordinates instead of 3D Cartesian +space if ``lonlat=True``. Polygons near the prime meridian (0 or 360 degrees +longitude) will end up on one side or the other based on the location of the +cell center. This leads to a "ragged" edge a the prime meridian, particularly +for coarse-resolution meshes: + +.. image:: images/ragged.png + :width: 500 px + :align: center + +Below, we will provide a method for handling this issue in ParaView. + +Here, we extract the temperature field as in :ref:`extract_temperature`, but +this time in lon/lat coordinates. + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list='timeDaily_avg_activeTracers_temperature', + dimension_list=['nVertLevels=0'], mesh_filename='init.nc', + lonlat=True, out_dir='vtk_files7', xtime='xtime_startDaily') + +In ParaView, the data lies approximately 0 and 360 degrees long the x axis but +with some polygons extending partially beyond these bounds. Since we typically +wish to see the data between -180 and 180 degrees longitude, the proposed fix +will take care of both the longitude range and the ragged edges in one go. + +First, we make a duplicate copy of the data, translated by -360 degrees. Open +a Transform Filter in ParaView and enter ``-360`` in the first Translate cell +(the x axis). Uncheck "Show Box" and hit "Apply". The original data will +disappear but you can simply click the eye icon next to it to make it reappear. + +Next, we want to combine the original and translated versions of the mesh into +a single dataset. Use the shift key to select both, then open the Group +Datasets Filter, then hit "Apply". + +Finally, we will crop the grouped dataset to the range of -180 to 180 degrees: + +* Select the final of the three "GroupDataset1" items, +* open a Clip Filter, +* select "Plane" as the Clip Type, +* set the Origin to -180, 0, 0, +* set the Normal to -1, 0, 0 + +This has clipped the extra data off the left edge. Now for the right edge: + +* Select the "Clip1" item, +* open a Clip Filter again, +* select "Plane" as the Clip Type, +* set the Origin to 180, 0, 0, +* set the Normal to 1, 0, 0, +* uncheck "Show Plane" + +Now, the data should have clean edges. If you want, you can put a plane behind +it to fill in the land: + +.. image:: images/clipped.png + :width: 500 px + :align: center + +Topographic Data +---------------- + +The extractor includes optional support for extracting geometry appropriate +for displaying variables at the depth of a topographic feature (typically +the top or bottom of the domain) for MPAS components with a spatially +variable top or bottom index (e.g. ``maxLevelCell`` in MPAS-Ocean). This is +accomplished with arguments such as: + +.. code-block:: python + + topo_dim='nVertLevels', topo_cell_index='maxLevelCell' + +Fields on cells are sampled at the topographic index and the geometry +includes polygons corresponding to edges so that vertical faces between +adjacent cells can be displayed. Fields are extracted as normal except +that they are sampled as point data rather than cell data, allowing +computations in ParaView to display the topography. A mask field is also +included, indicating which parts of edge polygons correspond to the boundary +of the domain (``boundaryMask == 1``) and which parts of cell and edge +polygons are interior (``boundaryMask == 0``). + +In the following, we make sure to use ``combine=True`` and +``include_mesh_vars=True`` because we need ``bottomDepth`` from the mesh file +to be included in the time-dependent output files. We are not interested in +variables with dimensions ``nVertLevelsP1`` or ``maxEdges`` so we remove those +dimensions by leaving their index strings blank. + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list='allOnCells', + dimension_list=['nVertLevelsP1=', 'maxEdges='], + topo_dim='nVertLevels', topo_cell_index='maxLevelCell', + combine=True, include_mesh_vars=True, mesh_filename='init.nc', + out_dir='vtk_files8', xtime='xtime_startDaily') + + +Together, this can be used to plot topography by using a Calculator Filter in +ParaView, checking the "Coordinate Result" box, and entering the following: + +.. code-block:: none + + coords*(1.0 + 100.0/mag(coords)*((1 - boundaryMask)*(-bottomDepth) + + 10.0*boundaryMask)) + +The result is that the MPAS-Ocean topography is displayed with a vertical +exaggeration of 100 and with a value equivalent to 10 m along boundary points of +edge polygons (a "water-tight" surface). + +Here is what that looks like for a 240-km (very coarse) ocean mesh: + +.. image:: images/qu240_topo.png + :width: 500 px + :align: center + +The same approach can be used with ``lonlat=True``. In this case, the +Calculator Filter is a bit simpler: + +.. code-block:: none + + coords + 1e-3*(1 - boundaryMask)*(-bottomDepth)*kHat + 1.0*boundaryMask*kHat + +Here is the bottom temperature in such a plot: + +.. image:: images/qu240_topo_lonlat.png + :width: 500 px + :align: center + +Extracting a Region +------------------- + +Some simulations are focused on a small region, even though the entire globe is +included in the mesh. For such situations, we provide a way to extract a +subset of the data over a region before converting it to VTK format. The user +specifies a +`FeatureCollection `_ +from the ``geometric_features`` package as an argument. The regions in this +feature collection are used to define a mask, and the MPAS data is culled to +lie within the mask before conversion to VTK proceeds. + +.. note:: + + The region should indicate the parts of the mesh to keep, not those to + remove. + +In this example, we extract sea surface temperature only in the Southern Ocean: + +.. code-block:: python + + from mpas_tools.viz.paraview_extractor import extract_vtk + from geometric_features import GeometricFeatures + + + gf = GeometricFeatures() + fc = gf.read(componentName='ocean', objectType='region', + featureNames=['Southern Ocean']) + + extract_vtk( + filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc', + variable_list='timeDaily_avg_activeTracers_temperature', + dimension_list=['nVertLevels=0'], mesh_filename='init.nc', + fc_region_mask=fc, out_dir='vtk_files9', xtime='xtime_startDaily') + + +.. image:: images/so_cropped.png + :width: 500 px + :align: center + +.. _paraview_macros: + +ParaView Macros +--------------- + +We also provide two macros that can be imported into ParaView, +`add_earth_sphere.py `_ +and +`annotate_date.py `_. +Download them and then go to Macros > Add New Macro, and select each file. + +The first of these adds a sphere that is just a bit smaller than the MPAS data +on the sphere so that continents are not holes in the data. The second can +be used to display the current time (extracted from the ``xtime`` variable) in +a ParaVeiw animation. + +.. _viz_mesh_tris: + +MPAS Mesh to Triangles +====================== + +A relatively new and under-explored functionality in MPAS-Tools is the +capability to extract a triangle mesh for visualization from an MPAS mesh. +This functionality comes from the function +:py:func:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()`. The function +takes an MPAS mesh as an ``xarray.Dataset`` object as its only required input +and produces another ``xarray.Dataset`` with the triangle mesh that connects +pairs of adjacent vertices to cell centers as its output. Thus, each hexagon +becomes 6 triangles, each pentagon becomes 5, and so on. + +In addition to the points and connectivity data for defining these trinagles, +the output dataset, ``dsTris``, also includes the cell index that each triangle +is in and cell indices and weights for interpolating data defined at cell +centers to triangle nodes. ``dsTris`` includes variables ``triCellIndices``, +the cell that each triangle is part of; ``nodeCellIndices`` and +``nodeCellWeights``, the indices and weights used to interpolate from MPAS cell +centers to triangle nodes; Cartesian coordinates ``xNode``, ``yNode``, and +``zNode``; and ``lonNode``` and ``latNode`` in radians. ``lonNode`` is +guaranteed to be within 180 degrees of the cell center corresponding to +``triCellIndices``. Nodes always have a counterclockwise winding. + +Here is an example workflow for using this function: + +.. code-block:: python + + import xarray + import numpy + import matplotlib.pyplot as plt + from matplotlib.tri import Triangulation + + from mpas_tools.viz import mesh_to_triangles + + + dsMesh = xarray.open_dataset('mpaso.rst.0501-01-01_00000.nc') + dsTris = mesh_to_triangles(dsMesh, periodicCopy=True) + + sst = dsMesh.temperature.isel(Time=0, nVertLevels=0).values + + sstTri = sst[dsTris.triCellIndices] + + sstNode = (sst[dsTris.nodeCellIndices]*dsTris.nodeCellWeights).sum('nInterp') + + nTriangles = dsTris.sizes['nTriangles'] + tris = numpy.arange(3*nTriangles).reshape(nTriangles, 3) + + lonNode = numpy.rad2deg(dsTris.lonNode.values).ravel() + latNode = numpy.rad2deg(dsTris.latNode.values).ravel() + sstNode = sstNode.values.ravel() + + triangles = Triangulation(lonNode, latNode, tris) + + plt.figure(1) + plt.tripcolor(triangles, sstNode, shading='gouraud') + plt.xlim([0., 360.]) + plt.ylim([-90., 90.]) + + plt.figure(2) + plt.tripcolor(triangles, sstTri, shading='flat') + plt.xlim([0., 360.]) + plt.ylim([-90., 90.]) + + plt.show() + +In this example, ``mpaso.rst.0501-01-01_00000.nc`` is a restart file from a +simulation with an EC at the default 30 to 60 km resolution (see +:ref:`ec_mesh`); the restart file contains both mesh information and a snapshot +of the 3D temperature field. + +Here are the resulting plots (which look nearly identical at this resolution): + +.. image:: images/ec60to30_tris_gouraud.png + :width: 500 px + :align: center + +.. image:: images/ec60to30_tris_flat.png + :width: 500 px + :align: center + +.. _viz_colormaps: + +Colormaps +========= + +Some MPAS-Tools routines include plots of mesh resolution and related variables. +We have found it handy to use the +`SciVisColor Colormaps `_ for some of these plots. +Unfortunately, there is not a standard python package for adding these +colormaps to ``matplotlib`` (as is the case for +`cmocean `_, for example). To add the +SciVisColor colormaps, call the function +:py:func:`mpas_tools.viz.colormaps.register_sci_viz_colormaps()`. No arguments +are required, as the XML files for defining the colormaps are included in the +package. + +In this example, we use the ``3Wbgy5`` colormap: + +.. image:: images/so60to12_res.png + :width: 500 px + :align: center diff --git a/0.22.0rc4/_static/basic.css b/0.22.0rc4/_static/basic.css new file mode 100644 index 000000000..7577acb1a --- /dev/null +++ b/0.22.0rc4/_static/basic.css @@ -0,0 +1,903 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- 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 p.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%; + margin-left: auto; + margin-right: auto; +} + +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 { + width: 100%; +} + +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; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +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; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/0.22.0rc4/_static/css/badge_only.css b/0.22.0rc4/_static/css/badge_only.css new file mode 100644 index 000000000..c718cee44 --- /dev/null +++ b/0.22.0rc4/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/0.22.0rc4/_static/css/fonts/Roboto-Slab-Bold.woff b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/0.22.0rc4/_static/css/fonts/Roboto-Slab-Bold.woff2 b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/0.22.0rc4/_static/css/fonts/Roboto-Slab-Regular.woff b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/0.22.0rc4/_static/css/fonts/Roboto-Slab-Regular.woff2 b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/0.22.0rc4/_static/css/fonts/fontawesome-webfont.eot b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/0.22.0rc4/_static/css/fonts/fontawesome-webfont.svg b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/0.22.0rc4/_static/css/fonts/fontawesome-webfont.ttf b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/0.22.0rc4/_static/css/fonts/fontawesome-webfont.woff b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/0.22.0rc4/_static/css/fonts/fontawesome-webfont.woff2 b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/0.22.0rc4/_static/css/fonts/lato-bold-italic.woff b/0.22.0rc4/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-bold-italic.woff differ diff --git a/0.22.0rc4/_static/css/fonts/lato-bold-italic.woff2 b/0.22.0rc4/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/0.22.0rc4/_static/css/fonts/lato-bold.woff b/0.22.0rc4/_static/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-bold.woff differ diff --git a/0.22.0rc4/_static/css/fonts/lato-bold.woff2 b/0.22.0rc4/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-bold.woff2 differ diff --git a/0.22.0rc4/_static/css/fonts/lato-normal-italic.woff b/0.22.0rc4/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-normal-italic.woff differ diff --git a/0.22.0rc4/_static/css/fonts/lato-normal-italic.woff2 b/0.22.0rc4/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/0.22.0rc4/_static/css/fonts/lato-normal.woff b/0.22.0rc4/_static/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-normal.woff differ diff --git a/0.22.0rc4/_static/css/fonts/lato-normal.woff2 b/0.22.0rc4/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/0.22.0rc4/_static/css/fonts/lato-normal.woff2 differ diff --git a/0.22.0rc4/_static/css/theme.css b/0.22.0rc4/_static/css/theme.css new file mode 100644 index 000000000..19a446a0e --- /dev/null +++ b/0.22.0rc4/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/0.22.0rc4/_static/doctools.js b/0.22.0rc4/_static/doctools.js new file mode 100644 index 000000000..d06a71d75 --- /dev/null +++ b/0.22.0rc4/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/0.22.0rc4/_static/documentation_options.js b/0.22.0rc4/_static/documentation_options.js new file mode 100644 index 000000000..20e6bf8db --- /dev/null +++ b/0.22.0rc4/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '0.22.0rc4', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/0.22.0rc4/_static/file.png b/0.22.0rc4/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/0.22.0rc4/_static/file.png differ diff --git a/0.22.0rc4/_static/js/badge_only.js b/0.22.0rc4/_static/js/badge_only.js new file mode 100644 index 000000000..526d7234b --- /dev/null +++ b/0.22.0rc4/_static/js/badge_only.js @@ -0,0 +1 @@ +!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); \ No newline at end of file diff --git a/0.22.0rc4/_static/js/html5shiv-printshiv.min.js b/0.22.0rc4/_static/js/html5shiv-printshiv.min.js new file mode 100644 index 000000000..2b43bd062 --- /dev/null +++ b/0.22.0rc4/_static/js/html5shiv-printshiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/0.22.0rc4/_static/js/html5shiv.min.js b/0.22.0rc4/_static/js/html5shiv.min.js new file mode 100644 index 000000000..cd1c674f5 --- /dev/null +++ b/0.22.0rc4/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/0.22.0rc4/_static/js/theme.js b/0.22.0rc4/_static/js/theme.js new file mode 100644 index 000000000..1fddb6ee4 --- /dev/null +++ b/0.22.0rc4/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/0.22.0rc4/_static/minus.png b/0.22.0rc4/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/0.22.0rc4/_static/minus.png differ diff --git a/0.22.0rc4/_static/plus.png b/0.22.0rc4/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/0.22.0rc4/_static/plus.png differ diff --git a/0.22.0rc4/_static/pygments.css b/0.22.0rc4/_static/pygments.css new file mode 100644 index 000000000..691aeb82d --- /dev/null +++ b/0.22.0rc4/_static/pygments.css @@ -0,0 +1,74 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/0.22.0rc4/_static/searchtools.js b/0.22.0rc4/_static/searchtools.js new file mode 100644 index 000000000..97d56a74d --- /dev/null +++ b/0.22.0rc4/_static/searchtools.js @@ -0,0 +1,566 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = docUrlRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = docUrlRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/0.22.0rc4/_static/sphinx_highlight.js b/0.22.0rc4/_static/sphinx_highlight.js new file mode 100644 index 000000000..aae669d7e --- /dev/null +++ b/0.22.0rc4/_static/sphinx_highlight.js @@ -0,0 +1,144 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + parent.insertBefore( + span, + parent.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(SphinxHighlight.highlightSearchWords); +_ready(SphinxHighlight.initEscapeListener); diff --git a/0.22.0rc4/api.html b/0.22.0rc4/api.html new file mode 100644 index 000000000..3e148764d --- /dev/null +++ b/0.22.0rc4/api.html @@ -0,0 +1,836 @@ + + + + + + + API reference — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

API reference

+

This page provides an auto-generated summary of the MPAS mesh-tools API. For +more details and examples, refer to the relevant chapters in the main part of +the documentation.

+
+

MPAS mesh tools

+
+

Mesh creation

+ + + + + + +

make_planar_hex_mesh(nx, ny, dc, ...[, ...])

Builds an MPAS periodic, planar hexagonal mesh with the requested dimensions, optionally saving it to a file, and returns it as an xarray.Dataset.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

build_mesh

build_mesh.build_spherical_mesh(cellWidth, ...)

Build an MPAS mesh using JIGSAW with the given cell sizes as a function of latitude and longitude.

build_mesh.build_planar_mesh(cellWidth, x, ...)

Build a planar MPAS mesh

jigsaw_driver.jigsaw_driver(cellWidth, x, y)

A function for building a jigsaw mesh

jigsaw_to_netcdf.jigsaw_to_netcdf(...[, ...])

Converts mesh data defined in triangle format to NetCDF

mesh_definition_tools

These functions are tools used to define the cellWidth variable on regular lat/lon grids.

mesh_definition_tools.mergeCellWidthVsLat(...)

Combine two cell width distributions using a tanh function.

mesh_definition_tools.EC_CellWidthVsLat(lat)

Create Eddy Closure spacing as a function of lat.

mesh_definition_tools.RRS_CellWidthVsLat(...)

Create Rossby Radius Scaling as a function of lat.

mesh_definition_tools.AtlanticPacificGrid(...)

Combine two cell width distributions using a tanh function.

mpas_to_triangle.mpas_to_triangle(mpasfile, ...)

Script to convert from MPAS netCDF format to the Triangle format: https://www.cs.cmu.edu/~quake/triangle.node.html https://www.cs.cmu.edu/~quake/triangle.ele.html

signed_distance

signed_distance.signed_distance_from_geojson(fc, ...)

Get the distance for each point on a lon/lat grid from the closest point on the boundary of the geojson regions.

signed_distance.mask_from_geojson(fc, ...)

Make a rasterized mask on a lon/lat grid from shapes (geojson multipolygon data).

signed_distance.distance_from_geojson(fc, ...)

Get the distance for each point on a lon/lat grid from the closest point on the boundary of the geojson regions.

triangle_to_netcdf.triangle_to_netcdf(node, ...)

Converts mesh data defined in triangle format to NetCDF

+
+
+

Mesh conversion

+ + + + + + + + + + + + +

convert(dsIn[, graphInfoFileName, logger, dir])

Use MpasMeshConverter.x to convert an input mesh to a valid MPAS mesh that is fully compliant with the MPAS mesh specification.

cull(dsIn[, dsMask, dsInverse, dsPreserve, ...])

Use MpasCellCuller.x to cull cells from a mesh based on the cullCell field in the input file or DataSet and/or the provided masks.

mask(dsMesh[, fcMask, logger, dir, cores])

Use compute_mpas_region_masks to create a set of region masks either from mask feature collections

+ + + + + + + + + + + + + + + +

compute_mpas_region_masks(dsMesh, fcMask[, ...])

Use shapely and processes to create a set of masks from a feature collection made up of regions (polygons)

compute_mpas_transect_masks(dsMesh, fcMask, ...)

Use shapely and processes to create a set of masks from a feature collection made up of transects (line strings)

compute_mpas_flood_fill_mask(dsMesh, fcSeed)

Flood fill from the given set of seed points to create a contiguous mask.

compute_lon_lat_region_masks(lon, lat, fcMask)

Use shapely and processes to create a set of masks from a feature collection made up of regions (polygons) on a tensor lon/lat grid

+ + + + + + +

merge_grids([infile1, infile2, outfile, runner])

Merges two MPAS non-contiguous meshes together into a single file

+ + + + + + +

split_grids([infile, outfile1, outfile2, ...])

Split two previously merged MPAS non-contiguous meshes together into separate files.

+ + + + + + + + + + + + +

translate(mesh[, xOffset, yOffset])

Translates the coordinate system of the planar MPAS mesh by an arbitrary shift in x and/or y

center(mesh)

Translates the coordinate system of the planar MPAS mesh by shifting the origin to the center of the domain

center_on_mesh(mesh, otherMesh)

Translates the coordinate system of the planar MPAS mesh by shifting the origin to the center of the domain described in a separate mesh

+ + + + + + +

scrip_from_mpas(mpasFile, scripFile[, ...])

Create a SCRIP file from an MPAS mesh

+
+
+

Config

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

MpasConfigParser()

A "meta" config parser that keeps a dictionary of config parsers and their sources to combine when needed.

MpasConfigParser.add_user_config(filename)

Add a the contents of a user config file to the parser.

MpasConfigParser.add_from_file(filename)

Add the contents of a config file to the parser.

MpasConfigParser.add_from_package(package, ...)

Add the contents of a config file to the parser.

MpasConfigParser.get(section, option)

Get an option value for a given section.

MpasConfigParser.getint(section, option)

Get an option integer value for a given section.

MpasConfigParser.getfloat(section, option)

Get an option float value for a given section.

MpasConfigParser.getboolean(section, option)

Get an option boolean value for a given section.

MpasConfigParser.getlist(section, option[, ...])

Get an option value as a list for a given section.

MpasConfigParser.getexpression(section, option)

Get an option as an expression (typically a list, though tuples and dicts are also available).

MpasConfigParser.has_section(section)

Whether the given section is part of the config

MpasConfigParser.has_option(section, option)

Whether the given section has the given option

MpasConfigParser.set(section, option[, ...])

Set the value of the given option in the given section. The file from

MpasConfigParser.write(fp[, ...])

Write the config options to the given file pointer.

MpasConfigParser.copy()

Get a deep copy of the config parser

MpasConfigParser.__getitem__(section)

Get get the config options for a given section.

+
+
+

I/O

+ + + + + + +

write_netcdf(ds, fileName[, fillValues, ...])

Write an xarray.Dataset to a file with NetCDF4 fill values and the given name of the string dimension.

+
+
+

Parallelism

+ + + + + + +

create_pool([process_count, method])

Crate a pool for creating masks with Python multiprocessing.

+
+
+

Interpolation

+ + + + + + +

interp_bilin(x, y, field, xCell, yCell)

Perform bilinear interpolation of field on a tensor grid to cell centers on an MPAS mesh.

+
+
+

CIME constants

+ + + + + + +

constants

+
+
+
+

Ocean Tools

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

coastline_alteration

coastline_alteration.add_critical_land_blockages(...)

Add the masks associated with one or more transects to the land mask

coastline_alteration.widen_transect_edge_masks(...)

Alter critical passages at polar latitudes to be at least two cells wide, to avoid sea ice blockage

coastline_alteration.add_land_locked_cells_to_mask(...)

Find ocean cells that are land-locked, and alter the cell mask so that they are counted as land cells.

moc

moc.make_moc_basins_and_transects(gf, ...[, ...])

Builds features defining the ocean basins and southern transects used in computing the meridional overturning circulation (MOC)

moc.add_moc_southern_boundary_transects(...)

+
param dsMask:
+

Region masks defining MOC basins

+
+
+

build_mesh

build_mesh.build_spherical_mesh(cellWidth, ...)

Build an MPAS mesh using JIGSAW with the given cell sizes as a function of latitude and longitude

build_mesh.build_planar_mesh(cellWidth, x, ...)

Build a planar MPAS mesh

coastal_tools

name: coastal_tools authors: Steven Brus

coastal_tools.coastal_refined_mesh(params[, ...])

Optionally create a background field of cell widths, then add a region of refined resolution to the cell widths.

coastal_tools.create_background_mesh(...[, ...])

Create a background field of cell widths

coastal_tools.extract_coastlines(nc_file, ...)

Extracts a set of coastline contours

coastal_tools.distance_to_coast(coastlines, ...)

Extracts a set of coastline contours

coastal_tools.compute_cell_width(D, ...[, ...])

Blend cell widths from the input field with the new resolution in the refined region determined by the distance to the coastline contour.

coastal_tools.save_matfile(cell_width, lon, lat)

coastal_tools.CPP_projection(lon, lat, origin)

coastal_tools.smooth_coastline(x, y, window)

coastal_tools.get_data_inside_box(lon, lat, ...)

coastal_tools.get_indices_inside_quad(lon, ...)

coastal_tools.get_convex_hull_coordinates(box)

coastal_tools.plot_coarse_coast(ax, plot_box)

coastal_tools.plot_region_box(box, color)

depth.add_depth(inFileName, outFileName[, ...])

Add a 1D depth coordinate to an MPAS-Ocean file.

depth.add_zmid(inFileName, outFileName[, ...])

Add a 3D, time-independent depth coordinate to an MPAS-Ocean file.

depth.write_time_varying_zmid(inFileName, ...)

Add a 3D, time-independent depth coordinate to an MPAS-Ocean file.

depth.compute_depth(refBottomDepth)

Computes depth and depth bounds given refBottomDepth

depth.compute_zmid(bottomDepth, ...[, depth_dim])

Computes zMid given data arrays for bottomDepth, maxLevelCell and layerThickness

+ + + + + + +

inject_bathymetry(mesh_file)

+ + + + + + + + + + + + +

inject_meshDensity_from_file(cw_filename, ...)

Add a meshDensity field into an MPAS mesh.

inject_spherical_meshDensity(cellWidth, lon, ...)

Add a meshDensity field into a spherical MPAS mesh.

inject_planar_meshDensity(cellWidth, x, y, ...)

Add a meshDensity field into a planar MPAS mesh.

+ + + + + + +

inject_preserve_floodplain(mesh_file, ...)

+ + + + + + + + + + + + + + + + + + +

find_transect_levels_and_weights(dsTransect, ...)

Construct a vertical coordinate for a transect produced by :py:fun:`mpas_tools.viz.transects.find_transect_cells_and_weights()`, then break each resulting quadrilateral into 2 triangles that can later be visualized with functions like tripcolor and tricontourf. Also, compute interpolation weights such that observations at points on the original transect and with vertical coordinate transectZ can be bilinearly interpolated to the nodes of the transect.

interp_mpas_to_transect_triangles(...)

Interpolate a 3D (nCells by nVertLevels) MPAS-Ocean DataArray to transect nodes with constant values in each MPAS cell

interp_mpas_to_transect_triangle_nodes(...)

Interpolate a 3D (nCells by nVertLevels) MPAS-Ocean DataArray to transect nodes, linearly interpolating fields between the closest neighboring cells

interp_transect_grid_to_transect_triangle_nodes(...)

Interpolate a DataArray on the original transect grid to triangle nodes on the MPAS-Ocean transect.

get_outline_segments(dsTransectTriangles[, ...])

Get a set of line segments that outline the given transect

+ + + + + + + + + +

plot_ocean_transects(fc, ds[, ds_mesh, ...])

Plot images of the given variables on the given transects.

add_inset(fig, fc[, latlonbuffer, ...])

Plots an inset map showing the location of a transect or polygon.

+
+
+

Sea-ice Tools

+ + + + + + +

extend_seaice_mask(filenameMesh, ...[, ...])

Add a field icePresenceExtended to filenamePresence if it doesn't already exist.

+ + + + + + + + + + + + + + + +

write_scrip_file(scripFilename, title, ...)

A low-level function for writing a SCRIP file for the given MPAS-Seaice mesh

write_2D_scripfile(filenameScripOut, ...[, ...])

Write a SCRIP file for the given 2D grid

make_mpas_scripfile_on_cells(meshFilename, ...)

Write a SCRIP file for cel quantities on the given MPAS-Seaice mesh

make_mpas_scripfile_on_vertices(...)

Write a SCRIP file for vertex quantities on the given MPAS-Seaice mesh

+ + + + + + + + + + + + +

gen_seaice_mesh_partition(meshFilename, ...)

Generate graph partition(s) for the given MPAS-Seaice mesh and the given number(s) of processors and a file defining regions that each processor should own part of (typically a polar region and an equatorial region)

prepare_partitions()

An entry point for performing preparatory work for making seaice partitions

create_partitions()

An entry point for creating sea-ice partitions

+ + + + + + +

make_regions_file(filenameIcePresent, ...)

"

+

+ + + + + + +

regrid_to_other_mesh(meshFilenameSrc, ...[, ...])

+
+
+

Logging

+ + + + + + + + + +

check_call(args[, logger, log_command, timeout])

Call the given subprocess with logging to the given logger.

LoggingContext(name[, logger, log_filename])

A context manager for creating a logger or using an existing logger

+
+
+

Transects

+ + + + + + + + + + + + + + + + + + + + + + + + +

subdivide_great_circle(x, y, z, maxRes, ...)

Subdivide each segment of the transect so the horizontal resolution approximately matches the requested resolution

cartesian_to_great_circle_distance(x, y, z, ...)

Cartesian transect points to great-circle distance

subdivide_planar(x, y, maxRes)

Subdivide each segment of the transect so the horizontal resolution approximately matches the requested resolution

lon_lat_to_cartesian(lon, lat, earth_radius, ...)

Convert from lon/lat to Cartesian x, y, z

cartesian_to_lon_lat(x, y, z, earth_radius, ...)

Convert from Cartesian x, y, z to lon/lat

angular_distance(x, y, z)

Compute angular distance between points on the sphere, following: https://en.wikipedia.org/wiki/Great-circle_distance

Vector(x, y, z)

A class for representing Cartesian vectors with x, y and z components that are either float or numpy.array objects of identical size.

+
+
+

Visualization

+ + + + + + +

extract_vtk(filename_pattern[, ...])

Extract fields from a time series of NetCDF files as VTK files for plotting in ParaView.

+ + + + + + +

mesh_to_triangles(dsMesh[, periodicCopy])

Construct a dataset in which each MPAS cell is divided into the triangles connecting pairs of adjacent vertices to cell centers.

+ + + + + + + + + + + + +

make_triangle_tree(dsTris)

Make a KD-Tree for finding triangle edges that are near enough to transect segments that they might intersect

find_transect_cells_and_weights(lonTransect, ...)

Find "nodes" where the transect intersects the edges of the triangles that make up MPAS cells.

find_planar_transect_cells_and_weights(...)

Find "nodes" where the transect intersects the edges of the triangles that make up MPAS cells.

+ + + + + + +

register_sci_viz_colormaps()

Register all SciVisColor colormaps with matplotlib

+
+
+

Tests

+ + + + + + +

test_cime_constants([e3sm_tag])

Parse relevant constants from CIME

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/authors.html b/0.22.0rc4/authors.html new file mode 100644 index 000000000..7d879588e --- /dev/null +++ b/0.22.0rc4/authors.html @@ -0,0 +1,177 @@ + + + + + + + Main Authors — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Main Authors

+
    +
  • Xylar Asay-Davis

  • +
  • Michael Duda

  • +
  • Matthew Hoffman

  • +
  • Douglas Jacobsen

  • +
+
+
+

Contributors

+
    +
  • Riley X. Brady

  • +
  • Miles Curry

  • +
  • Amrapalli Garanaik

  • +
  • Dom Heinzeller

  • +
  • Trevor Hillebrand

  • +
  • Joseph Kennedy

  • +
  • William Lipscomb

  • +
  • Mark Petersen

  • +
  • Stephen Price

  • +
  • Todd Ringler

  • +
  • Juan Saenz

  • +
  • Adrian Turner

  • +
  • Luke Van Roekel

  • +
  • Phillip J. Wolfram

  • +
  • Tong Zhang

  • +
+

For a list of all the contributions: +https://github.com/MPAS-Dev/MPAS-Tools/graphs/contributors

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/building_docs.html b/0.22.0rc4/building_docs.html new file mode 100644 index 000000000..5bb852bc2 --- /dev/null +++ b/0.22.0rc4/building_docs.html @@ -0,0 +1,160 @@ + + + + + + + Building the Documentation — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Building the Documentation

+

To make a local test build of the documentation, it is easiest to follow the +Testing Changes to mpas_tools procedure for how to make a local build of the +mpas_tools package. The development environment includes the packages +needed to build the documentation. Simply run:

+

code-block:

+
export DOCS_VERSION="test"
+cd conda_package/docs
+make html
+
+
+

Then, you can view the documentation by opening _build/html/index.html.

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/cime.html b/0.22.0rc4/cime.html new file mode 100644 index 000000000..2bf34d98b --- /dev/null +++ b/0.22.0rc4/cime.html @@ -0,0 +1,171 @@ + + + + + + + CIME Constants — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CIME Constants

+

The module mpas_tools.cime.constants contains constants that are in +sync with CIME, which provides infrastructure +and utilities for Earth System Models such at E3SM. Currently, we sync only +those constants given numerical values in CIME, not those that are derivied +from other constants. Constants are checked against their values on CIME’s +master branch during tests of the conda build. See +mpas_tools.tests.test_cime_constants.test_cime_constants().

+

Some of the constants most likely to be useful in MPAS-Tools, COMPASS and other +related projects are:

+
    +
  • SHR_CONST_CDAY - sec in calendar day (s)

  • +
  • SHR_CONST_REARTH - radius of Earth (m)

  • +
  • SHR_CONST_G - acceleration of gravity (m/s^2)

  • +
  • SHR_CONST_RHOFW - density of fresh water (kg/m^3)

  • +
  • SHR_CONST_RHOSW - density of sea water (kg/m^3)

  • +
  • SHR_CONST_RHOICE - density of ice (kg/m^3)

  • +
  • SHR_CONST_CPFW - specific heat of fresh water (J/kg/K)

  • +
  • SHR_CONST_CPSW - specific heat of sea water (J/kg/K)

  • +
  • SHR_CONST_CPICE - specific heat of fresh ice (J/kg/K)

  • +
  • SHR_CONST_LATICE - latent heat of fusion (J/kg)

  • +
  • SHR_CONST_LATVAP - latent heat of evaporation (J/kg)

  • +
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/config.html b/0.22.0rc4/config.html new file mode 100644 index 000000000..ac940e6e0 --- /dev/null +++ b/0.22.0rc4/config.html @@ -0,0 +1,228 @@ + + + + + + + Config files — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Config files

+

The mpas_tools.config module includes the +mpas_tools.config.MpasConfigParser class reading, getting, setting, +and writing config options and config files.

+

The mpas_tools.config.MpasConfigParser.add_from_package() method can +be used to add the contents of a config file within a package to the config +options.

+

Here is an example from compass +.. code-block:: python

+
+
+
self.config.add_from_package(

‘compass.ocean.tests.global_ocean.make_diagnostics_files’, +‘make_diagnostics_files.cfg’, exception=True)

+
+
+
+

The first and second arguments are the name of a package containing the config +file and the name of the config file itself, respectively. You can see that +the file is in the path compass/ocean/tests/global_ocean/make_diagnostics_files +(replacing the . in the module name with /). In this case, we know +that the config file should always exist, so we would like the code to raise +an exception (exception=True) if the file is not found. This is the +default behavior. In some cases, you would like the code to add the config +options if the config file exists and do nothing if it does not +(exception=False).

+

Ihe MpasConfigParser class also includes methods for adding a user +config file, mpas_tools.config.MpasConfigParser.add_user_config(), +and other config files by file name, +mpas_tools.config.MpasConfigParser.add_from_file().

+

The mpas_tools.config.MpasConfigParser.copy() method can be used to +make a deep copy of the config parser. This is useful in cases where config +options should be added or modified without affecting the original config +object. For example, this feature is used in MPAS-Analysis to set a reference +year as the start year in some analysis without affecting the start year in +other analysis.

+

The mpas_tools.config.MpasConfigParser.set() method has some +optional arguments not present in configparser.ConfigParser.set(). +The comment argument can be used to add a comment that will be written +out above the config option. The comment can cover multiple lines by including +a \n character. The comment should not include the # comment +character, as this is added automatically. The argument user=True can be +used to set “user” config options similar to reading a user config file with +mpas_tools.config.MpasConfigParser.add_user_config().

+

Other methods for the MpasConfigParser are similar to those for +configparser.ConfigParser. In addition to get(), +getinteger(), getfloat() and getboolean() methods, this class +implements mpas_tools.config.MpasConfigParser.getlist(), which +can be used to parse a config value separated by spaces and/or commas into +a list of strings, floats, integers, booleans, etc. Another useful method +is mpas_tools.config.MpasConfigParser.getexpression(), which can +be used to get python dictionaries, lists and tuples as well as a small set +of functions (range(), numpy.linspace(), +numpy.arange(), and numpy.array())

+

Currently, MpasConfigParser supports accessing a config section using +section names as keys, e.g.:

+
section = self.config['enthalpy_benchmark_viz']
+display_image = section.getboolean('display_image')
+...
+
+
+

But it does not allow assignment of a section or many of the other +dictionary-like features supported by configparser.ConfigParser.

+
+

Comments in config files

+

One of the main advantages of mpas_tools.config.MpasConfigParser +over configparser.ConfigParser is that it keeps track of comments +that are associated with config sections and options. There are a few “rules” +that make this possible.

+

Comments must begin with the # character. They must be placed before the +config section or option in question (preferably without blank lines between). +The comments can be any number of lines.

+
+

Note

+

Inline comments (after a config option on the same line) are not allowed +and will be parsed as part of the config option itself.

+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.cime.constants.html b/0.22.0rc4/generated/mpas_tools.cime.constants.html new file mode 100644 index 000000000..ec4d927fe --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.cime.constants.html @@ -0,0 +1,171 @@ + + + + + + + mpas_tools.cime.constants — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.cime.constants

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.__getitem__.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.__getitem__.html new file mode 100644 index 000000000..c5ff2e28d --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.__getitem__.html @@ -0,0 +1,200 @@ + + + + + + + mpas_tools.config.MpasConfigParser.__getitem__ — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.__getitem__

+
+
+MpasConfigParser.__getitem__(section)[source]
+

Get get the config options for a given section.

+
+
Parameters:
+

section (str) – The name of the section to retrieve.

+
+
Returns:
+

section_proxy (configparser.SectionProxy) – The config options for the given section.

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_from_file.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_from_file.html new file mode 100644 index 000000000..42e7352f4 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_from_file.html @@ -0,0 +1,197 @@ + + + + + + + mpas_tools.config.MpasConfigParser.add_from_file — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.add_from_file

+
+
+MpasConfigParser.add_from_file(filename)[source]
+

Add the contents of a config file to the parser.

+
+
Parameters:
+

filename (str) – The relative or absolute path to the config file

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_from_package.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_from_package.html new file mode 100644 index 000000000..91b07441e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_from_package.html @@ -0,0 +1,201 @@ + + + + + + + mpas_tools.config.MpasConfigParser.add_from_package — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.add_from_package

+
+
+MpasConfigParser.add_from_package(package, config_filename, exception=True)[source]
+

Add the contents of a config file to the parser.

+
+
Parameters:
+
    +
  • package (str or Package) – The package where config_filename is found

  • +
  • config_filename (str) – The name of the config file to add

  • +
  • exception (bool, optional) – Whether to raise an exception if the config file isn’t found

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_user_config.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_user_config.html new file mode 100644 index 000000000..00834f69f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.add_user_config.html @@ -0,0 +1,198 @@ + + + + + + + mpas_tools.config.MpasConfigParser.add_user_config — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.add_user_config

+
+
+MpasConfigParser.add_user_config(filename)[source]
+

Add a the contents of a user config file to the parser. These options +take precedence over all other options.

+
+
Parameters:
+

filename (str) – The relative or absolute path to the config file

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.copy.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.copy.html new file mode 100644 index 000000000..53539ca90 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.copy.html @@ -0,0 +1,197 @@ + + + + + + + mpas_tools.config.MpasConfigParser.copy — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.copy

+
+
+MpasConfigParser.copy()[source]
+

Get a deep copy of the config parser

+
+
Returns:
+

config_copy (mpas_tools.config.MpasConfigParser) – The deep copy

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.get.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.get.html new file mode 100644 index 000000000..ba707c138 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.get.html @@ -0,0 +1,203 @@ + + + + + + + mpas_tools.config.MpasConfigParser.get — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.get

+
+
+MpasConfigParser.get(section, option)[source]
+

Get an option value for a given section.

+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
+
+
Returns:
+

value (str) – The value of the config option

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getboolean.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getboolean.html new file mode 100644 index 000000000..9f1f10b0f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getboolean.html @@ -0,0 +1,203 @@ + + + + + + + mpas_tools.config.MpasConfigParser.getboolean — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.getboolean

+
+
+MpasConfigParser.getboolean(section, option)[source]
+

Get an option boolean value for a given section.

+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
+
+
Returns:
+

value (bool) – The value of the config option

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getexpression.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getexpression.html new file mode 100644 index 000000000..62c3cd043 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getexpression.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.config.MpasConfigParser.getexpression — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.getexpression

+
+
+MpasConfigParser.getexpression(section, option, dtype=None, use_numpyfunc=False)[source]
+

Get an option as an expression (typically a list, though tuples and +dicts are also available). The expression is required to have valid +python syntax, so that string entries are required to be in single or +double quotes.

+
+
Parameters:
+
    +
  • section (str) – The section in the config file

  • +
  • option (str) – The option in the config file

  • +
  • dtype ({Type[bool], Type[int], Type[float], Type[list], Type[tuple], Type[str]}, optional) – If supplied, each element in a list or tuple, or +each value in a dictionary are cast to this type. This is likely +most useful for ensuring that all elements in a list of numbers are +of type float, rather than int, when the distinction is important.

  • +
  • use_numpyfunc (bool, optional) – If True, the expression is evaluated including functionality +from the numpy package (which can be referenced either as numpy +or np).

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getfloat.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getfloat.html new file mode 100644 index 000000000..302a7834f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getfloat.html @@ -0,0 +1,203 @@ + + + + + + + mpas_tools.config.MpasConfigParser.getfloat — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.getfloat

+
+
+MpasConfigParser.getfloat(section, option)[source]
+

Get an option float value for a given section.

+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
+
+
Returns:
+

value (float) – The value of the config option

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getint.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getint.html new file mode 100644 index 000000000..30d8ceee0 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getint.html @@ -0,0 +1,203 @@ + + + + + + + mpas_tools.config.MpasConfigParser.getint — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.getint

+
+
+MpasConfigParser.getint(section, option)[source]
+

Get an option integer value for a given section.

+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
+
+
Returns:
+

value (int) – The value of the config option

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getlist.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getlist.html new file mode 100644 index 000000000..876897825 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.getlist.html @@ -0,0 +1,204 @@ + + + + + + + mpas_tools.config.MpasConfigParser.getlist — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.getlist

+
+
+MpasConfigParser.getlist(section, option, dtype=<class 'str'>)[source]
+

Get an option value as a list for a given section.

+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
  • dtype ({Type[str], Type[int], Type[float]}) – The type of the elements in the list

  • +
+
+
Returns:
+

value (list) – The value of the config option parsed into a list

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.has_option.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.has_option.html new file mode 100644 index 000000000..5c86af112 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.has_option.html @@ -0,0 +1,203 @@ + + + + + + + mpas_tools.config.MpasConfigParser.has_option — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.has_option

+
+
+MpasConfigParser.has_option(section, option)[source]
+

Whether the given section has the given option

+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
+
+
Returns:
+

found (bool) – Whether the option was found in the section

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.has_section.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.has_section.html new file mode 100644 index 000000000..b903811bc --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.has_section.html @@ -0,0 +1,200 @@ + + + + + + + mpas_tools.config.MpasConfigParser.has_section — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.has_section

+
+
+MpasConfigParser.has_section(section)[source]
+

Whether the given section is part of the config

+
+
Parameters:
+

section (str) – The name of the config section

+
+
Returns:
+

found (bool) – Whether the option was found in the section

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.html new file mode 100644 index 000000000..702ac6002 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.html @@ -0,0 +1,267 @@ + + + + + + + mpas_tools.config.MpasConfigParser — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser

+
+
+class mpas_tools.config.MpasConfigParser[source]
+

A “meta” config parser that keeps a dictionary of config parsers and their +sources to combine when needed. The custom config parser allows provenance +of the source of different config options and allows the “user” config +options to always take precedence over other config options (even if they +are added later).

+
+
Variables:
+
    +
  • combined ({None, configparser.ConfigParser}) – The combined config options

  • +
  • combined_comments ({None, dict}) – The combined comments associated with sections and options

  • +
  • sources ({None, dict}) – The source of each section or option

  • +
+
+
+
+
+__init__()[source]
+

Make a new (empty) config parser

+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

__init__()

Make a new (empty) config parser

add_from_file(filename)

Add the contents of a config file to the parser.

add_from_package(package, config_filename[, ...])

Add the contents of a config file to the parser.

add_user_config(filename)

Add a the contents of a user config file to the parser.

combine()

Combine the config files into one.

copy()

Get a deep copy of the config parser

get(section, option)

Get an option value for a given section.

getboolean(section, option)

Get an option boolean value for a given section.

getexpression(section, option[, dtype, ...])

Get an option as an expression (typically a list, though tuples and dicts are also available).

getfloat(section, option)

Get an option float value for a given section.

getint(section, option)

Get an option integer value for a given section.

getlist(section, option[, dtype])

Get an option value as a list for a given section.

has_option(section, option)

Whether the given section has the given option

has_section(section)

Whether the given section is part of the config

list_files()

Get a list of files contributing to the combined config options

set(section, option[, value, comment, user])

Set the value of the given option in the given section. The file from

write(fp[, include_sources, include_comments])

Write the config options to the given file pointer.

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.set.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.set.html new file mode 100644 index 000000000..51a2c0091 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.set.html @@ -0,0 +1,208 @@ + + + + + + + mpas_tools.config.MpasConfigParser.set — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.set

+
+
+MpasConfigParser.set(section, option, value=None, comment=None, user=False)[source]
+
+
Set the value of the given option in the given section. The file from

which this function was called is also retained for provenance.

+
+
+
+
Parameters:
+
    +
  • section (str) – The name of the config section

  • +
  • option (str) – The name of the config option

  • +
  • value (str, optional) – The value to set the option to

  • +
  • comment (str, optional) – A comment to include with the config option when it is written +to a file

  • +
  • user (bool, optional) – Whether this config option was supplied by the user (e.g. through +a command-line flag) and should take priority over other sources

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.write.html b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.write.html new file mode 100644 index 000000000..ed5d7edf5 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.config.MpasConfigParser.write.html @@ -0,0 +1,203 @@ + + + + + + + mpas_tools.config.MpasConfigParser.write — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.config.MpasConfigParser.write

+
+
+MpasConfigParser.write(fp, include_sources=True, include_comments=True)[source]
+

Write the config options to the given file pointer.

+
+
Parameters:
+
    +
  • fp (TestIO) – The file pointer to write to.

  • +
  • include_sources (bool, optional) – Whether to include a comment above each option indicating the +source file where it was defined

  • +
  • include_comments (bool, optional) – Whether to include the original comments associated with each +section or option

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.io.write_netcdf.html b/0.22.0rc4/generated/mpas_tools.io.write_netcdf.html new file mode 100644 index 000000000..0c03fab0e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.io.write_netcdf.html @@ -0,0 +1,202 @@ + + + + + + + mpas_tools.io.write_netcdf — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.io.write_netcdf

+
+
+mpas_tools.io.write_netcdf(ds, fileName, fillValues=None, format=None, engine=None, char_dim_name=None)[source]
+

Write an xarray.Dataset to a file with NetCDF4 fill values and the given +name of the string dimension. Also adds the time and command-line to the +history attribute.

+
+
Parameters:
+
    +
  • ds (xarray.Dataset) – The dataset to save

  • +
  • fileName (str) – The path for the NetCDF file to write

  • +
  • fillValues (dict, optional) – A dictionary of fill values for different NetCDF types. Default is +mpas_tools.io.default_fills, which can be modified but which +defaults to netCDF4.default_fillvals

  • +
  • format ({'NETCDF4', 'NETCDF4_CLASSIC', 'NETCDF3_64BIT',) – ‘NETCDF3_CLASSIC’}, optional +The NetCDF file format to use. Default is +mpas_tools.io.default_format, which can be modified but which +defaults to 'NETCDF3_64BIT'

  • +
  • engine ({'netcdf4', 'scipy', 'h5netcdf'}, optional) – The library to use for NetCDF output. The default is the same as +in xarray.Dataset.to_netcdf() and depends on format. +You can override the default by setting +mpas_tools.io.default_engine

  • +
  • char_dim_name (str, optional) – The name of the dimension used for character strings, or None to let +xarray figure this out. Default is +mpas_tools.io.default_char_dim_name, which can be modified but +which defaults to ``’StrLen’`

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.logging.LoggingContext.html b/0.22.0rc4/generated/mpas_tools.logging.LoggingContext.html new file mode 100644 index 000000000..7e3cfc778 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.logging.LoggingContext.html @@ -0,0 +1,205 @@ + + + + + + + mpas_tools.logging.LoggingContext — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.logging.LoggingContext

+
+
+class mpas_tools.logging.LoggingContext(name, logger=None, log_filename=None)[source]
+

A context manager for creating a logger or using an existing logger

+
+
Variables:
+

logger (logging.Logger) – A logger that sends output to a log file or stdout/stderr

+
+
+
+
+__init__(name, logger=None, log_filename=None)[source]
+

If logger is None, create a new logger either to a log file +or stdout/stderr. If logger is anything else, just set the logger +attribute

+
+
Parameters:
+
    +
  • name (str) – A unique name for the logger (e.g. __name__ of the calling +module)

  • +
  • logger (logging.Logger, optional) – An existing logger that sends output to a log file or stdout/stderr +to be used in this context

  • +
  • log_filename (str, optional) – The name of a file where output should be written. If none is +supplied, output goes to stdout/stderr

  • +
+
+
+
+ +

Methods

+ + + + + + +

__init__(name[, logger, log_filename])

If logger is None, create a new logger either to a log file or stdout/stderr.

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.logging.check_call.html b/0.22.0rc4/generated/mpas_tools.logging.check_call.html new file mode 100644 index 000000000..870449a23 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.logging.check_call.html @@ -0,0 +1,187 @@ + + + + + + + mpas_tools.logging.check_call — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.logging.check_call

+
+
+mpas_tools.logging.check_call(args, logger=None, log_command=True, timeout=None, **kwargs)[source]
+

Call the given subprocess with logging to the given logger.

+
+
Parameters:
+
    +
  • args (list or str) – A list or string of argument to the subprocess. If args is a +string, you must pass shell=True as one of the kwargs.

  • +
  • logger (logging.Logger, optional) – The logger to write output to

  • +
  • log_command (bool, optional) – Whether to write the command that is running ot the logger

  • +
  • timeout (int, optional) – A timeout in seconds for the call

  • +
  • **kwargs (dict) – Keyword arguments to pass to subprocess.Popen

  • +
+
+
Raises:
+

subprocess.CalledProcessError – If the given subprocess exists with nonzero status

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.merge_grids.merge_grids.html b/0.22.0rc4/generated/mpas_tools.merge_grids.merge_grids.html new file mode 100644 index 000000000..06e73167e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.merge_grids.merge_grids.html @@ -0,0 +1,199 @@ + + + + + + + mpas_tools.merge_grids.merge_grids — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.merge_grids.merge_grids

+
+
+mpas_tools.merge_grids.merge_grids(infile1=None, infile2=None, outfile=None, runner=None)[source]
+

Merges two MPAS non-contiguous meshes together into a single file

+
+
Parameters:
+
    +
  • infile1 (str) – The file name for the first mesh to merge

  • +
  • infile2 (str) – The file name for the second mesh to merge

  • +
  • outfile (str) – The file name for the first mesh to merge

  • +
  • runner (str, optional) – The command to write into the global history attribute of the outfile

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.conversion.convert.html b/0.22.0rc4/generated/mpas_tools.mesh.conversion.convert.html new file mode 100644 index 000000000..4c1bc6230 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.conversion.convert.html @@ -0,0 +1,207 @@ + + + + + + + mpas_tools.mesh.conversion.convert — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.conversion.convert

+
+
+mpas_tools.mesh.conversion.convert(dsIn, graphInfoFileName=None, logger=None, dir=None)[source]
+

Use MpasMeshConverter.x to convert an input mesh to a valid MPAS +mesh that is fully compliant with the MPAS mesh specification. +https://mpas-dev.github.io/files/documents/MPAS-MeshSpec.pdf

+
+
Parameters:
+
    +
  • dsIn (xarray.Dataset) – A data set to convert

  • +
  • graphInfoFileName (str, optional) – A file path (relative or absolute) where the graph file (typically +graph.info should be written out. By default, graph.info is +not saved.

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • dir (str, optional) – A directory in which a temporary directory will be added with files +produced during conversion and then deleted upon completion.

  • +
+
+
Returns:
+

dsOut (xarray.Dataset) – The MPAS mesh

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.conversion.cull.html b/0.22.0rc4/generated/mpas_tools.mesh.conversion.cull.html new file mode 100644 index 000000000..167e7420e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.conversion.cull.html @@ -0,0 +1,216 @@ + + + + + + + mpas_tools.mesh.conversion.cull — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.conversion.cull

+
+
+mpas_tools.mesh.conversion.cull(dsIn, dsMask=None, dsInverse=None, dsPreserve=None, graphInfoFileName=None, logger=None, dir=None)[source]
+

Use MpasCellCuller.x to cull cells from a mesh based on the +cullCell field in the input file or DataSet and/or the provided masks. +cullCell, dsMask and dsInverse are merged together so that the final +mask is the union of these 3. The preserve mask is then used to determine +where cells should not be culled.

+
+
Parameters:
+
    +
  • dsIn (xarray.Dataset) – A data set to cull, possibly with a cullCell field set to one where +cells should be removed

  • +
  • dsMask (xarray.Dataset or list, optional) – A data set (or data sets) with region masks that are 1 where cells +should be culled

  • +
  • dsInverse (xarray.Dataset or list, optional) – A data set (or data sets) with region masks that are 0 where cells +should be culled

  • +
  • dsPreserve (xarray.Dataset or list, optional) – A data set (or data sets) with region masks that are 1 where cells +should not be culled

  • +
  • graphInfoFileName (str, optional) – A file path (relative or absolute) where the graph file (typically +culled_graph.info should be written out. By default, +culled_graph.info is not saved.

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • dir (str, optional) – A directory in which a temporary directory will be added with files +produced during cell culling and then deleted upon completion.

  • +
+
+
Returns:
+

dsOut (xarray.Dataset) – The culled mesh

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.conversion.mask.html b/0.22.0rc4/generated/mpas_tools.mesh.conversion.mask.html new file mode 100644 index 000000000..f1fd33313 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.conversion.mask.html @@ -0,0 +1,205 @@ + + + + + + + mpas_tools.mesh.conversion.mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.conversion.mask

+
+
+mpas_tools.mesh.conversion.mask(dsMesh, fcMask=None, logger=None, dir=None, cores=1)[source]
+

Use compute_mpas_region_masks to create a set of region masks either +from mask feature collections

+
+
Parameters:
+
    +
  • dsMesh (xarray.Dataset, optional) – An MPAS mesh on which the masks should be created

  • +
  • fcMask (geometric_features.FeatureCollection, optional) – A feature collection containing features to use to create the mask

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • dir (str, optional) – A directory in which a temporary directory will be added with files +produced during mask creation and then deleted upon completion.

  • +
  • cores (int, optional) – The number of cores to use for python multiprocessing

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The masks

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.html new file mode 100644 index 000000000..40eac6614 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.html @@ -0,0 +1,207 @@ + + + + + + + mpas_tools.mesh.creation.build_mesh.build_planar_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.build_mesh.build_planar_mesh

+
+
+mpas_tools.mesh.creation.build_mesh.build_planar_mesh(cellWidth, x, y, geom_points, geom_edges, out_filename='base_mesh.nc', logger=None)[source]
+

Build a planar MPAS mesh

+
+
Parameters:
+
    +
  • cellWidth (ndarray) – m x n array of cell width in km

  • +
  • x (ndarray) – arrays defining planar coordinates in meters

  • +
  • y (ndarray) – arrays defining planar coordinates in meters

  • +
  • geom_points (ndarray) – list of point coordinates for bounding polygon for the planar mesh

  • +
  • geom_edges (ndarray) – list of edges between points in geom_points that define the +bounding polygon

  • +
  • out_filename (str, optional) – The file name of the resulting MPAS mesh

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.html new file mode 100644 index 000000000..ebc27195e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.html @@ -0,0 +1,213 @@ + + + + + + + mpas_tools.mesh.creation.build_mesh.build_spherical_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.build_mesh.build_spherical_mesh

+
+
+mpas_tools.mesh.creation.build_mesh.build_spherical_mesh(cellWidth, lon, lat, earth_radius, out_filename='base_mesh.nc', plot_cellWidth=True, dir='./', logger=None)[source]
+

Build an MPAS mesh using JIGSAW with the given cell sizes as a function of +latitude and longitude.

+

The result is a mesh file stored in out_filename as well as several +intermediate files: mesh.log, mesh-HFUN.msh, mesh.jig, +mesh-MESH.msh, mesh.msh, and mesh_triangles.nc.

+
+
Parameters:
+
    +
  • cellWidth (ndarray) – m x n array of cell width in km

  • +
  • lon (ndarray) – longitude in degrees (length n and between -180 and 180)

  • +
  • lat (ndarray) – longitude in degrees (length m and between -90 and 90)

  • +
  • earth_radius (float) – Earth radius in meters

  • +
  • out_filename (str, optional) – The file name of the resulting MPAS mesh

  • +
  • plot_cellWidth (bool, optional) – Whether to produce a plot of cellWidth. If so, it will be written +to cellWidthGlobal.png.

  • +
  • dir (str, optional) – A directory in which a temporary directory will be added with files +produced during mesh conversion and then deleted upon completion.

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.html new file mode 100644 index 000000000..f02270857 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.build_mesh.html @@ -0,0 +1,198 @@ + + + + + + + mpas_tools.mesh.creation.build_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.build_mesh

+

Functions

+ + + + + + + + + +

build_planar_mesh(cellWidth, x, y, ...[, ...])

Build a planar MPAS mesh

build_spherical_mesh(cellWidth, lon, lat, ...)

Build an MPAS mesh using JIGSAW with the given cell sizes as a function of latitude and longitude.

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.html new file mode 100644 index 000000000..ab4a49afb --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.html @@ -0,0 +1,209 @@ + + + + + + + mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver

+
+
+mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver(cellWidth, x, y, on_sphere=True, earth_radius=6371000.0, geom_points=None, geom_edges=None, logger=None)[source]
+

A function for building a jigsaw mesh

+
+
Parameters:
+
    +
  • cellWidth (ndarray) – The size of each cell in the resulting mesh as a function of space

  • +
  • x (ndarray) – The x and y coordinates of each point in the cellWidth array (lon and +lat for spherical mesh)

  • +
  • y (ndarray) – The x and y coordinates of each point in the cellWidth array (lon and +lat for spherical mesh)

  • +
  • on_sphere (logical, optional) – Whether this mesh is spherical or planar

  • +
  • earth_radius (float, optional) – Earth radius in meters

  • +
  • geom_points (ndarray, optional) – list of point coordinates for bounding polygon for planar mesh

  • +
  • geom_edges (ndarray, optional) – list of edges between points in geom_points that define the bounding polygon

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.html new file mode 100644 index 000000000..62181f1af --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.html @@ -0,0 +1,204 @@ + + + + + + + mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf

+
+
+mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf(msh_filename, output_name, on_sphere, sphere_radius=None)[source]
+

Converts mesh data defined in triangle format to NetCDF

+
+
Parameters:
+
    +
  • msh_filename (str) – A JIGSAW mesh file name

  • +
  • output_name (str) – The name of the output file

  • +
  • on_sphere (bool) – Whether the mesh is spherical or planar

  • +
  • sphere_radius (float, optional) – The radius of the sphere in meters. If on_sphere=True this argument +is required, otherwise it is ignored.

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.html new file mode 100644 index 000000000..189513764 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.html @@ -0,0 +1,206 @@ + + + + + + + mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid

+
+
+mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid(lat, lon, cellWidthInAtlantic, cellWidthInPacific)[source]
+

Combine two cell width distributions using a tanh function.

+
+
Parameters:
+
    +
  • lat (ndarray) – vector of length n, with entries between -90 and 90, degrees

  • +
  • lon (ndarray) – vector of length m, with entries between -180, 180, degrees

  • +
  • cellWidthInAtlantic (float, optional) – vector of length n, cell width in Atlantic as a function of lon, km

  • +
  • cellWidthInPacific (float, optional) – vector of length n, cell width in Pacific as a function of lon, km

  • +
+
+
Returns:
+

cellWidthOut (ndarray) – m by n array, grid cell width on globe, km

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.html new file mode 100644 index 000000000..20f693c5f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.html @@ -0,0 +1,222 @@ + + + + + + + mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat

+
+
+mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat(lat, cellWidthEq=30.0, cellWidthMidLat=60.0, cellWidthPole=35.0, latPosEq=15.0, latPosPole=73.0, latTransition=40.0, latWidthEq=6.0, latWidthPole=9.0)[source]
+

Create Eddy Closure spacing as a function of lat. This is intended as part +of the workflow to make an MPAS global mesh.

+
+
Parameters:
+
    +
  • lat (ndarray) – vector of length n, with entries between -90 and 90, degrees

  • +
  • cellWidthEq (float, optional) – Cell width in km at the equator

  • +
  • cellWidthMidLat (float, optional) – Cell width in km at mid latitudes

  • +
  • cellWidthPole (float, optional) – Cell width in km at the poles

  • +
  • latPosEq (float, optional) – Latitude in degrees of center of the equatorial transition region

  • +
  • latPosPole (float, optional) – Latitude in degrees of center of the polar transition region

  • +
  • latTransition (float, optional) – Latitude in degrees of the change from equatorial to polar function

  • +
  • latWidthEq (float, optional) – Width in degrees latitude of the equatorial transition region

  • +
  • latWidthPole (float, optional) – Width in degrees latitude of the polar transition region

  • +
+
+
Returns:
+

cellWidthOut (ndarray) – 1D array of same length as lat with entries that are cell width as +a function of lat

+
+
+

Examples

+

Default

+
>>> EC60to30 = EC_CellWidthVsLat(lat)
+
+
+

Half the default resolution:

+
>>> EC120to60 = EC_CellWidthVsLat(lat, cellWidthEq=60., cellWidthMidLat=120., cellWidthPole=70.)
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.html new file mode 100644 index 000000000..ca4a42253 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.html @@ -0,0 +1,211 @@ + + + + + + + mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat

+
+
+mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat(lat, cellWidthEq, cellWidthPole)[source]
+

Create Rossby Radius Scaling as a function of lat. This is intended as +part of the workflow to make an MPAS global mesh.

+
+
Parameters:
+
    +
  • lat (ndarray) – vector of length n, with entries between -90 and 90, degrees

  • +
  • cellWidthEq (float, optional) – Cell width in km at the equator

  • +
  • cellWidthPole (float, optional) – Cell width in km at the poles

  • +
+
+
Returns:
+

cellWidthOut (ndarray) – 1D array of same length as lat with entries that are cell width as +a function of lat

+
+
+

Examples

+
>>> RRS18to6 = EC_CellWidthVsLat(lat, 18., 6.)
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.html new file mode 100644 index 000000000..52d519d11 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.html @@ -0,0 +1,207 @@ + + + + + + + mpas_tools.mesh.creation.mesh_definition_tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.mesh_definition_tools

+

These functions are tools used to define the cellWidth variable on +regular lat/lon grids. The cellWidth variable is a jigsaw input that +defines the mesh.

+

Functions

+ + + + + + + + + + + + + + + +

AtlanticPacificGrid(lat, lon, ...)

Combine two cell width distributions using a tanh function.

EC_CellWidthVsLat(lat[, cellWidthEq, ...])

Create Eddy Closure spacing as a function of lat.

RRS_CellWidthVsLat(lat, cellWidthEq, ...)

Create Rossby Radius Scaling as a function of lat.

mergeCellWidthVsLat(lat, cellWidthInSouth, ...)

Combine two cell width distributions using a tanh function.

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.html new file mode 100644 index 000000000..15152472a --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.html @@ -0,0 +1,209 @@ + + + + + + + mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat

+
+
+mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat(lat, cellWidthInSouth, cellWidthInNorth, latTransition, latWidthTransition)[source]
+

Combine two cell width distributions using a tanh function. This is +intended as part of the workflow to make an MPAS global mesh.

+
+
Parameters:
+
    +
  • lat (ndarray) – vector of length n, with entries between -90 and 90, degrees

  • +
  • cellWidthInSouth (ndarray) – vector of length n, first distribution

  • +
  • cellWidthInNorth (ndarray) – vector of length n, second distribution

  • +
  • latTransition (float) – lat to change from cellWidthInSouth to cellWidthInNorth in +degrees

  • +
  • latWidthTransition (float) – width of lat transition in degrees

  • +
+
+
Returns:
+

cellWidthOut (ndarray) – vector of length n, entries are cell width as a function of lat

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.html new file mode 100644 index 000000000..8a6213152 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.html @@ -0,0 +1,205 @@ + + + + + + + mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle

+
+
+mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle(mpasfile, trifile)[source]
+

Script to convert from MPAS netCDF format to the Triangle format: +https://www.cs.cmu.edu/~quake/triangle.node.html +https://www.cs.cmu.edu/~quake/triangle.ele.html

+
+
Parameters:
+
    +
  • mpasfile (str) – The path to an MPAS mesh in NetCDF format

  • +
  • trifile (str) – The prefix for the Triangle output files. Files with extensions +.node and .ele will be produced.

  • +
  • meshes. (Only works for planar) –

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.html new file mode 100644 index 000000000..1f103ee6a --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.html @@ -0,0 +1,212 @@ + + + + + + + mpas_tools.mesh.creation.signed_distance.distance_from_geojson — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.signed_distance.distance_from_geojson

+
+
+mpas_tools.mesh.creation.signed_distance.distance_from_geojson(fc, lon_grd, lat_grd, earth_radius, nn_search='kdtree', max_length=None, workers=-1)[source]
+

Get the distance for each point on a lon/lat grid from the closest point +on the boundary of the geojson regions.

+
+
Parameters:
+
    +
  • fc (geometrics_features.FeatureCollection) – The regions to be rasterized

  • +
  • lon_grd (numpy.ndarray) – A 1D array of longitude values

  • +
  • lat_grd (numpy.ndarray) – A 1D array of latitude values

  • +
  • earth_radius (float) – Earth radius in meters

  • +
  • nn_search ({'kdtree'}, optional) – The method used to find the nearest point on the shape boundary

  • +
  • max_length (float, optional) – The maximum distance (in degrees) between points on the boundary of the +geojson region. If the boundary is too coarse, it will be subdivided.

  • +
  • workers (int, optional) – The number of threads used for finding nearest neighbors. The default +is all available threads (workers=-1)

  • +
+
+
Returns:
+

distance (numpy.ndarray) – A 2D field of distances to the shape boundary

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.html new file mode 100644 index 000000000..78aba743e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.html @@ -0,0 +1,201 @@ + + + + + + + mpas_tools.mesh.creation.signed_distance — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.signed_distance

+

Functions

+ + + + + + + + + + + + +

distance_from_geojson(fc, lon_grd, lat_grd, ...)

Get the distance for each point on a lon/lat grid from the closest point on the boundary of the geojson regions.

mask_from_geojson(fc, lon_grd, lat_grd)

Make a rasterized mask on a lon/lat grid from shapes (geojson multipolygon data).

signed_distance_from_geojson(fc, lon_grd, ...)

Get the distance for each point on a lon/lat grid from the closest point on the boundary of the geojson regions.

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.html new file mode 100644 index 000000000..accc27d4d --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.html @@ -0,0 +1,206 @@ + + + + + + + mpas_tools.mesh.creation.signed_distance.mask_from_geojson — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.signed_distance.mask_from_geojson

+
+
+mpas_tools.mesh.creation.signed_distance.mask_from_geojson(fc, lon_grd, lat_grd)[source]
+

Make a rasterized mask on a lon/lat grid from shapes (geojson multipolygon +data).

+
+
Parameters:
+
    +
  • fc (geometrics_features.FeatureCollection) – The regions to be rasterized

  • +
  • lon_grd (numpy.ndarray) – A 1D array of longitude values

  • +
  • lat_grd (numpy.ndarray) – A 1D array of latitude values

  • +
+
+
Returns:
+

mask (numpy.ndarray) – A 2D mask with the shapes rasterized (0.0 outside, 1.0 inside)

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.html new file mode 100644 index 000000000..9d78dd3f5 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.html @@ -0,0 +1,212 @@ + + + + + + + mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson

+
+
+mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson(fc, lon_grd, lat_grd, earth_radius, max_length=None, workers=-1)[source]
+

Get the distance for each point on a lon/lat grid from the closest point +on the boundary of the geojson regions.

+
+
Parameters:
+
    +
  • fc (geometrics_features.FeatureCollection) – The regions to be rasterized

  • +
  • lon_grd (numpy.ndarray) – A 1D array of longitude values

  • +
  • lat_grd (numpy.ndarray) – A 1D array of latitude values

  • +
  • earth_radius (float) – Earth radius in meters

  • +
  • max_length (float, optional) – The maximum distance (in degrees) between points on the boundary of the +geojson region. If the boundary is too coarse, it will be subdivided.

  • +
  • workers (int, optional) – The number of threads used for finding nearest neighbors. The default +is all available threads (workers=-1)

  • +
+
+
Returns:
+

signed_distance (numpy.ndarray) – A 2D field of distances (negative inside the region, positive outside) +to the shape boundary

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.html b/0.22.0rc4/generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.html new file mode 100644 index 000000000..9cde5c1b4 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.html @@ -0,0 +1,202 @@ + + + + + + + mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf

+
+
+mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf(node, ele, output_name)[source]
+

Converts mesh data defined in triangle format to NetCDF

+
+
Parameters:
+
    +
  • node (str) – A node file name

  • +
  • ele (str) – An element file name

  • +
  • output_name (str) – The name of the output file

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.interpolation.interp_bilin.html b/0.22.0rc4/generated/mpas_tools.mesh.interpolation.interp_bilin.html new file mode 100644 index 000000000..24a2b259a --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.interpolation.interp_bilin.html @@ -0,0 +1,196 @@ + + + + + + + mpas_tools.mesh.interpolation.interp_bilin — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.interpolation.interp_bilin

+
+
+mpas_tools.mesh.interpolation.interp_bilin(x, y, field, xCell, yCell)[source]
+

Perform bilinear interpolation of field on a tensor grid to cell centers +on an MPAS mesh. xCell and yCell must be bounded by x and y, +respectively.

+

If x and y coordinates are longitude and latitude, respectively, it is +recommended that they be passed in degrees to avoid round-off problems at +the north and south poles and at the date line.

+
+
Parameters:
+
    +
  • x (ndarray) – x coordinate of the input field (length n)

  • +
  • y (ndarray) – y coordinate fo the input field (length m)

  • +
  • field (ndarray) – a field of size m x n

  • +
  • xCell (ndarray) – x coordinate of MPAS cell centers

  • +
  • yCell (ndarray) – y coordinate of MPAS cell centers

  • +
+
+
Returns:
+

mpasField (ndarray) – field interpoyed to MPAS cell centers

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.html b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.html new file mode 100644 index 000000000..ca13a7823 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.html @@ -0,0 +1,211 @@ + + + + + + + mpas_tools.mesh.mask.compute_lon_lat_region_masks — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.mask.compute_lon_lat_region_masks

+
+
+mpas_tools.mesh.mask.compute_lon_lat_region_masks(lon, lat, fcMask, logger=None, pool=None, chunkSize=1000, showProgress=False, subdivisionThreshold=30.0)[source]
+

Use shapely and processes to create a set of masks from a feature +collection made up of regions (polygons) on a tensor lon/lat grid

+
+
Parameters:
+
    +
  • lon (numpy.ndarray) – A 1D array of longitudes in degrees between -180 and 180

  • +
  • lat (numpy.ndarray) – A 1D array of latitudes in degrees between -90 and 90

  • +
  • fcMask (geometric_features.FeatureCollection) – A feature collection containing features to use to create the mask

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • pool (multiprocessing.Pool, optional) – A pool for performing multiprocessing

  • +
  • chunkSize (int, optional) – The number of cells, vertices or edges that are processed in one +operation. Experimentation has shown that 1000 is a reasonable +compromise between dividing the work into sufficient subtasks to +distribute the load and having sufficient work for each thread.

  • +
  • showProgress (bool, optional) – Whether to show a progress bar

  • +
  • subdivisionThreshold (float, optional) – A threshold in degrees (lon or lat) above which the mask region will +be subdivided into smaller polygons for faster intersection checking

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The masks

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.html b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.html new file mode 100644 index 000000000..00bc1f164 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.html @@ -0,0 +1,205 @@ + + + + + + + mpas_tools.mesh.mask.compute_mpas_flood_fill_mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.mask.compute_mpas_flood_fill_mask

+
+
+mpas_tools.mesh.mask.compute_mpas_flood_fill_mask(dsMesh, fcSeed, logger=None, workers=-1)[source]
+

Flood fill from the given set of seed points to create a contiguous mask. +The flood fill operates using cellsOnCell, starting from the cells +whose centers are closest to the seed points.

+
+
Parameters:
+
    +
  • dsMesh (xarray.Dataset) – An MPAS mesh on which the masks should be created

  • +
  • fcSeed (geometric_features.FeatureCollection) – A feature collection containing points at which to start the flood fill

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • workers (int, optional) – The number of threads used for finding nearest neighbors. The default +is all available threads (workers=-1)

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The masks

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_region_masks.html b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_region_masks.html new file mode 100644 index 000000000..eaea4072c --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_region_masks.html @@ -0,0 +1,214 @@ + + + + + + + mpas_tools.mesh.mask.compute_mpas_region_masks — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.mask.compute_mpas_region_masks

+
+
+mpas_tools.mesh.mask.compute_mpas_region_masks(dsMesh, fcMask, maskTypes=('cell', 'vertex'), logger=None, pool=None, chunkSize=1000, showProgress=False, subdivisionThreshold=30.0)[source]
+

Use shapely and processes to create a set of masks from a feature collection +made up of regions (polygons)

+
+
Parameters:
+
    +
  • dsMesh (xarray.Dataset) – An MPAS mesh on which the masks should be created

  • +
  • fcMask (geometric_features.FeatureCollection) – A feature collection containing features to use to create the mask

  • +
  • maskTypes (tuple of {'cell', 'edge', 'vertex'}, optional) – Which type(s) of masks to make. Masks are created based on whether +the latitude and longitude associated with each of these locations +(e.g. dsMesh.latCell and dsMesh.lonCell for 'cell') are +inside or outside of the regions in fcMask.

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • pool (multiprocessing.Pool, optional) – A pool for performing multiprocessing

  • +
  • chunkSize (int, optional) – The number of cells, vertices or edges that are processed in one +operation. Experimentation has shown that 1000 is a reasonable +compromise between dividing the work into sufficient subtasks to +distribute the load and having sufficient work for each thread.

  • +
  • showProgress (bool, optional) – Whether to show a progress bar

  • +
  • subdivisionThreshold (float, optional) – A threshold in degrees (lon or lat) above which the mask region will +be subdivided into smaller polygons for faster intersection checking

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The masks

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.html b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.html new file mode 100644 index 000000000..81601d360 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.html @@ -0,0 +1,218 @@ + + + + + + + mpas_tools.mesh.mask.compute_mpas_transect_masks — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.mesh.mask.compute_mpas_transect_masks

+
+
+mpas_tools.mesh.mask.compute_mpas_transect_masks(dsMesh, fcMask, earthRadius, maskTypes=('cell', 'edge', 'vertex'), logger=None, pool=None, chunkSize=1000, showProgress=False, subdivisionResolution=10000.0, addEdgeSign=False)[source]
+

Use shapely and processes to create a set of masks from a feature +collection made up of transects (line strings)

+
+
Parameters:
+
    +
  • dsMesh (xarray.Dataset) – An MPAS mesh on which the masks should be created

  • +
  • fcMask (geometric_features.FeatureCollection) – A feature collection containing features to use to create the mask

  • +
  • earthRadius (float) – The radius of the earth in meters

  • +
  • maskTypes (tuple of {'cell', 'edge', 'vertex'}, optional) – Which type(s) of masks to make. Masks are created based on whether +the latitude and longitude associated with each of these locations +(e.g. dsMesh.latCell and dsMesh.lonCell for 'cell') are +inside or outside of the transects in fcMask.

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • pool (multiprocessing.Pool, optional) – A pool for performing multiprocessing

  • +
  • chunkSize (int, optional) – The number of cells, vertices or edges that are processed in one +operation. Experimentation has shown that 1000 is a reasonable +compromise between dividing the work into sufficient subtasks to +distribute the load and having sufficient work for each thread.

  • +
  • showProgress (bool, optional) – Whether to show a progress bar

  • +
  • subdivisionResolution (float, optional) – The maximum resolution (in meters) of segments in a transect. If a +transect is too coarse, it will be subdivided. Pass None for no +subdivision.

  • +
  • addEdgeSign (bool, optional) – Whether to add the edgeSign variable, which requires significant +extra computation

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The masks

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.build_planar_mesh.html b/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.build_planar_mesh.html new file mode 100644 index 000000000..917de8c81 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.build_planar_mesh.html @@ -0,0 +1,233 @@ + + + + + + + mpas_tools.ocean.build_mesh.build_planar_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.build_mesh.build_planar_mesh

+
+
+mpas_tools.ocean.build_mesh.build_planar_mesh(cellWidth, x, y, geom_points, geom_edges, out_filename='base_mesh.nc', vtk_dir='base_mesh_vtk', preserve_floodplain=False, floodplain_elevation=20.0, do_inject_bathymetry=False, logger=None, use_progress_bar=True)[source]
+

Build a planar MPAS mesh

+
+
Parameters:
+
    +
  • cellWidth (ndarray) – m x n array of cell width in km

  • +
  • x (ndarray) – arrays defining planar coordinates in meters

  • +
  • y (ndarray) – arrays defining planar coordinates in meters

  • +
  • geom_points (ndarray) – list of point coordinates for bounding polygon for the planar mesh

  • +
  • geom_edges (ndarray) – list of edges between points in geom_points that define the +bounding polygon

  • +
  • out_filename (str, optional) – The file name of the resulting MPAS mesh

  • +
  • vtk_dir (str, optional) – The name of the directory where mesh data will be extracted for viewing +in ParaVeiw.

  • +
  • preserve_floodplain (bool, optional) – Whether a flood plain (bathymetry above z = 0) should be preserved in +the mesh

  • +
  • floodplain_elevation (float, optional) – The elevation in meters to which the flood plain is preserved

  • +
  • do_inject_bathymetry (bool, optional) – Whether one of the default bathymetry datasets, earth_relief_15s.nc +or topo.msh, should be added to the MPAS mesh

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • use_progress_bar (bool, optional) – Whether to display progress bars (problematic in logging to a file)

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.html b/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.html new file mode 100644 index 000000000..87da80f05 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.html @@ -0,0 +1,236 @@ + + + + + + + mpas_tools.ocean.build_mesh.build_spherical_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.build_mesh.build_spherical_mesh

+
+
+mpas_tools.ocean.build_mesh.build_spherical_mesh(cellWidth, lon, lat, out_filename='base_mesh.nc', plot_cellWidth=True, vtk_dir='base_mesh_vtk', preserve_floodplain=False, floodplain_elevation=20.0, do_inject_bathymetry=False, logger=None, use_progress_bar=True)[source]
+

Build an MPAS mesh using JIGSAW with the given cell sizes as a function of +latitude and longitude

+

The result is a mesh file stored in out_filename as well as several +intermediate files: mesh.log, mesh-HFUN.msh, mesh.jig, +mesh-MESH.msh, mesh.msh, and mesh_triangles.nc.

+
+
Parameters:
+
    +
  • cellWidth (ndarray) – m x n array of cell width in km

  • +
  • lon (ndarray) – longitude in degrees (length n and between -180 and 180)

  • +
  • lat (ndarray) – longitude in degrees (length m and between -90 and 90)

  • +
  • out_filename (str, optional) – The file name of the resulting MPAS mesh

  • +
  • plot_cellWidth (bool, optional) – Whether to produce a plot of cellWidth. If so, it will be written +to cellWidthGlobal.png.

  • +
  • vtk_dir (str, optional) – The name of the directory where mesh data will be extracted for viewing +in ParaVeiw.

  • +
  • preserve_floodplain (bool, optional) – Whether a flood plain (bathymetry above z = 0) should be preserved in +the mesh

  • +
  • floodplain_elevation (float, optional) – The elevation in meters to which the flood plain is preserved

  • +
  • do_inject_bathymetry (bool, optional) – Whether one of the default bathymetry datasets, earth_relief_15s.nc +or topo.msh, should be added to the MPAS mesh

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • use_progress_bar (bool, optional) – Whether to display progress bars (problematic in logging to a file)

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.html b/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.html new file mode 100644 index 000000000..8100c7ddc --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.build_mesh.html @@ -0,0 +1,213 @@ + + + + + + + mpas_tools.ocean.build_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.build_mesh

+

Functions

+ + + + + + + + + +

build_planar_mesh(cellWidth, x, y, ...[, ...])

Build a planar MPAS mesh

build_spherical_mesh(cellWidth, lon, lat[, ...])

Build an MPAS mesh using JIGSAW with the given cell sizes as a function of latitude and longitude

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.CPP_projection.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.CPP_projection.html new file mode 100644 index 000000000..c7355aef9 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.CPP_projection.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.CPP_projection — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.CPP_projection

+
+
+mpas_tools.ocean.coastal_tools.CPP_projection(lon, lat, origin)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.html new file mode 100644 index 000000000..2328ceb1d --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.html @@ -0,0 +1,233 @@ + + + + + + + mpas_tools.ocean.coastal_tools.coastal_refined_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.coastal_refined_mesh

+
+
+mpas_tools.ocean.coastal_tools.coastal_refined_mesh(params, cell_width=None, lon_grd=None, lat_grd=None)[source]
+

Optionally create a background field of cell widths, then add a region of +refined resolution to the cell widths.

+
+
Parameters:
+
    +
  • params (dict) – A dictionary of parameters determining how the mesh is constructed. +See mpas_tools.ocean.coastal_tools.default_params.

  • +
  • cell_width (ndarray, optional) – A 2D array of cell widths in meters. If none is provided, one a base +cell_width field constructed using parameter values from params +to call create_background_mesh.

  • +
  • lon_grd (ndarray, optional) – A 1D array of longitudes in degrees in the range from -180 to 180

  • +
  • lat_grd (ndarray, optional) – A 1D array of latitudes in degrees in the range from -90 to 90

  • +
+
+
Returns:
+

    +
  • cell_width (ndarray) – A 2D array of cell widths in meters.

  • +
  • lon_grd (ndarray) – A 1D array of longitudes in degrees in the range from -180 to 180

  • +
  • lat_grd (ndarray) – A 1D array of latitudes in degrees in the range from -90 to 90

  • +
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.compute_cell_width.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.compute_cell_width.html new file mode 100644 index 000000000..be1462149 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.compute_cell_width.html @@ -0,0 +1,245 @@ + + + + + + + mpas_tools.ocean.coastal_tools.compute_cell_width — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.compute_cell_width

+
+
+mpas_tools.ocean.coastal_tools.compute_cell_width(D, cell_width, lon, lat, dx_min, trans_start, trans_width, restrict_box, plot_option=False, plot_box=[], coastlines=[], call=None)[source]
+

Blend cell widths from the input field with the new resolution in the +refined region determined by the distance to the coastline contour.

+
+
Parameters:
+
    +
  • D (ndarray) – A len(lat) x len(lon) array of distances in meters on the lon/lat grid +to the closest point in the (smoothed) coastline contour returned from +distance_to_coast()

  • +
  • cell_width (ndarray) – A len(lat) x len(lon) array of cell widths in meters

  • +
  • lon (ndarray) – A 1D array of longitudes in degrees in the range from -180 to 180

  • +
  • lat (ndarray) – A 1D array of latitudes in degrees in the range from -90 to 90

  • +
  • dx_min (float) – The resolution in meters of the new refined region.

  • +
  • trans_start (float) – The approximate value of D in meters at which the transition in +resolution should start

  • +
  • trans_width (float) – The approximate width in meters over which the transition in resolution +should take place

  • +
  • restrict_box (dict of lists of ndarrays) – A region of made up of quadrilaterals to include and exclude +that defines where resolution may be altered. Outside of the +restrict_box, the resolution remains unchanged.

  • +
  • plot_option (bool, optional) – Whether to plot the resulting coastline points and the plot to files +named cell_width###.png and trans_func###.png`, where ### +is given by call and is meant to indicate how many times this +function has been called during mesh creation.

  • +
  • plot_box (list of float, optional) – The extent of the plot if plot_option=True

  • +
  • coastlines (ndarray) – An n x 2 array of (longitude, latitude) points along the coastline +contours returned from extract_coastlines() used in plotting if +plot_option=True

  • +
  • call (int, optional) – The number of times the function has been called, used to give the +plot a unique name.

  • +
+
+
Returns:
+

cell_width (ndarray) – A len(lat) x len(lon) array of the new cell widths in meters

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.create_background_mesh.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.create_background_mesh.html new file mode 100644 index 000000000..0acb38727 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.create_background_mesh.html @@ -0,0 +1,244 @@ + + + + + + + mpas_tools.ocean.coastal_tools.create_background_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.create_background_mesh

+
+
+mpas_tools.ocean.coastal_tools.create_background_mesh(grd_box, ddeg, mesh_type, dx_min, dx_max, plot_option=False, plot_box=[], call=None)[source]
+

Create a background field of cell widths

+
+
Parameters:
+
    +
  • grd_box (list of float) – A list of 4 floats defining the bounds (min lon, max lon, min lat, max +lat) of the grid

  • +
  • ddeg (float) – The resolution of the mesh in degrees

  • +
  • mesh_type ({'QU', 'EC', 'RRS'}) – The type of mesh: quasi-uniform (QU), Eddy-closure (EC) or Rossby-radius +scaling (RRS)

  • +
  • dx_min (float) – The resolution in meters of a QU mesh or the minimum resolution of of +an RRS mesh. This parameter is ignored for EC meshes and the default +function arguments to EC_CellWidthVsLat() are used instead.

  • +
  • dx_max (float) – The maximum resolution in meters of of an RRS mesh. This parameter is +ignored for QU meshes and EC meshes. For EC meshes, the default +function arguments are used instead.

  • +
  • plot_option (bool, optional) – Whether to plot the resulting cell width and save it to files +named bckgrnd_grid_cell_width_vs_lat###.png and +bckgnd_grid_cell_width###.png, where ### is given by +call and is meant to indicate how many times this function has been +called during mesh creation.

  • +
  • plot_box (list of float, optional) – The extent of the plot if plot_option=True

  • +
  • call (int, optional) – The number of times the function has been called, used to give the +plot a unique name.

  • +
+
+
Returns:
+

    +
  • cell_width (ndarray) – A 2D array of cell widths in meters.

  • +
  • lon_grd (ndarray) – A 1D array of longitudes in degrees in the range from -180 to 180

  • +
  • lat_grd (ndarray) – A 1D array of latitudes in degrees in the range from -90 to 90

  • +
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.distance_to_coast.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.distance_to_coast.html new file mode 100644 index 000000000..5c0888db9 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.distance_to_coast.html @@ -0,0 +1,237 @@ + + + + + + + mpas_tools.ocean.coastal_tools.distance_to_coast — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.distance_to_coast

+
+
+mpas_tools.ocean.coastal_tools.distance_to_coast(coastlines, lon_grd, lat_grd, nn_search='kdtree', smooth_window=0, plot_option=False, plot_box=[], call=None, workers=-1)[source]
+

Extracts a set of coastline contours

+
+
Parameters:
+
    +
  • coastlines (ndarray) – An n x 2 array of (longitude, latitude) points along the coastline +contours returned from extract_coastlines()

  • +
  • lon_grd (ndarray) – A 1D array of longitudes in degrees in the range from -180 to 180

  • +
  • lat_grd (ndarray) – A 1D array of latitudes in degrees in the range from -90 to 90

  • +
  • nn_search ({'kdtree'}, optional) – The algorithm to use for the nearest neightbor search.

  • +
  • smooth_window (int, optional) – The number of adjacent coastline points to average together to smooth +the coastal contours. Use 0 to indicate no smoothing.

  • +
  • plot_option (bool, optional) – Whether to plot the resulting coastline points and the plot to a file +named bathy_coastlines###.png, where ### is given by +call and is meant to indicate how many times this function has been +called during mesh creation.

  • +
  • plot_box (list of float, optional) – The extent of the plot if plot_option=True

  • +
  • call (int, optional) – The number of times the function has been called, used to give the +plot a unique name.

  • +
  • workers (int, optional) – The number of threads used for finding nearest neighbors. The default +is all available threads (workers=-1)

  • +
+
+
Returns:
+

D (ndarray) – A len(lat_grd) x len(lon_grd) array of distances in meters on the +lon/lat grid to the closest point in the (smoothed) coastline contour.

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.extract_coastlines.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.extract_coastlines.html new file mode 100644 index 000000000..18771dcdd --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.extract_coastlines.html @@ -0,0 +1,238 @@ + + + + + + + mpas_tools.ocean.coastal_tools.extract_coastlines — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.extract_coastlines

+
+
+mpas_tools.ocean.coastal_tools.extract_coastlines(nc_file, nc_vars, region_box, z_contour=0, n_longest=10, point_list=None, plot_option=False, plot_box=None, call=None)[source]
+

Extracts a set of coastline contours

+
+
Parameters:
+
    +
  • nc_file (str) – A bathymetry dataset on a lon/lat grid in NetCDF format

  • +
  • nc_vars (list of str) – The names of the longitude (nc_vars[0]), latitude (nc_vars[1]) and +bathymetry (nc_vars[2]) variables.

  • +
  • region_box (dict of list of ndarrays) – A region made up of a list of quadrilaterals to include and another +list to exclude. The quadrilaterals are either bounding rectangles +(min lon, max lon, min lat, max lat) or lists of 4 (lon, lat) points.

  • +
  • z_contour (float, optional) – The isocontour of the bathymetry dataset to extract

  • +
  • n_longest (int, optional) – The maximum number of contours to keep, after sorting from the longest +to the shortest

  • +
  • point_list (ndarray, optional) – A list of points to add to the coastline

  • +
  • plot_option (bool, optional) – Whether to plot the resulting coastline points and the plot to a file +named bathy_coastlines###.png, where ### is given by +call and is meant to indicate how many times this function has been +called during mesh creation.

  • +
  • plot_box (list of float, optional) – The extent of the plot if plot_option=True

  • +
  • call (int, optional) – The number of times the function has been called, used to give the +plot a unique name.

  • +
+
+
Returns:
+

coastlines (ndarray) – An n x 2 array of (longitude, latitude) points along the coastline +contours

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.html new file mode 100644 index 000000000..f7280f165 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates

+
+
+mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates(box)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.html new file mode 100644 index 000000000..82352f11b --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.get_data_inside_box — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.get_data_inside_box

+
+
+mpas_tools.ocean.coastal_tools.get_data_inside_box(lon, lat, data, box, idx=False)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.html new file mode 100644 index 000000000..5bb042228 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.get_indices_inside_quad — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.get_indices_inside_quad

+
+
+mpas_tools.ocean.coastal_tools.get_indices_inside_quad(lon, lat, box, grid=True)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.html new file mode 100644 index 000000000..dcd03646d --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.html @@ -0,0 +1,252 @@ + + + + + + + mpas_tools.ocean.coastal_tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools

+

name: coastal_tools +authors: Steven Brus

+

last modified: 07/09/2018

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

CPP_projection(lon, lat, origin)

coastal_refined_mesh(params[, cell_width, ...])

Optionally create a background field of cell widths, then add a region of refined resolution to the cell widths.

compute_cell_width(D, cell_width, lon, lat, ...)

Blend cell widths from the input field with the new resolution in the refined region determined by the distance to the coastline contour.

create_background_mesh(grd_box, ddeg, ...[, ...])

Create a background field of cell widths

distance_to_coast(coastlines, lon_grd, lat_grd)

Extracts a set of coastline contours

extract_coastlines(nc_file, nc_vars, region_box)

Extracts a set of coastline contours

flag_wrap(box)

get_convex_hull_coordinates(box)

get_data_inside_box(lon, lat, data, box[, idx])

get_indices_inside_quad(lon, lat, box[, grid])

plot_coarse_coast(ax, plot_box)

plot_region_box(box, color)

save_matfile(cell_width, lon, lat)

smooth_coastline(x, y, window)

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.html new file mode 100644 index 000000000..49a3f955c --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.plot_coarse_coast — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.plot_coarse_coast

+
+
+mpas_tools.ocean.coastal_tools.plot_coarse_coast(ax, plot_box)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.plot_region_box.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.plot_region_box.html new file mode 100644 index 000000000..6d55b8aa5 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.plot_region_box.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.plot_region_box — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.plot_region_box

+
+
+mpas_tools.ocean.coastal_tools.plot_region_box(box, color)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.save_matfile.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.save_matfile.html new file mode 100644 index 000000000..152f07f01 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.save_matfile.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.save_matfile — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.save_matfile

+
+
+mpas_tools.ocean.coastal_tools.save_matfile(cell_width, lon, lat)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.smooth_coastline.html b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.smooth_coastline.html new file mode 100644 index 000000000..3f68fb45f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastal_tools.smooth_coastline.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.coastal_tools.smooth_coastline — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastal_tools.smooth_coastline

+
+
+mpas_tools.ocean.coastal_tools.smooth_coastline(x, y, window)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.html b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.html new file mode 100644 index 000000000..22612e9ef --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.html @@ -0,0 +1,223 @@ + + + + + + + mpas_tools.ocean.coastline_alteration.add_critical_land_blockages — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastline_alteration.add_critical_land_blockages

+
+
+mpas_tools.ocean.coastline_alteration.add_critical_land_blockages(dsMask, dsBlockages)[source]
+

Add the masks associated with one or more transects to the land mask

+
+
Parameters:
+
    +
  • dsMask (xarray.Dataset) – The mask to which critical blockages should be added

  • +
  • dsBlockages (xarray.Dataset) – The transect masks defining critical land regions that should block +ocean flow (e.g. the Antarctic Peninsula)

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The mask with critical blockages included

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.html b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.html new file mode 100644 index 000000000..0a84dc8aa --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.html @@ -0,0 +1,226 @@ + + + + + + + mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask

+
+
+mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask(dsMask, dsMesh, latitude_threshold=43.0, nSweeps=10)[source]
+

Find ocean cells that are land-locked, and alter the cell mask so that they +are counted as land cells.

+
+
Parameters:
+
    +
  • dsMask (xarray.Dataset) – A land-mask data set

  • +
  • dsMesh (xarray.Dataset) – MPAS Mesh data set

  • +
  • latitude_threshold (float, optional) – Minimum latitude, in degrees, for transect widening

  • +
  • nSweeps (int, optional) – Maximum number of sweeps to search for land-locked cells

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – A copy of the land-mask data set with land-locked cells added to the +mask for the first region

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.html b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.html new file mode 100644 index 000000000..0e43b4d1c --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.html @@ -0,0 +1,216 @@ + + + + + + + mpas_tools.ocean.coastline_alteration — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastline_alteration

+

Functions

+ + + + + + + + + + + + +

add_critical_land_blockages(dsMask, dsBlockages)

Add the masks associated with one or more transects to the land mask

add_land_locked_cells_to_mask(dsMask, dsMesh)

Find ocean cells that are land-locked, and alter the cell mask so that they are counted as land cells.

widen_transect_edge_masks(dsMask, dsMesh[, ...])

Alter critical passages at polar latitudes to be at least two cells wide, to avoid sea ice blockage

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.html b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.html new file mode 100644 index 000000000..e49d87382 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.html @@ -0,0 +1,225 @@ + + + + + + + mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks

+
+
+mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks(dsMask, dsMesh, latitude_threshold=43.0)[source]
+

Alter critical passages at polar latitudes to be at least two cells wide, to +avoid sea ice blockage

+
+
Parameters:
+
    +
  • dsMask (xarray.Dataset) – The mask to which critical blockages should be added

  • +
  • dsMesh (xarray.Dataset) – The transect masks defining critical land regions that should block +ocean flow (e.g. the Antarctic Peninsula)

  • +
  • latitude_threshold (float) – Minimum latitude, degrees, for transect widening

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – The mask with critical blockages included

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.depth.add_depth.html b/0.22.0rc4/generated/mpas_tools.ocean.depth.add_depth.html new file mode 100644 index 000000000..ce5f5bd00 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.depth.add_depth.html @@ -0,0 +1,221 @@ + + + + + + + mpas_tools.ocean.depth.add_depth — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.depth.add_depth

+
+
+mpas_tools.ocean.depth.add_depth(inFileName, outFileName, coordFileName=None)[source]
+

Add a 1D depth coordinate to an MPAS-Ocean file.

+
+
Parameters:
+
    +
  • inFileName (str) – An input MPAS-Ocean file that depth should be added to, used for coords +if another file is not provided via coordFileName.

  • +
  • outFileName (str) – An output MPAS-Ocean file with depth added

  • +
  • coordFileName (str, optional) – An MPAS-Ocean file with refBottomDepth

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.depth.add_zmid.html b/0.22.0rc4/generated/mpas_tools.ocean.depth.add_zmid.html new file mode 100644 index 000000000..9c117a7da --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.depth.add_zmid.html @@ -0,0 +1,222 @@ + + + + + + + mpas_tools.ocean.depth.add_zmid — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.depth.add_zmid

+
+
+mpas_tools.ocean.depth.add_zmid(inFileName, outFileName, coordFileName=None)[source]
+

Add a 3D, time-independent depth coordinate to an MPAS-Ocean file.

+
+
Parameters:
+
    +
  • inFileName (str) – An input MPAS-Ocean file that zMid should be added to, used for +coords if another file is not provided via coordFileName.

  • +
  • outFileName (str) – An output MPAS-Ocean file with zMid added

  • +
  • coordFileName (str, optional) – An MPAS-Ocean file with bottomDepth, maxLevelCell and +layerThickness but not zMid

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.depth.compute_depth.html b/0.22.0rc4/generated/mpas_tools.ocean.depth.compute_depth.html new file mode 100644 index 000000000..8cb2c2b49 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.depth.compute_depth.html @@ -0,0 +1,224 @@ + + + + + + + mpas_tools.ocean.depth.compute_depth — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.depth.compute_depth

+
+
+mpas_tools.ocean.depth.compute_depth(refBottomDepth)[source]
+

Computes depth and depth bounds given refBottomDepth

+
+
Parameters:
+

refBottomDepth (xarray.DataArray) – the depth of the bottom of each vertical layer in the initial state +(perfect z-level coordinate)

+
+
Returns:
+

    +
  • depth (numpy.ndarray) – the vertical coordinate defining the middle of each layer

  • +
  • depth_bnds (numpy.ndarray) – the vertical coordinate defining the top and bottom of each layer

  • +
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.depth.compute_zmid.html b/0.22.0rc4/generated/mpas_tools.ocean.depth.compute_zmid.html new file mode 100644 index 000000000..2e69896c4 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.depth.compute_zmid.html @@ -0,0 +1,226 @@ + + + + + + + mpas_tools.ocean.depth.compute_zmid — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.depth.compute_zmid

+
+
+mpas_tools.ocean.depth.compute_zmid(bottomDepth, maxLevelCell, layerThickness, depth_dim='nVertLevels')[source]
+

Computes zMid given data arrays for bottomDepth, maxLevelCell and +layerThickness

+
+
Parameters:
+
    +
  • bottomDepth (xarray.DataArray) – the depth of the ocean bottom (positive)

  • +
  • maxLevelCell (xarray.DataArray) – the 1-based vertical index of the bottom of the ocean

  • +
  • layerThickness (xarray.DataArray) – the thickness of MPAS-Ocean layers (possibly as a function of time)

  • +
  • depth_dim (str, optional) – the name of the vertical dimension

  • +
+
+
Returns:
+

zMid (xarray.DataArray) – the vertical coordinate defining the middle of each layer, masked below +the bathymetry

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.depth.write_time_varying_zmid.html b/0.22.0rc4/generated/mpas_tools.ocean.depth.write_time_varying_zmid.html new file mode 100644 index 000000000..a58b18486 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.depth.write_time_varying_zmid.html @@ -0,0 +1,224 @@ + + + + + + + mpas_tools.ocean.depth.write_time_varying_zmid — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.depth.write_time_varying_zmid

+
+
+mpas_tools.ocean.depth.write_time_varying_zmid(inFileName, outFileName, coordFileName=None, prefix='')[source]
+

Add a 3D, time-independent depth coordinate to an MPAS-Ocean file.

+
+
Parameters:
+
    +
  • inFileName (str) – An input MPAS-Ocean file with some form of layerThickness, and also +bottomDepth and maxLevelCell if no coordFileName +is provided.

  • +
  • outFileName (str) – An output MPAS-Ocean file with zMid for each time in the input file

  • +
  • coordFileName (str, optional) – An MPAS-Ocean file with bottomDepth and maxLevelCell

  • +
  • prefix (str, optional) – A prefix on layerThickness (in) and zMid (out), such as +timeMonthly_avg_

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.html b/0.22.0rc4/generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.html new file mode 100644 index 000000000..adcf636a8 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.inject_bathymetry.inject_bathymetry — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.inject_bathymetry.inject_bathymetry

+
+
+mpas_tools.ocean.inject_bathymetry.inject_bathymetry(mesh_file)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.html b/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.html new file mode 100644 index 000000000..0db028694 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.html @@ -0,0 +1,224 @@ + + + + + + + mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file

+
+
+mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file(cw_filename, mesh_filename, on_sphere=True)[source]
+

Add a meshDensity field into an MPAS mesh. The mesh density is defined +as:

+
+

meshDensity = (minCellWidth / cellWidth)**4

+
+
+
Parameters:
+
    +
  • cw_filename (str) – The file name to read cellWidth and coordinates from

  • +
  • mesh_filename (str) – The mesh file to add meshDensity to

  • +
  • on_sphere (bool, optional) – Whether the mesh is spherical (as opposed to planar)

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.html b/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.html new file mode 100644 index 000000000..68e21d66e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.html @@ -0,0 +1,225 @@ + + + + + + + mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity

+
+
+mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity(cellWidth, x, y, mesh_filename)[source]
+

Add a meshDensity field into a planar MPAS mesh. The mesh density is +defined as:

+
+

meshDensity = (minCellWidth / cellWidth)**4

+
+
+
Parameters:
+
    +
  • cellWidth (ndarray) – m x n array of cell width in km

  • +
  • x (ndarray) – Planar coordinates in meters

  • +
  • y (ndarray) – Planar coordinates in meters

  • +
  • mesh_filename (str) – The mesh file to add meshDensity to

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.html b/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.html new file mode 100644 index 000000000..e753e31cd --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.html @@ -0,0 +1,225 @@ + + + + + + + mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity

+
+
+mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity(cellWidth, lon, lat, mesh_filename)[source]
+

Add a meshDensity field into a spherical MPAS mesh. The mesh density is +defined as:

+
+

meshDensity = (minCellWidth / cellWidth)**4

+
+
+
Parameters:
+
    +
  • cellWidth (ndarray) – m x n array of cell width in km

  • +
  • lon (ndarray) – longitude in degrees (length n and between -180 and 180)

  • +
  • lat (ndarray) – longitude in degrees (length m and between -90 and 90)

  • +
  • mesh_filename (str) – The mesh file to add meshDensity to

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.html b/0.22.0rc4/generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.html new file mode 100644 index 000000000..d93080696 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.html @@ -0,0 +1,210 @@ + + + + + + + mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain

+
+
+mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain(mesh_file, floodplain_elevation)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.html b/0.22.0rc4/generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.html new file mode 100644 index 000000000..b460fbf00 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.html @@ -0,0 +1,223 @@ + + + + + + + mpas_tools.ocean.moc.add_moc_southern_boundary_transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.moc.add_moc_southern_boundary_transects

+
+
+mpas_tools.ocean.moc.add_moc_southern_boundary_transects(dsMask, dsMesh, logger=None)[source]
+
+
Parameters:
+
    +
  • dsMask (xarray.Dataset) – Region masks defining MOC basins

  • +
  • dsMesh (xarray.Dataset, optional) – An MPAS mesh on which the masks should be created

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
+
+
Returns:
+

dsMask (xarray.Dataset) – Region masks defining MOC basins and the corresponding southern-boundary +transects

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.moc.html b/0.22.0rc4/generated/mpas_tools.ocean.moc.html new file mode 100644 index 000000000..01d28ad23 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.moc.html @@ -0,0 +1,218 @@ + + + + + + + mpas_tools.ocean.moc — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.moc

+

Functions

+ + + + + + + + + +

add_moc_southern_boundary_transects(dsMask, ...)

+
param dsMask:
+

Region masks defining MOC basins

+
+
+

make_moc_basins_and_transects(gf, ...[, ...])

Builds features defining the ocean basins and southern transects used in computing the meridional overturning circulation (MOC)

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.html b/0.22.0rc4/generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.html new file mode 100644 index 000000000..e4a40fa6d --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.html @@ -0,0 +1,229 @@ + + + + + + + mpas_tools.ocean.moc.make_moc_basins_and_transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.moc.make_moc_basins_and_transects

+
+
+mpas_tools.ocean.moc.make_moc_basins_and_transects(gf, mesh_filename, mask_and_transect_filename, geojson_filename=None, mask_filename=None, logger=None, dir=None)[source]
+

Builds features defining the ocean basins and southern transects used in +computing the meridional overturning circulation (MOC)

+
+
Parameters:
+
    +
  • gf (geometric_features.GeometricFeatures) – An object that knows how to download and read geometric features

  • +
  • mesh_filename (str) – A file with MPAS mesh information

  • +
  • mask_and_transect_filename (str) – A file to write the MOC region masks and southern-boundary transects to

  • +
  • geojson_filename (str, optional) – A file to write MOC regions to

  • +
  • mask_filename (str, optional) – A file to write MOC region masks to

  • +
  • logger (logging.Logger, optional) – A logger for the output if not stdout

  • +
  • dir (str, optional) – A directory in which a temporary directory will be added with files +produced during conversion and then deleted upon completion.

  • +
+
+
Returns:
+

fc (geometric_features.FeatureCollection) – The new feature collection

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.html b/0.22.0rc4/generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.html new file mode 100644 index 000000000..c431fcbb0 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.html @@ -0,0 +1,283 @@ + + + + + + + mpas_tools.ocean.transects.find_transect_levels_and_weights — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.transects.find_transect_levels_and_weights

+
+
+mpas_tools.ocean.transects.find_transect_levels_and_weights(dsTransect, layerThickness, bottomDepth, maxLevelCell, zTransect=None)[source]
+

Construct a vertical coordinate for a transect produced by +:py:fun:`mpas_tools.viz.transects.find_transect_cells_and_weights()`, then +break each resulting quadrilateral into 2 triangles that can later be +visualized with functions like tripcolor and tricontourf. Also, +compute interpolation weights such that observations at points on the +original transect and with vertical coordinate transectZ can be +bilinearly interpolated to the nodes of the transect.

+
+
Parameters:
+
+
+
Returns:
+

dsTransectTriangles (xarray.Dataset) – A dataset that contains nodes and triangles that make up a 2D transect. +For convenience in visualization, the quadrilaterals of each cell making +up the transect have been divided into an upper and lower triangle. The +nodes of the triangles are completely independent of one another, +allowing for potential jumps in fields values between nodes of different +triangles that are at the same location. This is convenient, for +example, when visualizing data with constant values within each MPAS +cell.

+

There are nTransectTriangles = 2*nTransectCells triangles, each with +nTriangleNodes = 3 nodes, where nTransectCells is the number of +valid transect cells (quadrilaterals) that are above the MPAS-Ocean +bathymetry.

+

In addition to the variables and coordinates in dsTransect, the +output dataset contains:

+
+
    +
  • nodeHorizBoundsIndices: which of the nHorizBounds = 2 +bounds of a horizontal transect segment a given node is on

  • +
  • segmentIndices: the transect segment of a given triangle

  • +
  • cellIndices: the MPAS-Ocean cell of a given triangle

  • +
  • levelIndices: the MPAS-Ocean vertical level of a given triangle

  • +
  • zTransectNode: the vertical height of each triangle node

  • +
  • ssh, zSeaFloor: the sea-surface height and sea-floor height at +each node of each transect segment

  • +
  • interpCellIndices, interpLevelIndices: the MPAS-Ocean cells and +levels from which the value at a given triangle node are +interpolated. This can involve up to nWeights = 12 different +cells and levels.

  • +
  • interpCellWeights: the weight to multiply each field value by +to perform interpolation to a triangle node.

  • +
  • transectInterpVertIndices, transectInterpVertWeights - if +zTransect is not None, vertical indices and weights for +interpolating from the original transect grid to MPAS-Ocean +transect nodes.

  • +
+
+

Interpolation of a DataArray from MPAS cells and levels to transect +triangle nodes can be performed with +interp_mpas_to_transect_triangle_nodes(). Similarly, interpolation of a +DataArray (e.g. an observation) from the original transect grid to +transect triangle nodes can be performed with +interp_transect_grid_to_transect_triangle_nodes()

+

To visualize constant values on MPAS cells, a field can be sampled +at indices nCells=cellIndices and nVertLevels=levelIndices. +If a smoother visualization is desired, bilinear interpolation can be +performed by first sampling the field at indices +nCells=interpCellIndices and nVertLevels=interpLevelIndices and +then multiplying by interpCellWeights and summing over +nWeights.

+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.transects.get_outline_segments.html b/0.22.0rc4/generated/mpas_tools.ocean.transects.get_outline_segments.html new file mode 100644 index 000000000..ac5829a0e --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.transects.get_outline_segments.html @@ -0,0 +1,211 @@ + + + + + + + mpas_tools.ocean.transects.get_outline_segments — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.transects.get_outline_segments

+
+
+mpas_tools.ocean.transects.get_outline_segments(dsTransectTriangles, epsilon=0.001)[source]
+

Get a set of line segments that outline the given transect

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.html b/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.html new file mode 100644 index 000000000..f2f71a3bb --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.html @@ -0,0 +1,228 @@ + + + + + + + mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes

+
+
+mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes(dsTransectTriangles, da)[source]
+

Interpolate a 3D (nCells by nVertLevels) MPAS-Ocean DataArray +to transect nodes, linearly interpolating fields between the closest +neighboring cells

+
+
Parameters:
+
    +
  • dsTransectTriangles (xarray.Dataset) – A dataset that defines triangles making up an MPAS-Ocean transect, the +results of calling find_transect_levels_and_weights()

  • +
  • da (xarray.DataArray) – An MPAS-Ocean 3D field with dimensions nCells` and nVertLevels +(possibly among others)

  • +
+
+
Returns:
+

daNodes (xarray.DataArray) – The data array interpolated to transect nodes with dimensions +nTransectTriangles and nTriangleNodes (in addition to whatever +dimensions were in da besides nCells and nVertLevels)

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.html b/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.html new file mode 100644 index 000000000..be90c0ea8 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.html @@ -0,0 +1,227 @@ + + + + + + + mpas_tools.ocean.transects.interp_mpas_to_transect_triangles — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.transects.interp_mpas_to_transect_triangles

+
+
+mpas_tools.ocean.transects.interp_mpas_to_transect_triangles(dsTransectTriangles, da)[source]
+

Interpolate a 3D (nCells by nVertLevels) MPAS-Ocean DataArray +to transect nodes with constant values in each MPAS cell

+
+
Parameters:
+
    +
  • dsTransectTriangles (xarray.Dataset) – A dataset that defines triangles making up an MPAS-Ocean transect, the +results of calling find_transect_levels_and_weights()

  • +
  • da (xarray.DataArray) – An MPAS-Ocean 3D field with dimensions nCells` and nVertLevels +(possibly among others)

  • +
+
+
Returns:
+

daNodes (xarray.DataArray) – The data array interpolated to transect nodes with dimensions +nTransectTriangles and nTriangleNodes (in addition to whatever +dimensions were in da besides nCells and nVertLevels)

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.html b/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.html new file mode 100644 index 000000000..62939ead0 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.html @@ -0,0 +1,225 @@ + + + + + + + mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes

+
+
+mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes(dsTransectTriangles, da)[source]
+

Interpolate a DataArray on the original transect grid to triangle nodes on +the MPAS-Ocean transect.

+
+
Parameters:
+
    +
  • dsTransectTriangles (xarray.Dataset) – A dataset that defines triangles making up an MPAS-Ocean transect, the +results of calling find_transect_levels_and_weights()

  • +
  • da (xarray.DataArray) – An field on the original triangle mesh

  • +
+
+
Returns:
+

daNodes (xarray.DataArray) – The data array interpolated to transect nodes with dimensions +nTransectTriangles and nTriangleNodes

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.viz.add_inset.html b/0.22.0rc4/generated/mpas_tools.ocean.viz.add_inset.html new file mode 100644 index 000000000..99eb815aa --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.viz.add_inset.html @@ -0,0 +1,238 @@ + + + + + + + mpas_tools.ocean.viz.add_inset — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.viz.add_inset

+
+
+mpas_tools.ocean.viz.add_inset(fig, fc, latlonbuffer=45.0, polarbuffer=5.0, width=1.0, height=1.0, lowerleft=None, xbuffer=None, ybuffer=None, maxlength=1.0)[source]
+

Plots an inset map showing the location of a transect or polygon. Shapes +are plotted on a polar grid if they are entirely poleward of +/-50 deg. +latitude and with a lat/lon grid if not.

+
+
Parameters:
+
    +
  • fig (matplotlib.figure.Figure) – A matplotlib figure to add the inset to

  • +
  • fc (geometric_features.FeatureCollection) – A collection of regions, transects and/or points to plot in the inset

  • +
  • latlonbuffer (float, optional) – The number of degrees lat/lon to use as a buffer around the shape(s) +to plot if a lat/lon plot is used.

  • +
  • polarbuffer (float, optional) – The number of degrees latitude to use as a buffer equatorward of the +shape(s) in polar plots

  • +
  • width (float, optional) – width and height in inches of the inset

  • +
  • height (float, optional) – width and height in inches of the inset

  • +
  • lowerleft (pair of floats, optional) – the location of the lower left corner of the axis in inches, default +puts the inset in the upper right corner of fig.

  • +
  • xbuffer (float, optional) – right and top buffers from the top-right corner (in inches) if +lowerleft is None.

  • +
  • ybuffer (float, optional) – right and top buffers from the top-right corner (in inches) if +lowerleft is None.

  • +
  • maxlength (float or None, optional) – Any segments longer than maxlength will be subdivided in the plot to +ensure curvature. If None, no subdivision is performed.

  • +
+
+
Returns:
+

inset (matplotlib.axes.Axes) – The new inset axis

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.ocean.viz.plot_ocean_transects.html b/0.22.0rc4/generated/mpas_tools.ocean.viz.plot_ocean_transects.html new file mode 100644 index 000000000..8e321463f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.ocean.viz.plot_ocean_transects.html @@ -0,0 +1,225 @@ + + + + + + + mpas_tools.ocean.viz.plot_ocean_transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.ocean.viz.plot_ocean_transects

+
+
+mpas_tools.ocean.viz.plot_ocean_transects(fc, ds, ds_mesh=None, variable_list=None, cmap=None, flip=False)[source]
+

Plot images of the given variables on the given transects. One image +named <transect_name>_<variable_name>.png will be produced in the +current directory for each transect and variable

+
+
Parameters:
+
    +
  • fc (geometric_features.FeatureCollection) – The transects to plot

  • +
  • ds (xarray.Dataset) – The MPAS-Ocean dataset to plot

  • +
  • ds_mesh (xarray.Dataset, optional) – The MPAS-Ocean mesh to use for plotting, the same as ds by default

  • +
  • variable_list (list of str, optional) – The variables to plot

  • +
  • cmap (str, optional) – The name of a colormap to use

  • +
  • flip (book, optional) – Whether to flip the x axes of all transect plot

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.parallel.create_pool.html b/0.22.0rc4/generated/mpas_tools.parallel.create_pool.html new file mode 100644 index 000000000..06a574528 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.parallel.create_pool.html @@ -0,0 +1,190 @@ + + + + + + + mpas_tools.parallel.create_pool — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.parallel.create_pool

+
+
+mpas_tools.parallel.create_pool(process_count=None, method='forkserver')[source]
+

Crate a pool for creating masks with Python multiprocessing. This should +be called only once at the beginning of the script performing cell culling. +pool.terminate() should be called before exiting the script.

+
+
Parameters:
+
    +
  • process_count (int, optional) – The number of processors or None to use all available processors

  • +
  • method ({'fork', 'spawn', 'forkserver'}) – The mutiprocessing method

  • +
+
+
Returns:
+

pool (multiprocessing.Pool) – A pool to use for python-based mask creation.

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.planar_hex.make_planar_hex_mesh.html b/0.22.0rc4/generated/mpas_tools.planar_hex.make_planar_hex_mesh.html new file mode 100644 index 000000000..442ead6fd --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.planar_hex.make_planar_hex_mesh.html @@ -0,0 +1,218 @@ + + + + + + + mpas_tools.planar_hex.make_planar_hex_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.planar_hex.make_planar_hex_mesh

+
+
+mpas_tools.planar_hex.make_planar_hex_mesh(nx, ny, dc, nonperiodic_x, nonperiodic_y, outFileName=None, compareWithFileName=None, format=None, engine=None)[source]
+

Builds an MPAS periodic, planar hexagonal mesh with the requested +dimensions, optionally saving it to a file, and returns it as an +xarray.Dataset.

+
+
Parameters:
+
    +
  • nx (int) – The number of cells in the x direction

  • +
  • ny (even int) – The number of cells in the y direction (must be an even number for +periodicity to work out)

  • +
  • dc (float) – The distance in meters between adjacent cell centers.

  • +
  • nonperiodic_x (bool) – is the mesh non-periodic in x and y directions?

  • +
  • nonperiodic_y (bool) – is the mesh non-periodic in x and y directions?

  • +
  • outFileName (str, optional) – The name of a file to save the mesh to. The mesh is not saved to a +file if no file name is supplied.

  • +
  • compareWithFileName (str, optional) – The name of a grid file to compare with to see if they are identical, +used for testing purposes

  • +
  • format ({'NETCDF4', 'NETCDF4_CLASSIC', 'NETCDF3_64BIT', ') – NETCDF3_CLASSIC’}, optional +The NetCDF format to use for output

  • +
  • engine ({'netcdf4', 'scipy', 'h5netcdf'}, optional) – The library to use for NetCDF output

  • +
+
+
Returns:
+

mesh (xarray.Dataset) – The mesh data set, available for further manipulation such as culling +cells or removing periodicity.

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.html b/0.22.0rc4/generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.html new file mode 100644 index 000000000..64b9ac4a7 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.html @@ -0,0 +1,198 @@ + + + + + + + mpas_tools.scrip.from_mpas.scrip_from_mpas — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.scrip.from_mpas.scrip_from_mpas

+
+
+mpas_tools.scrip.from_mpas.scrip_from_mpas(mpasFile, scripFile, useLandIceMask=False)[source]
+

Create a SCRIP file from an MPAS mesh

+
+
Parameters:
+
    +
  • mpasFile (str) – The path to a NetCDF file with the MPAS mesh

  • +
  • scripFile (str) – The path to the output SCRIP file

  • +
  • useLandIceMask (bool) – Whether to use the landIceMask field for masking

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.mask.extend_seaice_mask.html b/0.22.0rc4/generated/mpas_tools.seaice.mask.extend_seaice_mask.html new file mode 100644 index 000000000..51061afaa --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.mask.extend_seaice_mask.html @@ -0,0 +1,195 @@ + + + + + + + mpas_tools.seaice.mask.extend_seaice_mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.mask.extend_seaice_mask

+
+
+mpas_tools.seaice.mask.extend_seaice_mask(filenameMesh, filenamePresence, extendDistance, unitSphere=False)[source]
+

Add a field icePresenceExtended to filenamePresence if it doesn’t +already exist. This field is the icePresence field extended by +a distance of extendDistance.

+
+
Parameters:
+
    +
  • filenameMesh (str) – The filename of the MPAS-Seaice mesh

  • +
  • filenamePresence (str) – A filename for a file containing an icePresence field to be +extended and to which a new icePresenceExtended will be added

  • +
  • extendDistance (float) – The distance in km to expand (no expansion is performed if +extendDistance=0.0)

  • +
  • unitSphere (bool, optional) – Whether the mesh is provided on the unit sphere, rather than one with +the radius of the Earth

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.html b/0.22.0rc4/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.html new file mode 100644 index 000000000..e0ffe351c --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.html @@ -0,0 +1,189 @@ + + + + + + + mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells

+
+
+mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells(meshFilename, scripFilename, title)[source]
+

Write a SCRIP file for cel quantities on the given MPAS-Seaice mesh

+
+
Parameters:
+
    +
  • meshFilename (str) – The name of a file containing the MPAS-Seaice mesh

  • +
  • scripFilename (str) – The name of the resulting SCRIP file

  • +
  • title (str) – A string to include as the title attribute in the SCRIP file

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.html b/0.22.0rc4/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.html new file mode 100644 index 000000000..e6df82814 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.html @@ -0,0 +1,189 @@ + + + + + + + mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices

+
+
+mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices(meshFilename, scripFilename, title)[source]
+

Write a SCRIP file for vertex quantities on the given MPAS-Seaice mesh

+
+
Parameters:
+
    +
  • meshFilename (str) – The name of a file containing the MPAS-Seaice mesh

  • +
  • scripFilename (str) – The name of the resulting SCRIP file

  • +
  • title (str) – A string to include as the title attribute in the SCRIP file

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.mesh.write_2D_scripfile.html b/0.22.0rc4/generated/mpas_tools.seaice.mesh.write_2D_scripfile.html new file mode 100644 index 000000000..20200a0cb --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.mesh.write_2D_scripfile.html @@ -0,0 +1,196 @@ + + + + + + + mpas_tools.seaice.mesh.write_2D_scripfile — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.mesh.write_2D_scripfile

+
+
+mpas_tools.seaice.mesh.write_2D_scripfile(filenameScripOut, scripTitle, nColumns, nRows, latsCentre, lonsCentre, latsVertex, lonsVertex, degrees=False)[source]
+

Write a SCRIP file for the given 2D grid

+
+
Parameters:
+
    +
  • filenameScripOut (str) – The name of the resulting SCRIP file

  • +
  • scripTitle (str) – A string to include as the title attribute in the SCRIP file

  • +
  • nColumns (int) – The number of columns in the grid

  • +
  • nRows (int) – The number of rows in the grid

  • +
  • latsCentre (numpy.ndarray) – The latitude (in radians) of cell centers

  • +
  • lonsCentre (numpy.ndarray) – The longitude (in radians) of cell centers

  • +
  • latsVertex (numpy.ndarray) – The latitude (in radians) of cell vertices

  • +
  • lonsVertex (numpy.ndarray) – The longitude (in radians) of cell vertices

  • +
  • degrees (bool, optional) – Whether the latitude and longitude variables are in degrees (as opposed +to radians)

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.mesh.write_scrip_file.html b/0.22.0rc4/generated/mpas_tools.seaice.mesh.write_scrip_file.html new file mode 100644 index 000000000..e855db008 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.mesh.write_scrip_file.html @@ -0,0 +1,196 @@ + + + + + + + mpas_tools.seaice.mesh.write_scrip_file — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.mesh.write_scrip_file

+
+
+mpas_tools.seaice.mesh.write_scrip_file(scripFilename, title, nCells, maxEdges, latCell, lonCell, corner_lat, corner_lon, mask=None)[source]
+

A low-level function for writing a SCRIP file for the given MPAS-Seaice +mesh

+
+
Parameters:
+
    +
  • scripFilename (str) – The name of the resulting SCRIP file

  • +
  • title (str) – A string to include as the title attribute in the SCRIP file

  • +
  • nCells (int) – The number of cells in the mesh

  • +
  • maxEdges (int) – The maximum number of edges/vertices on a cell in the mesh

  • +
  • latCell (numpy.ndarray) – The latitude (in radians) of cell centers

  • +
  • lonCell (numpy.ndarray) – The longitude (in radians) of cell centers

  • +
  • corner_lat (numpy.ndarray) – The latitude (in radians) of cell vertices

  • +
  • corner_lon (numpy.ndarray) – The longitude (in radians) of cell vertices

  • +
  • mask (numpy.ndarray, optional) – A mask of where cells are valid

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.partition.create_partitions.html b/0.22.0rc4/generated/mpas_tools.seaice.partition.create_partitions.html new file mode 100644 index 000000000..6988bd508 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.partition.create_partitions.html @@ -0,0 +1,180 @@ + + + + + + + mpas_tools.seaice.partition.create_partitions — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.partition.create_partitions

+
+
+mpas_tools.seaice.partition.create_partitions()[source]
+

An entry point for creating sea-ice partitions

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.html b/0.22.0rc4/generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.html new file mode 100644 index 000000000..fde32fda6 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.html @@ -0,0 +1,199 @@ + + + + + + + mpas_tools.seaice.partition.gen_seaice_mesh_partition — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.partition.gen_seaice_mesh_partition

+
+
+mpas_tools.seaice.partition.gen_seaice_mesh_partition(meshFilename, regionFilename, nProcsArray, mpasCullerLocation, outputPrefix, plotting, metis, cullEquatorialRegion)[source]
+

Generate graph partition(s) for the given MPAS-Seaice mesh and the given +number(s) of processors and a file defining regions that each processor +should own part of (typically a polar region and an equatorial region)

+
+
Parameters:
+
    +
  • meshFilename (str) – The name of a file containing the MPAS-Seaice mesh

  • +
  • regionFilename (str) – The name of a file containing a region field defining different +regions that each processor should own part of

  • +
  • nProcsArray (list or int) – The number(s) of processors to create graph partitions for

  • +
  • mpasCullerLocation (str or None) – The directory for the MpasCellCuller.x tool or None to look in +the user’s path

  • +
  • outputPrefix (str) – The prefix to prepend to each graph partition file

  • +
  • plotting (bool) – Whether to create a NetCDF file partition_diag.nc to use for +plotting the partitions

  • +
  • metis (str) – The exectable to use for partitioning in each region

  • +
  • cullEquatorialRegion (bool) – Whether to remove the equatorial region from the paritions

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.partition.prepare_partitions.html b/0.22.0rc4/generated/mpas_tools.seaice.partition.prepare_partitions.html new file mode 100644 index 000000000..b7061a8b9 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.partition.prepare_partitions.html @@ -0,0 +1,180 @@ + + + + + + + mpas_tools.seaice.partition.prepare_partitions — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.partition.prepare_partitions

+
+
+mpas_tools.seaice.partition.prepare_partitions()[source]
+

An entry point for performing preparatory work for making seaice partitions

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.regions.make_regions_file.html b/0.22.0rc4/generated/mpas_tools.seaice.regions.make_regions_file.html new file mode 100644 index 000000000..f9dc2079f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.regions.make_regions_file.html @@ -0,0 +1,196 @@ + + + + + + + mpas_tools.seaice.regions.make_regions_file — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.regions.make_regions_file

+
+
+mpas_tools.seaice.regions.make_regions_file(filenameIcePresent, filenameMesh, regionType, varname, limit, filenameOut)[source]
+

+
+
Parameters:
+
    +
  • filenameIcePresent (str) – A filename for a file containing the field specified in varname +that determines where ice may be present

  • +
  • filenameMesh (str) – The name of a file containing the MPAS-Seaice mesh

  • +
  • regionType ({"three_region", "two_region_eq", "three_region_eq", "five_region_eq"}) – The type of regions to write

  • +
  • varname (str) – The name of the variable that determines where ice might be present

  • +
  • limit (float) – For regionType either three_region or five_region_eq, +the value of the varname field above which ice is considered to +be present. For other regionType values, the limit is always 0.5 +and this parameter is ignored.

  • +
  • filenameOut (str) – The NetCDF filename to write the resulting region field to

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.html b/0.22.0rc4/generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.html new file mode 100644 index 000000000..fe4381601 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.html @@ -0,0 +1,179 @@ + + + + + + + mpas_tools.seaice.regrid.regrid_to_other_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.seaice.regrid.regrid_to_other_mesh

+
+
+mpas_tools.seaice.regrid.regrid_to_other_mesh(meshFilenameSrc, filenameData, meshFilenameDst, filenameOut, generateWeights=True, weightsFilename=None)[source]
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.split_grids.split_grids.html b/0.22.0rc4/generated/mpas_tools.split_grids.split_grids.html new file mode 100644 index 000000000..8d9e8d0af --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.split_grids.split_grids.html @@ -0,0 +1,216 @@ + + + + + + + mpas_tools.split_grids.split_grids — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.split_grids.split_grids

+
+
+mpas_tools.split_grids.split_grids(infile=None, outfile1=None, outfile2=None, nCells=None, nEdges=None, nVertices=None, maxEdges=None, runner=None)[source]
+

Split two previously merged MPAS non-contiguous meshes together into +separate files. Typical usage is:

+
split_grids(infile='infile.nc', outfile1='outfile1.nc', outfile2='outfile2.nc')
+
+
+

The optional arguments for nCells, nEdges, nVertices, and maxEdges +should generally not be required as this information sould have been saved in +infiles’s global attribute merge_point when created by +mpas_tools.merge_grids.merge_grids().

+
+
Parameters:
+
    +
  • infile (str) – The file name for the mesh to split

  • +
  • outfile1 (str) – The file name for the first split mesh

  • +
  • outfile2 (str) – The file name for the second split mesh

  • +
  • nCells (int, optional) – The number of cells in the first mesh (default: the value specified in +infile global attribute merge_point)

  • +
  • nEdges (int, optional) – The number of edges in the first mesh (default: the value specified in +infile global attribute merge_point

  • +
  • nVertices (int, optional) – The number of vertices in the first mesh (default: the value specified in +infile global attribute merge_point

  • +
  • maxEdges (list[int, int], optional) – A list of the number of max edges (int) in each mesh (default: the value +specified in infile global attribute merge_point OR will use infile +maxEdges dimension and assume same for both)

  • +
  • runner (str, optional) – The command to write into the global history attribute of the outfile

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.tests.test_cime_constants.test_cime_constants.html b/0.22.0rc4/generated/mpas_tools.tests.test_cime_constants.test_cime_constants.html new file mode 100644 index 000000000..c5db9a6e1 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.tests.test_cime_constants.test_cime_constants.html @@ -0,0 +1,176 @@ + + + + + + + mpas_tools.tests.test_cime_constants.test_cime_constants — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.tests.test_cime_constants.test_cime_constants

+
+
+mpas_tools.tests.test_cime_constants.test_cime_constants(e3sm_tag='master')[source]
+

Parse relevant constants from CIME

+
+
Parameters:
+

e3sm_tag (str, optional) – The E3SM tag to download constants from

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.Vector.html b/0.22.0rc4/generated/mpas_tools.transects.Vector.html new file mode 100644 index 000000000..17be02692 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.Vector.html @@ -0,0 +1,237 @@ + + + + + + + mpas_tools.transects.Vector — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.Vector

+
+
+class mpas_tools.transects.Vector(x, y, z)[source]
+

A class for representing Cartesian vectors with x, y and z +components that are either float or numpy.array objects of +identical size.

+
+
Variables:
+
+
+
+
+
+__init__(x, y, z)[source]
+

A class for representing Cartesian vectors with x, y and z +components that are either float or numpy.array objects of +identical size.

+
+
Parameters:
+
+
+
+
+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

__init__(x, y, z)

A class for representing Cartesian vectors with x, y and z components that are either float or numpy.array objects of identical size.

angular_distance(other)

Compute angular distance between points on the sphere, following: https://en.wikipedia.org/wiki/Great-circle_distance

cross(other)

Compute the dot product between this vector and other.

det(v1, v2, v3)

The determinant of the matrix defined by the three Vector objects

dot(other)

Compute the dot product between this vector and other.

intersection(a1, a2, b1, b2)

Based on https://stackoverflow.com/a/26669130/7728169 Find the intersection point as a unit vector between great circle arc from a1 to a2 and from b1 to b2.

intersects(a1, a2, b1, b2)

Based on https://stackoverflow.com/a/26669130/7728169 Determine if the great circle arc from a1 to a2 intersects that from b1 to b2.

mag()

The magnitude of the vector

straddles(a1, a2, b1, b2)

Based on https://stackoverflow.com/a/26669130/7728169 Determines if the great circle segment determined by (a1, a2) straddles the great circle determined by (b1, b2)

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.angular_distance.html b/0.22.0rc4/generated/mpas_tools.transects.angular_distance.html new file mode 100644 index 000000000..8624a67d1 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.angular_distance.html @@ -0,0 +1,191 @@ + + + + + + + mpas_tools.transects.angular_distance — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.angular_distance

+
+
+mpas_tools.transects.angular_distance(x, y, z)[source]
+

Compute angular distance between points on the sphere, following: +https://en.wikipedia.org/wiki/Great-circle_distance

+
+
Parameters:
+
    +
  • x (numpy.ndarray) – The Cartesian x coordinate of a transect, where the number of segments +is len(x) - 1. x, y and z are of the same lengt.

  • +
  • y (numpy.ndarray) – The Cartesian y coordinate of the transect

  • +
  • z (numpy.ndarray) – The Cartesian z coordinate of the transect

  • +
+
+
Returns:
+

distance (numpy.ndarray) – The angular distance (in radians) between segments of the transect.

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.cartesian_to_great_circle_distance.html b/0.22.0rc4/generated/mpas_tools.transects.cartesian_to_great_circle_distance.html new file mode 100644 index 000000000..8d9c34c99 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.cartesian_to_great_circle_distance.html @@ -0,0 +1,190 @@ + + + + + + + mpas_tools.transects.cartesian_to_great_circle_distance — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.cartesian_to_great_circle_distance

+
+
+mpas_tools.transects.cartesian_to_great_circle_distance(x, y, z, earth_radius)[source]
+

Cartesian transect points to great-circle distance

+
+
Parameters:
+
    +
  • x (numpy.ndarray) – The Cartesian x coordinate of a transect

  • +
  • y (numpy.ndarray) – The Cartesian y coordinate of the transect

  • +
  • z (numpy.ndarray) – The Cartesian z coordinate of the transect

  • +
  • earth_radius (float) – The radius of the earth

  • +
+
+
Returns:
+

distance (numpy.ndarray) – The distance along the transect

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.cartesian_to_lon_lat.html b/0.22.0rc4/generated/mpas_tools.transects.cartesian_to_lon_lat.html new file mode 100644 index 000000000..df1d2c600 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.cartesian_to_lon_lat.html @@ -0,0 +1,177 @@ + + + + + + + mpas_tools.transects.cartesian_to_lon_lat — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.cartesian_to_lon_lat

+
+
+mpas_tools.transects.cartesian_to_lon_lat(x, y, z, earth_radius, degrees)[source]
+

Convert from Cartesian x, y, z to lon/lat

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.lon_lat_to_cartesian.html b/0.22.0rc4/generated/mpas_tools.transects.lon_lat_to_cartesian.html new file mode 100644 index 000000000..5d00c7be4 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.lon_lat_to_cartesian.html @@ -0,0 +1,177 @@ + + + + + + + mpas_tools.transects.lon_lat_to_cartesian — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.lon_lat_to_cartesian

+
+
+mpas_tools.transects.lon_lat_to_cartesian(lon, lat, earth_radius, degrees)[source]
+

Convert from lon/lat to Cartesian x, y, z

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.subdivide_great_circle.html b/0.22.0rc4/generated/mpas_tools.transects.subdivide_great_circle.html new file mode 100644 index 000000000..11f7a03f4 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.subdivide_great_circle.html @@ -0,0 +1,204 @@ + + + + + + + mpas_tools.transects.subdivide_great_circle — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.subdivide_great_circle

+
+
+mpas_tools.transects.subdivide_great_circle(x, y, z, maxRes, earthRadius)[source]
+

Subdivide each segment of the transect so the horizontal resolution +approximately matches the requested resolution

+

Uses a formula for interpolating unit vectors on the sphere from +https://en.wikipedia.org/wiki/Slerp

+
+
Parameters:
+
    +
  • x (numpy.ndarray) – The Cartesian x coordinate of a transect, where the number of segments +is len(x) - 1. x, y and z are of the same length.

  • +
  • y (numpy.ndarray) – The Cartesian y coordinate of the transect

  • +
  • z (numpy.ndarray) – The Cartesian z coordinate of the transect

  • +
  • maxRes (float) – The maximum allowed spacing in m after subdivision

  • +
  • earthRadius (float) – The radius of the Earth in m

  • +
+
+
Returns:
+

    +
  • xOut (numpy.ndarray) – The Cartesian x values of the transect subdivided into segments with +segment length at most maxRes. All the points in x, y and +z are guaranteed to be included.

  • +
  • yOut (numpy.ndarray) – The Cartesian y values of the subdivided transect

  • +
  • zOut (numpy.ndarray) – The Cartesian y values of the subdivided transect

  • +
  • dIn (numpy.ndarray) – The distance along the transect before subdivision

  • +
  • dOut (numpy.ndarray) – The distance along the transect after subdivision

  • +
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.transects.subdivide_planar.html b/0.22.0rc4/generated/mpas_tools.transects.subdivide_planar.html new file mode 100644 index 000000000..11df63eec --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.transects.subdivide_planar.html @@ -0,0 +1,202 @@ + + + + + + + mpas_tools.transects.subdivide_planar — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.transects.subdivide_planar

+
+
+mpas_tools.transects.subdivide_planar(x, y, maxRes)[source]
+

Subdivide each segment of the transect so the horizontal resolution +approximately matches the requested resolution

+

Uses a formula for interpolating unit vectors on the sphere from +https://en.wikipedia.org/wiki/Slerp

+
+
Parameters:
+
    +
  • x (numpy.ndarray) – The planar x coordinate of a transect, where the number of segments +is len(x) - 1

  • +
  • y (numpy.ndarray) – The planar y coordinates of the transect, the same length as x

  • +
  • maxRes (float) – The maximum allowed spacing in m after subdivision

  • +
+
+
Returns:
+

    +
  • xOut (numpy.ndarray) – The x coordinate of the transect, subdivided into segments with length +at most maxRes. All the points in x are guaranteed to be +included.

  • +
  • yOut (numpy.ndarray) – The y coordinate of the transect. All the points in y are +guaranteed to be included.

  • +
  • dIn (numpy.ndarray) – The distance along the transect before subdivision

  • +
  • dOut (numpy.ndarray) – The distance along the transect after subdivision

  • +
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.translate.center.html b/0.22.0rc4/generated/mpas_tools.translate.center.html new file mode 100644 index 000000000..b81f651cf --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.translate.center.html @@ -0,0 +1,195 @@ + + + + + + + mpas_tools.translate.center — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.translate.center

+
+
+mpas_tools.translate.center(mesh)[source]
+

Translates the coordinate system of the planar MPAS mesh by shifting the +origin to the center of the domain

+
+
Parameters:
+

mesh (xarray.Dataset) – A planar mesh to translate

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.translate.center_on_mesh.html b/0.22.0rc4/generated/mpas_tools.translate.center_on_mesh.html new file mode 100644 index 000000000..2f06b6bcd --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.translate.center_on_mesh.html @@ -0,0 +1,200 @@ + + + + + + + mpas_tools.translate.center_on_mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.translate.center_on_mesh

+
+
+mpas_tools.translate.center_on_mesh(mesh, otherMesh)[source]
+

Translates the coordinate system of the planar MPAS mesh by shifting the +origin to the center of the domain described in a separate mesh

+
+
Parameters:
+
    +
  • mesh (xarray.Dataset) – A planar mesh to translate

  • +
  • otherMesh (xarray.Dataset) – Another planar mesh whose center will become the center of this mesh. +Uses xCell,yCell or, if those fields do not exist, will secondly try +x1,y1 fields

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.translate.translate.html b/0.22.0rc4/generated/mpas_tools.translate.translate.html new file mode 100644 index 000000000..be2532465 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.translate.translate.html @@ -0,0 +1,199 @@ + + + + + + + mpas_tools.translate.translate — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.translate.translate

+
+
+mpas_tools.translate.translate(mesh, xOffset=0.0, yOffset=0.0)[source]
+

Translates the coordinate system of the planar MPAS mesh by an arbitrary +shift in x and/or y

+
+
Parameters:
+
    +
  • mesh (xarray.Dataset) – A planar mesh to translate

  • +
  • xOffset (float, optional) – user-specified shift in the x-direction

  • +
  • yOffset (float, optional) – user-specified shift in the y-direction

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.html b/0.22.0rc4/generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.html new file mode 100644 index 000000000..97107d01a --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.html @@ -0,0 +1,176 @@ + + + + + + + mpas_tools.viz.colormaps.register_sci_viz_colormaps — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.viz.colormaps.register_sci_viz_colormaps

+
+
+mpas_tools.viz.colormaps.register_sci_viz_colormaps()[source]
+

Register all SciVisColor colormaps with matplotlib

+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.html b/0.22.0rc4/generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.html new file mode 100644 index 000000000..04251de71 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.html @@ -0,0 +1,199 @@ + + + + + + + mpas_tools.viz.mesh_to_triangles.mesh_to_triangles — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.viz.mesh_to_triangles.mesh_to_triangles

+
+
+mpas_tools.viz.mesh_to_triangles.mesh_to_triangles(dsMesh, periodicCopy=False)[source]
+

Construct a dataset in which each MPAS cell is divided into the triangles +connecting pairs of adjacent vertices to cell centers.

+
+
Parameters:
+
    +
  • dsMesh (xarray.Dataset) – An MPAS mesh

  • +
  • periodicCopy (bool, optional) – Whether to make a periodic copy of triangles that cross -180/180 degrees +longitude. This is helpful when plotting triangles in a lon/lat space.

  • +
+
+
Returns:
+

dsTris (xarray.Dataset) – A dataset that defines triangles connecting pairs of adjacent vertices +to cell centers as well as the cell index that each triangle is in and +cell indices and weights for interpolating data defined at cell centers +to triangle nodes. dsTris includes variables triCellIndices, +the cell that each triangle is part of; nodeCellIndices and +nodeCellWeights, the indices and weights used to interpolate from +MPAS cell centers to triangle nodes; Cartesian coordinates xNode, +yNode, and zNode; and lonNode` and latNode in radians. +lonNode is guaranteed to be within 180 degrees of the cell center +corresponding to triCellIndices. Nodes always have a +counterclockwise winding.

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.viz.paraview_extractor.extract_vtk.html b/0.22.0rc4/generated/mpas_tools.viz.paraview_extractor.extract_vtk.html new file mode 100644 index 000000000..77a884fbf --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.viz.paraview_extractor.extract_vtk.html @@ -0,0 +1,274 @@ + + + + + + + mpas_tools.viz.paraview_extractor.extract_vtk — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.viz.paraview_extractor.extract_vtk

+
+
+mpas_tools.viz.paraview_extractor.extract_vtk(filename_pattern, variable_list='all', dimension_list=None, mesh_filename=None, blocking=10000, output_32bit=False, combine=False, append=False, out_dir='vtk_files', xtime='xtime', lonlat=False, time=None, ignore_time=False, topo_dim=None, topo_cell_index=None, include_mesh_vars=False, fc_region_mask=None, temp_dir='./culled_region', use_progress_bar=True)[source]
+

Extract fields from a time series of NetCDF files as VTK files for plotting +in ParaView.

+

To extract fields across multiple files, passing in a regular expression +for the filename pattern, for example filename_pattern="hist.comp.*.nc".

+

By default, time-independent fields on cells are written to a file

+
vtk_files/staticFieldsOnCells.vtp
+
+
+

and time-dependent fields on cells are written to

+
vtk_files/timeDependentFieldsOnCells.pvd
+vtk_files/time_series/timeDependentFieldsOnCells.0.vtp
+vtk_files/time_series/timeDependentFieldsOnCells.1.vtp
+...
+
+
+

and similarly for edges and vertices. Time-independent fields can be +included in each time step of the time-dependent fields for with +combine=True. This allows time-dependent and -independent fields +to be combined in filters within ParaView at the expense of considerable +additional storage space.

+

Indices for extra dimensions can either be supplied at runtime at a prompt +(if dimension_list=None) or via a list of strings with the dimensions +and associated indices. For each extra dimension, you can specify +nothing for the indices (an empty string, meaning skip any fields with this +dimension), a single index, a comma-separated list of indices, or a range +of indices (separated by 1 or 2 colons). For example,

+
dimension_list=['maxEdges=', 'nVertLeves=0:10:2', 'nParticles=0,2,4,6,8']
+
+
+

will ignore any fields with dimension maxEdges, extract every other +layer from the first 10 vertical levels (each into its own field) and +extract the 5 specified particles.

+

An index array can also be specified in this way (and these can be mixed +with integer indices in a comma-separated list but not in a colon-separated +range):

+
dimension_list=['nVertLeves=0,maxLevelCell']
+
+
+

will extract fields from the first vertical level and the vertical level +with index given by maxLevelCell.

+

The extractor includes optional support for extracting geometry appropriate +for displaying variables at the depth of a topographic feature (typically +the top or bottom of the domain) for MPAS components with a spatially +variable top or bottom index (e.g. maxLevelCell in MPAS-Ocean). This is +accomplished with arguments such as:

+
topo_dim='nVertLevels', topo_cell_index='maxLevelCell'
+
+
+

Fields on cells are sampled at the topographic index and the geometry +includes polygons corresponding to edges so that vertical faces between +adjacent cells can be displayed. Fields are extracted as normal except +that they are sampled as point data rather than cell data, allowing +computations in ParaView to display the topography. A mask field is also +included indicating which parts of edge polygons correspond to the boundary +of the domain (boundaryMask == 1) and which parts of cell and edge +polygons are interior (boundaryMask == 0). Together, this can be used +to plot topography by using a calculator filter like the following:

+
coords*(1.0 + 100.0/mag(coords)*((1 - boundaryMask)*(-bottomDepth)
+                                 + 10.0*boundaryMask))
+
+
+

If this is entered into a Calculator Filter in ParaView with the “coordinate +result” box checked, the result will to display the MPAS-Ocean topography, +exaggerated by a factor of 100, with a value equivalent to 10 m along +boundary points of edge polygons (a “water-tight” surface).

+
+
Parameters:
+
    +
  • filename_pattern (str) – MPAS Filename pattern

  • +
  • variable_list (list of str, optional) – List of variables to extract (‘all’ for all variables, ‘allOnCells’ +for all variables on cells, etc.)”

  • +
  • dimension_list (list of str, optional) – A list of dimensions and associated indices

  • +
  • mesh_filename (str, optional) – MPAS Mesh filename. By default, the first file matching +filename_pattern will be used

  • +
  • blocking (int, optional) – Size of blocks when reading MPAS file

  • +
  • output_32bit (bool, optional) – Whether the vtk files will be written using 32bit floats

  • +
  • combine (bool, optional) – Whether time-independent fields are written to each file along with +time-dependent fields

  • +
  • append (bool, optional) – Whether only vtp files that do not already exist are written out

  • +
  • out_dir (str, optional) – The output directory

  • +
  • xtime (str, optional") – The name of the xtime variable or ‘none’ to extract Time dim without +xtime

  • +
  • lonlat (bool, optional) – Whether the resulting points are in lon-lat space, not Cartesian

  • +
  • time (str, optional) – Indices for the time dimension

  • +
  • ignore_time (bool, optional) – Whether to ignore the Time dimension if it exists for files with a Time +dimension but no xtime variable (e.g. mesh file)

  • +
  • topo_dim (str, optional) – Dimension and range for topography dimension

  • +
  • topo_cell_index (str, optional) – Index array indicating the bottom of the domain (default is the +topo_dim-1 for all cells)

  • +
  • include_mesh_vars (bool, optional) – Whether to include mesh variables as well as time-series variables +in the extraction

  • +
  • fc_region_mask (geometric_features.FeatureCollection, optional) – A feature collection used to define a mask. The MPAS data is culled to +lie within the mask before conversion to VTK proceeds

  • +
  • temp_dir (str, optional) – If fc_region_mask is supplied, a temporary directory where the culled +mesh and time series files are stored

  • +
  • use_progress_bar (bool, optional) – Whether to display progress bars (problematic in logging to a file)

  • +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.html b/0.22.0rc4/generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.html new file mode 100644 index 000000000..597b18097 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.html @@ -0,0 +1,230 @@ + + + + + + + mpas_tools.viz.transects.find_planar_transect_cells_and_weights — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.viz.transects.find_planar_transect_cells_and_weights

+
+
+mpas_tools.viz.transects.find_planar_transect_cells_and_weights(xTransect, yTransect, dsTris, dsMesh, tree, subdivisionRes=10000.0)[source]
+

Find “nodes” where the transect intersects the edges of the triangles +that make up MPAS cells.

+
+
Parameters:
+
    +
  • xTransect (xarray.DataArray) – The x points defining segments making up the transect

  • +
  • yTransect (xarray.DataArray) – The y points defining segments making up the transect

  • +
  • dsTris (xarray.Dataset) – A dataset that defines triangles, the results of calling +:py:fun:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()

  • +
  • dsMesh (xarray.Dataset) – A data set with the full MPAS mesh.

  • +
  • tree (scipy.spatial.cKDTree) – A tree of edge centers from triangles making up an MPAS mesh, the return +value from make_triangle_tree()

  • +
  • subdivisionRes (float, optional) – Resolution in m to use to subdivide the transect when looking for +intersection candidates. Should be small enough that curvature is +small.

  • +
+
+
Returns:
+

dsOut (xarray.Dataset) – A dataset that contains “nodes” where the transect intersects the +edges of the triangles in dsTris. The nodes also include the two +end points of the transect, which typically lie within triangles. Each +internal node (that is, not including the end points) is purposefully +repeated twice, once for each triangle that node touches. This allows +for discontinuous fields between triangles (e.g. if one wishes to plot +constant values on each MPAS cell). The planar coordinates of these +nodes are xNode and yNode. The distance along the transect of +each intersection is dNode. The index of the triangle and the first +triangle node in dsTris associated with each intersection node are +given by horizTriangleIndices and horizTriangleNodeIndices, +respectively. The second node on the triangle for the edge associated +with the intersection is given by +numpy.mod(horizTriangleNodeIndices + 1, 3).

+

The MPAS cell that a given node belongs to is given by +horizCellIndices. Each node also has an associated set of 6 +interpHorizCellIndices and interpHorizCellWeights that can be +used to interpolate from MPAS cell centers to nodes first with +area-weighted averaging to MPAS vertices and then linear interpolation +along triangle edges. Some of the weights may be zero, in which case +the associated interpHorizCellIndices will be -1.

+

Finally, xTransect and yTransect are included in the +dataset, along with dTransect, the distance along the transect of +each original transect point. In order to interpolate values (e.g. +observations) from the original transect points to the intersection +nodes, linear interpolation indices transectIndicesOnHorizNode and +weights transectWeightsOnHorizNode are provided. The values at +nodes are found by:

+
nodeValues = ((transectValues[transectIndicesOnHorizNode] *
+               transectWeightsOnHorizNode)
+              + (transectValues[transectIndicesOnHorizNode+1] *
+                 (1.0 - transectWeightsOnHorizNode))
+
+
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.viz.transects.find_transect_cells_and_weights.html b/0.22.0rc4/generated/mpas_tools.viz.transects.find_transect_cells_and_weights.html new file mode 100644 index 000000000..ea3d2d4f8 --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.viz.transects.find_transect_cells_and_weights.html @@ -0,0 +1,235 @@ + + + + + + + mpas_tools.viz.transects.find_transect_cells_and_weights — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.viz.transects.find_transect_cells_and_weights

+
+
+mpas_tools.viz.transects.find_transect_cells_and_weights(lonTransect, latTransect, dsTris, dsMesh, tree, degrees=True, subdivisionRes=10000.0)[source]
+

Find “nodes” where the transect intersects the edges of the triangles +that make up MPAS cells.

+
+
Parameters:
+
    +
  • lonTransect (xarray.DataArray) – The longitude of segments making up the transect

  • +
  • latTransect (xarray.DataArray) – The latitude of segments making up the transect

  • +
  • dsTris (xarray.Dataset) – A dataset that defines triangles, the results of calling +:py:fun:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()`

  • +
  • dsMesh (xarray.Dataset) – A data set with the full MPAS mesh.

  • +
  • tree (scipy.spatial.cKDTree) – A tree of edge centers from triangles making up an MPAS mesh, the return +value from make_triangle_tree()

  • +
  • degrees (bool, optional) – Whether lonTransect and latTransect are in degrees (as opposed +to radians).

  • +
  • subdivisionRes (float, optional) – Resolution in m to use to subdivide the transect when looking for +intersection candidates. Should be small enough that curvature is +small.

  • +
+
+
Returns:
+

dsOut (xarray.Dataset) – A dataset that contains “nodes” where the transect intersects the +edges of the triangles in dsTris. The nodes also includes the two +end points of the transect, which typically lie within triangles. Each +internal node (that is, not including the end points) is purposefully +repeated twice, once for each triangle that node touches. This allows +for discontinuous fields between triangles (e.g. if one wishes to plot +constant values on each MPAS cell). The Cartesian and lon/lat +coordinates of these nodes are xCartNode, yCartNode, +zCartNode, lonNode and latNode. The distance along the +transect of each intersection is dNode. The index of the triangle +and the first triangle node in dsTris associated with each +intersection node are given by horizTriangleIndices and +horizTriangleNodeIndices, respectively. The second node on the +triangle for the edge associated with the intersection is given by +numpy.mod(horizTriangleNodeIndices + 1, 3).

+

The MPAS cell that a given node belongs to is given by +horizCellIndices. Each node also has an associated set of 6 +interpHorizCellIndices and interpHorizCellWeights that can be +used to interpolate from MPAS cell centers to nodes first with +area-weighted averaging to MPAS vertices and then linear interpolation +along triangle edges. Some of the weights may be zero, in which case +the associated interpHorizCellIndices will be -1.

+

Finally, lonTransect and latTransect are included in the +dataset, along with Cartesian coordinates xCartTransect, +yCartTransect, zCartTransect`, and dTransect, the great-circle +distance along the transect of each original transect point. In order +to interpolate values (e.g. observations) from the original transect +points to the intersection nodes, linear interpolation indices +transectIndicesOnHorizNode and weights +transectWeightsOnHorizNode are provided. The values at nodes are +found by:

+
nodeValues = ((transectValues[transectIndicesOnHorizNode] *
+               transectWeightsOnHorizNode)
+              + (transectValues[transectIndicesOnHorizNode+1] *
+                 (1.0 - transectWeightsOnHorizNode))
+
+
+

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/generated/mpas_tools.viz.transects.make_triangle_tree.html b/0.22.0rc4/generated/mpas_tools.viz.transects.make_triangle_tree.html new file mode 100644 index 000000000..fd98c776f --- /dev/null +++ b/0.22.0rc4/generated/mpas_tools.viz.transects.make_triangle_tree.html @@ -0,0 +1,186 @@ + + + + + + + mpas_tools.viz.transects.make_triangle_tree — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

mpas_tools.viz.transects.make_triangle_tree

+
+
+mpas_tools.viz.transects.make_triangle_tree(dsTris)[source]
+

Make a KD-Tree for finding triangle edges that are near enough to transect +segments that they might intersect

+
+
Parameters:
+

dsTris (xarray.Dataset) – A dataset that defines triangles, the results of calling +:py:fun:`mpas_tools.viz.mesh_to_triangles.mesh_to_triangles()`

+
+
Returns:
+

tree (scipy.spatial.cKDTree) – A tree of edge centers from triangles making up an MPAS mesh

+
+
+
+ +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/genindex.html b/0.22.0rc4/genindex.html new file mode 100644 index 000000000..b5a97b9e6 --- /dev/null +++ b/0.22.0rc4/genindex.html @@ -0,0 +1,619 @@ + + + + + + Index — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | L + | M + | P + | R + | S + | T + | V + | W + +
+

_

+ + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

V

+ + +
+ +

W

+ + + +
+ + + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/index.html b/0.22.0rc4/index.html new file mode 100644 index 000000000..19a43c273 --- /dev/null +++ b/0.22.0rc4/index.html @@ -0,0 +1,308 @@ + + + + + + + MPAS-Tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

MPAS-Tools

+_images/so60to10.png +

MPAS-Tools includes a python package, compiled Fortran, C and C++ tools, and +scripts for supporting initialization, visualization and analysis of Model for +Prediction Across Scales (MPAS) components. These tools are used by the +COMPASS +(Configuring of MPAS Setups) framework within +MPAS-Model used to create +ocean and land-ice test cases, +the MPAS-Analysis package for +analyzing simulations, and in other MPAS-related workflows.

+ + + + +
+
+

Indices and tables

+ +
+

Authors

+ +
+
+

Versions

+ +
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/interpolation.html b/0.22.0rc4/interpolation.html new file mode 100644 index 000000000..061079add --- /dev/null +++ b/0.22.0rc4/interpolation.html @@ -0,0 +1,186 @@ + + + + + + + Interpolation — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Interpolation

+

Previously, various tools in this package used scipy for interpolation. +However, the interpolation routines in scipy are not well suited to +interpolation from regular grids to MPAS meshes—they are slow and very memory +intensive, particularly for large meshes.

+

For bilinear interpolation from a tensor lon/lat grid to an MPAS mesh, it will +be faster to use the function +mpas_tools.mesh.interpolation.interp_bilin() +Here is an example where we define cell width for an EC mesh (see +Defining an Eddy-closure Mesh), read in longitude and latitude from an MPAS mesh, and +interpolate the cell widths to cell centers on the MPAS mesh.

+
import numpy as np
+import netCDF4 as nc4
+from mpas_tools.mesh.interpolation import interp_bilin
+
+dlon = 1.
+dlat = dlon
+earth_radius = constants['SHR_CONST_REARTH']
+nlon = int(360./dlon) + 1
+nlat = int(180./dlat) + 1
+lon = np.linspace(-180., 180., nlon)
+lat = np.linspace(-90., 90., nlat)
+
+cellWidth = mdt.EC_CellWidthVsLat(lat)
+
+# broadcast cellWidth to 2D
+_, cellWidth = np.meshgrid(lon, cellWidthVsLat)
+
+ds = nc4.Dataset('base_mesh.nc', 'r+')
+lonCell = ds.variables['lonCell'][:]
+latCell = ds.variables['latCell'][:]
+
+lonCell = np.mod(np.rad2deg(lonCell) + 180., 360.) - 180.
+latCell = np.rad2deg(latCell)
+
+cellWidthOnMpas = interp_bilin(lon, lat, cellWidth, lonCell, latCell)
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/logging.html b/0.22.0rc4/logging.html new file mode 100644 index 000000000..8ab1169e7 --- /dev/null +++ b/0.22.0rc4/logging.html @@ -0,0 +1,244 @@ + + + + + + + Logging — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Logging

+

MPAS-Tools includes capabilities for logging output from many of its function +calls to either stdout/stderr or to a log file.

+
+

Using logging

+

Logging is performed by creating a +mpas_tools.logging.LoggingContext object inside a with +statement:

+
with LoggingContext(__name__) as logger:
+
+    ...
+    logger.info('Step 1. Generate mesh with JIGSAW')
+    ...
+    logger.info('Step 2. Convert triangles from jigsaw format to netcdf')
+    ...
+    logger.info('Step 3. Convert from triangles to MPAS mesh')
+    ...
+
+
+

A LoggingContext is given a unique name (typically the name of the module, +__name__). If no other arguments are supplied, the logger will write to +stdout with calls to logger.info() and logger.debug(), and to +stderr for calls to logger.error().

+

It is convenient to create this kind of a logger in contexts where logging +might be to a file or might be to stdout/stderr, depending on the +calling code.

+

Often, a function should support output to a logger but you do not +necessarily want the calling code to have to crate one if the calling code just +wants output to stdout/stderr. In such contexts, the function can take +logger=None as an optional argument. Then, in the function itself, a new +LoggingContext can be created that will just use the existing logger +if there is one or create a new ong for stdout/stderr if none is +provided. As an example, here is a snippet from +mpas_tools.mesh.creation.build_mesh.build_spherical_mesh():

+
def build_spherical_mesh(cellWidth, lon, lat, earth_radius,
+                         out_filename='base_mesh.nc', plot_cellWidth=True,
+                         dir='./', logger=None):
+    ...
+    with LoggingContext(__name__, logger=logger) as logger:
+
+        ...
+        logger.info('Step 1. Generate mesh with JIGSAW')
+        jigsaw_driver(cellWidth, lon, lat, on_sphere=True,
+                      earth_radius=earth_radius, logger=logger)
+
+        logger.info('Step 2. Convert triangles from jigsaw format to netcdf')
+        jigsaw_to_netcdf(msh_filename='mesh-MESH.msh',
+                         output_name='mesh_triangles.nc', on_sphere=True,
+                         sphere_radius=earth_radius)
+
+        logger.info('Step 3. Convert from triangles to MPAS mesh')
+        write_netcdf(convert(xarray.open_dataset('mesh_triangles.nc'), dir=dir,
+                             logger=logger),
+                     out_filename)
+
+
+

The optional argument logger is passed to a new LoggingContext. That +way logger is guaranteed not to be None (so calls to logger.info +work properly). The logger is also passed on to +mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver() and +mpas_tools.io.write_netcdf() for output from those functions.

+

To log to a new log file, simply pass a file name to the log_filename +argument:

+
with LoggingContext(name=__name__, log_filename='output.log') as logger:
+    ...
+    logger.info('Step 1. Generate mesh with JIGSAW')
+
+
+

If both the logger and log_filename arguments are not None, the +log_filename is ignored and the existing logger is simply used for +logging.

+
+
+

Logging subprocess calls

+

You can also run subprocesses and capture the output to a logger. This is +accomplished with the function mpas_tools.logging.check_call(), which +acts a lot like subprocess.check_call() but with output going to +the logger, as in this example from +mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver()

+
from mpas_tools.logging import check_call
+
+
+def jigsaw_driver(cellWidth, x, y, on_sphere=True, earth_radius=6371.0e3,
+                  geom_points=None, geom_edges=None, logger=None):
+
+    ...
+    opts.jcfg_file = 'mesh.jig'
+    ...
+    check_call(['jigsaw', opts.jcfg_file], logger=logger)
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/making_changes.html b/0.22.0rc4/making_changes.html new file mode 100644 index 000000000..936b57ffb --- /dev/null +++ b/0.22.0rc4/making_changes.html @@ -0,0 +1,261 @@ + + + + + + + Making Changes to mpas_tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Making Changes to mpas_tools

+

New python functions and modules (.py files) can be added within the +conda_package/mpas_tools. These will automatically be part of the +mpas_tools package. New directories with python modules should include an +__init__.py file (which can be empty) to indicate that they are also part of +the package.

+
+

Entry Points

+

The best way to add new “scripts” to the package is to add a function without +any arguments somewhere in the package, and then to add it as an “entry point” +both in conda_package/setup.py and conda_package/recipe/meta.yaml.

+

As an example, the entry point planar_hex is defined in setup.py as:

+
setup(name='mpas_tools',
+...
+      entry_points={'console_scripts':
+                  ['planar_hex = mpas_tools.planar_hex:main',
+...
+
+
+

and in meta.yaml as:

+
build:
+  number: 0
+  entry_points:
+    - planar_hex = mpas_tools.planar_hex:main
+
+
+

When the package is installed in a conda environment, a stub script +planar_hex will be in the user’s path that will call the function main() +in the module mpas_tools.planar_hex:

+
def main():
+
+    parser = argparse.ArgumentParser(
+        description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
+    parser.add_argument('--nx', dest='nx', type=int, required=True,
+                        help='Cells in x direction')
+    ...
+    args = parser.parse_args()
+
+    make_planar_hex_mesh(args.nx, args.ny, args.dc,
+                         args.nonperiodic_x, args.nonperiodic_y,
+                         args.outFileName)
+
+
+

As you can see, the function pointed to by the entry point can used to parse +command-line arguments, just as a “normal” python script would do

+

By convention, entry points do not typically include the .py extension.

+
+
+

Dependencies

+

If you changes introduce new dependencies, these need to be added to both +the recipe for the conda package in conda_package/recipe/meta.yaml and +to the text file describing the development environment, +conda_package/dev-spec.txt.

+

In meta.yaml, add these changes in alphabetical order to the run +section of requirements:

+
requirements:
+...
+  run:
+    - python
+    - affine
+    ...
+
+
+

These requirements must be on the conda-forge anaconda channel. If you +need help with this, please contact the developers.

+

Add the new dependencies in alphabetical order to dev-speck.txt +under the # Base comment:

+
...
+# This file may be used to create an environment using:
+# $ conda create --name <env> --file <this file>
+
+# Base
+python>=3.8
+cartopy
+...
+
+
+
+
+

Updating the Version

+

Before a release of the package, the version of mpas_tools needs to be +updated in 3 places. First, in conda_package/mpas_tools/__init__.py:

+
__version_info__ = (0, 6, 0)
+__version__ = '.'.join(str(vi) for vi in __version_info__)
+
+
+

Increment __version_info__ (major, minor or micro version, depending on +what makes sense).

+

Second, the version in the conda recipe (conda_package/recipe/meta.yaml) +needs to match:

+
{% set name = "mpas_tools" %}
+{% set version = "0.6.0" %}
+
+
+

Third, Add the new version to the Versions in the documentation.

+
`v0.6.0`_         `0.6.0`_
+================ ===============
+
+...
+
+.. _`v0.6.0`: ../0.6.0/index.html
+.. _`0.6.0`: https://github.com/MPAS-Dev/MPAS-Analysis/tree/0.6.0
+
+
+

The new links won’t be valid until a new release is made and Azure Pipelines +has generated the associated documentation. Eventually, it should be possible +to do this automatically but that has not yet been implemented.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/mesh_conversion.html b/0.22.0rc4/mesh_conversion.html new file mode 100644 index 000000000..cab88e3ab --- /dev/null +++ b/0.22.0rc4/mesh_conversion.html @@ -0,0 +1,848 @@ + + + + + + + Mesh Conversion — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Mesh Conversion

+
+

Mesh Converter

+

The command-line tool MpasMeshConverter.x and the corresponding wrapper +function mpas_tools.mesh.conversion.convert() are used to convert a +dataset describing cell locations, vertex locations, and connectivity between +cells and vertices into a valid MPAS mesh following the MPAS mesh specification.

+

Example call to the command-line tool:

+
$ planar_hex --nx 4 --ny 4 --dc 10e3 -o base_mesh.nc
+$ MpasMeshConverter.x base_mesh.nc mesh.nc
+
+
+

This example uses the planar_hex tool to generate a small, doubly periodic +MPAS mesh with 10-km cells, then uses the MPAS mesh converter to make sure the +resulting mesh adheres to the mesh specification. MpasMeshConverter.x takes +two arguments, the input and output mesh files, and will prompt the user for +file names if these arguments are not supplied.

+

The same example in a python script can be accomplished with:

+
from mpas_tools.planar_hex import make_planar_hex_mesh
+from mpas_tools.mesh.conversion import convert
+from mpas_tools.io import write_netcdf
+
+ds = make_planar_hex_mesh(nx=4, ny=4, dc=10e3, nonperiodic_x=False,
+                          nonperiodic_y=False)
+ds = convert(ds)
+write_netcdf(ds, 'mesh.nc')
+
+
+

Regardless of which of these methods is used, the input mesh must define the +following dimensions, variables and global attributes (not the dimension sizes +are merely examples from the mesh generated in the previous examples):

+
netcdf mesh {
+dimensions:
+  nCells = 16 ;
+  nVertices = 32 ;
+  vertexDegree = 3 ;
+variables:
+  double xCell(nCells) ;
+  double yCell(nCells) ;
+  double zCell(nCells) ;
+  double xVertex(nVertices) ;
+  double yVertex(nVertices) ;
+  double zVertex(nVertices) ;
+  int cellsOnVertex(nVertices, vertexDegree) ;
+  double meshDensity(nCells) ;
+
+// global attributes:
+      :on_a_sphere = "NO" ;
+      :sphere_radius = 0. ;
+      :is_periodic = "YES" ;
+
+
+

The variable meshDensity is required for historical reasons and is passed +unchanged to the resulting mesh. It can contain all ones (or zeros), the +resolution of the mesh in kilometers, or whatever field the user wishes.

+

The following global attributes are optional but will be passed on to the +resulting mesh:

+
// global attributes:
+      :x_period = 40000. ;
+      :y_period = 34641.0161513775 ;
+      :history = "Tue May 26 20:58:10 2020: /home/xylar/miniconda3/envs/mpas/bin/planar_hex --nx 4 --ny 4 --dc 10e3 -o base_mesh.nc" ;
+
+
+

The file_id global attribute is also optional and is preserved in the +resulting mesh as parent_id. A new file_id (a random hash tag) is +generated by the mesh converter.

+

The resulting dataset has all the dimensions and variables required for an MPAS +mesh.

+

The mesh converter also generates a file called graph.info that is used to +create graph partitions from tools like Metis. This file is not stored by +default when the python cull function is used but can be specified with +the graphInfoFileName argument. The python function also takes a logger +that can be used to capture the output that would otherwise go to the screen +via stdout and stderr.

+
+
+

Cell Culler

+

The command-line tool MpasCellCuller.x and the corresponding wrapper +function mpas_tools.mesh.conversion.cull() are used to cull cells from +a mesh based on the cullCell field in the input dataset and/or the provided +masks. The contents of the cullCell field is merge with the mask(s) from a +masking dataset and the inverse of the mask(s) from an inverse-masking dataset. +Then, a preserve-masking dataset is used to determine where cells should not +be culled.

+

Example call to the command-line tool, assuming you start with a spherical mesh +called base_mesh.nc (not the doubly periodic planar mesh from the examples +above):

+
$ merge_features -c natural_earth -b region -n "Land Coverage" -o land.geojson
+$ MpasMaskCreator.x base_mesh.nc land.nc -f land.geojson
+$ MpasCellCuller.x base_mesh.nc culled_mesh.nc -m land.nc
+
+
+

This example uses the merge_features tool from the geometric_features +conda package to get a geojson file containing land coverage. Then, it uses +the mask creator (see the next section) to create a mask on the MPAS mesh that +is one inside this region and zero outside. Finally, it culls the base mesh +to only those cells where the mask is zero (i.e. the mask indicates which cells +are to be removed).

+

The same example in a python script can be accomplished with:

+
import xarray
+from geometric_features import GeometricFeatures
+from mpas_tools.mesh.conversion import mask, cull
+
+gf = GeometricFeatures()
+
+fcLandCoverage = gf.read(componentName='natural_earth', objectType='region',
+                         featureNames=['Land Coverage'])
+
+dsBaseMesh = xarray.open_dataset('base_mesh.nc')
+dsLandMask = mask(dsBaseMesh, fcMask=fcLandCoverage)
+dsCulledMesh = conversion.cull(dsBaseMesh, dsMask=dsLandMask)
+write_netcdf(dsCulledMesh, 'culled_mesh.nc')
+
+
+

Here is the full usage of MpasCellCuller.x:

+
MpasCellCuller.x [input_name] [output_name] [[-m/-i/-p] masks_name] [-c]
+
+    input_name:
+        This argument specifies the input MPAS mesh.
+    output_name:
+        This argument specifies the output culled MPAS mesh.
+        If not specified, it defaults to culled_mesh.nc, but
+        it is required if additional arguments are specified.
+    -m/-i/-p:
+        These arguments control how a set of masks is used when
+        culling a mesh.
+        The -m argument applies a mask to cull based on (i.e.
+        where the mask is 1, the mesh will be culled).
+        The -i argument applies the inverse mask to cull based
+        on (i.e. where the mask is 0, the mesh will be
+        culled).
+        The -p argument forces any marked cells to not be
+        culled.
+        If this argument is specified, the masks_name argument
+        is required
+    -c:
+        Output the mapping from old to new mesh (cellMap) in
+            cellMapForward.txt,
+        and output the reverse mapping from new to old mesh in
+            cellMapBackward.txt.
+
+
+
+
+

Mask Creator

+

The command-line tool MpasMaskCreator.x and the corresponding wrapper +function mpas_tools.mesh.conversion.mask() are used to create a set of +region masks either from mask features or from seed points to be used to flood +fill a contiguous block of cells.

+

Examples usage of the mask creator can be found above under the Cell Culler.

+

Here is the full usage of MpasMaskCreator.x:

+
MpasMaskCreator.x in_file out_file [ [-f/-s] file.geojson ] [--positive_lon]
+    in_file: This argument defines the input file that masks will be created for.
+    out_file: This argument defines the file that masks will be written to.
+    -s file.geojson: This argument pair defines a set of points (from the geojson point definition)
+        that will be used as seed points in a flood fill algorithim. This is useful when trying to remove isolated cells from a mesh.
+    -f file.geojson: This argument pair defines a set of geojson features (regions, transects, or points)
+        that will be converted into masks / lists.
+    --positive_lon: It is unlikely that you want this argument.  In rare cases when using a non-standard geojson
+        file where the logitude ranges from 0 to 360 degrees (with the prime meridian at 0 degrees), use this flag.
+        If this flag is not set, the logitude range is -180-180 with 0 degrees being the prime meridian, which is the
+        case for standar geojson files including all features from the geometric_feature repo.
+        The fact that longitudes in the input MPAS mesh range from 0 to 360 is not relevant to this flag,
+        as latitude and longitude are recomputed internally from Cartesian coordinates.
+        Whether this flag is passed in or not, any longitudes written are in the 0-360 range.
+
+
+
+
+

Mask Creation with Python Multiprocessing

+

The Mask Creator is a serial code, and the algorithms it uses to find points in +a region or cells, edges and vertices along a transect are not particularly +efficient or sophisticated.

+

To provide better efficiency and to enable more sophisticated algorithms (now +and in the future), a set of related python functions has been developed to +provide much (but not all) of the functionality of the C++ Mask Creator +described above.

+
+

Computing MPAS Region Masks

+

The function mpas_tools.mesh.mask.compute_mpas_region_masks() +or the compute_mpas_region_masks command-line tool can +be used to create region masks on cells, edges and/or vertices given an MPAS +mesh xarray.Dataset dsMesh and a +geometric_features.FeatureCollection fcMask containing regions. +The resulting masks, in the variable regionCellMasks, are 1 where the center +of the polygon corresponding to the cell, edge or vertex (see the +MPAS Mesh Specification) +are inside the given region and 0 where they are outside. This function is +far more useful if the user provides a multiprocessing.Pool in the +pool argument. pool should be created at the beginning of the calling +code (when memory usage is small), possibly with +mpas_tools.parallel.create_pool(), and terminated +(multiprocessing.Pool.terminate()) before the code has finished. +The same pool can be used in multiple calls to this and the other Python-based +masking functions. If pool = None (the default), the masks are computed in +serial, which will likely be frustratingly slow.

+

The chunkSize argument can be used to control how much work (how many cells, +edges or vertices) each process computes on at one time. A very small +chunkSize will incur a high overhead, while a very large chunkSize will +lead to poor load balancing and infrequent progress updates (if +showProgress = True). The default chunkSize of 1000 seems to perform +well across a wide variety of mesh sizes and processor counts.

+

It is a good idea to provide a logger (see Logging) to get some +output as the mask creation is progressing.

+

For efficiency, large shapes (e.g. the global coastline) are divided into +smaller “tiles”. This subdivision is controlled with subdivisionThreshold, +which should be set to a minimum size in degrees (latitude or longitude). If +a shape is larger than this, it will be divided into tiles. The underlying +algorithm first check bounding boxes of the resulting shapes against points +before performing the more time-consuming step of determining if the point is +inside the shape. The default value of 30 degrees performs much better than +no subdivision for large shapes (again, such as the global coastline), but +alternative values have not yet been explored.

+

The resulting variables are:

+
+
    +
  • regionCellMasks(nCells, nRegions) - a cell mask (1 for inside and 0 for +outside the region) for each region

  • +
  • regionEdgeMasks(nEdges, nRegions) - an edge mask for each region

  • +
  • regionVertexMasks(nVertices, nRegions) - a vertex mask for each region

  • +
  • regionNames(nRegions, string64) - the names of the regions

  • +
+
+

NetCDF fill values are used for invalid mask values, so nCellsInRegion, +etc. are not produced.

+

The command-line tool takes the following arguments:

+
$ compute_mpas_region_masks --help
+usage: compute_mpas_region_masks [-h] -m MESH_FILE_NAME -g GEOJSON_FILE_NAME
+                                 -o MASK_FILE_NAME
+                                 [-t MASK_TYPES [MASK_TYPES ...]]
+                                 [-c CHUNK_SIZE] [--show_progress]
+                                 [-s SUBDIVISION]
+                                 [--process_count PROCESS_COUNT]
+                                 [--multiprocessing_method MULTIPROCESSING_METHOD]
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -m MESH_FILE_NAME, --mesh_file_name MESH_FILE_NAME
+                        An MPAS mesh file
+  -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME
+                        An Geojson file containing mask regions
+  -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME
+                        An output MPAS region masks file
+  -t MASK_TYPES [MASK_TYPES ...], --mask_types MASK_TYPES [MASK_TYPES ...]
+                        Which type(s) of masks to make: cell, edge or vertex.
+                        Default is cell and vertex.
+  -c CHUNK_SIZE, --chunk_size CHUNK_SIZE
+                        The number of cells, vertices or edges that are
+                        processed in one operation
+  --show_progress       Whether to show a progress bar
+  -s SUBDIVISION, --subdivision SUBDIVISION
+                        A threshold in degrees (lon or lat) above which the
+                        mask region will be subdivided into smaller polygons
+                        for faster intersection checking
+  --process_count PROCESS_COUNT
+                        The number of processes to use to compute masks. The
+                        default is to use all available cores
+  --multiprocessing_method MULTIPROCESSING_METHOD
+                        The multiprocessing method use for python mask
+                        creation ('fork', 'spawn' or 'forkserver')
+
+
+
+
+

Computing Transect Masks

+

The function mpas_tools.mesh.mask.compute_mpas_transect_masks() +and the compute_mpas_transect_masks command-line tool +are similar to the function for computing region masks. The function takes a +geometric_features.FeatureCollection fcMask that is made up of +transects, rather than regions. One mask is produced for each feature in the +collection, indicating where the transect +intersects the cell, edge or vertex polygons (see the +MPAS Mesh Specification).

+

The arguments logger, pool, chunkSize and showProgress are the +same as for region-mask creation above.

+

The argument subdivisionResolution is a length in meters, above which +segments of the transect are subdivided to provide a better representation of +the spherical path in longitude/latitude space. The default value of 10 km is +typically good enough to capture distortion at typical MPAS mesh resolutions.

+

The algorithm perform intersections in longitude/latitude space using the +shapely library. Because shapely is designed for 2D shapes in a +Cartesian plane, it is not designed for spherical coordinates. Care has been +taken to handle periodicity at the dateline (antimeridian) but there may be +issues with MPAS mesh polygons containing the north or south pole. If a user +needs to handle a transect that is very close to the pole, it is likely worth +contacting the developers to request modifications to the code to support this +case.

+

The resulting variables are:

+
+
    +
  • transectCellMasks(nCells, nTransects) - a cell mask (1 if the transect +intersects the cell and 0 if not) for each transect

  • +
  • transectEdgeMasks(nEdges, nTransects) - an edge mask for each transect

  • +
  • transectVertexMasks(nVertices, nTransects) - a vertex mask for each +transect

  • +
  • transectNames(nTransects, string64) - the names of the transects

  • +
+
+

We don’t currently provide cell, edge or vertex indices (e.g. +transectCellGlobalIDs) for path along a transect. This is, in part, +because the algorithm doesn’t keep track of the relative order of points along +a transect. This could be updated in the future if there is sufficient demand.

+

The edge sign (transectEdgeMaskSigns) is computed only if +addEdgeSign=True, since this takes extra time to compute and isn’t always +needed.

+
+

Note

+

While the default subdivisionResolution is 10 km for +mpas_tools.mesh.mask.compute_mpas_transect_masks(), the default +behavior in the command-line tool compute_mpas_transect_masks is no +subdivision because there is otherwise not a good way to specify at the +command line that no subdivision is desired. Typically, users will want +to request subdivision with something like -s 10e3

+
+

The command-line tool takes the following arguments:

+
$ compute_mpas_transect_masks --help
+usage: compute_mpas_transect_masks [-h] -m MESH_FILE_NAME -g GEOJSON_FILE_NAME
+                                   -o MASK_FILE_NAME
+                                   [-t MASK_TYPES [MASK_TYPES ...]]
+                                   [-c CHUNK_SIZE] [--show_progress]
+                                   [-s SUBDIVISION]
+                                   [--process_count PROCESS_COUNT]
+                                   [--multiprocessing_method MULTIPROCESSING_METHOD]
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -m MESH_FILE_NAME, --mesh_file_name MESH_FILE_NAME
+                        An MPAS mesh file
+  -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME
+                        An Geojson file containing transects
+  -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME
+                        An output MPAS transect masks file
+  -t MASK_TYPES [MASK_TYPES ...], --mask_types MASK_TYPES [MASK_TYPES ...]
+                        Which type(s) of masks to make: cell, edge or vertex.
+                        Default is cell, edge and vertex.
+  -c CHUNK_SIZE, --chunk_size CHUNK_SIZE
+                        The number of cells, vertices or edges that are
+                        processed in one operation
+  --show_progress       Whether to show a progress bar
+  -s SUBDIVISION, --subdivision SUBDIVISION
+                        The maximum resolution (in meters) of segments in a
+                        transect. If a transect is too coarse, it will be
+                        subdivided. Default is no subdivision.
+  --process_count PROCESS_COUNT
+                        The number of processes to use to compute masks. The
+                        default is to use all available cores
+  --multiprocessing_method MULTIPROCESSING_METHOD
+                        The multiprocessing method use for python mask
+                        creation ('fork', 'spawn' or 'forkserver')
+  --add_edge_sign       Whether to add the transectEdgeMaskSigns variable
+
+
+
+
+

Computing a Flood-fill Mask

+

The function mpas_tools.mesh.mask.compute_mpas_flood_fill_mask() +and the command-line tool compute_mpas_flood_fill_mask +fill in a mask, starting with the ocean points closest to the seed points +given in geometric_features.FeatureCollection fcSeed. This +algorithm runs in serial, and will be more efficient the more seed points +are provided and the more widely scattered over the ocean they are.

+

The resulting dataset contains a single variable:

+
+
    +
  • cellSeedMask(nCells) - a cell mask that is 1 where the flood fill +(following cellsOnCell) propagated starting from the seed points and 0 +elsewhere

  • +
+
+

The command-line tool takes the following arguments:

+
$ compute_mpas_flood_fill_mask --help
+usage: compute_mpas_flood_fill_mask [-h] -m MESH_FILE_NAME -g
+                                    GEOJSON_FILE_NAME -o MASK_FILE_NAME
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -m MESH_FILE_NAME, --mesh_file_name MESH_FILE_NAME
+                        An MPAS mesh file
+  -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME
+                        An Geojson file containing points at which to start
+                        the flood fill
+  -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME
+                        An output MPAS region masks file
+
+
+
+
+

Computing Lon/Lat Region Masks

+

The function mpas_tools.mesh.mask.compute_lon_lat_region_masks() +or the compute_lon_lat_region_masks command-line tool compute region masks +on a longitude/latitude grid but are otherwise functionally very similar to +the corresponding tools for compute MPAS region masks. The major difference is +that 1D arrays of longitude and latitude are provided instead of an MPAS mesh +dataset. There is no argument equivalent to the mask type for MPAS meshes. +Instead, mask values are given at each point on the 2D longitude/latitude grid. +All other arguments serve the same purpose as for the MPAS region mask creation +described above.

+

The command-line tool takes the following arguments:

+
$ compute_lon_lat_region_masks --help
+usage: compute_lon_lat_region_masks [-h] -i GRID_FILE_NAME [--lon LON]
+                                    [--lat LAT] -g GEOJSON_FILE_NAME -o
+                                    MASK_FILE_NAME [-c CHUNK_SIZE]
+                                    [--show_progress] [-s SUBDIVISION]
+                                    [--process_count PROCESS_COUNT]
+                                    [--multiprocessing_method MULTIPROCESSING_METHOD]
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -i GRID_FILE_NAME, --grid_file_name GRID_FILE_NAME
+                        An input lon/lat grid file
+  --lon LON             The name of the longitude coordinate
+  --lat LAT             The name of the latitude coordinate
+  -g GEOJSON_FILE_NAME, --geojson_file_name GEOJSON_FILE_NAME
+                        An Geojson file containing mask regions
+  -o MASK_FILE_NAME, --mask_file_name MASK_FILE_NAME
+                        An output MPAS region masks file
+  -c CHUNK_SIZE, --chunk_size CHUNK_SIZE
+                        The number of grid points that are processed in one
+                        operation
+  --show_progress       Whether to show a progress bar
+  -s SUBDIVISION, --subdivision SUBDIVISION
+                        A threshold in degrees (lon or lat) above which the
+                        mask region will be subdivided into smaller polygons
+                        for faster intersection checking
+  --process_count PROCESS_COUNT
+                        The number of processes to use to compute masks. The
+                        default is to use all available cores
+  --multiprocessing_method MULTIPROCESSING_METHOD
+                        The multiprocessing method use for python mask
+                        creation ('fork', 'spawn' or 'forkserver')
+
+
+
+
+
+

Merging and Splitting

+

In order to support running +MPAS-Albany Land Ice (MALI) +with both Greenland and Antarctica at the same time, tools have been added to +support merging and splitting MPAS meshes.

+

Merging two meshes can be accomplished with +mpas_tools.merge_grids.merge_grids():

+
from mpas_tools.translate import translate
+from mpas_tools.merge_grids import merge_grids
+from mpas_tools.planar_hex import make_planar_hex_mesh
+from mpas_tools.io import write_netcdf
+
+
+dsMesh1 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True,
+                               nonperiodic_y=True)
+
+dsMesh2 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True,
+                               nonperiodic_y=True)
+
+translate(dsMesh2, xOffset=20000., yOffset=0.)
+
+write_netcdf(dsMesh1, 'mesh1.nc')
+write_netcdf(dsMesh2, 'mesh2.nc')
+
+merge_grids(infile1='mesh1.nc', infile2='mesh2.nc',
+            outfile='merged_mesh.nc')
+
+
+

Typically, it will only make sense to merge non-periodic meshes in this way.

+

Later, perhaps during analysis or visualization, it can be useful to split +apart the merged meshes. This can be done with +mpas_tools.split_grids.split_grids()

+
from mpas_tools.translate import translate
+from mpas_tools.split_grids import split_grids
+from mpas_tools.planar_hex import make_planar_hex_mesh
+from mpas_tools.io import write_netcdf
+
+
+dsMesh1 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True,
+                               nonperiodic_y=True)
+
+dsMesh2 = make_planar_hex_mesh(nx=10, ny=10, dc=1000., nonperiodic_x=True,
+                               nonperiodic_y=True)
+
+translate(dsMesh2, xOffset=20000., yOffset=0.)
+
+write_netcdf(dsMesh1, 'mesh1.nc')
+write_netcdf(dsMesh2, 'mesh2.nc')
+
+
+split_grids(infile='merged_mesh.nc', outfile1='split_mesh1.nc',
+            outfile='split_mesh2.nc')
+
+
+

Merging meshes can also be accomplished with the merge_grids command-line +tool:

+
$ merge_grids --help
+
+usage: merge_grids [-h] [-o FILENAME] FILENAME1 FILENAME2
+
+Tool to merge 2 MPAS non-contiguous meshes together into a single file
+
+positional arguments:
+  FILENAME1    File name for first mesh to merge
+  FILENAME2    File name for second mesh to merge
+
+optional arguments:
+  -h, --help   show this help message and exit
+  -o FILENAME  The merged mesh file
+
+
+

Similarly, split_grids can be used to to split meshes:

+
$ split_grids --help
+
+usage: split_grids [-h] [-1 FILENAME] [-2 FILENAME] [--nCells NCELLS]
+                   [--nEdges NEDGES] [--nVertices NVERTICES]
+                   [--maxEdges MAXEDGES1 MAXEDGES2]
+                   MESHFILE
+
+Tool to split 2 previously merged MPAS non-contiguous meshes into separate files.
+Typical usage is:
+    split_grids.py -1 outfile1.nc -2 outfile2.nc infile
+The optional arguments for nCells, nEdges, nVertices, and maxEdges should
+generally not be required as this information is saved in the combined mesh file
+as global attributes by the merge_grids.py script.
+
+positional arguments:
+  MESHFILE              Mesh file to split
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -1 FILENAME, --outfile1 FILENAME
+                        File name for first mesh output
+                        (default: mesh1.nc)
+  -2 FILENAME, --outfile2 FILENAME
+                        File name for second mesh output
+                        (default: mesh2.nc)
+  --nCells NCELLS       The number of cells in the first mesh
+                        (default: the value specified in MESHFILE global attribute merge_point)
+  --nEdges NEDGES       The number of edges in the first mesh
+                        (default: the value specified in MESHFILE global attribute merge_point)
+  --nVertices NVERTICES
+                        The number of vertices in the first mesh
+                        (default: the value specified in MESHFILE global attribute merge_point)
+  --maxEdges MAXEDGES1 MAXEDGES2
+                        The number of maxEdges in each mesh
+                        (default: the value specified in MESHFILE global attribute merge_point
+                              OR: will use MESHFILE maxEdges dimension and assume same for both)
+
+
+
+
+

Translation

+

A planar mesh can be translated in x, y or both by calling +mpas_tools.translate.translate():

+
from mpas_tools.translate import translate
+from mpas_tools.planar_hex import make_planar_hex_mesh
+
+dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False,
+                              nonperiodic_y=False)
+
+translate(dsMesh, xOffset=1000., yOffset=2000.)
+
+
+

This creates a periodic, planar mesh and then translates it by 1 km in x and +2 km in y.

+
+

Note

+

All the functions in the mpas_tools.translate module modify the mesh +inplace, rather than returning a new xarray.Dataset object. This is +in contrast to typical xarray functions and methods.

+
+

A mesh can be translated so that its center is at x = 0., y = 0. with +the function mpas_tools.translate.center():

+
from mpas_tools.translate import center
+from mpas_tools.planar_hex import make_planar_hex_mesh
+
+dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False,
+                              nonperiodic_y=False)
+
+center(dsMesh)
+
+
+

A mesh can be translated so its center matches the center of another mesh by +using mpas_tools.translate.center_on_mesh():

+
from mpas_tools.translate import center_on_mesh
+from mpas_tools.planar_hex import make_planar_hex_mesh
+
+dsMesh1 = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False,
+                               nonperiodic_y=False)
+
+dsMesh2 = make_planar_hex_mesh(nx=20, ny=40, dc=2000., nonperiodic_x=False,
+                               nonperiodic_y=False)
+
+center_on_mesh(dsMesh2, dsMesh1)
+
+
+

In this example, the coordinates of dsMesh2 are altered so its center +matches that of dsMesh1.

+

The functionality of all three of these functions is also available via the +translate_planar_grid command-line tool:

+
$ translate_planar_grid --help
+
+== Gathering information.  (Invoke with --help for more details. All arguments are optional)
+Usage: translate_planar_grid [options]
+
+This script translates the coordinate system of the planar MPAS mesh specified
+with the -f flag.  There are 3 possible methods to choose from: 1) shift the
+origin to the center of the domain 2) arbirary shift in x and/or y 3) shift to
+the center of the domain described in a separate file
+
+Options:
+  -h, --help            show this help message and exit
+  -f FILENAME, --file=FILENAME
+                        MPAS planar grid file name. [default: grid.nc]
+  -d FILENAME, --datafile=FILENAME
+                        data file name to which to match the domain center of.
+                        Uses xCell,yCell or, if those fields do not exist,
+                        will secondly try x1,y1 fields.
+  -x SHIFT_VALUE        user-specified shift in the x-direction. [default:
+                        0.0]
+  -y SHIFT_VALUE        user-specified shift in the y-direction. [default:
+                        0.0]
+  -c                    shift so origin is at center of domain [default:
+                        False]
+
+
+
+
+

Converting Between Mesh Formats

+
+

MSH to MPAS NetCDF

+

jigsawpy produces meshes in .msh format that need to be converted to +NetCDF files for use by MPAS +components. A utility function +mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf() or the +command-line utility jigsaw_to_netcdf are used for this purpose.

+

In addition to the input .msh and output .nc files, the user must +specify whether this is a spherical or planar mesh and, if it is spherical, +provide the radius of the Earth in meters.

+
+
+

Triangle to MPAS NetCDF

+

Meshes in Triangle format +can be converted to MPAS NetCDF format using +mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf() or +the triangle_to_netcdf command-line tool.

+

The user supplies the names of input .node and .ele files and the +name of an output MPAS mesh file.

+
+
+

MPAS NetCDF to Triangle

+

MPAS meshes in NetCDF format can be converted to Triangle format using +mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle() or +the mpas_to_triangle command-line tool.

+

The user supplies the name of an input MPAS mesh file and the output prefix +for the resulting Triangle .node and .ele files.

+
+
+

MPAS NetCDF to SCRIP

+

The function mpas_tools.scrip.from_mpas.scrip_from_mpas() can be +used to convert an MPAS mesh file in NetCDF format to +SCRIP +format. SCRIP files are typically used to create mapping files used to +interpolate between meshes.

+

A command-line tools is also available for this purpose:

+
$ scrip_from_mpas --help
+== Gathering information.  (Invoke with --help for more details. All arguments are optional)
+Usage: scrip_from_mpas [options]
+
+This script takes an MPAS grid file and generates a SCRIP grid file.
+
+Options:
+  -h, --help            show this help message and exit
+  -m FILENAME, --mpas=FILENAME
+                        MPAS grid file name used as input. [default: grid.nc]
+  -s FILENAME, --scrip=FILENAME
+                        SCRIP grid file to output. [default: scrip.nc]
+  -l, --landice         If flag is on, landice masks will be computed and
+                        used.
+
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/mesh_creation.html b/0.22.0rc4/mesh_creation.html new file mode 100644 index 000000000..fad8e733c --- /dev/null +++ b/0.22.0rc4/mesh_creation.html @@ -0,0 +1,583 @@ + + + + + + + Mesh Creation — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Mesh Creation

+
+

Uniform, Planar Meshes

+

The most basic tool for creating an MPAS mesh is the function +mpas_tools.planar_hex.make_planar_hex_mesh() or the associated +command-line tool planar_hex. These tools create a uniform, planar mesh +of hexagons that may optionally be periodic in either or both of the x and +y directions. A typical call to make_planar_hex_mesh() might look like +the following:

+
from mpas_tools.planar_hex import make_planar_hex_mesh
+
+dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=False,
+                              nonperiodic_y=False)
+
+
+

This creates a periodic mesh in both x and y that is 10 grid cells by 20 grid +cells in size with 1-km resolution. The mesh is not save to a file in this +example but is instead returned as an xarray.Dataset object.

+

The command-line approach for generating the same mesh would be:

+
$ planar_hex --nx=10 --ny=20 --dc=1000. \
+     --outFileName=periodic_mesh_10x20_1km.nc
+
+
+

In this case, the resulting mesh is written to a file.

+

The default is to make a periodic mesh (awkwardly, it’s “not non-periodic”). If +you want a mesh that is not periodic in one or both directions, you first need +to create a mesh and then cull the cells along the periodic boundary. It +doesn’t hurt to run the mesh converter as well, just to be sure the mesh +conforms correctly to the MPAS mesh specification:

+
from mpas_tools.planar_hex import make_planar_hex_mesh
+from mpas_tools.mesh.conversion import cull, convert
+
+dsMesh = make_planar_hex_mesh(nx=10, ny=20, dc=1000., nonperiodic_x=True,
+                              nonperiodic_y=True)
+
+dsMesh = cull(dsMesh)
+dsMesh = convert(dsMesh)
+
+
+

On the command line, this looks like:

+
$ planar_hex --nx=10 --ny=20 --dc=1000. --npx --npy \
+     --outFileName=mesh_to_cull.nc
+
+$ MpasCellCuller.x mesh_to_cull.nc culled_mesh.nc
+
+$ MpasMeshConverter.x culled_mesh.nc nonperiodic_mesh_10x20_1km.nc
+
+
+
+
+

Building a JIGSAW Mesh

+

The mpas_tools.mesh.creation.build_mesh module is used +create an MPAS mesh using the JIGSAW +and JIGSAW-Python (jigsawpy) +packages.

+
+

Spherical Meshes

+

Spherical meshes are constructed with the function +mpas_tools.mesh.creation.build_mesh.build_spherical_mesh(). +The user provides a 2D array cellWidth of cell sizes in kilometers along +1D arrays for the longitude and latitude (the cell widths must be on a lon/lat +tensor grid) and the radius of the earth in meters.

+

The result is an MPAS mesh file, called base_mesh.nc by default, as well as +several intermediate files: mesh.log, mesh-HFUN.msh, mesh.jig, +mesh-MESH.msh, mesh.msh, and mesh_triangles.nc.

+

Here is a simple example script for creating a uniform MPAS mesh with 240-km +resolution:

+
#!/usr/bin/env python
+import numpy as np
+from mpas_tools.ocean import build_spherical_mesh
+
+
+def cellWidthVsLatLon():
+    """
+    Create cell width array for this mesh on a regular latitude-longitude grid.
+    Returns
+    -------
+    cellWidth : ndarray
+        m x n array of cell width in km
+    lon : ndarray
+        longitude in degrees (length n and between -180 and 180)
+    lat : ndarray
+        longitude in degrees (length m and between -90 and 90)
+    """
+    dlat = 10
+    dlon = 10
+    constantCellWidth = 240
+
+    nlat = int(180/dlat) + 1
+    nlon = int(360/dlon) + 1
+
+    lat = np.linspace(-90., 90., nlat)
+    lon = np.linspace(-180., 180., nlon)
+
+    cellWidth = constantCellWidth * np.ones((lat.size, lon.size))
+    return cellWidth, lon, lat
+
+
+def main():
+    cellWidth, lon, lat = cellWidthVsLatLon()
+    build_spherical_mesh(cellWidth, lon, lat, out_filename='base_mesh.nc')
+
+
+if __name__ == '__main__':
+    main()
+
+
+

We define the resolution on a coarse (10 degree by 10 degree) grid because it +is uniform. Meshes with more complex variation may require higher resolution +grids to cell widths.

+
+
+

Planar Meshes

+

Planar meshes can be constructed with the function +mpas_tools.mesh.creation.build_mesh.build_planar_mesh(). Provide +this function with a 2D array cellWidth of cell sizes in kilometers and +1D arrays for x and y (the cell widths must be on a 2D tensor grid). Planar +meshes also require geom_points, a list of point coordinates for bounding +polygon for the planar mesh, and geom_edges, a list of edges between points +in geom_points that define the bounding polygon.

+

As for spehrical meshes, the result is an MPAS mesh file, called +base_mesh.nc by default, as well as several intermediate files: +mesh.log, mesh-HFUN.msh, mesh.jig, mesh-MESH.msh, mesh.msh, +and mesh_triangles.nc.

+
+
+

JIGSAW Driver

+

Underlying both spherical and planar mesh creation is the JIGSAW driver +function mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver(). This +function is used to setup data structures and then build a JIGSAW mesh using +jigsawpy.

+
+
+
+

Mesh Definition Tools

+

The mpas_tools.mesh.creation.mesh_definition_tools module includes +several tools for defining the cellWidth variable.

+
+

Merging Cell Widths

+

The function +mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat() +is used to combine two cell-width distributions that are functions of latitude +only and which asymptote to different constant values north and south of a given +transition latitude with a tanh function of a given characteristic width.

+

For example, the following code snippet will produce cell widths as a function +of latitude of about 30 km south of the Arctic Circle and 10 km north of that +latitude, transitioning over a characteristic “distance” of about 5 degrees.

+
import numpy
+from mpas_tools.mesh.creation.mesh_definition_tools import \
+    mergeCellWidthVsLat
+
+
+lat = numpy.linspace(-90., 90., 181)
+cellWidthInSouth = 30.
+cellWidthInNorth = 10.
+latTransition = 66.5
+latWidthTransition = 5.
+
+cellWidths = mergeCellWidthVsLat(lat, cellWidthInSouth, cellWidthInNorth,
+    latTransition, latWidthTransition)
+
+
+
+
+

Defining an Eddy-closure Mesh

+

One of the commonly used flavor of MPAS-Ocean and MPAS-Seaice meshes is designed +with relatively coarse resolution in mind (requiring parameterization of ocean +eddies with an “eddy closure”). This flavor of mesh has resolution that is +purely a function of latitude, with 5 regions of relatively uniform resolution +(north polar, northern mid-latitudes, equatorial, southern mid-latitudes and +south polar) with smooth (tanh) transitions between these resolutions.

+

The default EC mesh has resolutions of 35 km at the poles, 60 km at +mid-latitudes and 30 km at the equator. Transitions between equatorial and +mid-latitude regions are at 15 degrees N/S latitude and transitions between +mid-latitude and polar regions are at 73 degrees N/S latitude. The +transition near the equator is somewhat more abrupt (~6 degrees) than near the +poles (~9 degrees). The switch between the transitional tanh functions is +made at 40 degrees N/S latitude, where the resolution is nearly constant and no +appreciable discontinuity arises. The default EC mesh can be obtained with the +function +mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat():

+
import numpy
+from mpas_tools.mesh.creation.mesh_definition_tools import \
+    EC_CellWidthVsLat
+
+lat = numpy.linspace(-90., 90., 181)
+cellWidths = EC_CellWidthVsLat(lat)
+
+
+
+
+

Defining a Rossby-radius Mesh

+

Another common flavor of MPAS-Ocean and MPAS-Seaice meshes is designed for +higher resolutions, where the Rossby radius of deformation can be (at least +partially) resolved. These meshes approximately scale their resolution in +proportion to the Rossby radius.

+

A typical Rossby Radius Scaling (RRS) mesh has a resolution at the poles that is +three times finer than the resolution at the equator. For example, the RRS mesh +used in E3SMv1 high resolution simulations would be defined, using the function +mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat() +by:

+
import numpy
+from mpas_tools.mesh.creation.mesh_definition_tools import \
+    RRS_CellWidthVsLat
+
+lat = numpy.linspace(-90., 90., 181)
+cellWidths = RRS_CellWidthVsLat(lat, cellWidthEq=18., cellWidthPole=6.)
+
+
+
+
+

Defining an Atlantic/Pacific Mesh

+

The function +mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid() +can be used to define a mesh that has two different, constant resolutions in the +Atlantic and Pacific Oceans.

+
+
+
+

Signed Distance Functions

+

The mpas_tools.mesh.creation.signed_distance module includes several +functions for creating cellWidth variables based on the signed distance from +a boundary curve on the sphere. A signed distance function is positive outside +the bounding shape and negative inside, with a value proportional to the +distance to the nearest point on the curve (so the function is equal to zero on +the curve). Signed distance functions provide a useful way ot define +transitions in resolution based on complex shapes that can be defined using +geojson files. These files can be created by hand, +e.g. at geojson.io or in python using libraries like +shapely.

+

Calls to the functions in this module require a +FeatureCollection +object from the +geometric_features +package. The FeatureColleciton must define one or more regions on the +sphere from which the distance, mask, or signed distance will be computed. +The FeatureColleciton could come from the predefined features included in +geometric_features, could be read in from a geojson file (see +Reading in Features), +or could be created as part of a python script with shapely or other tools.

+

In this example, we first define a base resolution using the default EC mesh +(see Defining an Eddy-closure Mesh) and then use +mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson() +to create a signed distance function from a FeatureCollection read in from +this geojson file. +The signed distance function is used to define a region of high resolution (12 +km) around Antarctica.

+
import numpy as np
+import mpas_tools.mesh.creation.mesh_definition_tools as mdt
+from mpas_tools.mesh.creation.signed_distance import \
+    signed_distance_from_geojson
+from geometric_features import read_feature_collection
+from mpas_tools.cime.constants import constants
+
+
+dlon = 0.1
+dlat = dlon
+earth_radius = constants['SHR_CONST_REARTH']
+nlon = int(360./dlon) + 1
+nlat = int(180./dlat) + 1
+lon = np.linspace(-180., 180., nlon)
+lat = np.linspace(-90., 90., nlat)
+
+cellWidth = mdt.EC_CellWidthVsLat(lat)
+
+# broadcast cellWidth to 2D
+_, cellWidth = np.meshgrid(lon, cellWidthVsLat)
+
+# now, add the high-res region
+fc = read_feature_collection('high_res_region.geojson')
+
+so_signed_distance = signed_distance_from_geojson(fc, lon, lat,
+                                                  earth_radius,
+                                                  max_length=0.25)
+
+# Equivalent to 20 degrees latitude
+trans_width = 1600e3
+trans_start = -500e3
+dx_min = 12.
+
+weights = 0.5 * (1 + np.tanh((so_signed_distance - trans_start) /
+                             trans_width))
+
+cellWidth = dx_min * (1 - weights) + cellWidth * weights
+
+
+

Sometimes it can be useful to extract just the mask of the region of interest +(defined as 0 outside the the region and 1 inside it) or the unsigned +distance. For these purposes, use the functions +mpas_tools.mesh.creation.signed_distance.mask_from_geojson() +and +mpas_tools.mesh.creation.signed_distance.distance_from_geojson(), +respectively.

+

The grid does not necessarily have to be uniform in resolution. Here is a +relatively complicated example where the highest resolution (1/100 degree) of +the lon/lat grid is concentrated within +/- 10 degrees of 0 degrees longitude +and 0 degrees latitude and the resolution is ~2 degrees elsewhere. The shape +test.geojson is given below, and is in the high-res region:

+
import numpy
+import matplotlib.pyplot as plt
+
+from geometric_features import read_feature_collection
+
+from mpas_tools.cime.constants import constants
+from mpas_tools.mesh.creation.signed_distance import \
+    distance_from_geojson, mask_from_geojson, signed_distance_from_geojson
+
+
+def gaussian(dcoarse, dfine, cmin, cmax, center, width, iter_count=10):
+    def get_res(xval):
+        res = dcoarse + \
+            (dfine - dcoarse) * numpy.exp(-(xval - center) ** 2 /
+                                          (2. * width**2))
+        return res
+
+    x = [cmin]
+    while x[-1] < cmax:
+        d = get_res(x[-1])
+        for index in range(iter_count):
+            x_mid = x[-1] + 0.5*d
+            d = get_res(x_mid)
+        x.append(x[-1] + d)
+
+    x = numpy.array(x)
+    factor = (cmax - cmin)/(x[-1] - x[0])
+    x = cmin + factor*(x - x[0])
+    return x
+
+
+def main():
+    dcoarse = 2.
+    dfine = 0.01
+    width = 10.
+
+    lon = gaussian(dcoarse=dcoarse, dfine=dfine, cmin=-180., cmax=180.,
+                   center=0., width=width)
+
+    lat = gaussian(dcoarse=dcoarse, dfine=dfine, cmin=-90., cmax=90.,
+                   center=0., width=width)
+
+    earth_radius = constants['SHR_CONST_REARTH']
+
+    fc = read_feature_collection('test.geojson')
+
+    distance = distance_from_geojson(fc, lon, lat, earth_radius,
+                                     max_length=dfine)
+
+    mask = mask_from_geojson(fc, lon, lat, max_length=dfine)
+
+    signed_distance = signed_distance_from_geojson(fc, lon, lat, earth_radius,
+                                                   max_length=dfine)
+
+
+

Here is test.geojson:

+
{
+  "type": "FeatureCollection",
+  "features": [
+    {
+      "type": "Feature",
+      "properties": {
+        "name": "weird shape",
+        "component": "ocean",
+        "object": "region",
+        "author": "Xylar Asay-Davis"
+      },
+      "geometry": {
+        "type": "Polygon",
+        "coordinates": [
+          [
+            [
+              3.8232421875000173,
+              3.283113991917228
+            ],
+            [
+              1.5600585937500142,
+              3.8752158957336085
+            ],
+            [
+              0.9448242187500171,
+              1.8453839885731744
+            ],
+            [
+              -0.3186035156249841,
+              0.8239462091017558
+            ],
+            [
+              0.6372070312500188,
+              -0.37353251022881745
+            ],
+            [
+              2.3181152343750147,
+              0.03295898255728466
+            ],
+            [
+              3.636474609375017,
+              -0.3405741662837591
+            ],
+            [
+              4.163818359375015,
+              1.5159363834516735
+            ],
+            [
+              2.9443359375000164,
+              1.9771465537125645
+            ],
+            [
+              3.8232421875000173,
+              3.283113991917228
+            ]
+          ]
+        ]
+      }
+    }
+  ]
+}
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/objects.inv b/0.22.0rc4/objects.inv new file mode 100644 index 000000000..ce6bfcf7a Binary files /dev/null and b/0.22.0rc4/objects.inv differ diff --git a/0.22.0rc4/ocean/coastal_tools.html b/0.22.0rc4/ocean/coastal_tools.html new file mode 100644 index 000000000..7f4ec88e1 --- /dev/null +++ b/0.22.0rc4/ocean/coastal_tools.html @@ -0,0 +1,482 @@ + + + + + + + Coastal Tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Coastal Tools

+

The mpas_tools.ocean.coastal_tools module contains several functions +that aid in the construction of meshes refined around coastlines.

+
+

Refining a Mesh

+

The main driver of coastal tools is the function +mpas_tools.ocean.coastal_tools.coastal_refined_mesh(). This function +is called repeatedly with different dictionaries of params to add refinement +in different locations, starting from a background mesh (see +Creating a Background Mesh).

+

coastal_tools provides the following dictionary of default parameters as +a starting point for params:

+
default_params = {
+
+    # Path to bathymetry data and name of file
+    "nc_file": "./earth_relief_15s.nc",
+    "nc_vars": ["lon","lat","z"],
+
+    # Bounding box of coastal refinement region
+    "region_box": Continental_US,
+    "origin": np.array([-100, 40]),
+    "restrict_box": Empty,
+
+    # Coastline extraction parameters
+    "z_contour": 0.0,
+    "n_longest": 10,
+    "smooth_coastline": 0,
+    "point_list": None,
+
+    # Global mesh parameters
+    "grd_box": Entire_Globe,
+    "ddeg": .1,
+    # 'EC' (defaults to 60to30), 'QU' (uses dx_max_global),
+    # 'RRS' (uses dx_max_global and dx_min_global)
+    "mesh_type": 'EC',
+    "dx_max_global": 30.0 * km,
+    "dx_min_global": 10.0 * km,
+
+    # Coastal mesh parameters
+    "dx_min_coastal": 10.0 * km,
+    "trans_width": 600.0 * km,
+    "trans_start": 400.0 * km,
+
+    # Bounding box of plotting region
+    "plot_box": North_America,
+
+    # Options
+    "nn_search": "kdtree",
+    "plot_option": True
+
+}
+
+
+

A coastal mesh is defined by:

+
    +
  1. Creating a Background Mesh

  2. +
  3. Extracting Coastlines

  4. +
  5. Computing Distance to Coast

  6. +
  7. Blending Cell Widths

  8. +
+

Steps 2-4 can be repeated with several different regions to add more refinement.

+

The first time coastal_refined_mesh() is called, no cell width, latitude or +longitude coordinates are supplied. In this case, a background mesh resolution +is defined through a call to +mpas_tools.ocean.coastal_tools.create_background_mesh(). The +following entries in params are used as arguments:

+
    +
  • 'grd_box' - the bounds of the grid defining the mesh resolution

  • +
  • 'ddeg' - the resolution in longitude and latitude in degrees

  • +
  • 'mesh_type' - one of {'QU', 'EC' or 'RRS'} indicating the +type of mesh

  • +
  • 'dx_min_global' - the resolution for a QU mesh, the minimum resolution +for an RRS mesh, ignored for EC meshes.

  • +
  • 'dx_max_global' - the maximum resolution for an RRS mesh, ignored for +QU and EC meshes.

  • +
  • 'plot_option' - whether to plot the results and save it to a PNG file.

  • +
  • 'plot_box' - If plot_option is True, the bounds of the plot in +longitude and latitude.

  • +
+

After the background field of cell widths has been created or using the +cell widths passed in as function arguments, coastal_refined_mesh() then +adds a region of refinement.

+

First, a set of coastline contours is extracted by calling +mpas_tools.ocean.coastal_tools.extract_coastlines() with the +following values from params:

+
    +
  • 'nc_file' - A bathymetry dataset on a lon/lat grid in NetCDF format

  • +
  • 'nc_vars' - The names of the lon, lat and bathymetry variables in a list

  • +
  • 'region_box' - see Regions

  • +
  • 'z_contour' - A contour level from the bathymetry dataset to extract as a +region boundary

  • +
  • 'n_longest' - The maximum number of contours to retain (sorted from +longest to shortest).

  • +
  • 'point_list' - An optional list of points to add to the coastline

  • +
  • 'plot_option' - Whether to plot the extracted coastline.

  • +
  • 'plot_box' - If plot_option is True, the bounds of the plot in +longitude and latitude.

  • +
+

Next, the distance to the coastal contours is computed using +mpas_tools.ocean.coastal_tools.distance_to_coast() with the +following values from params:

+
    +
  • 'nn_search' - currently, only the 'kdtree' algorithm is supported

  • +
  • 'smooth_coastline' - The number of neighboring cells along the coastline +over which to average locations to smooth the coastline

  • +
  • 'plot_option' - Whether to plot the distance function.

  • +
  • 'plot_box' - If plot_option is True, the bounds of the plot in +longitude and latitude.

  • +
+

Finally, the distance function is used to blend the background and refined +regions using +mpas_tools.ocean.coastal_tools.compute_cell_width() with the +following values from params:

+
    +
  • 'dx_min_coastal' - the resolution in meters of the refined region

  • +
  • 'trans_start' - the distance in meters from the coast at which the +transition in resolution begins—the center of the transition is half a +trans_width farther from the coastline

  • +
  • 'trans_width' - the distance in meters over which the transition occurs

  • +
  • 'restrict_box' - A region of made up of quadrilaterals to include and +exclude that defines where resolution may be altered. Outside of the +restrict_box, the resolution remains unchanged. See +Regions.

  • +
  • 'plot_option' - Whether to plot the cell widths and transition function.

  • +
  • 'plot_box' - If plot_option is True, the bounds of the plot in +longitude and latitude.

  • +
+

Here is an example of multiple calls to coastal_refined_mesh() in action, +taken from the +hurricane/USDEQU120at30cr10rr2 +test case from +COMPASS. +This workflow refines a background uniform mesh with 120-km resolution with +successively higher and higher resolution down to the Delaware Bay at 2-km +resolution.

+
import mpas_tools.ocean.coastal_tools as ct
+
+
+km = 1000.0
+
+params = ct.default_params
+
+print("****QU 120 background mesh and enhanced Atlantic (30km)****")
+params["mesh_type"] = "QU"
+params["dx_max_global"] = 120.0 * km
+params["region_box"] = ct.Atlantic
+params["restrict_box"] = ct.Atlantic_restrict
+params["plot_box"] = ct.Western_Atlantic
+params["dx_min_coastal"] = 30.0 * km
+params["trans_width"] = 5000.0 * km
+params["trans_start"] = 500.0 * km
+
+cell_width, lon, lat = ct.coastal_refined_mesh(params)
+
+print("****Northeast refinement (10km)***")
+params["region_box"] = ct.Delaware_Bay
+params["plot_box"] = ct.Western_Atlantic
+params["dx_min_coastal"] = 10.0 * km
+params["trans_width"] = 600.0 * km
+params["trans_start"] = 400.0 * km
+
+cell_width, lon, lat = ct.coastal_refined_mesh(
+    params, cell_width, lon, lat)
+
+print("****Delaware regional refinement (5km)****")
+params["region_box"] = ct.Delaware_Region
+params["plot_box"] = ct.Delaware
+params["dx_min_coastal"] = 5.0 * km
+params["trans_width"] = 175.0 * km
+params["trans_start"] = 75.0 * km
+
+cell_width, lon, lat = ct.coastal_refined_mesh(
+    params, cell_width, lon, lat)
+
+print("****Delaware Bay high-resolution (2km)****")
+params["region_box"] = ct.Delaware_Bay
+params["plot_box"] = ct.Delaware
+params["restrict_box"] = ct.Delaware_restrict
+params["dx_min_coastal"] = 2.0 * km
+params["trans_width"] = 100.0 * km
+params["trans_start"] = 17.0 * km
+
+cell_width, lon, lat = ct.coastal_refined_mesh(
+    params, cell_width, lon, lat)
+
+
+
+
+

Creating a Background Mesh

+

A background mesh is typically created by calling +mpas_tools.ocean.coastal_tools.coastal_refined_mesh() without +providing an input mesh but can also be created by calling +mpas_tools.ocean.coastal_tools.create_background_mesh() directly.

+

The user must define the bounds of the grid in longitude and latitude (typically +-180 to 180 and -90 to 90, respectively) and the resolution in degrees. The +mesh can be any of three types: {'QU', 'EC' or 'RRS'}. For +Quasi-Uniform (QU) meshes, the resulting cell width will be a constant equal to +dx_min_global. For Eddy-Closure (EC) meshes, the default parameters are +always used (see Defining an Eddy-closure Mesh). For Rossby-Radius Scaled (RRS) meshes, +dx_min_global is the resolution at the poles while dx_max_global is the +resolution at the equator (see Defining a Rossby-radius Mesh).

+
+
+

Extracting Coastlines

+

coastal_tools extracts points along a coastline using +mpas_tools.ocean.coastal_tools.extract_coastlines(). The default +parameters are set up to use the +earth_relief_15s.nc dataset, +but any bathymetry data set on a lon/lat grid could be used as long as +params['nc_file'] is modified to point to the new name of the dataset and +params['nc_vars'] is set to the appropriate variable names.

+

By default, the coastline is extracted using the z = 0.0 contour of the +bathyemtry but other values can be selected (e.g. to use distance from the +continental shelf break) by defining params['z_contour']. +By default, only the 10 longest contours are retained to reduce computational +cost but more (or fewer) contours can be retained by setting +params['n_longest'] to another number.

+

Optionally, the results can be plotted withing the given “plot box” and saved +to a file.

+
+
+

Computing Distance to Coast

+

A key ingredient in defining resolution in coastal meshes is a field containing +the distance from each location in the field to the nearest point on the +coastline. This distance field D is computed with +mpas_tools.ocean.coastal_tools.distance_to_coast() +The user could previouly control the search algorithm used via +params['nn_search'] but 'kdtree' is now the only option. +They can also decide to smooth the coastline as long as there is +a single coastline contour—with multiple contours, the current algorithm will +average the end of one contour with the start fo the next—by specifying an +integer number of neighbors as params['smooth_coastline']. The default is +no smoothing (0 neighbors).

+
+
+

Blending Cell Widths

+

The final step in each iteration of coastal refinement is to blend the new, +refined resolution into the previous grid of cell widths with the function +mpas_tools.ocean.coastal_tools.compute_cell_width().

+

The most important parameters to set are params['dx_min_coastal'], the +resolution in meters of the refined region; params['trans_start'], the +distance from the coast in meters where the transition in resolution should +start; and params['trans_width'], the width of the transition itself in +meters.

+

The resolution refinement can be confined to a region using +params['restrict_box'] to supply a region of made up of quadrilaterals to +include and exclude from the restricted region. include boxes +specify regions where the distance-based coastal refinement function should be +used to update the desired cell width values. exclude boxes eliminate areas +within the include regions so they are not affected by the coastal +refinement function. This is useful for preventing resolution from appearing on +one side of a narrow piece of land. For example, coastal refinement in the Gulf +of Mexico should not appear on the other Pacific Ocean side of Central America. +The params['restrict_box'] regions can be used to enforce this.

+

Here is an example of a restriction box for the region around Delaware, used in +the example above:

+
Delaware_restrict = {"include": [np.array([[-75.853, 39.732],
+                                           [-74.939, 36.678],
+                                           [-71.519, 40.156],
+                                           [-75.153, 40.077]]),
+                                 np.array([[-76.024, 37.188],
+                                           [-75.214, 36.756],
+                                           [-74.512, 37.925],
+                                           [-75.274, 38.318]])],
+                     "exclude": []}
+
+
+
+
+

Regions

+

Extracting Coastlines requires a set of bounding regions to be defined. +These regions are made up of a list of quadrilaterals to include and another +list to exclude. The quadrilaterals are either bounding rectangles +(min lon, max lon, min lat, max lat) or lists of 4 (lon, lat) points numbered +counter clockwise.

+

include boxes specify areas where coastline contours will be extracted from +the underlying bathymetry dataset. exclude boxes can be used to select +regions within include regions where coastline extraction should not be +done. For example, a large include box covering the U.S. East Coast may contain +small islands in the Atlantic, which may need to be ignored when placing coastal +refinement. In this case, exclude boxes can be specified to eliminate the +small coastlines.

+

An example of such a region is:

+
Greenland = {"include":[np.array([-81.5, -12.5, 60, 85])],
+             "exclude":[np.array([[-87.6, 58.7],
+                                  [-51.9, 56.6],
+                                  [-68.9, 75.5],
+                                  [-107.0, 73.3]]),
+                        np.array([[-119.0, 74.5],
+                                  [-92.7, 75.9],
+                                  [-52.84, 83.25],
+                                  [-100.8, 84.0]]),
+                        np.array([[-101.3, 68.5],
+                                  [-82.4, 72.3],
+                                  [-68.7, 81.24],
+                                  [-117.29, 77.75]]),
+                        np.array([-25.0, -10.0, 62.5, 67.5])]}
+
+
+
+

Note

+

This example includes both bounding rectangles (e.g. +np.array([-81.5, -12.5, 60, 85])) and more general quadrilaterals (e.g. +np.array([[-101.3, 68.5], [-82.4, 72.3],...)

+
+

coastal_tools defines 16 regions via dictionaries of this type. The defined +regions are:

+
    +
  • Delaware_Bay

  • +
  • Galveston_Bay

  • +
  • Delaware_Region

  • +
  • US_East_Coast

  • +
  • US_Gulf_Coast

  • +
  • Caribbean

  • +
  • US_West_Coast

  • +
  • Hawaii

  • +
  • Alaska

  • +
  • Bering_Sea_E

  • +
  • Bering_Sea_W

  • +
  • Aleutian_Islands_E

  • +
  • Aleutian_Islands_W

  • +
  • Greenland

  • +
  • CONUS

  • +
  • Continental_US

  • +
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/ocean/coastline_alteration.html b/0.22.0rc4/ocean/coastline_alteration.html new file mode 100644 index 000000000..d4eea7bea --- /dev/null +++ b/0.22.0rc4/ocean/coastline_alteration.html @@ -0,0 +1,285 @@ + + + + + + + Coastline Alteration — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Coastline Alteration

+

The mpas_tools.ocean.coastline_alteration module contains several +functions for modifying the coastline in MPAS cells. This is accomplished by +modifying the land mask that indicates which MPAS cells are ocean vs. land +(or grounded ice).

+
+

Adding Land Blockages

+

The function +mpas_tools.ocean.coastline_alteration.add_critical_land_blockages() +add the masks associated with one or more transects to the land mask. This is +useful if there are land features (typically peninsulas or narrow land bridges) +that must block the ocean flow even if they are too narrow to be resolved in +the MPAS mesh.

+

An example of the typical workflow that uses this function would be:

+
import xarray
+
+from geometric_features import GeometricFeatures
+from mpas_tools.mesh import conversion
+from mpas_tools.ocean.coastline_alteration import add_critical_land_blockages
+
+
+# an object used to read feature collections from the geometric_features
+# package
+gf = GeometricFeatures()
+
+# get geometry of the land coverage from Natural Earth
+fcLandCoverage = gf.read(componentName='natural_earth', objectType='region',
+                         featureNames=['Land Coverage'])
+
+# read in the base mesh
+dsBaseMesh = xarray.open_dataset('base_mesh.nc')
+# create a mask on the base mesh that is ones for land or grounded ice and
+# zeros for ocean
+dsLandMask = conversion.mask(dsBaseMesh, fcMask=fcLandCoverage)
+
+# get a collection of features from geometric_features that are meant for
+# use as critical land blockages
+fcCritBlockages = gf.read(componentName='ocean', objectType='transect',
+                          tags=['Critical_Land_Blockage'])
+
+# make masks from the transects
+dsCritBlockMask = conversion.mask(dsBaseMesh, fcMask=fcCritBlockages)
+
+# add the masks to the "land" mask
+dsLandMask = add_critical_land_blockages(dsLandMask, dsCritBlockMask)
+
+
+
+
+

Masking Land-locked Cells

+

By default, the land mask produced by the MPAS Mask Creator can produce +ocean cells with vertices that are all on the land-ocean boundary. MPAS-Seaice +uses a so-called +Arakawa B-grid, +meaning that velocities are located at vertices of the MPAS mesh. This means +that sea-ice flow into or out of a given cell is not possible if all vertices +of that cell are boundary vertices (where the velocity is, by definition, zero). +This problem is alleviated by calling +mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask(). +Any “land-locked” cells with only boundary vertices are removed from the mesh. +Land-locked cells are only removed poleward of a threshold latitude (43 degrees +by default). The user can specify the number of iterations (nSweeps) of +land-locked cell removal, since removing land-locked cells can produce new +land-locked cells.

+

Here is an example workflow that removes land-locked cells:

+
import xarray
+
+from geometric_features import GeometricFeatures
+from mpas_tools.mesh import conversion
+from mpas_tools.ocean.coastline_alteration import \
+    add_land_locked_cells_to_mask
+
+
+# an object used to read feature collections from the geometric_features
+# package
+gf = GeometricFeatures()
+
+# get geometry of the land coverage from Natural Earth
+fcLandCoverage = gf.read(componentName='natural_earth', objectType='region',
+                         featureNames=['Land Coverage'])
+
+# read in the base mesh
+dsBaseMesh = xarray.open_dataset('base_mesh.nc')
+# create a mask on the base mesh that is ones for land or grounded ice and
+# zeros for ocean
+dsLandMask = conversion.mask(dsBaseMesh, fcMask=fcLandCoverage)
+
+# Find ocean cells that are land-locked, and alter the cell mask so that
+# they are counted as land cells
+dsLandMask = add_land_locked_cells_to_mask(dsLandMask, dsBaseMesh,
+                                           latitude_threshold=43.0,
+                                           nSweeps=20)
+
+
+
+
+

Widening Transects

+

Similarly to Masking Land-locked Cells, if critical passages in polar +regions are too narrow, they can become blocked by sea ice that cannot be +advected. Sea-ice flow is not possible unless channels are at least 2 cells +wide. This widening is accomplished with +mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks(). +Channels are only widened poleward of a threshold latitude (43 degrees by +default).

+

An example workflow that includes transect-widening is:

+
import xarray
+
+from geometric_features import GeometricFeatures
+from mpas_tools.mesh import conversion
+from mpas_tools.ocean.coastline_alteration import widen_transect_edge_masks
+
+# an object used to read feature collections from the geometric_features
+# package
+gf = GeometricFeatures()
+
+# read in the base mesh
+dsBaseMesh = xarray.open_dataset('base_mesh.nc')
+
+# merge transects for critical passages into critical_passages.geojson
+fcCritPassages = gf.read(componentName='ocean', objectType='transect',
+                         tags=['Critical_Passage'])
+
+# create masks from the transects
+dsCritPassMask = conversion.mask(dsBaseMesh, fcMask=fcCritPassages)
+
+# Alter critical passages to be at least two cells wide, to avoid sea ice
+# blockage.
+dsCritPassMask = widen_transect_edge_masks(dsCritPassMask, dsBaseMesh,
+                                           latitude_threshold=43.0)
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/ocean/depth.html b/0.22.0rc4/ocean/depth.html new file mode 100644 index 000000000..461cdc88d --- /dev/null +++ b/0.22.0rc4/ocean/depth.html @@ -0,0 +1,194 @@ + + + + + + + Adding a Depth Coordinate — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Adding a Depth Coordinate

+
+

Adding a 1D depth coordinate

+

The function mpas_tools.ocean.depth.add_depth() can be used to add +a 1D depth coordinate that is appropriate for runs with a z-star MPAS-Ocean +mesh. The coordinate is only approximately correct but is useful for +visualization.

+

Internally, the depth is computed with +mpas_tools.ocean.depth.compute_depth(), which could also be called +directly if one has a suitable refBottomDepth data array indicating the +reference depth of the bottom of each layer in a 1D coordinate that is +independent of both time and horizontal coordinate.

+
+
+

Adding a 3D zMid coordinate

+

The function mpas_tools.ocean.depth.add_zmid() can be used to add +a time-independent, 3D zMid coordinate that is appropriate for runs with +any MPAS-Ocean vertical coordinate that is not a significant function of time. +This is appropriate for both z-star simulations and those with ice-shelf +cavities, which have a more complex vertical coordinate. The coordinate is only +approximately correct because MPAS-Ocean coordinates vary at least slightly +in time (with the undulation of the sea surface). The time-independent zMid +is appropriate for visualization an analysis that does not need to account for +this time variability.

+

Internally, the zMid is computed with +mpas_tools.ocean.depth.compute_zmid(), which could also be called +directly if one has a suitable bottomDepth, maxLevelCell, +and (reference) layerThickness data arrays.

+
+
+

Writing a time-dependent, 3D zMid variable

+

The function mpas_tools.ocean.depth.write_time_varying_zmid() can be +used to write out a time-dependent, 3D zMid variable to its own file. +This is the “true” MPAS-Ocean vertical coordinate, in contrast to the 1D and +3D time-independent coordinates mentioned above. However, it requires a +significant amount of disk space so may not be desirable in many contexts.

+

Internally, the <prefix>zMid is computed with +mpas_tools.ocean.depth.compute_zmid() using the time-dependent +<prefix>layerThickness variable, where <prefix> is a prefix such as +'timeMonthly_avg_' or an empty string ('') for no prefix.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/ocean/mesh_creation.html b/0.22.0rc4/ocean/mesh_creation.html new file mode 100644 index 000000000..854cb51b3 --- /dev/null +++ b/0.22.0rc4/ocean/mesh_creation.html @@ -0,0 +1,182 @@ + + + + + + + Ocean Mesh Creation — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Ocean Mesh Creation

+

The mpas_tools.ocean.build_mesh module is used create +ocean-specific MPAS meshes using the +mpas_tools.mesh.creation.build_mesh module.

+

Spherical meshes are constructed with the function +mpas_tools.ocean.build_mesh.build_spherical_mesh(). The basic +arguments are the same as those to +mpas_tools.mesh.creation.build_mesh.build_spherical_mesh().

+

Similarly, planar meshes can be constructed with the function +mpas_tools.ocean.build_mesh.build_planar_mesh(), which has the +same basic arguments as +mpas_tools.mesh.creation.build_mesh.build_planar_mesh().

+

Each of these functions has additional, optional arguments that allow users to:

+
+
    +
  • specify a directory for extracting VTK geometry for viewing in +ParaVeiw. +The mpas_tools.viz.paraview_extractor.extract_vtk() function is +used to produce a VTK file in this directory, named base_mesh_vtk +by default.

  • +
  • Specify whether to preserve a region of the mesh above sea level as a +floodplain, and the elevation up to which this regions should remain part +of the mesh. This feature is used in coastal simulations that support +wetting and drying. A field, cellSeedMask, is added to the mesh file +that can later be used preserve the floodplain. +See mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain().

  • +
  • Whether to add a default bathymetry data set to the mesh. A field, +bottomDepthObserved, is added to the mesh file with bathymetry data +from one of two topography files: earth_relief_15s.nc or topo.msh. +If bathymetry should be added to the mesh, a local link with one of these +file names must exist. +See mpas_tools.ocean.inject_bathymetry.inject_bathymetry().

  • +
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/ocean/moc.html b/0.22.0rc4/ocean/moc.html new file mode 100644 index 000000000..078880b0b --- /dev/null +++ b/0.22.0rc4/ocean/moc.html @@ -0,0 +1,279 @@ + + + + + + + Meridional Overturning Circulation — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Meridional Overturning Circulation

+

The mpas_tools.ocean.moc module contains tools for setting up masks +used by both +MPAS-Ocean and +MPAS-Analysis for +computing the global and basin-wide Meridional Overturning Circulation (MOC).

+
+

Building MOC Basins

+

The mpas_tools.ocean.moc.build_moc_basins() function can be used to +merge a large number of individual seas from the +geometric_features <http://mpas-dev.github.io/geometric_features/stable/> +package into 5 larger features defining the MOC basins:

+
    +
  • Global

  • +
  • Atlantic

  • +
  • Indian

  • +
  • Pacific

  • +
  • Indo-pacific

  • +
+

A call to this function returns a +FeatureCollection +with these 5 basins.

+

A typical workflow calling this function would look like:

+
from geometric_features import GeometricFeatures
+from mpas_tools.ocean.moc import build_moc_basins
+
+
+gf = GeometricFeatures()
+fcMOC = build_moc_basins(gf)
+
+
+
+
+

Adding Southern Transects

+

Typically, the basins on their own are not particularly useful. For all but +the global MOC, a southern transect is needed to determine the flow into or +out of the basin from the south. The function +mpas_tools.ocean.mocadd_moc_southern_boundary_transects() can be +used to add masks for all the edges associated with the southern boundary of +each MOC basin.

+

A typical workflow calling this function would look like:

+
import xarray
+from geometric_features import GeometricFeatures
+from mpas_tools.ocean.moc import build_moc_basins
+
+
+mesh_filename = 'mesh.nc'
+
+gf = GeometricFeatures()
+fcMOC = build_moc_basins(gf)
+
+dsMesh = xarray.open_dataset(mesh_filename)
+dsMasks = mpas_tools.mesh.conversion.mask(dsMesh=dsMesh, fcMask=fcMOC)
+
+dsMasksAndTransects = add_moc_southern_boundary_transects(dsMasks, dsMesh)
+
+
+

In this example, only the mesh.nc file is required as an input. The +resulting xarray.Dataset contains both the basin and southern-transect +masks.

+

A command-line tool moc_southern_boundary_extractor.py is also available +for this purpose:

+
$ moc_southern_boundary_extractor.py --help
+
+usage: moc_southern_boundary_extractor.py [-h] -f IN_FILE -m MESH_FILE -o
+                                          OUT_FILE
+
+This script takes a mesh file (-m flag) and a file with MOC regions masks
+(-f flag) produce by the MPAS mask creator.  The script produces a copy of
+the contents of the MOC mask file, adding transects that mark the southern
+boundary of each region in a file indicated with the -o flag.  The transect
+is applied only to vertices and edges, not cells, because the need for southern
+boundary transect data on cells is not foreseen.
+
+Author: Xylar Asay-Davis
+last modified: 5/22/2018
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -f IN_FILE, --in_file IN_FILE
+                        Input file with MOC masks
+  -m MESH_FILE, --mesh_file MESH_FILE
+                        Input mesh file
+  -o OUT_FILE, --out_file OUT_FILE
+                        Output file for MOC masks and southern-boundary transects
+
+
+

The command-line tool is largely intended for backwards compatibility and the +python function is the preferred way of building a workflow with this +functionality.

+
+
+

Building MOC Basins and Transects Together

+

Typically, a workflow can be made more efficient by using the function +mpas_tools.ocean.moc.make_moc_basins_and_transects() takes care of +both Building MOC Basins and Adding Southern Transects as well as writing out +the results to files.

+

A typical workflow calling this function would look like:

+
from geometric_features import GeometricFeatures
+from mpas_tools.ocean.moc import make_moc_basins_and_transects
+
+
+mesh_filename = 'mesh.nc'
+mesh_name = 'EC30to60kmL60E3SMv2r03'
+
+mask_filename = '{}_moc_masks.nc'.format(mesh_name)
+mask_and_transect_filename = '{}_moc_masks_and_transects.nc'.format(
+    mesh_name)
+
+geojson_filename = 'moc_basins.geojson'
+
+gf = GeometricFeatures()
+
+make_moc_basins_and_transects(gf, mesh_filename, mask_and_transect_filename,
+                              geojson_filename=geojson_filename,
+                              mask_filename=mask_filename)
+
+
+

In this example, only the mesh.nc file is required as an input. The basin +and transect masks are written to mask_and_transect_filename, and we also +request that the intermediate data sets get written out for, perhaps for +purposes of debugging or provenance. The MOC feature collection from +Building MOC Basins will be written to geojson_filename, while the basin +masks (without the associate transect masks) will be written to +mask_filename.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/ocean/visualization.html b/0.22.0rc4/ocean/visualization.html new file mode 100644 index 000000000..b2b8e595d --- /dev/null +++ b/0.22.0rc4/ocean/visualization.html @@ -0,0 +1,235 @@ + + + + + + + Visualization — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Visualization

+
+

Plotting Ocean Transects

+../_images/south_atlantic_temperature_transect.png +

The function mpas_tools.ocean.viz.plot_ocean_transects() and the +associated plot_ocean_transects command-line tool can be used to plot +transects of various MPAS-Ocean variables. The arguments to the command-line +tool are:

+
$ plot_ocean_transects --help
+usage: plot_ocean_transects [-h] -g GEOJSON_FILENAME [-m MESH_FILENAME] -f
+                            FILENAME [-v VARIABLE_LIST [VARIABLE_LIST ...]]
+                            [-c COLORMAP] [--flip]
+
+options:
+  -h, --help            show this help message and exit
+  -g GEOJSON_FILENAME, --geojson GEOJSON_FILENAME
+                        A geojson file with transects to plot
+  -m MESH_FILENAME, --mesh MESH_FILENAME
+                        An MPAS-Ocean mesh file.  If not specified, the MPAS-Ocean data file must contain the mesh.
+  -f FILENAME, --file FILENAME
+                        An MPAS-Ocean data file
+  -v VARIABLE_LIST [VARIABLE_LIST ...], --variable_list VARIABLE_LIST [VARIABLE_LIST ...]
+                        List of variables to plot.  All variables on cells in the data file is the default.
+  -c COLORMAP, --colormap COLORMAP
+                        A colormap to use for the plots, default depends on the field name.
+  --flip                Flip the x axis for all transects
+
+
+

See transects +from geometric_features for a examples of what a geojson transect might +look like:

+
{
+    "type": "FeatureCollection",
+    "features": [
+        {
+            "type": "Feature",
+            "properties": {
+                "name": "Drake Passage",
+                "object": "transect",
+                "component": "ocean",
+                "author": "Mark Petersen, Xylar Asay-Davis, Milena Veneziani",
+            },
+            "geometry": {
+                "type": "LineString",
+                "coordinates": [
+                    [
+                        -63.02,
+                        -65.46
+                    ],
+                    [
+                        -63.81,
+                        -63.8
+                    ],
+                    [
+                        -64.42,
+                        -62.02
+                    ],
+                    [
+                        -65.04,
+                        -60.25
+                    ],
+                    [
+                        -65.74,
+                        -58.28
+                    ],
+                    [
+                        -66.37,
+                        -56.39
+                    ],
+                    [
+                        -67.02,
+                        -54.44
+                    ]
+                ]
+            }
+        }
+    ]
+}
+
+
+

Add more features to the features list to plot multiple transects at the +same time.

+

The MPAS-Ocean mesh file must including not just the horizontal mesh variables +but also the vertical mesh variables (minLevelCell, maxLevelCell, +layerThickness, etc.)

+

If you don’t specify the list of variables to plot, all variables with +dimensions nCells and nVertLevels will be plotted.

+

One way of customizing these visualizaitons is to make your own copy of +transects.py <https://github.com/MPAS-Dev/MPAS-Tools/blob/master/conda_package/mpas_tools/ocean/viz/transects.py> +and change _plot_transect() to suite your needs, (changing figure size, dpi, +colorbar, etc.)

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/py-modindex.html b/0.22.0rc4/py-modindex.html new file mode 100644 index 000000000..6a1f249e5 --- /dev/null +++ b/0.22.0rc4/py-modindex.html @@ -0,0 +1,200 @@ + + + + + + Python Module Index — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ m +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ m
+ mpas_tools +
    + mpas_tools.cime.constants +
    + mpas_tools.mesh.creation.build_mesh +
    + mpas_tools.mesh.creation.mesh_definition_tools +
    + mpas_tools.mesh.creation.signed_distance +
    + mpas_tools.ocean.build_mesh +
    + mpas_tools.ocean.coastal_tools +
    + mpas_tools.ocean.coastline_alteration +
    + mpas_tools.ocean.moc +
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/seaice/mask.html b/0.22.0rc4/seaice/mask.html new file mode 100644 index 000000000..184ecc636 --- /dev/null +++ b/0.22.0rc4/seaice/mask.html @@ -0,0 +1,161 @@ + + + + + + + Mask — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Mask

+

The mpas_tools.seaice.mask module contains a function for +manipulating sea-ice region masks.

+
+

Extending a Mask

+

The function mpas_tools.seaice.mask.extend_seaice_mask() is used to +extend a sea-ice “presence” mask that covers the area where sea-ice is present +by a given distance. This is useful as part of creating a sea-ice +seaice_partition.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/seaice/mesh.html b/0.22.0rc4/seaice/mesh.html new file mode 100644 index 000000000..b63165543 --- /dev/null +++ b/0.22.0rc4/seaice/mesh.html @@ -0,0 +1,168 @@ + + + + + + + Mesh — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Mesh

+

The mpas_tools.seaice.mesh module contains several functions for +creating scrip files for sea-ice meshes and regular grids.

+
+

MPAS-Seaice SCRIP files

+

The functions mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells() +and mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices() are for +creating scrip files for fields on cells and vertices, respectively.

+

These are both created using a lower-level function +mpas_tools.seaice.mesh.write_scrip_file().

+
+
+

SCRIP files for 2D grids

+

The function mpas_tools.seaice.mesh.write_2D_scripfile() is for +creating scrip files for a regular, 2D latitude/longitude grid.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/seaice/partition.html b/0.22.0rc4/seaice/partition.html new file mode 100644 index 000000000..92a57b0e2 --- /dev/null +++ b/0.22.0rc4/seaice/partition.html @@ -0,0 +1,328 @@ + + + + + + + Graph partitioning — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Graph partitioning

+

The mpas_tools.seaice.partition module contains a function for +creating graph partition files for MPAS-Seaice that are better balanced than +those created from Metis tools directly.

+
+

Running from compass

+

One way to run the tools is from compass using the +files_for_e3sm +test case.

+

This has the advantage that it can run with a version of ESMF that has been +compiled with system compilers for compass. Compass also automatically +downloads and links the files needed for determining the regions of sea-ice +coverage. However, if you are unfamiliar with compass, there may be a learning +curve involved in setting up and running the test case.

+
+
+

Conda environment

+

The other preferred way to use the sea ice partitioning tool is through the +mpas_tools conda package. To install it, first install +Mambaforge +(if you don’t already have Miniconda3):

+

To activate it, run:

+
source ~/mambaforge/etc/profile.d/conda.sh
+source ~/mambaforge/etc/profile.d/mamba.sh
+
+
+

To create a new conda environment for mpas_tools, run:

+
mamba activate
+mamba create -y -n mpas_tools python=3.11 mpas_tools "esmf=*=nompi*"
+
+
+

This will create a new conda environment called mpas_tools that contains +the mpas_tools package and also the version of ESMF without MPI support. +This is necessary because the version with MPI support (the default) doesn’t +typically work on HPC.

+

Each time you want to run the sea-ice partitioning tools, run:

+
source ~/mambaforge/etc/profile.d/conda.sh
+source ~/mambaforge/etc/profile.d/mamba.sh
+mamba activate mpas_tools
+
+
+

All the tools (including fix_regrid_output.exe built from the Fortran code) +are part of the mpas_tools conda package.

+

You will also need an MPAS mesh file to partition. You do not need to pass +a location for the MPAS cell culler (-c) or Metis (-g) because theses +will be found automatically in the conda package

+
+
+

Graph partition tools

+

The tools prepare_seaice_partitions and create_seaice_partitions are +used to create MPAS-Seaice graph partitions that are better balanced so that +each processor “owns” cells from both polar and equatorial regions.

+
$ prepare_seaice_partitions --help
+usage: prepare_seaice_partitions [-h] -i MESHFILENAMESRC -p FILENAMEDATA -m
+                                 MESHFILENAMEDST -o OUTPUTDIR
+
+Perform preparatory work for making seaice partitions.
+
+options:
+  -h, --help            show this help message and exit
+  -i MESHFILENAMESRC, --inputmesh MESHFILENAMESRC
+                        MPAS mesh file for source regridding mesh.
+  -p FILENAMEDATA, --presence FILENAMEDATA
+                        Input ice presence file for source mesh.
+  -m MESHFILENAMEDST, --outputmesh MESHFILENAMEDST
+                        MPAS mesh file for destination regridding mesh.
+  -o OUTPUTDIR, --outputDir OUTPUTDIR
+                        Output direct
+
+
+

The input mesh file contains the MPAS-Seaice mesh fields for the mesh used to +create the “presence” file. The “presence” file itself contains an +icePresence field that indicates where sea ice might be present. We +typically use a +60-km mesh file +and the corresponding +presence file. +The presence file will be regridded to the given output MPAS-Seaice mesh. Here the ice +presence was determined as any cell in the mesh to have had ice present at any time +during a 50 year MPAS-Seaice standalone simulation with the above 60-km mesh file. +The output directory is often the current directory.

+

After this preprocessing has finished, the create_seaice_partitions tool +can be run one or more times. It is significantly more efficient to provide +a list of processor numbers than to call the tool for each processor number +separately.

+
$ create_seaice_partitions --help
+usage: create_seaice_partitions [-h] -m MESHFILENAME -o OUTPUTDIR
+                                [-c MPASCULLERLOCATION] [-p OUTPUTPREFIX] [-x]
+                                [-g METIS] [-n NPROCS] [-f NPROCSFILE]
+
+Create sea-ice partitions.
+
+options:
+  -h, --help            show this help message and exit
+  -m MESHFILENAME, --outputmesh MESHFILENAME
+                        MPAS mesh file for destination regridding mesh.
+  -o OUTPUTDIR, --outputDir OUTPUTDIR
+                        Output directory for temporary files and partition
+                        files.
+  -c MPASCULLERLOCATION, --cullerDir MPASCULLERLOCATION
+                        Location of MPAS MpasCellCuller.x executable.
+  -p OUTPUTPREFIX, --prefix OUTPUTPREFIX
+                        prefix for output partition filenames.
+  -x, --plotting        create diagnostic plotting file of partitions
+  -g METIS, --metis METIS
+                        name of metis utility
+  -n NPROCS, --nProcs NPROCS
+                        number of processors to create partition for.
+  -f NPROCSFILE, --nProcsFile NPROCSFILE
+                        number of processors to create partition for.
+
+
+

The mesh filename provides the desired MPAS-Seaice mesh, the same as the +destination mesh for prepare_seaice_partitions. The output directory +is often the current directory. A directory containing the +MpasCellCuller.x tool can be provided but by default it will be found in +your path as part of the mpas_tools conda package. The output prefix will +be prepended onto each graph partition file, and defaults to graph.info. +The Metis tool is nearly always gpmetis, the default, and must be available +in your path (which is the case if you use mpas_tools conda package). +One graph partition file is created for each number of processors (one or more +integers) provided. Alternatively, these can be listed, one value on each +line, in a file. You can optionally save a NetCDF file with partition +information partition_diag.nc, which will contain a partition_{nProcs} +field for each number of processors requested.

+

A simplified tool, primarily intended for use on LCRC machines Anvil and +Chrysalis, has only a few arguments:

+
$ simple_seaice_partitions --help
+usage: simple_seaice_partitions [-h] -m MESHFILENAME -p OUTPUTPREFIX -n
+                                [NPROCSARRAY ...] [-d DATADIR]
+
+Create sea-ice partitions on LCRC.
+
+options:
+  -h, --help            show this help message and exit
+  -m MESHFILENAME, --mesh MESHFILENAME
+                        MPAS-Seaice mesh file.
+  -p OUTPUTPREFIX, --prefix OUTPUTPREFIX
+                        prefix for output partition filenames.
+  -n [NPROCSARRAY ...], --nprocs [NPROCSARRAY ...]
+                        list of the number of processors to create partition
+                        for.
+  -d DATADIR, --datadir DATADIR
+                        Directory with seaice_QU60km_polar.nc and
+                        icePresent_QU60km_polar.nc.
+
+
+

The mesh file is any file that contains the MPAS-Seaice mesh. Some meshes +are available in inputdata/share/meshes/mpas/sea-ice and also each +MPAS-Seaice initial condition in inputdata/ice/mpas-seaice/<mesh_name> +contains the MPAS mesh. Which specific initial condition you choose should +not matter because the mesh should be identical.

+

The output prefix can be an absolute or relative path prefix for the graph +partition file to be created. Typically, this will be something like +partitions/mpas-seaice.graph.info.230313. It should end in a date that +matches other existing partition files (i.e. it can’t typically be today’s +date or E3SM won’t find the new partition file) and should not contain the +.part.<task_count> suffix.

+

You can provide several task counts with -n for efficiency. There is a +significant overhead in calling the tool multiple times for different task +counts.

+

Here is an example:

+
cd /lcrc/group/e3sm/public_html/inputdata/ice/mpas-seaice/WC14to60E2r3
+simple_seaice_partitions -m seaice.WC14to60E2r3.210210.nc -p partitions/mpas-seaice.graph.info.230313 -n 468
+
+
+
+
+

Graph partition function

+

A helper function mpas_tools.seaice.partition.gen_seaice_mesh_partition() +is used within create_seaice_partitions. It can also be called directly +but must already have the files resulting from prepare_seaice_partitions +available in the output directory.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/seaice/regions.html b/0.22.0rc4/seaice/regions.html new file mode 100644 index 000000000..a96e1a149 --- /dev/null +++ b/0.22.0rc4/seaice/regions.html @@ -0,0 +1,160 @@ + + + + + + + Region masks — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Region masks

+

The mpas_tools.seaice.regions module contains a function for +creating masks to help with graph partitioning.

+
+

Make a region mask for partitioning

+

The function mpas_tools.seaice.regions.make_regions_file() is used +to create a region field with different integer values for different +regions that are used as part of creating a sea-ice seaice_partition.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/seaice/regrid.html b/0.22.0rc4/seaice/regrid.html new file mode 100644 index 000000000..438b2edea --- /dev/null +++ b/0.22.0rc4/seaice/regrid.html @@ -0,0 +1,160 @@ + + + + + + + Regrid — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Regrid

+

The mpas_tools.seaice.regrid module contains a function for +regridding between MPAS-Seaice meshes.

+
+

Regridding between MPAS-Seaice meshes

+

The function mpas_tools.seaice.regrid.regrid_to_other_mesh() is used +to regrid between MPAS-Seaice meshes, used as part of preparing for sea-ice +seaice_partition.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/search.html b/0.22.0rc4/search.html new file mode 100644 index 000000000..9fdbd3bdd --- /dev/null +++ b/0.22.0rc4/search.html @@ -0,0 +1,160 @@ + + + + + + Search — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/0.22.0rc4/searchindex.js b/0.22.0rc4/searchindex.js new file mode 100644 index 000000000..d7875e370 --- /dev/null +++ b/0.22.0rc4/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["api", "authors", "building_docs", "cime", "config", "generated/mpas_tools.cime.constants", "generated/mpas_tools.config.MpasConfigParser", "generated/mpas_tools.config.MpasConfigParser.__getitem__", "generated/mpas_tools.config.MpasConfigParser.add_from_file", "generated/mpas_tools.config.MpasConfigParser.add_from_package", "generated/mpas_tools.config.MpasConfigParser.add_user_config", "generated/mpas_tools.config.MpasConfigParser.copy", "generated/mpas_tools.config.MpasConfigParser.get", "generated/mpas_tools.config.MpasConfigParser.getboolean", "generated/mpas_tools.config.MpasConfigParser.getexpression", "generated/mpas_tools.config.MpasConfigParser.getfloat", "generated/mpas_tools.config.MpasConfigParser.getint", "generated/mpas_tools.config.MpasConfigParser.getlist", "generated/mpas_tools.config.MpasConfigParser.has_option", "generated/mpas_tools.config.MpasConfigParser.has_section", "generated/mpas_tools.config.MpasConfigParser.set", "generated/mpas_tools.config.MpasConfigParser.write", "generated/mpas_tools.io.write_netcdf", "generated/mpas_tools.logging.LoggingContext", "generated/mpas_tools.logging.check_call", "generated/mpas_tools.merge_grids.merge_grids", "generated/mpas_tools.mesh.conversion.convert", "generated/mpas_tools.mesh.conversion.cull", "generated/mpas_tools.mesh.conversion.mask", "generated/mpas_tools.mesh.creation.build_mesh", "generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh", "generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh", "generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver", "generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf", "generated/mpas_tools.mesh.creation.mesh_definition_tools", "generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid", "generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat", "generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat", "generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat", "generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle", "generated/mpas_tools.mesh.creation.signed_distance", "generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson", "generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson", "generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson", "generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf", "generated/mpas_tools.mesh.interpolation.interp_bilin", "generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks", "generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask", "generated/mpas_tools.mesh.mask.compute_mpas_region_masks", "generated/mpas_tools.mesh.mask.compute_mpas_transect_masks", "generated/mpas_tools.ocean.build_mesh", "generated/mpas_tools.ocean.build_mesh.build_planar_mesh", "generated/mpas_tools.ocean.build_mesh.build_spherical_mesh", "generated/mpas_tools.ocean.coastal_tools", "generated/mpas_tools.ocean.coastal_tools.CPP_projection", "generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh", "generated/mpas_tools.ocean.coastal_tools.compute_cell_width", "generated/mpas_tools.ocean.coastal_tools.create_background_mesh", "generated/mpas_tools.ocean.coastal_tools.distance_to_coast", "generated/mpas_tools.ocean.coastal_tools.extract_coastlines", "generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates", "generated/mpas_tools.ocean.coastal_tools.get_data_inside_box", "generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad", "generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast", "generated/mpas_tools.ocean.coastal_tools.plot_region_box", "generated/mpas_tools.ocean.coastal_tools.save_matfile", "generated/mpas_tools.ocean.coastal_tools.smooth_coastline", "generated/mpas_tools.ocean.coastline_alteration", "generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages", "generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask", "generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks", "generated/mpas_tools.ocean.depth.add_depth", "generated/mpas_tools.ocean.depth.add_zmid", "generated/mpas_tools.ocean.depth.compute_depth", "generated/mpas_tools.ocean.depth.compute_zmid", "generated/mpas_tools.ocean.depth.write_time_varying_zmid", "generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry", "generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file", "generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity", "generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity", "generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain", "generated/mpas_tools.ocean.moc", "generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects", "generated/mpas_tools.ocean.moc.make_moc_basins_and_transects", "generated/mpas_tools.ocean.transects.find_transect_levels_and_weights", "generated/mpas_tools.ocean.transects.get_outline_segments", "generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes", "generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles", "generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes", "generated/mpas_tools.ocean.viz.add_inset", "generated/mpas_tools.ocean.viz.plot_ocean_transects", "generated/mpas_tools.parallel.create_pool", "generated/mpas_tools.planar_hex.make_planar_hex_mesh", "generated/mpas_tools.scrip.from_mpas.scrip_from_mpas", "generated/mpas_tools.seaice.mask.extend_seaice_mask", "generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells", "generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices", "generated/mpas_tools.seaice.mesh.write_2D_scripfile", "generated/mpas_tools.seaice.mesh.write_scrip_file", "generated/mpas_tools.seaice.partition.create_partitions", "generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition", "generated/mpas_tools.seaice.partition.prepare_partitions", "generated/mpas_tools.seaice.regions.make_regions_file", "generated/mpas_tools.seaice.regrid.regrid_to_other_mesh", "generated/mpas_tools.split_grids.split_grids", "generated/mpas_tools.tests.test_cime_constants.test_cime_constants", "generated/mpas_tools.transects.Vector", "generated/mpas_tools.transects.angular_distance", "generated/mpas_tools.transects.cartesian_to_great_circle_distance", "generated/mpas_tools.transects.cartesian_to_lon_lat", "generated/mpas_tools.transects.lon_lat_to_cartesian", "generated/mpas_tools.transects.subdivide_great_circle", "generated/mpas_tools.transects.subdivide_planar", "generated/mpas_tools.translate.center", "generated/mpas_tools.translate.center_on_mesh", "generated/mpas_tools.translate.translate", "generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps", "generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles", "generated/mpas_tools.viz.paraview_extractor.extract_vtk", "generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights", "generated/mpas_tools.viz.transects.find_transect_cells_and_weights", "generated/mpas_tools.viz.transects.make_triangle_tree", "index", "interpolation", "logging", "making_changes", "mesh_conversion", "mesh_creation", "ocean/coastal_tools", "ocean/coastline_alteration", "ocean/depth", "ocean/mesh_creation", "ocean/moc", "ocean/visualization", "seaice/mask", "seaice/mesh", "seaice/partition", "seaice/regions", "seaice/regrid", "testing_changes", "transects", "versions", "visualization"], "filenames": ["api.rst", "authors.rst", "building_docs.rst", "cime.rst", "config.rst", "generated/mpas_tools.cime.constants.rst", "generated/mpas_tools.config.MpasConfigParser.rst", "generated/mpas_tools.config.MpasConfigParser.__getitem__.rst", "generated/mpas_tools.config.MpasConfigParser.add_from_file.rst", "generated/mpas_tools.config.MpasConfigParser.add_from_package.rst", "generated/mpas_tools.config.MpasConfigParser.add_user_config.rst", "generated/mpas_tools.config.MpasConfigParser.copy.rst", "generated/mpas_tools.config.MpasConfigParser.get.rst", "generated/mpas_tools.config.MpasConfigParser.getboolean.rst", "generated/mpas_tools.config.MpasConfigParser.getexpression.rst", "generated/mpas_tools.config.MpasConfigParser.getfloat.rst", "generated/mpas_tools.config.MpasConfigParser.getint.rst", "generated/mpas_tools.config.MpasConfigParser.getlist.rst", "generated/mpas_tools.config.MpasConfigParser.has_option.rst", "generated/mpas_tools.config.MpasConfigParser.has_section.rst", "generated/mpas_tools.config.MpasConfigParser.set.rst", "generated/mpas_tools.config.MpasConfigParser.write.rst", "generated/mpas_tools.io.write_netcdf.rst", "generated/mpas_tools.logging.LoggingContext.rst", "generated/mpas_tools.logging.check_call.rst", "generated/mpas_tools.merge_grids.merge_grids.rst", "generated/mpas_tools.mesh.conversion.convert.rst", "generated/mpas_tools.mesh.conversion.cull.rst", "generated/mpas_tools.mesh.conversion.mask.rst", "generated/mpas_tools.mesh.creation.build_mesh.rst", "generated/mpas_tools.mesh.creation.build_mesh.build_planar_mesh.rst", "generated/mpas_tools.mesh.creation.build_mesh.build_spherical_mesh.rst", "generated/mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver.rst", "generated/mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf.rst", "generated/mpas_tools.mesh.creation.mesh_definition_tools.rst", "generated/mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid.rst", "generated/mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat.rst", "generated/mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat.rst", "generated/mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat.rst", "generated/mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle.rst", "generated/mpas_tools.mesh.creation.signed_distance.rst", "generated/mpas_tools.mesh.creation.signed_distance.distance_from_geojson.rst", "generated/mpas_tools.mesh.creation.signed_distance.mask_from_geojson.rst", "generated/mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson.rst", "generated/mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf.rst", "generated/mpas_tools.mesh.interpolation.interp_bilin.rst", "generated/mpas_tools.mesh.mask.compute_lon_lat_region_masks.rst", "generated/mpas_tools.mesh.mask.compute_mpas_flood_fill_mask.rst", "generated/mpas_tools.mesh.mask.compute_mpas_region_masks.rst", "generated/mpas_tools.mesh.mask.compute_mpas_transect_masks.rst", "generated/mpas_tools.ocean.build_mesh.rst", "generated/mpas_tools.ocean.build_mesh.build_planar_mesh.rst", "generated/mpas_tools.ocean.build_mesh.build_spherical_mesh.rst", "generated/mpas_tools.ocean.coastal_tools.rst", "generated/mpas_tools.ocean.coastal_tools.CPP_projection.rst", "generated/mpas_tools.ocean.coastal_tools.coastal_refined_mesh.rst", "generated/mpas_tools.ocean.coastal_tools.compute_cell_width.rst", "generated/mpas_tools.ocean.coastal_tools.create_background_mesh.rst", "generated/mpas_tools.ocean.coastal_tools.distance_to_coast.rst", "generated/mpas_tools.ocean.coastal_tools.extract_coastlines.rst", "generated/mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates.rst", "generated/mpas_tools.ocean.coastal_tools.get_data_inside_box.rst", "generated/mpas_tools.ocean.coastal_tools.get_indices_inside_quad.rst", "generated/mpas_tools.ocean.coastal_tools.plot_coarse_coast.rst", "generated/mpas_tools.ocean.coastal_tools.plot_region_box.rst", "generated/mpas_tools.ocean.coastal_tools.save_matfile.rst", "generated/mpas_tools.ocean.coastal_tools.smooth_coastline.rst", "generated/mpas_tools.ocean.coastline_alteration.rst", "generated/mpas_tools.ocean.coastline_alteration.add_critical_land_blockages.rst", "generated/mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask.rst", "generated/mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks.rst", "generated/mpas_tools.ocean.depth.add_depth.rst", "generated/mpas_tools.ocean.depth.add_zmid.rst", "generated/mpas_tools.ocean.depth.compute_depth.rst", "generated/mpas_tools.ocean.depth.compute_zmid.rst", "generated/mpas_tools.ocean.depth.write_time_varying_zmid.rst", "generated/mpas_tools.ocean.inject_bathymetry.inject_bathymetry.rst", "generated/mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file.rst", "generated/mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity.rst", "generated/mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity.rst", "generated/mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain.rst", "generated/mpas_tools.ocean.moc.rst", "generated/mpas_tools.ocean.moc.add_moc_southern_boundary_transects.rst", "generated/mpas_tools.ocean.moc.make_moc_basins_and_transects.rst", "generated/mpas_tools.ocean.transects.find_transect_levels_and_weights.rst", "generated/mpas_tools.ocean.transects.get_outline_segments.rst", "generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes.rst", "generated/mpas_tools.ocean.transects.interp_mpas_to_transect_triangles.rst", "generated/mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes.rst", "generated/mpas_tools.ocean.viz.add_inset.rst", "generated/mpas_tools.ocean.viz.plot_ocean_transects.rst", "generated/mpas_tools.parallel.create_pool.rst", "generated/mpas_tools.planar_hex.make_planar_hex_mesh.rst", "generated/mpas_tools.scrip.from_mpas.scrip_from_mpas.rst", "generated/mpas_tools.seaice.mask.extend_seaice_mask.rst", "generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells.rst", "generated/mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices.rst", "generated/mpas_tools.seaice.mesh.write_2D_scripfile.rst", "generated/mpas_tools.seaice.mesh.write_scrip_file.rst", "generated/mpas_tools.seaice.partition.create_partitions.rst", "generated/mpas_tools.seaice.partition.gen_seaice_mesh_partition.rst", "generated/mpas_tools.seaice.partition.prepare_partitions.rst", "generated/mpas_tools.seaice.regions.make_regions_file.rst", "generated/mpas_tools.seaice.regrid.regrid_to_other_mesh.rst", "generated/mpas_tools.split_grids.split_grids.rst", "generated/mpas_tools.tests.test_cime_constants.test_cime_constants.rst", "generated/mpas_tools.transects.Vector.rst", "generated/mpas_tools.transects.angular_distance.rst", "generated/mpas_tools.transects.cartesian_to_great_circle_distance.rst", "generated/mpas_tools.transects.cartesian_to_lon_lat.rst", "generated/mpas_tools.transects.lon_lat_to_cartesian.rst", "generated/mpas_tools.transects.subdivide_great_circle.rst", "generated/mpas_tools.transects.subdivide_planar.rst", "generated/mpas_tools.translate.center.rst", "generated/mpas_tools.translate.center_on_mesh.rst", "generated/mpas_tools.translate.translate.rst", "generated/mpas_tools.viz.colormaps.register_sci_viz_colormaps.rst", "generated/mpas_tools.viz.mesh_to_triangles.mesh_to_triangles.rst", "generated/mpas_tools.viz.paraview_extractor.extract_vtk.rst", "generated/mpas_tools.viz.transects.find_planar_transect_cells_and_weights.rst", "generated/mpas_tools.viz.transects.find_transect_cells_and_weights.rst", "generated/mpas_tools.viz.transects.make_triangle_tree.rst", "index.rst", "interpolation.rst", "logging.rst", "making_changes.rst", "mesh_conversion.rst", "mesh_creation.rst", "ocean/coastal_tools.rst", "ocean/coastline_alteration.rst", "ocean/depth.rst", "ocean/mesh_creation.rst", "ocean/moc.rst", "ocean/visualization.rst", "seaice/mask.rst", "seaice/mesh.rst", "seaice/partition.rst", "seaice/regions.rst", "seaice/regrid.rst", "testing_changes.rst", "transects.rst", "versions.rst", "visualization.rst"], "titles": ["API reference", "Main Authors", "Building the Documentation", "CIME Constants", "Config files", "mpas_tools.cime.constants", "mpas_tools.config.MpasConfigParser", "mpas_tools.config.MpasConfigParser.__getitem__", "mpas_tools.config.MpasConfigParser.add_from_file", "mpas_tools.config.MpasConfigParser.add_from_package", "mpas_tools.config.MpasConfigParser.add_user_config", "mpas_tools.config.MpasConfigParser.copy", "mpas_tools.config.MpasConfigParser.get", "mpas_tools.config.MpasConfigParser.getboolean", "mpas_tools.config.MpasConfigParser.getexpression", "mpas_tools.config.MpasConfigParser.getfloat", "mpas_tools.config.MpasConfigParser.getint", "mpas_tools.config.MpasConfigParser.getlist", "mpas_tools.config.MpasConfigParser.has_option", "mpas_tools.config.MpasConfigParser.has_section", "mpas_tools.config.MpasConfigParser.set", "mpas_tools.config.MpasConfigParser.write", "mpas_tools.io.write_netcdf", "mpas_tools.logging.LoggingContext", "mpas_tools.logging.check_call", "mpas_tools.merge_grids.merge_grids", "mpas_tools.mesh.conversion.convert", "mpas_tools.mesh.conversion.cull", "mpas_tools.mesh.conversion.mask", "mpas_tools.mesh.creation.build_mesh", "mpas_tools.mesh.creation.build_mesh.build_planar_mesh", "mpas_tools.mesh.creation.build_mesh.build_spherical_mesh", "mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver", "mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf", "mpas_tools.mesh.creation.mesh_definition_tools", "mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid", "mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat", "mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat", "mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat", "mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle", "mpas_tools.mesh.creation.signed_distance", "mpas_tools.mesh.creation.signed_distance.distance_from_geojson", "mpas_tools.mesh.creation.signed_distance.mask_from_geojson", "mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson", "mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf", "mpas_tools.mesh.interpolation.interp_bilin", "mpas_tools.mesh.mask.compute_lon_lat_region_masks", "mpas_tools.mesh.mask.compute_mpas_flood_fill_mask", "mpas_tools.mesh.mask.compute_mpas_region_masks", "mpas_tools.mesh.mask.compute_mpas_transect_masks", "mpas_tools.ocean.build_mesh", "mpas_tools.ocean.build_mesh.build_planar_mesh", "mpas_tools.ocean.build_mesh.build_spherical_mesh", "mpas_tools.ocean.coastal_tools", "mpas_tools.ocean.coastal_tools.CPP_projection", "mpas_tools.ocean.coastal_tools.coastal_refined_mesh", "mpas_tools.ocean.coastal_tools.compute_cell_width", "mpas_tools.ocean.coastal_tools.create_background_mesh", "mpas_tools.ocean.coastal_tools.distance_to_coast", "mpas_tools.ocean.coastal_tools.extract_coastlines", "mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates", "mpas_tools.ocean.coastal_tools.get_data_inside_box", "mpas_tools.ocean.coastal_tools.get_indices_inside_quad", "mpas_tools.ocean.coastal_tools.plot_coarse_coast", "mpas_tools.ocean.coastal_tools.plot_region_box", "mpas_tools.ocean.coastal_tools.save_matfile", "mpas_tools.ocean.coastal_tools.smooth_coastline", "mpas_tools.ocean.coastline_alteration", "mpas_tools.ocean.coastline_alteration.add_critical_land_blockages", "mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask", "mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks", "mpas_tools.ocean.depth.add_depth", "mpas_tools.ocean.depth.add_zmid", "mpas_tools.ocean.depth.compute_depth", "mpas_tools.ocean.depth.compute_zmid", "mpas_tools.ocean.depth.write_time_varying_zmid", "mpas_tools.ocean.inject_bathymetry.inject_bathymetry", "mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file", "mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity", "mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity", "mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain", "mpas_tools.ocean.moc", "mpas_tools.ocean.moc.add_moc_southern_boundary_transects", "mpas_tools.ocean.moc.make_moc_basins_and_transects", "mpas_tools.ocean.transects.find_transect_levels_and_weights", "mpas_tools.ocean.transects.get_outline_segments", "mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes", "mpas_tools.ocean.transects.interp_mpas_to_transect_triangles", "mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes", "mpas_tools.ocean.viz.add_inset", "mpas_tools.ocean.viz.plot_ocean_transects", "mpas_tools.parallel.create_pool", "mpas_tools.planar_hex.make_planar_hex_mesh", "mpas_tools.scrip.from_mpas.scrip_from_mpas", "mpas_tools.seaice.mask.extend_seaice_mask", "mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells", "mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices", "mpas_tools.seaice.mesh.write_2D_scripfile", "mpas_tools.seaice.mesh.write_scrip_file", "mpas_tools.seaice.partition.create_partitions", "mpas_tools.seaice.partition.gen_seaice_mesh_partition", "mpas_tools.seaice.partition.prepare_partitions", "mpas_tools.seaice.regions.make_regions_file", "mpas_tools.seaice.regrid.regrid_to_other_mesh", "mpas_tools.split_grids.split_grids", "mpas_tools.tests.test_cime_constants.test_cime_constants", "mpas_tools.transects.Vector", "mpas_tools.transects.angular_distance", "mpas_tools.transects.cartesian_to_great_circle_distance", "mpas_tools.transects.cartesian_to_lon_lat", "mpas_tools.transects.lon_lat_to_cartesian", "mpas_tools.transects.subdivide_great_circle", "mpas_tools.transects.subdivide_planar", "mpas_tools.translate.center", "mpas_tools.translate.center_on_mesh", "mpas_tools.translate.translate", "mpas_tools.viz.colormaps.register_sci_viz_colormaps", "mpas_tools.viz.mesh_to_triangles.mesh_to_triangles", "mpas_tools.viz.paraview_extractor.extract_vtk", "mpas_tools.viz.transects.find_planar_transect_cells_and_weights", "mpas_tools.viz.transects.find_transect_cells_and_weights", "mpas_tools.viz.transects.make_triangle_tree", "MPAS-Tools", "Interpolation", "Logging", "Making Changes to mpas_tools", "Mesh Conversion", "Mesh Creation", "Coastal Tools", "Coastline Alteration", "Adding a Depth Coordinate", "Ocean Mesh Creation", "Meridional Overturning Circulation", "Visualization", "Mask", "Mesh", "Graph partitioning", "Region masks", "Regrid", "Testing Changes to mpas_tools", "Transects", "Versions", "Visualization"], "terms": {"thi": [0, 4, 14, 20, 22, 23, 32, 33, 36, 37, 38, 56, 57, 58, 59, 84, 91, 94, 102, 104, 114, 117, 118, 119, 120, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 136, 139, 140, 142], "page": 0, "provid": [0, 3, 27, 55, 71, 72, 75, 94, 119, 120, 124, 126, 127, 128, 136, 140, 142], "an": [0, 4, 9, 12, 13, 14, 15, 16, 17, 22, 23, 26, 28, 31, 36, 37, 38, 39, 44, 45, 47, 48, 49, 52, 56, 57, 58, 59, 71, 72, 75, 77, 82, 83, 84, 86, 87, 88, 89, 92, 93, 94, 99, 100, 101, 115, 117, 118, 119, 120, 121, 123, 124, 125, 126, 128, 129, 130, 132, 133, 136, 142], "auto": 0, "gener": [0, 100, 104, 124, 125, 126, 127, 128], "summari": 0, "For": [0, 1, 4, 57, 84, 102, 118, 123, 126, 127, 128, 132, 140, 142], "more": [0, 68, 126, 127, 128, 129, 130, 132, 133, 136, 142], "detail": [0, 126], "exampl": [0, 4, 36, 37, 84, 118, 123, 124, 125, 126, 127, 128, 129, 132, 133, 136, 142], "relev": [0, 105, 126], "chapter": 0, "main": [0, 4, 122, 125, 127, 128], "part": [0, 4, 19, 36, 37, 38, 100, 117, 118, 125, 126, 127, 131, 134, 136, 137, 138, 142], "document": [0, 26, 122, 125, 139, 141], "xylar": [1, 126, 127, 132, 133], "asai": [1, 127, 132, 133], "davi": [1, 127, 132, 133], "michael": 1, "duda": 1, "matthew": 1, "hoffman": 1, "dougla": 1, "jacobsen": 1, "rilei": 1, "x": [1, 26, 27, 30, 31, 32, 45, 51, 52, 56, 58, 59, 66, 78, 79, 90, 92, 100, 106, 107, 108, 109, 110, 111, 112, 115, 119, 124, 125, 126, 127, 133, 136, 142], "bradi": 1, "mile": 1, "curri": 1, "amrap": 1, "garanaik": 1, "dom": 1, "heinzel": 1, "trevor": 1, "hillebrand": 1, "joseph": 1, "kennedi": 1, "william": 1, "lipscomb": 1, "mark": [1, 126, 132, 133], "petersen": [1, 133], "stephen": 1, "price": 1, "todd": 1, "ringler": 1, "juan": 1, "saenz": 1, "adrian": 1, "turner": 1, "luke": 1, "van": 1, "roekel": 1, "phillip": 1, "j": [1, 3], "wolfram": 1, "tong": 1, "zhang": 1, "list": [1, 4, 14, 17, 24, 27, 30, 32, 51, 56, 57, 58, 59, 90, 100, 104, 118, 126, 127, 128, 133, 136, 142], "all": [1, 10, 14, 41, 43, 47, 58, 90, 91, 111, 112, 116, 118, 126, 129, 132, 133, 136, 139], "contribut": 1, "http": [1, 26, 39, 107, 111, 112, 125, 132, 133], "github": [1, 26, 125, 132, 133, 141], "com": [1, 125, 133], "mpa": [1, 3, 4, 25, 26, 28, 30, 31, 36, 37, 38, 39, 45, 47, 48, 49, 51, 52, 69, 71, 72, 74, 75, 77, 78, 79, 82, 83, 84, 86, 87, 88, 90, 92, 93, 94, 95, 96, 98, 100, 102, 104, 113, 114, 115, 117, 118, 119, 120, 121, 123, 124, 125, 127, 129, 130, 131, 132, 133, 136, 140], "dev": [1, 26, 125, 132, 133, 139], "tool": [1, 3, 34, 100, 123, 124, 126, 132, 133, 139, 142], "graph": [1, 26, 27, 100, 122, 126, 137], "To": [2, 84, 118, 124, 126, 136, 139, 142], "make": [2, 4, 6, 36, 37, 38, 42, 48, 49, 84, 86, 87, 88, 101, 117, 119, 120, 121, 122, 126, 127, 129, 133, 136, 139, 142], "local": [2, 131, 139], "test": [2, 3, 4, 92, 122, 127, 128, 136], "i": [2, 4, 9, 14, 19, 20, 22, 23, 24, 26, 27, 31, 32, 33, 34, 36, 37, 38, 41, 43, 45, 46, 47, 48, 49, 51, 52, 55, 56, 57, 58, 59, 71, 72, 75, 77, 78, 79, 84, 89, 92, 94, 102, 104, 107, 111, 112, 117, 118, 119, 120, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142], "easiest": 2, "follow": [2, 107, 118, 126, 127, 128, 142], "chang": [2, 36, 38, 122, 133], "mpas_tool": [2, 3, 4, 122, 123, 124, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 140, 142], "procedur": 2, "how": [2, 55, 56, 57, 58, 59, 83, 126, 139], "packag": [2, 4, 9, 14, 122, 123, 125, 126, 127, 129, 132, 136, 139, 140, 142], "The": [2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 39, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 56, 57, 58, 59, 68, 70, 77, 78, 79, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 102, 104, 105, 106, 107, 108, 111, 112, 118, 119, 120, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 140, 142], "develop": [2, 125, 126, 139], "environ": [2, 122, 125], "includ": [2, 4, 14, 20, 21, 56, 59, 68, 70, 95, 96, 97, 98, 111, 112, 117, 118, 119, 120, 122, 124, 125, 126, 127, 128, 129, 133, 136, 142], "need": [2, 6, 125, 126, 127, 128, 130, 132, 133, 136, 139, 142], "simpli": [2, 124, 142], "run": [2, 24, 122, 124, 125, 126, 127, 130, 139], "code": [2, 4, 124, 126, 127, 136, 139], "block": [2, 4, 68, 70, 118, 126, 129], "export": 2, "docs_vers": 2, "cd": [2, 136, 139], "conda_packag": [2, 125, 133, 139], "doc": 2, "html": [2, 39, 125], "Then": [2, 124, 126], "you": [2, 4, 22, 24, 118, 124, 125, 126, 127, 133, 136, 139, 142], "can": [2, 4, 14, 22, 84, 118, 119, 120, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 136, 139, 140, 142], "view": [2, 51, 52, 131, 142], "open": [2, 142], "_build": 2, "index": [2, 74, 84, 117, 118, 119, 120, 122, 125, 127], "modul": [3, 4, 23, 124, 125, 126, 127, 128, 129, 131, 132, 134, 135, 136, 137, 138, 140], "contain": [3, 4, 28, 46, 47, 48, 49, 84, 94, 95, 96, 100, 102, 119, 120, 126, 128, 129, 132, 133, 134, 135, 136, 137, 138, 140, 142], "ar": [3, 4, 6, 14, 27, 34, 36, 37, 38, 45, 46, 47, 48, 49, 57, 59, 69, 84, 89, 92, 97, 98, 106, 107, 111, 112, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 132, 133, 135, 136, 137, 139, 140, 142], "sync": 3, "which": [3, 4, 14, 20, 22, 26, 27, 28, 31, 46, 47, 48, 49, 51, 52, 56, 68, 70, 82, 83, 84, 94, 102, 117, 118, 119, 120, 124, 125, 126, 127, 128, 129, 130, 131, 136, 142], "infrastructur": 3, "util": [3, 126, 136], "earth": [3, 31, 32, 41, 43, 49, 94, 108, 111, 126, 127, 129], "system": [3, 113, 114, 115, 126, 136], "model": [3, 122, 142], "e3sm": [3, 105, 136], "current": [3, 4, 90, 126, 128, 136, 139, 142], "we": [3, 4, 123, 126, 127, 132, 136, 139, 142], "onli": [3, 39, 91, 118, 126, 127, 128, 129, 130, 132, 136, 142], "those": [3, 4, 114, 124, 126, 130, 131, 136, 142], "given": [3, 7, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 24, 31, 47, 52, 56, 57, 58, 59, 73, 74, 84, 85, 90, 95, 96, 97, 98, 100, 118, 119, 120, 124, 126, 127, 128, 129, 134, 136, 142], "numer": 3, "valu": [3, 4, 12, 13, 14, 15, 16, 17, 20, 22, 41, 42, 43, 55, 56, 84, 87, 102, 104, 111, 118, 119, 120, 126, 127, 128, 136, 137, 142], "derivi": 3, "from": [3, 4, 14, 20, 27, 28, 36, 38, 39, 41, 42, 43, 46, 47, 48, 49, 55, 56, 57, 58, 59, 77, 84, 89, 93, 100, 105, 109, 110, 111, 112, 117, 118, 119, 120, 121, 122, 123, 124, 126, 127, 128, 129, 131, 132, 133, 139, 142], "other": [3, 4, 6, 10, 20, 86, 87, 102, 118, 122, 124, 126, 127, 128, 136, 142], "check": [3, 46, 48, 118, 126, 142], "against": [3, 126], "": [3, 48, 49, 89, 100, 104, 106, 125, 126, 127, 128, 136, 142], "master": [3, 105, 133, 141], "branch": [3, 139], "dure": [3, 26, 27, 28, 31, 56, 57, 58, 59, 83, 126, 136, 142], "conda": [3, 122, 125, 126, 139], "build": [3, 30, 31, 32, 51, 52, 83, 92, 122, 125, 139], "see": [3, 4, 55, 92, 123, 125, 126, 127, 128, 131, 133, 139, 142], "test_cime_const": 3, "some": [3, 4, 75, 119, 120, 126, 136, 140, 142], "most": [3, 14, 111, 112, 127, 128], "like": [3, 4, 14, 84, 118, 124, 126, 127, 132, 133, 136, 142], "us": [3, 4, 14, 22, 23, 26, 27, 28, 31, 34, 35, 38, 41, 43, 46, 47, 48, 49, 52, 55, 56, 57, 58, 59, 71, 72, 83, 89, 90, 91, 92, 93, 100, 104, 111, 112, 114, 117, 118, 119, 120, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 142], "compass": [3, 4, 122, 128], "relat": [3, 122, 126, 142], "project": 3, "shr_const_cdai": 3, "sec": 3, "calendar": 3, "dai": [3, 142], "shr_const_rearth": [3, 123, 127], "radiu": [3, 31, 32, 33, 37, 41, 43, 49, 57, 94, 108, 111, 126, 128], "m": [3, 30, 31, 35, 45, 51, 52, 78, 79, 111, 112, 118, 119, 120, 126, 127, 132, 133, 136, 139, 142], "shr_const_g": 3, "acceler": 3, "graviti": 3, "2": [3, 56, 58, 59, 84, 118, 124, 126, 127, 128, 129, 140, 141, 142], "shr_const_rhofw": 3, "densiti": [3, 77, 78, 79], "fresh": 3, "water": [3, 118, 142], "kg": 3, "3": [3, 27, 84, 119, 120, 124, 125, 126, 127, 128, 136, 141, 142], "shr_const_rhosw": 3, "sea": [3, 70, 84, 99, 129, 130, 131, 132, 134, 135, 136, 137, 138, 142], "shr_const_rhoic": 3, "ic": [3, 70, 99, 102, 126, 129, 130, 134, 135, 136, 137, 138, 142], "shr_const_cpfw": 3, "specif": [3, 26, 126, 127, 131, 136], "heat": 3, "k": 3, "shr_const_cpsw": 3, "shr_const_cpic": 3, "shr_const_latic": 3, "latent": 3, "fusion": 3, "shr_const_latvap": 3, "evapor": 3, "mpasconfigpars": 4, "class": [4, 6, 17, 23, 106], "read": [4, 77, 83, 118, 123, 126, 127, 129, 142], "get": [4, 7, 11, 13, 14, 15, 16, 17, 41, 43, 85, 126, 129, 132, 142], "set": [4, 22, 23, 26, 27, 28, 46, 47, 48, 49, 58, 59, 69, 85, 92, 119, 120, 125, 126, 128, 131, 132, 136, 139, 142], "write": [4, 22, 24, 25, 83, 95, 96, 97, 98, 102, 104, 122, 124, 132], "option": [4, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 35, 36, 37, 41, 43, 46, 47, 48, 49, 51, 52, 55, 56, 57, 58, 59, 69, 71, 72, 74, 75, 77, 82, 83, 84, 89, 90, 91, 92, 94, 97, 98, 104, 105, 115, 117, 118, 119, 120, 124, 126, 127, 128, 131, 132, 133, 136, 142], "add_from_packag": 4, "method": [4, 6, 23, 41, 91, 106, 126, 142], "add": [4, 8, 9, 10, 22, 49, 55, 59, 68, 71, 72, 75, 77, 78, 79, 89, 94, 125, 126, 127, 128, 129, 130, 131, 132, 133, 139, 142], "content": [4, 8, 9, 10, 126, 132], "within": [4, 84, 117, 118, 119, 120, 122, 125, 127, 128, 136, 139, 142], "here": [4, 123, 124, 126, 127, 128, 129, 136, 139, 142], "python": [4, 14, 28, 91, 122, 125, 127, 132, 136, 139, 142], "self": 4, "ocean": [4, 118, 126, 127, 128, 129, 130, 132, 142], "global_ocean": 4, "make_diagnostics_fil": 4, "cfg": 4, "except": [4, 9, 118, 142], "true": [4, 9, 14, 21, 24, 31, 32, 33, 51, 52, 56, 57, 58, 59, 62, 77, 103, 118, 120, 124, 125, 126, 127, 128, 130, 142], "first": [4, 25, 38, 69, 84, 104, 118, 119, 120, 125, 126, 127, 128, 136, 142], "second": [4, 24, 25, 38, 104, 119, 120, 125, 126, 142], "argument": [4, 24, 33, 57, 104, 118, 124, 125, 126, 128, 131, 132, 133, 136, 142], "name": [4, 7, 9, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 30, 31, 33, 44, 51, 52, 53, 56, 57, 58, 59, 74, 77, 90, 92, 95, 96, 97, 98, 100, 102, 104, 118, 124, 125, 126, 127, 128, 131, 133, 136, 142], "itself": [4, 124, 128, 136], "respect": [4, 45, 119, 120, 127, 128, 135], "path": [4, 8, 10, 22, 26, 27, 39, 93, 100, 125, 126, 128, 136, 139], "replac": 4, "In": [4, 84, 119, 120, 124, 125, 126, 127, 128, 132, 142], "case": [4, 119, 120, 122, 126, 127, 128, 136, 142], "know": [4, 83], "should": [4, 20, 23, 26, 27, 28, 47, 48, 49, 51, 52, 56, 68, 70, 71, 72, 82, 91, 100, 104, 119, 120, 124, 125, 126, 128, 131, 136, 139, 142], "alwai": [4, 6, 102, 117, 126, 128, 136, 142], "exist": [4, 23, 24, 94, 114, 118, 124, 126, 131, 136, 139], "so": [4, 14, 27, 31, 52, 69, 111, 112, 118, 124, 126, 127, 128, 129, 130, 136, 142], "would": [4, 125, 126, 127, 129, 132], "rais": [4, 9, 24], "found": [4, 9, 18, 19, 119, 120, 126, 136, 140, 142], "default": [4, 22, 26, 27, 36, 41, 43, 47, 51, 52, 57, 58, 89, 90, 104, 118, 126, 127, 128, 129, 131, 133, 136, 142], "behavior": [4, 126], "do": [4, 114, 118, 124, 125, 126, 136, 142], "noth": [4, 118, 142], "doe": [4, 127, 130], "fals": [4, 14, 20, 46, 48, 49, 51, 52, 56, 57, 58, 59, 61, 90, 93, 94, 97, 117, 118, 126, 127, 142], "ih": 4, "also": [4, 14, 20, 22, 75, 84, 118, 119, 120, 124, 125, 126, 127, 128, 130, 132, 133, 136, 140, 142], "ad": [4, 6, 26, 27, 28, 31, 51, 52, 68, 69, 70, 71, 72, 83, 94, 122, 125, 126, 131, 139, 142], "user": [4, 6, 10, 20, 100, 115, 125, 126, 127, 128, 129, 131, 142], "add_user_config": 4, "add_from_fil": 4, "copi": [4, 69, 117, 132, 133, 142], "deep": [4, 11], "parser": [4, 6, 8, 9, 10, 11, 125], "where": [4, 9, 21, 23, 26, 27, 51, 52, 56, 57, 58, 59, 84, 98, 102, 107, 111, 112, 118, 119, 120, 123, 124, 126, 127, 128, 129, 130, 134, 136, 142], "modifi": [4, 22, 53, 126, 128, 129, 132], "without": [4, 118, 125, 128, 132, 136], "affect": [4, 128], "origin": [4, 21, 54, 84, 88, 113, 114, 119, 120, 126, 128, 142], "object": [4, 83, 106, 124, 126, 127, 129, 133, 142], "featur": [4, 28, 46, 47, 48, 49, 83, 118, 126, 127, 129, 131, 132, 133, 142], "analysi": [4, 122, 125, 126, 130, 132], "refer": [4, 122, 130], "year": [4, 136], "start": [4, 47, 56, 126, 128, 142], "ha": [4, 18, 46, 48, 49, 56, 57, 58, 59, 119, 120, 125, 126, 127, 128, 130, 131, 136, 142], "present": [4, 102, 134, 136], "configpars": [4, 6, 7], "written": [4, 20, 23, 26, 27, 31, 52, 118, 126, 127, 132, 142], "out": [4, 22, 26, 27, 75, 92, 118, 129, 130, 132, 139], "abov": [4, 21, 46, 48, 51, 52, 84, 102, 126, 128, 130, 131, 136], "cover": [4, 128, 134], "multipl": [4, 118, 126, 128, 133, 136], "line": [4, 20, 22, 45, 49, 85, 125, 126, 127, 132, 133, 136, 139, 142], "n": [4, 30, 31, 35, 36, 37, 38, 45, 51, 52, 56, 58, 59, 78, 79, 126, 127, 136, 139, 142], "charact": [4, 22], "automat": [4, 125, 136], "similar": [4, 126], "addit": [4, 84, 86, 87, 118, 126, 131, 142], "getinteg": 4, "getfloat": 4, "getboolean": 4, "implement": [4, 125], "getlist": 4, "pars": [4, 17, 105, 125], "separ": [4, 104, 114, 118, 126, 136, 142], "space": [4, 32, 36, 111, 112, 117, 118, 126, 130, 142], "comma": [4, 118, 142], "string": [4, 14, 22, 24, 49, 95, 96, 97, 98, 118, 130, 142], "float": [4, 14, 15, 17, 31, 32, 33, 35, 36, 37, 38, 41, 43, 46, 48, 49, 51, 52, 56, 57, 58, 59, 69, 70, 89, 92, 94, 102, 106, 108, 111, 112, 115, 118, 119, 120], "integ": [4, 16, 118, 128, 136, 137, 142], "boolean": [4, 13], "etc": [4, 118, 126, 133, 136, 142], "anoth": [4, 59, 71, 72, 84, 114, 126, 127, 128, 139, 140, 142], "getexpress": 4, "dictionari": [4, 6, 14, 22, 55, 128], "tupl": [4, 14, 48, 49], "well": [4, 31, 52, 117, 118, 123, 126, 127, 132], "small": [4, 119, 120, 126, 128, 142], "function": [4, 14, 20, 29, 31, 32, 34, 35, 36, 37, 38, 40, 50, 52, 53, 56, 57, 58, 59, 67, 74, 81, 84, 98, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 135, 137, 138, 139, 142], "rang": [4, 55, 56, 57, 58, 118, 126, 127, 142], "numpi": [4, 14, 41, 42, 43, 46, 73, 97, 98, 106, 107, 108, 111, 112, 119, 120, 123, 127, 142], "linspac": [4, 123, 127], "arang": [4, 142], "arrai": [4, 30, 31, 32, 35, 36, 37, 41, 42, 43, 46, 51, 52, 55, 56, 57, 58, 59, 74, 78, 79, 86, 87, 88, 106, 118, 126, 127, 128, 130, 142], "support": [4, 118, 122, 124, 126, 128, 131, 136, 142], "access": 4, "section": [4, 6, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 125, 126, 140], "kei": [4, 128, 142], "e": [4, 20, 23, 48, 49, 68, 70, 84, 118, 119, 120, 126, 127, 128, 136, 139, 142], "g": [4, 20, 23, 48, 49, 68, 70, 84, 118, 119, 120, 126, 127, 128, 133, 136, 142], "enthalpy_benchmark_viz": 4, "display_imag": 4, "But": [4, 142], "allow": [4, 6, 84, 111, 112, 118, 119, 120, 131, 142], "assign": 4, "mani": [4, 56, 57, 58, 59, 124, 126, 130, 142], "One": [4, 90, 126, 127, 133, 136], "advantag": [4, 136], "over": [4, 6, 10, 20, 56, 84, 126, 127, 128, 142], "keep": [4, 6, 59, 126, 142], "track": [4, 126], "associ": [4, 6, 21, 48, 49, 68, 118, 119, 120, 125, 127, 129, 132, 133, 142], "There": [4, 84, 126, 136, 139, 142], "few": [4, 136, 142], "rule": 4, "possibl": [4, 125, 126, 129, 142], "must": [4, 24, 45, 84, 92, 125, 126, 127, 128, 129, 131, 133, 136], "begin": [4, 91, 126, 128, 142], "thei": [4, 6, 45, 69, 89, 92, 118, 121, 123, 125, 126, 128, 129, 139, 140, 142], "place": [4, 56, 125, 128], "befor": [4, 91, 111, 112, 118, 125, 126, 142], "question": 4, "prefer": [4, 132, 136, 142], "blank": [4, 142], "between": [4, 30, 31, 32, 35, 36, 37, 38, 41, 43, 46, 48, 49, 51, 52, 79, 84, 86, 92, 107, 118, 119, 120, 122, 127, 142], "ani": [4, 89, 118, 125, 126, 128, 129, 130, 136, 142], "number": [4, 14, 28, 41, 43, 46, 47, 48, 49, 56, 57, 58, 59, 69, 84, 89, 91, 92, 97, 98, 100, 104, 107, 111, 112, 125, 126, 128, 129, 132, 136, 142], "inlin": 4, "after": [4, 59, 111, 112, 128, 136], "same": [4, 22, 36, 37, 84, 90, 104, 107, 111, 112, 126, 127, 131, 133, 136, 142], "sourc": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 136], "A": [6, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 55, 56, 57, 58, 59, 69, 75, 82, 83, 84, 86, 87, 88, 89, 91, 94, 95, 96, 97, 98, 102, 104, 106, 113, 114, 115, 117, 118, 119, 120, 121, 124, 126, 127, 128, 131, 132, 133, 136, 142], "meta": [6, 125], "combin": [6, 35, 38, 118, 126, 127, 142], "when": [6, 14, 20, 84, 104, 117, 118, 119, 120, 125, 126, 128], "custom": [6, 133], "proven": [6, 20, 132], "differ": [6, 22, 84, 100, 126, 127, 128, 136, 137, 142], "take": [6, 10, 20, 56, 124, 126, 132, 142], "preced": [6, 10], "even": [6, 92, 129, 142], "later": [6, 84, 126, 131], "variabl": [6, 23, 34, 49, 59, 84, 90, 97, 102, 106, 117, 118, 122, 123, 126, 127, 128, 133, 142], "none": [6, 14, 20, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 41, 43, 46, 47, 48, 49, 51, 52, 55, 56, 57, 58, 59, 71, 72, 75, 82, 83, 84, 89, 90, 91, 92, 98, 100, 103, 104, 118, 124, 126, 128, 142], "combined_com": 6, "dict": [6, 14, 22, 24, 55, 56, 59], "comment": [6, 20, 21, 122, 125], "each": [6, 14, 21, 32, 41, 43, 46, 48, 49, 73, 74, 75, 84, 87, 90, 100, 104, 111, 112, 117, 118, 119, 120, 126, 128, 130, 131, 132, 136, 142], "__init__": [6, 23, 106, 125], "new": [6, 23, 56, 83, 89, 94, 124, 125, 126, 128, 129, 136, 142], "empti": [6, 118, 125, 128, 130, 142], "paramet": [7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 55, 56, 57, 58, 59, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 102, 104, 105, 106, 107, 108, 111, 112, 113, 114, 115, 117, 118, 119, 120, 121, 128], "str": [7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 28, 30, 31, 33, 39, 44, 51, 52, 59, 71, 72, 74, 75, 77, 78, 79, 83, 90, 92, 93, 94, 95, 96, 97, 98, 100, 102, 104, 105, 118, 125], "retriev": 7, "return": [7, 11, 12, 13, 15, 16, 17, 18, 19, 26, 27, 28, 35, 36, 37, 38, 41, 42, 43, 45, 46, 47, 48, 49, 55, 56, 57, 58, 59, 68, 69, 70, 73, 74, 82, 83, 84, 86, 87, 88, 89, 91, 92, 107, 108, 111, 112, 117, 119, 120, 121, 126, 127, 132], "section_proxi": 7, "sectionproxi": 7, "filenam": [8, 10, 22, 94, 102, 118, 126, 133, 136, 142], "file": [8, 9, 10, 14, 20, 21, 22, 23, 25, 26, 27, 28, 30, 31, 33, 39, 44, 51, 52, 56, 57, 58, 59, 71, 72, 75, 77, 78, 79, 83, 92, 93, 94, 95, 96, 97, 98, 100, 102, 104, 118, 122, 124, 125, 126, 127, 128, 130, 131, 132, 133, 136, 139, 142], "rel": [8, 10, 26, 27, 126, 127, 136, 142], "absolut": [8, 10, 26, 27, 136], "config_filenam": 9, "bool": [9, 13, 14, 18, 19, 20, 21, 24, 31, 33, 46, 48, 49, 51, 52, 56, 57, 58, 59, 77, 92, 93, 94, 97, 100, 117, 118, 120], "whether": [9, 18, 19, 20, 21, 24, 31, 32, 33, 46, 48, 49, 51, 52, 56, 57, 58, 59, 77, 90, 93, 94, 97, 100, 117, 118, 120, 126, 128, 131], "isn": [9, 126], "t": [9, 94, 125, 126, 127, 133, 136], "These": [10, 34, 122, 125, 126, 127, 128, 135, 140, 142], "config_copi": 11, "dtype": [14, 17], "use_numpyfunc": 14, "express": [14, 118, 142], "typic": [14, 26, 27, 100, 104, 118, 119, 120, 124, 125, 126, 127, 128, 129, 132, 136, 140, 142], "though": [14, 142], "avail": [14, 41, 43, 47, 58, 91, 92, 126, 132, 136, 139, 142], "requir": [14, 33, 49, 104, 125, 126, 127, 128, 130, 132, 142], "have": [14, 46, 48, 49, 84, 104, 117, 124, 126, 127, 130, 136, 139, 142], "valid": [14, 26, 84, 98, 125, 126], "syntax": 14, "entri": [14, 35, 36, 37, 38, 99, 101, 122, 128, 139], "singl": [14, 25, 118, 126, 128, 142], "doubl": [14, 126], "quot": 14, "type": [14, 17, 22, 48, 49, 57, 102, 125, 126, 127, 128, 133, 142], "int": [14, 16, 17, 24, 28, 41, 43, 46, 47, 48, 49, 56, 57, 58, 59, 69, 91, 92, 97, 98, 100, 104, 118, 123, 125, 126, 127], "If": [14, 23, 24, 31, 33, 41, 43, 45, 49, 52, 55, 84, 89, 118, 124, 125, 126, 127, 128, 131, 133, 139, 142], "suppli": [14, 20, 23, 92, 118, 124, 126, 128, 142], "element": [14, 17, 44], "cast": 14, "ensur": [14, 89], "rather": [14, 94, 118, 126, 142], "than": [14, 89, 94, 118, 126, 127, 136, 142], "distinct": 14, "import": [14, 123, 124, 126, 127, 128, 129, 132, 139, 142], "evalu": 14, "referenc": 14, "either": [14, 23, 28, 59, 102, 106, 118, 124, 126, 127, 128, 142], "np": [14, 123, 127, 128], "wa": [18, 19, 20, 21, 136], "call": [20, 23, 24, 55, 56, 57, 58, 59, 84, 86, 87, 88, 91, 119, 120, 121, 122, 125, 126, 127, 128, 129, 130, 132, 136, 139, 142], "retain": [20, 128], "through": [20, 128, 136, 140, 142], "command": [20, 22, 24, 25, 104, 125, 126, 127, 132, 133, 139, 142], "flag": [20, 126, 132], "prioriti": [20, 139], "fp": 21, "include_sourc": 21, "include_com": 21, "pointer": 21, "testio": 21, "indic": [21, 56, 57, 58, 59, 84, 117, 118, 119, 120, 125, 126, 128, 129, 130, 132, 136, 142], "defin": [21, 30, 32, 33, 34, 44, 51, 56, 57, 68, 70, 73, 74, 77, 78, 79, 82, 83, 84, 86, 87, 88, 100, 117, 118, 119, 120, 121, 123, 125, 126, 128, 132, 140, 142], "d": [22, 56, 58, 90, 123, 126, 127, 128, 136, 142], "fillvalu": 22, "format": [22, 33, 39, 44, 59, 92, 122, 124, 128, 132, 142], "engin": [22, 92], "char_dim_nam": 22, "xarrai": [22, 26, 27, 28, 46, 47, 48, 49, 68, 69, 70, 73, 74, 82, 84, 86, 87, 88, 90, 92, 113, 114, 115, 117, 119, 120, 121, 124, 126, 127, 129, 132, 142], "dataset": [22, 26, 27, 28, 46, 47, 48, 49, 51, 52, 59, 68, 69, 70, 82, 84, 86, 87, 88, 90, 92, 113, 114, 115, 117, 119, 120, 121, 123, 126, 127, 128, 132, 142], "netcdf4": [22, 92, 123], "fill": [22, 47, 142], "dimens": [22, 74, 84, 86, 87, 88, 92, 104, 118, 126, 133], "time": [22, 56, 57, 58, 59, 72, 74, 75, 118, 122, 126, 127, 128, 133, 136], "histori": [22, 25, 104, 126], "attribut": [22, 23, 25, 95, 96, 97, 98, 104, 126], "save": [22, 26, 27, 57, 92, 104, 126, 127, 128, 136], "netcdf": [22, 33, 39, 44, 59, 92, 93, 100, 102, 118, 124, 128, 136], "default_fil": 22, "default_fillv": 22, "netcdf4_class": [22, 92], "netcdf3_64bit": [22, 92], "netcdf3_class": [22, 92], "default_format": 22, "scipi": [22, 92, 119, 120, 121, 123], "h5netcdf": [22, 92], "librari": [22, 92, 126, 127], "output": [22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 39, 44, 46, 47, 48, 49, 51, 52, 71, 72, 75, 82, 83, 84, 92, 93, 118, 124, 126, 132, 136, 142], "to_netcdf": 22, "depend": [22, 118, 122, 124, 133, 142], "overrid": 22, "default_engin": 22, "let": 22, "figur": [22, 89, 133, 142], "default_char_dim_nam": 22, "strlen": 22, "logger": [23, 24, 26, 27, 28, 30, 31, 32, 46, 47, 48, 49, 51, 52, 82, 83, 124, 126], "log_filenam": [23, 124], "context": [23, 124, 130], "manag": 23, "creat": [23, 28, 36, 37, 46, 47, 48, 49, 55, 57, 82, 91, 93, 99, 100, 104, 122, 124, 125, 126, 127, 129, 131, 134, 135, 136, 137, 139, 140, 142], "send": 23, "stdout": [23, 26, 27, 28, 30, 31, 32, 46, 47, 48, 49, 51, 52, 82, 83, 124, 126], "stderr": [23, 124, 126], "anyth": 23, "els": 23, "just": [23, 124, 125, 127, 133, 142], "uniqu": [23, 56, 57, 58, 59, 124], "__name__": [23, 124, 127], "goe": 23, "arg": [24, 125], "log_command": 24, "timeout": 24, "kwarg": 24, "subprocess": [24, 122], "pass": [24, 45, 49, 84, 118, 124, 126, 128, 136, 142], "shell": 24, "one": [24, 27, 46, 48, 49, 51, 52, 55, 68, 84, 94, 119, 120, 124, 126, 127, 128, 129, 130, 131, 136, 140, 142], "ot": [24, 127], "keyword": 24, "popen": 24, "calledprocesserror": 24, "nonzero": 24, "statu": 24, "infile1": [25, 126], "infile2": [25, 126], "outfil": [25, 104, 126], "runner": [25, 104], "merg": [25, 27, 104, 122, 129, 132], "two": [25, 35, 38, 70, 104, 119, 120, 126, 127, 129, 131, 142], "non": [25, 92, 104, 126, 127], "contigu": [25, 47, 104, 126], "mesh": [25, 51, 52, 55, 56, 57, 58, 59, 69, 77, 78, 79, 82, 83, 84, 88, 90, 92, 93, 94, 100, 102, 104, 113, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 129, 130, 132, 133, 136, 140], "togeth": [25, 27, 58, 104, 118, 122, 126, 142], "global": [25, 36, 37, 38, 104, 126, 128, 132], "dsin": [26, 27], "graphinfofilenam": [26, 27, 126], "dir": [26, 27, 28, 31, 83, 124], "mpasmeshconvert": [26, 126, 127], "input": [26, 27, 34, 45, 56, 71, 72, 75, 126, 128, 132, 136, 142], "fulli": 26, "compliant": 26, "io": [26, 124, 126, 127, 132], "meshspec": 26, "pdf": 26, "data": [26, 27, 33, 42, 44, 51, 52, 61, 69, 74, 84, 86, 87, 88, 92, 117, 118, 119, 120, 126, 127, 128, 130, 131, 132, 133, 140], "info": [26, 27, 124, 126, 136], "By": [26, 27, 118, 125, 128, 129, 142], "log": [26, 27, 28, 30, 31, 32, 46, 47, 48, 49, 51, 52, 82, 83, 118, 122, 126, 127], "directori": [26, 27, 28, 31, 51, 52, 83, 90, 100, 118, 125, 131, 136, 142], "temporari": [26, 27, 28, 31, 83, 118, 136], "produc": [26, 27, 28, 31, 39, 52, 83, 84, 90, 126, 127, 129, 131, 132, 142], "delet": [26, 27, 28, 31, 83], "upon": [26, 27, 28, 31, 83], "complet": [26, 27, 28, 31, 83, 84, 142], "dsout": [26, 27, 119, 120], "dsmask": [27, 28, 46, 47, 48, 49, 68, 69, 70, 82, 126, 132], "dsinvers": 27, "dspreserv": 27, "mpascellcul": [27, 100, 126, 127, 136], "cell": [27, 30, 31, 32, 35, 36, 37, 38, 45, 46, 47, 48, 49, 51, 52, 55, 56, 57, 69, 70, 78, 79, 84, 86, 87, 91, 92, 97, 98, 104, 117, 118, 119, 120, 122, 123, 125, 132, 133, 135, 136, 140, 142], "base": [27, 48, 49, 55, 74, 84, 91, 125, 126, 127, 128, 129, 142], "cullcel": [27, 126], "field": [27, 41, 43, 45, 55, 56, 57, 77, 78, 79, 84, 86, 87, 88, 93, 94, 100, 102, 114, 118, 119, 120, 126, 128, 131, 133, 135, 136, 137], "mask": [27, 42, 68, 69, 70, 74, 82, 83, 91, 93, 98, 118, 122, 127, 132, 140, 142], "final": [27, 119, 120, 126, 128, 142], "union": 27, "preserv": [27, 51, 52, 126, 131], "determin": [27, 55, 56, 102, 126, 132, 136, 140], "possibli": [27, 74, 86, 87, 126], "remov": [27, 92, 100, 122, 126, 129, 142], "region": [27, 28, 36, 41, 42, 43, 46, 48, 55, 56, 59, 68, 69, 70, 82, 83, 89, 100, 122, 127, 129, 131, 132, 134, 136], "1": [27, 28, 41, 42, 43, 47, 58, 59, 74, 89, 107, 111, 112, 118, 119, 120, 123, 124, 126, 127, 128, 141, 142], "0": [27, 32, 36, 42, 46, 48, 49, 51, 52, 58, 59, 69, 70, 85, 89, 94, 102, 115, 118, 119, 120, 125, 126, 127, 128, 129, 141, 142], "culled_graph": 27, "dsmesh": [28, 47, 48, 49, 69, 70, 82, 117, 119, 120, 126, 127, 132, 142], "fcmask": [28, 46, 48, 49, 126, 129, 132], "core": [28, 126], "compute_mpas_region_mask": [28, 126], "collect": [28, 46, 47, 48, 49, 83, 89, 118, 126, 129, 132, 142], "geometric_featur": [28, 46, 47, 48, 49, 83, 89, 90, 118, 126, 127, 129, 132, 133, 142], "featurecollect": [28, 41, 42, 43, 46, 47, 48, 49, 83, 89, 90, 118, 126, 127, 132, 133, 142], "creation": [28, 56, 57, 58, 59, 91, 122, 124], "multiprocess": [28, 46, 48, 49, 91, 122], "cellwidth": [30, 31, 32, 34, 51, 52, 77, 78, 79, 123, 124, 127], "y": [30, 32, 45, 51, 66, 78, 92, 106, 107, 108, 109, 110, 111, 112, 115, 119, 124, 126, 127, 136, 139], "geom_point": [30, 32, 51, 124, 127], "geom_edg": [30, 32, 51, 124, 127], "out_filenam": [30, 31, 51, 52, 124, 127], "base_mesh": [30, 31, 51, 52, 123, 124, 126, 127, 129], "nc": [30, 31, 51, 52, 100, 104, 118, 123, 124, 126, 127, 128, 129, 131, 132, 136, 142], "planar": [30, 32, 33, 39, 51, 77, 78, 92, 112, 113, 114, 115, 119, 122, 126, 131, 140], "ndarrai": [30, 31, 32, 35, 36, 37, 38, 41, 42, 43, 45, 46, 51, 52, 55, 56, 57, 58, 59, 73, 78, 79, 97, 98, 106, 107, 108, 111, 112, 127], "width": [30, 31, 35, 36, 37, 38, 51, 52, 55, 56, 57, 78, 79, 89, 122, 123], "km": [30, 31, 35, 36, 37, 51, 52, 78, 79, 94, 126, 127, 128, 136, 142], "coordin": [30, 32, 45, 51, 71, 72, 73, 74, 75, 77, 78, 84, 107, 108, 111, 112, 113, 114, 115, 117, 118, 119, 120, 122, 126, 127, 128, 133, 140], "meter": [30, 31, 32, 33, 41, 43, 49, 51, 52, 55, 56, 57, 58, 78, 92, 126, 127, 128], "point": [30, 32, 41, 43, 47, 51, 56, 58, 59, 84, 89, 99, 101, 107, 108, 111, 112, 118, 119, 120, 122, 126, 127, 128, 139, 140, 142], "bound": [30, 32, 45, 51, 57, 59, 73, 84, 126, 127, 128, 142], "polygon": [30, 32, 46, 48, 51, 89, 118, 126, 127, 142], "edg": [30, 32, 46, 48, 49, 51, 98, 104, 118, 119, 120, 121, 126, 127, 132, 140, 142], "result": [30, 31, 32, 51, 52, 56, 57, 58, 59, 84, 86, 87, 88, 95, 96, 97, 98, 102, 118, 119, 120, 121, 126, 127, 128, 132, 136, 142], "lon": [31, 32, 34, 35, 41, 42, 43, 46, 48, 52, 54, 56, 57, 58, 59, 61, 62, 65, 79, 84, 89, 109, 110, 117, 118, 120, 123, 124, 127, 128], "lat": [31, 32, 34, 35, 36, 37, 38, 41, 42, 43, 46, 48, 52, 54, 56, 57, 58, 59, 61, 62, 65, 79, 84, 89, 109, 110, 117, 118, 120, 123, 124, 127, 128], "earth_radiu": [31, 32, 41, 43, 108, 109, 110, 123, 124, 127], "plot_cellwidth": [31, 52, 124], "jigsaw": [31, 32, 33, 34, 52, 122, 124], "size": [31, 32, 45, 52, 106, 118, 126, 127, 133, 142], "latitud": [31, 36, 41, 42, 43, 45, 46, 48, 49, 52, 55, 56, 57, 58, 59, 69, 70, 89, 97, 98, 120, 123, 126, 127, 128, 129, 135, 140], "longitud": [31, 41, 42, 43, 45, 46, 48, 49, 52, 55, 56, 57, 58, 59, 79, 97, 98, 117, 120, 123, 126, 127, 128, 135, 140, 142], "store": [31, 52, 118, 126], "sever": [31, 52, 127, 128, 129, 135, 136, 142], "intermedi": [31, 52, 127, 132], "hfun": [31, 52, 127], "msh": [31, 51, 52, 124, 127, 131], "jig": [31, 52, 124, 127], "mesh_triangl": [31, 52, 124, 127], "degre": [31, 35, 36, 37, 38, 41, 43, 45, 46, 48, 52, 55, 56, 57, 58, 69, 70, 79, 89, 97, 109, 110, 117, 120, 126, 127, 128, 129, 142], "length": [31, 35, 36, 37, 38, 45, 52, 79, 111, 112, 126, 127, 140], "180": [31, 35, 46, 52, 55, 56, 57, 58, 79, 117, 123, 126, 127, 128, 142], "90": [31, 35, 36, 37, 38, 46, 52, 55, 56, 57, 58, 79, 123, 127, 128, 142], "plot": [31, 52, 56, 57, 58, 59, 89, 90, 100, 117, 118, 119, 120, 128, 136, 140, 142], "cellwidthglob": [31, 52], "png": [31, 52, 56, 57, 58, 59, 90, 128], "convers": [31, 83, 118, 122, 127, 129, 132, 142], "on_spher": [32, 33, 77, 124], "6371000": 32, "spheric": [32, 33, 77, 79, 126, 131, 140], "logic": 32, "msh_filenam": [33, 124], "output_nam": [33, 44, 124, 126], "sphere_radiu": [33, 124, 126], "convert": [33, 39, 44, 109, 110, 122, 124, 127, 140, 142], "triangl": [33, 39, 44, 84, 86, 87, 88, 117, 119, 120, 121, 122, 124], "sphere": [33, 94, 107, 111, 112, 127, 140, 142], "otherwis": [33, 126], "ignor": [33, 57, 102, 118, 124, 128], "regular": [34, 118, 123, 127, 135, 142], "grid": [34, 35, 41, 42, 43, 45, 46, 56, 57, 58, 59, 62, 84, 88, 89, 92, 97, 122, 123, 126, 127, 128, 129], "cellwidthinatlant": 35, "cellwidthinpacif": 35, "distribut": [35, 38, 46, 48, 49, 127], "tanh": [35, 38, 127], "vector": [35, 36, 37, 38, 111, 112], "atlant": [35, 128, 132], "pacif": [35, 128, 132], "cellwidthout": [35, 36, 37, 38], "globe": [35, 142], "cellwidtheq": [36, 37, 127], "30": [36, 46, 48, 126, 127, 128, 142], "cellwidthmidlat": 36, "60": [36, 127, 128, 133, 136, 142], "cellwidthpol": [36, 37, 127], "35": [36, 127], "latposeq": 36, "15": [36, 127, 141], "latpospol": 36, "73": [36, 127, 128], "lattransit": [36, 38, 127], "40": [36, 126, 127, 128], "latwidtheq": 36, "6": [36, 37, 118, 119, 120, 125, 127, 128, 141, 142], "latwidthpol": 36, "9": [36, 127, 128, 141], "eddi": [36, 57, 123, 128, 142], "closur": [36, 57, 123, 128, 142], "intend": [36, 37, 38, 132, 136], "workflow": [36, 37, 38, 122, 128, 129, 132, 139, 142], "equat": [36, 37, 127, 128], "mid": [36, 127], "pole": [36, 37, 45, 126, 127, 128], "center": [36, 45, 47, 92, 97, 98, 114, 117, 119, 120, 121, 123, 126, 127, 128, 142], "equatori": [36, 100, 127, 136], "transit": [36, 38, 56, 127, 128], "polar": [36, 70, 89, 100, 127, 129, 136], "1d": [36, 37, 41, 42, 43, 46, 55, 56, 57, 58, 71, 84, 122, 126, 127], "ec60to30": 36, "half": [36, 128], "resolut": [36, 49, 55, 56, 57, 111, 112, 119, 120, 126, 127, 128, 142], "ec120to60": 36, "120": [36, 128], "70": 36, "rossbi": [37, 57, 128], "scale": [37, 57, 122, 127, 128], "rrs18to6": 37, "ec_cellwidthvslat": [37, 57, 123, 127], "18": [37, 127, 141], "cellwidthinsouth": [38, 127], "cellwidthinnorth": [38, 127], "latwidthtransit": [38, 127], "mpasfil": [39, 93], "trifil": 39, "script": [39, 91, 122, 125, 126, 127, 132, 139], "www": 39, "c": [39, 122, 126, 133, 136], "cmu": 39, "edu": 39, "quak": 39, "node": [39, 44, 84, 86, 87, 88, 117, 119, 120, 126, 142], "el": [39, 44, 126], "prefix": [39, 75, 100, 126, 130, 136], "extens": [39, 125], "work": [39, 46, 48, 49, 92, 101, 124, 126, 136, 139, 142], "fc": [41, 42, 43, 83, 89, 90, 127, 142], "lon_grd": [41, 42, 43, 55, 57, 58], "lat_grd": [41, 42, 43, 55, 57, 58], "nn_search": [41, 58, 128], "kdtree": [41, 58, 128], "max_length": [41, 43, 127], "worker": [41, 43, 47, 58], "distanc": [41, 43, 56, 58, 92, 94, 107, 108, 111, 112, 119, 120, 122, 134], "closest": [41, 43, 47, 56, 58, 86, 126], "boundari": [41, 43, 82, 83, 118, 127, 128, 129, 132, 142], "geojson": [41, 42, 43, 126, 127, 129, 132, 133], "geometrics_featur": [41, 42, 43], "raster": [41, 42, 43], "find": [41, 43, 47, 58, 69, 119, 120, 121, 126, 129, 136, 139, 140], "nearest": [41, 43, 47, 58, 127, 128], "shape": [41, 42, 43, 46, 48, 49, 89, 126, 127], "maximum": [41, 43, 49, 57, 59, 69, 98, 111, 112, 126, 128], "too": [41, 43, 49, 126, 129, 142], "coars": [41, 43, 49, 126, 127, 142], "subdivid": [41, 43, 46, 48, 49, 89, 111, 112, 119, 120, 122, 126], "thread": [41, 43, 46, 47, 48, 49, 58], "neighbor": [41, 43, 47, 58, 86, 128], "2d": [41, 42, 43, 55, 57, 84, 97, 122, 123, 126, 127], "multipolygon": 42, "outsid": [42, 43, 48, 49, 56, 126, 127, 128], "insid": [42, 43, 48, 49, 124, 126, 127], "neg": [43, 127], "posit": [43, 74, 84, 126, 127], "xcell": [45, 114, 126], "ycell": [45, 114, 126], "perform": [45, 46, 48, 49, 84, 89, 91, 94, 101, 124, 126, 136, 140, 142], "bilinear": [45, 84, 123], "tensor": [45, 46, 123, 127], "recommend": 45, "avoid": [45, 70, 129], "round": 45, "off": [45, 142], "problem": [45, 129, 142], "north": [45, 126, 127], "south": [45, 126, 127, 132], "date": [45, 136, 142], "fo": [45, 128, 142], "mpasfield": 45, "interpoi": 45, "pool": [46, 48, 49, 91, 126], "chunksiz": [46, 48, 49, 126], "1000": [46, 48, 49, 126, 127, 128], "showprogress": [46, 48, 49, 126], "subdivisionthreshold": [46, 48, 126], "process": [46, 48, 49, 126], "made": [46, 48, 49, 56, 59, 125, 126, 127, 128, 132], "up": [46, 48, 49, 56, 59, 84, 86, 87, 88, 119, 120, 121, 126, 128, 131, 132, 136, 142], "vertic": [46, 48, 49, 73, 74, 84, 97, 98, 104, 117, 118, 119, 120, 126, 129, 130, 132, 133, 135, 140, 142], "oper": [46, 47, 48, 49, 126], "experiment": [46, 48, 49], "shown": [46, 48, 49], "reason": [46, 48, 49, 126, 142], "compromis": [46, 48, 49], "divid": [46, 48, 49, 84, 117, 126], "suffici": [46, 48, 49, 126], "subtask": [46, 48, 49], "load": [46, 48, 49, 126], "show": [46, 48, 49, 89, 126, 132, 133, 136, 142], "progress": [46, 48, 49, 51, 52, 118, 126], "bar": [46, 48, 49, 51, 52, 118, 126], "threshold": [46, 48, 126, 129], "smaller": [46, 48, 126, 140, 142], "faster": [46, 48, 123, 126], "intersect": [46, 48, 119, 120, 121, 126, 140], "fcseed": [47, 126], "flood": [47, 51, 52], "seed": [47, 126], "cellsoncel": [47, 126, 142], "whose": [47, 114], "masktyp": [48, 49], "vertex": [48, 49, 96, 126], "locat": [48, 49, 84, 89, 126, 128, 129, 136, 142], "latcel": [48, 49, 98, 123], "loncel": [48, 49, 98, 123], "earthradiu": [49, 111], "subdivisionresolut": [49, 126], "10000": [49, 118, 119, 120], "addedgesign": [49, 126], "transect": [49, 68, 69, 70, 82, 83, 89, 90, 122], "segment": [49, 84, 85, 89, 107, 111, 112, 119, 120, 121, 126, 140], "subdivis": [49, 89, 111, 112, 126, 140], "edgesign": 49, "signific": [49, 130, 136, 142], "extra": [49, 118, 126, 142], "comput": [49, 73, 74, 83, 84, 107, 118, 122, 127, 130, 132, 142], "vtk_dir": [51, 52], "base_mesh_vtk": [51, 52, 131], "preserve_floodplain": [51, 52], "floodplain_elev": [51, 52, 80], "20": [51, 52, 126, 127, 129, 141], "do_inject_bathymetri": [51, 52], "use_progress_bar": [51, 52, 118], "extract": [51, 52, 58, 59, 118, 122, 127, 131], "paraveiw": [51, 52, 131, 142], "plain": [51, 52], "bathymetri": [51, 52, 59, 74, 84, 128, 131], "z": [51, 52, 73, 84, 106, 107, 108, 109, 110, 111, 128, 130], "elev": [51, 52, 131], "earth_relief_15": [51, 52, 128, 131], "topo": [51, 52, 131], "displai": [51, 52, 118, 142], "problemat": [51, 52, 118], "author": [53, 127, 132, 133], "steven": 53, "bru": 53, "last": [53, 132], "07": 53, "09": 53, "2018": [53, 132], "param": [55, 128], "cell_width": [55, 56, 57, 65, 128], "background": [55, 57, 122], "refin": [55, 56, 122], "construct": [55, 84, 117, 127, 128, 131, 142], "default_param": [55, 128], "create_background_mesh": [55, 128], "dx_min": [56, 57, 127], "trans_start": [56, 127, 128], "trans_width": [56, 127, 128], "restrict_box": [56, 128], "plot_opt": [56, 57, 58, 59, 128], "plot_box": [56, 57, 58, 59, 63, 128], "coastlin": [56, 58, 59, 122, 126], "blend": [56, 122], "contour": [56, 58, 59, 128], "len": [56, 58, 107, 111, 112], "smooth": [56, 58, 127, 128], "distance_to_coast": [56, 128], "approxim": [56, 111, 112, 127, 130, 142], "quadrilater": [56, 59, 84, 128, 142], "exclud": [56, 59, 128, 142], "mai": [56, 102, 119, 120, 125, 126, 127, 128, 130, 136, 139, 142], "alter": [56, 69, 70, 122, 126, 128], "remain": [56, 128, 131], "unchang": [56, 126, 128], "trans_func": 56, "meant": [56, 57, 58, 59, 129], "been": [56, 57, 58, 59, 84, 104, 125, 126, 128, 136], "extent": [56, 57, 58, 59], "along": [56, 58, 59, 84, 108, 111, 112, 118, 119, 120, 126, 127, 128, 140, 142], "extract_coastlin": [56, 58, 128], "give": [56, 57, 58, 59], "grd_box": [57, 128], "ddeg": [57, 128], "mesh_typ": [57, 128], "dx_max": 57, "4": [57, 59, 77, 78, 79, 118, 126, 127, 128, 141, 142], "min": [57, 59, 128], "max": [57, 59, 104, 128], "qu": [57, 128], "ec": [57, 123, 127, 128, 142], "rr": [57, 127, 128], "quasi": [57, 128], "uniform": [57, 122, 128], "minimum": [57, 69, 70, 126, 128], "instead": [57, 126, 127, 142], "bckgrnd_grid_cell_width_vs_lat": 57, "bckgnd_grid_cell_width": 57, "smooth_window": 58, "algorithm": [58, 126, 128], "neightbor": 58, "search": [58, 69, 128], "adjac": [58, 92, 117, 118, 142], "averag": [58, 119, 120, 128, 142], "coastal": [58, 122, 131], "bathy_coastlin": [58, 59], "nc_file": [59, 128], "nc_var": [59, 128], "region_box": [59, 128], "z_contour": [59, 128], "n_longest": [59, 128], "10": [59, 69, 118, 126, 127, 128, 141, 142], "point_list": [59, 128], "rectangl": [59, 128], "isocontour": 59, "sort": [59, 128], "longest": [59, 128], "shortest": [59, 128], "box": [60, 61, 62, 64, 118, 126, 128, 142], "idx": 61, "ax": [63, 89, 90], "color": 64, "window": 66, "dsblockag": 68, "land": [68, 69, 70, 122, 126, 128, 142], "critic": [68, 70, 129], "blockag": [68, 70, 122], "flow": [68, 70, 129, 132], "antarct": [68, 70], "peninsula": [68, 70, 129], "latitude_threshold": [69, 70, 129], "43": [69, 70, 129], "nsweep": [69, 129], "lock": [69, 122], "count": [69, 126, 129, 136], "widen": [69, 70, 122], "sweep": 69, "passag": [70, 129, 133], "least": [70, 127, 129, 130], "wide": [70, 126, 129, 132], "infilenam": [71, 72, 75], "outfilenam": [71, 72, 75, 92, 125, 127], "coordfilenam": [71, 72, 75], "coord": [71, 72, 118, 142], "via": [71, 72, 118, 126, 128, 142], "refbottomdepth": [71, 73, 130], "3d": [72, 75, 86, 87, 122, 142], "independ": [72, 75, 84, 118, 130, 142], "zmid": [72, 74, 75, 122], "bottomdepth": [72, 74, 75, 84, 118, 130, 142], "maxlevelcel": [72, 74, 75, 84, 118, 130, 133, 142], "layerthick": [72, 74, 75, 84, 130, 133], "dataarrai": [73, 74, 84, 86, 87, 88, 119, 120], "bottom": [73, 74, 118, 130, 142], "layer": [73, 74, 84, 118, 130, 142], "initi": [73, 122, 136, 142], "state": 73, "perfect": 73, "level": [73, 84, 98, 118, 122, 128, 131, 135, 142], "middl": [73, 74], "depth_bnd": 73, "top": [73, 89, 118, 142], "depth_dim": 74, "nvertlevel": [74, 84, 86, 87, 118, 133, 142], "thick": [74, 84, 142], "below": [74, 127, 139, 142], "form": [75, 142], "timemonthly_avg_": [75, 130], "mesh_fil": [76, 80, 132], "cw_filenam": 77, "mesh_filenam": [77, 78, 79, 83, 118, 132, 133, 142], "meshdens": [77, 78, 79, 126], "mincellwidth": [77, 78, 79], "oppos": [77, 97, 120], "basin": [82, 83, 122], "correspond": [82, 117, 118, 126, 136, 142], "southern": [82, 83, 122, 127, 142], "gf": [83, 126, 129, 132, 142], "mask_and_transect_filenam": [83, 132], "geojson_filenam": [83, 132, 133], "mask_filenam": [83, 132], "meridion": [83, 122], "overturn": [83, 122], "circul": [83, 122], "geometricfeatur": [83, 126, 129, 132, 142], "download": [83, 105, 136, 142], "geometr": 83, "inform": [83, 104, 126, 136, 142], "dstransect": 84, "ztransect": 84, "py": [84, 119, 120, 121, 125, 126, 132, 133, 142], "fun": [84, 119, 120, 121], "viz": [84, 131, 133, 142], "find_transect_cells_and_weight": 84, "break": [84, 128], "visual": [84, 122, 126, 130, 140], "tripcolor": [84, 142], "tricontourf": 84, "interpol": [84, 86, 87, 88, 111, 112, 117, 119, 120, 122, 126, 142], "weight": [84, 117, 119, 120, 127, 142], "observ": [84, 119, 120], "transectz": 84, "bilinearli": 84, "down": [84, 128], "depth": [84, 118, 122, 142], "seafloor": [84, 142], "zero": [84, 119, 120, 126, 127, 129], "dstransecttriangl": [84, 85, 86, 87, 88], "conveni": [84, 124, 142], "upper": [84, 89], "lower": [84, 89, 135, 140], "potenti": 84, "jump": 84, "constant": [84, 87, 105, 119, 120, 122, 123, 127, 128, 142], "ntransecttriangl": [84, 86, 87, 88], "ntransectcel": 84, "ntrianglenod": [84, 86, 87, 88], "nodehorizboundsindic": 84, "nhorizbound": 84, "horizont": [84, 111, 112, 130, 133], "segmentindic": 84, "cellindic": 84, "levelindic": 84, "ztransectnod": 84, "height": [84, 89], "ssh": 84, "zseafloor": 84, "surfac": [84, 118, 130, 142], "floor": 84, "interpcellindic": 84, "interplevelindic": 84, "involv": [84, 136, 142], "nweight": 84, "12": [84, 127, 128, 141], "interpcellweight": 84, "multipli": 84, "transectinterpvertindic": 84, "transectinterpvertweight": 84, "interp_mpas_to_transect_triangle_nod": 84, "similarli": [84, 118, 126, 129, 131, 142], "interp_transect_grid_to_transect_triangle_nod": 84, "sampl": [84, 118, 142], "ncell": [84, 86, 87, 98, 104, 126, 133, 142], "smoother": 84, "desir": [84, 126, 128, 130, 136, 142], "sum": [84, 142], "epsilon": 85, "001": 85, "outlin": 85, "da": [86, 87, 88], "linearli": [86, 142], "find_transect_levels_and_weight": [86, 87, 88], "among": [86, 87], "danod": [86, 87, 88], "whatev": [86, 87, 126], "were": [86, 87, 142], "besid": [86, 87], "fig": 89, "latlonbuff": 89, "45": 89, "polarbuff": 89, "5": [89, 102, 118, 127, 128, 132, 141, 142], "lowerleft": 89, "xbuffer": 89, "ybuffer": 89, "maxlength": 89, "inset": 89, "map": [89, 126], "entir": [89, 142], "poleward": [89, 129], "50": [89, 136], "deg": 89, "matplotlib": [89, 116, 127, 142], "buffer": 89, "around": [89, 127, 128], "equatorward": 89, "inch": 89, "pair": [89, 117, 126, 142], "left": [89, 142], "corner": 89, "axi": [89, 133, 142], "put": [89, 142], "right": [89, 142], "longer": 89, "curvatur": [89, 119, 120], "ds_mesh": 90, "variable_list": [90, 118, 133, 142], "cmap": 90, "flip": [90, 133], "imag": 90, "transect_nam": 90, "_": [90, 123, 125, 127], "variable_nam": 90, "colormap": [90, 122, 133], "book": 90, "process_count": [91, 126], "forkserv": [91, 126], "crate": [91, 124], "onc": [91, 119, 120], "cull": [91, 92, 118, 126, 127, 142], "termin": [91, 126], "exit": [91, 126, 132, 133, 136], "processor": [91, 100, 126, 136], "fork": [91, 126], "spawn": [91, 126], "mutiprocess": 91, "nx": [92, 125, 126, 127], "ny": [92, 125, 126, 127], "dc": [92, 125, 126, 127], "nonperiodic_x": [92, 125, 126, 127], "nonperiodic_i": [92, 125, 126, 127], "comparewithfilenam": 92, "period": [92, 117, 126, 127], "hexagon": [92, 127, 142], "request": [92, 111, 112, 126, 132, 136, 142], "direct": [92, 115, 125, 126, 127, 136], "compar": 92, "ident": [92, 106, 136, 142], "purpos": [92, 126, 127, 132, 142], "further": 92, "manipul": [92, 134, 142], "scripfil": 93, "uselandicemask": 93, "landicemask": 93, "filenamemesh": [94, 102], "filenamepres": 94, "extenddist": 94, "unitspher": 94, "icepresenceextend": 94, "doesn": [94, 126, 127, 136], "alreadi": [94, 118, 136, 139], "icepres": [94, 136], "extend": [94, 122, 142], "expand": [94, 142], "expans": 94, "unit": [94, 111, 112], "meshfilenam": [95, 96, 100, 136], "scripfilenam": [95, 96, 98], "titl": [95, 96, 97, 98], "scrip": [95, 96, 97, 98, 122], "cel": 95, "quantiti": [95, 96], "filenamescripout": 97, "scriptitl": 97, "ncolumn": 97, "nrow": 97, "latscentr": 97, "lonscentr": 97, "latsvertex": 97, "lonsvertex": 97, "column": [97, 142], "row": 97, "radian": [97, 98, 107, 117, 120, 140, 142], "maxedg": [98, 104, 118, 126, 142], "corner_lat": 98, "corner_lon": 98, "low": [98, 122], "regionfilenam": 100, "nprocsarrai": [100, 136], "mpascullerloc": [100, 136], "outputprefix": [100, 136], "meti": [100, 126, 136], "cullequatorialregion": 100, "own": [100, 118, 130, 132, 133, 136, 142], "look": [100, 119, 120, 127, 132, 133, 142], "prepend": [100, 136], "partition_diag": [100, 136], "exect": 100, "parit": 100, "preparatori": [101, 136], "filenameicepres": 102, "regiontyp": 102, "varnam": 102, "limit": [102, 142], "filenameout": [102, 103], "specifi": [102, 104, 115, 118, 126, 128, 129, 131, 133, 142], "three_region": 102, "two_region_eq": 102, "three_region_eq": 102, "five_region_eq": 102, "might": [102, 121, 124, 127, 133, 136, 142], "consid": [102, 142], "meshfilenamesrc": [103, 136], "filenamedata": [103, 136], "meshfilenamedst": [103, 136], "generateweight": 103, "weightsfilenam": 103, "infil": [104, 126], "outfile1": [104, 126], "outfile2": [104, 126], "nedg": [104, 126, 142], "nvertic": [104, 126, 142], "split": [104, 122], "previous": [104, 123, 126], "usag": [104, 126, 132, 133, 136], "sould": 104, "merge_point": [104, 126], "merge_grid": [104, 126], "OR": [104, 126], "assum": [104, 126], "both": [104, 124, 125, 126, 127, 128, 130, 132, 135, 136, 139, 140, 142], "e3sm_tag": 105, "cime": [105, 122, 127], "tag": [105, 126, 129], "repres": 106, "cartesian": [106, 107, 108, 109, 110, 111, 117, 118, 120, 126, 140, 142], "compon": [106, 118, 122, 126, 127, 133, 142], "angular": 107, "en": [107, 111, 112], "wikipedia": [107, 111, 112], "org": [107, 111, 112], "wiki": [107, 111, 112], "great": [107, 108, 120], "circle_dist": 107, "lengt": 107, "circl": [108, 120, 127], "maxr": [111, 112], "match": [111, 112, 118, 125, 126, 136], "formula": [111, 112], "slerp": [111, 112], "xout": [111, 112], "guarante": [111, 112, 117, 124, 142], "yout": [111, 112], "zout": 111, "din": [111, 112], "dout": [111, 112], "shift": [113, 114, 115, 126, 142], "domain": [113, 114, 118, 126, 142], "othermesh": 114, "describ": [114, 125, 126, 139, 142], "becom": [114, 129, 142], "secondli": [114, 126], "try": [114, 126], "x1": [114, 126], "y1": [114, 126], "xoffset": [115, 126], "yoffset": [115, 126], "arbitrari": 115, "regist": 116, "sciviscolor": [116, 142], "periodiccopi": [117, 142], "connect": [117, 126, 142], "cross": [117, 140], "help": [117, 125, 126, 132, 133, 136, 137], "dstri": [117, 119, 120, 121, 142], "tricellindic": [117, 142], "nodecellindic": [117, 142], "nodecellweight": [117, 142], "xnode": [117, 119, 142], "ynode": [117, 119, 142], "znode": [117, 142], "lonnod": [117, 120, 142], "latnod": [117, 120, 142], "counterclockwis": [117, 142], "wind": [117, 142], "filename_pattern": [118, 142], "dimension_list": [118, 142], "output_32bit": 118, "append": [118, 127], "out_dir": [118, 142], "vtk_file": [118, 142], "xtime": [118, 142], "lonlat": [118, 142], "ignore_tim": [118, 142], "topo_dim": [118, 142], "topo_cell_index": [118, 142], "include_mesh_var": [118, 142], "fc_region_mask": [118, 142], "temp_dir": 118, "culled_region": 118, "seri": 118, "vtk": [118, 122, 131], "paraview": [118, 122], "across": [118, 122, 126, 142], "pattern": [118, 142], "hist": [118, 142], "comp": 118, "staticfieldsoncel": [118, 142], "vtp": [118, 142], "timedependentfieldsoncel": [118, 142], "pvd": [118, 142], "time_seri": [118, 142], "step": [118, 124, 126, 128, 142], "filter": [118, 142], "expens": [118, 142], "consider": [118, 142], "storag": [118, 142], "runtim": [118, 142], "prompt": [118, 126, 142], "mean": [118, 129, 139, 142], "skip": [118, 142], "colon": [118, 142], "nvertlev": [118, 142], "nparticl": [118, 142], "8": [118, 125, 128, 133, 141, 142], "everi": [118, 142], "its": [118, 124, 126, 130, 142], "particl": [118, 142], "wai": [118, 124, 125, 126, 127, 132, 133, 136, 139, 142], "mix": [118, 142], "extractor": [118, 122], "geometri": [118, 127, 129, 131, 133, 142], "appropri": [118, 128, 130, 142], "topograph": 118, "spatial": [118, 119, 120, 121, 142], "accomplish": [118, 124, 126, 129, 142], "face": [118, 142], "normal": [118, 125, 142], "topographi": [118, 131, 142], "boundarymask": [118, 142], "interior": [118, 142], "calcul": [118, 142], "100": [118, 127, 128, 142], "mag": [118, 142], "enter": [118, 142], "exagger": [118, 142], "factor": [118, 127], "equival": [118, 126, 127, 142], "tight": [118, 142], "alloncel": [118, 142], "32bit": 118, "dim": 118, "lie": [118, 119, 120, 142], "proce": [118, 142], "xtransect": 119, "ytransect": 119, "tree": [119, 120, 121, 125], "subdivisionr": [119, 120], "mesh_to_triangl": [119, 120, 121, 142], "full": [119, 120, 126, 142], "ckdtree": [119, 120, 121], "make_triangle_tre": [119, 120], "candid": [119, 120], "enough": [119, 120, 121, 126], "end": [119, 120, 128, 136, 142], "intern": [119, 120, 126, 130], "purposefulli": [119, 120], "repeat": [119, 120, 128], "twice": [119, 120], "touch": [119, 120], "discontinu": [119, 120, 127], "wish": [119, 120, 126, 142], "dnode": [119, 120], "horiztriangleindic": [119, 120], "horiztrianglenodeindic": [119, 120], "mod": [119, 120, 123], "belong": [119, 120], "horizcellindic": [119, 120], "interphorizcellindic": [119, 120], "interphorizcellweight": [119, 120], "area": [119, 120, 128, 134, 142], "linear": [119, 120], "dtransect": [119, 120], "order": [119, 120, 125, 126], "transectindicesonhoriznod": [119, 120], "transectweightsonhoriznod": [119, 120], "nodevalu": [119, 120], "transectvalu": [119, 120], "lontransect": 120, "lattransect": 120, "xcartnod": 120, "ycartnod": 120, "zcartnod": 120, "xcarttransect": 120, "ycarttransect": 120, "zcarttransect": 120, "kd": 121, "compil": [122, 136], "fortran": [122, 136], "predict": 122, "configur": 122, "setup": [122, 125, 127], "framework": 122, "analyz": 122, "simul": [122, 127, 130, 131, 136, 142], "definit": [122, 126, 129, 139], "sign": [122, 126], "culler": [122, 136], "creator": [122, 129, 132], "translat": [122, 142], "config": [122, 139], "coast": 122, "moc": 122, "seaic": [122, 127, 129, 134, 136, 137], "partit": [122, 126], "regrid": [122, 136], "updat": [122, 126, 128, 139], "api": 122, "contributor": 122, "variou": [123, 133, 139], "howev": [123, 130, 136, 142], "routin": [123, 142], "suit": [123, 133], "slow": [123, 126], "veri": [123, 126, 142], "memori": [123, 126], "intens": 123, "particularli": [123, 126, 132, 142], "larg": [123, 126, 128, 132, 142], "interp_bilin": 123, "nc4": 123, "dlon": [123, 127], "dlat": [123, 127], "nlon": [123, 127], "360": [123, 126, 127, 142], "nlat": [123, 127], "mdt": [123, 127], "broadcast": [123, 127], "meshgrid": [123, 127], "cellwidthvslat": [123, 127], "r": 123, "rad2deg": [123, 142], "cellwidthonmpa": 123, "capabl": [124, 142], "loggingcontext": 124, "statement": 124, "debug": [124, 132], "error": 124, "It": [124, 126, 127, 136, 142], "kind": [124, 142], "often": [124, 136, 140, 142], "necessarili": [124, 127], "want": [124, 126, 127, 136, 142], "ong": 124, "As": [124, 125, 127], "snippet": [124, 127], "build_mesh": [124, 127, 131], "build_spherical_mesh": [124, 127, 131], "def": [124, 125, 127], "jigsaw_driv": [124, 127], "jigsaw_to_netcdf": [124, 126], "write_netcdf": [124, 126], "open_dataset": [124, 126, 129, 132, 142], "That": 124, "properli": 124, "captur": [124, 126], "check_cal": 124, "act": 124, "lot": [124, 142], "go": [124, 126, 142], "6371": 124, "0e3": 124, "opt": 124, "jcfg_file": 124, "best": [125, 139], "somewher": 125, "recip": 125, "yaml": 125, "planar_hex": [125, 126, 127], "entry_point": 125, "console_script": 125, "instal": [125, 136, 139], "stub": 125, "argpars": 125, "argumentpars": 125, "descript": 125, "__doc__": 125, "formatter_class": 125, "rawtexthelpformatt": 125, "add_argu": 125, "dest": 125, "parse_arg": 125, "make_planar_hex_mesh": [125, 126, 127], "convent": [125, 142], "introduc": 125, "text": 125, "spec": [125, 139], "txt": [125, 126, 139], "alphabet": 125, "affin": 125, "forg": [125, 139], "anaconda": 125, "channel": [125, 129, 139], "pleas": 125, "contact": [125, 126], "speck": 125, "under": [125, 126, 142], "env": [125, 126, 127, 139], "cartopi": 125, "releas": 125, "__version_info__": 125, "__version__": 125, "join": 125, "vi": 125, "increment": 125, "major": [125, 126], "minor": 125, "micro": 125, "what": [125, 133, 142], "sens": [125, 126, 140], "third": 125, "v0": [125, 141], "link": [125, 131, 136], "won": [125, 136], "until": 125, "azur": 125, "pipelin": 125, "eventu": 125, "yet": [125, 126], "wrapper": 126, "10e3": 126, "o": [126, 132, 136, 142], "doubli": 126, "sure": [126, 127, 139, 142], "adher": 126, "regardless": 126, "mere": 126, "previou": [126, 128, 139, 142], "16": [126, 128, 141], "32": 126, "vertexdegre": 126, "zcell": 126, "xvertex": 126, "yvertex": 126, "zvertex": 126, "cellsonvertex": 126, "on_a_spher": 126, "NO": 126, "is_period": 126, "ye": 126, "histor": 126, "ones": [126, 127, 129], "kilomet": [126, 127], "x_period": 126, "40000": 126, "y_period": 126, "34641": 126, "0161513775": 126, "tue": 126, "26": 126, "58": [126, 128, 133], "2020": 126, "home": 126, "miniconda3": [126, 136], "bin": [126, 127], "file_id": 126, "parent_id": 126, "random": 126, "hash": 126, "screen": 126, "invers": 126, "merge_featur": 126, "natural_earth": [126, 129], "b": [126, 129], "coverag": [126, 129, 136], "mpasmaskcr": 126, "f": [126, 132, 133, 136, 139, 142], "culled_mesh": [126, 127], "next": [126, 128, 142], "fclandcoverag": [126, 129], "componentnam": [126, 129, 142], "objecttyp": [126, 129, 142], "featurenam": [126, 129, 142], "dsbasemesh": [126, 129], "dslandmask": [126, 129], "dsculledmesh": 126, "input_nam": 126, "p": [126, 136, 142], "masks_nam": 126, "control": [126, 128], "appli": [126, 132, 142], "forc": 126, "old": 126, "cellmap": 126, "cellmapforward": 126, "revers": 126, "cellmapbackward": 126, "in_fil": [126, 132], "out_fil": [126, 132], "positive_lon": 126, "algorithim": 126, "isol": 126, "unlik": 126, "rare": 126, "standard": [126, 142], "logitud": 126, "prime": [126, 142], "meridian": [126, 142], "being": 126, "standar": 126, "repo": [126, 139], "fact": 126, "recomput": 126, "serial": 126, "effici": [126, 132, 136, 142], "sophist": 126, "better": [126, 136], "enabl": 126, "now": [126, 127, 128, 139, 142], "futur": 126, "much": 126, "regioncellmask": 126, "far": 126, "parallel": 126, "create_pool": 126, "finish": [126, 136], "frustratingli": 126, "incur": 126, "high": [126, 127, 128], "overhead": [126, 136], "while": [126, 127, 128, 132], "lead": [126, 142], "poor": 126, "balanc": [126, 136], "infrequ": 126, "seem": 126, "varieti": 126, "good": 126, "idea": 126, "tile": 126, "larger": [126, 132], "underli": [126, 127, 128], "consum": 126, "again": [126, 139, 142], "altern": [126, 136], "explor": [126, 142], "nregion": 126, "regionedgemask": 126, "regionvertexmask": 126, "regionnam": 126, "string64": 126, "invalid": 126, "ncellsinregion": 126, "h": [126, 132, 133, 136], "mesh_file_nam": 126, "geojson_file_nam": 126, "mask_file_nam": 126, "mask_typ": 126, "chunk_siz": 126, "show_progress": 126, "multiprocessing_method": 126, "messag": [126, 132, 133, 136], "compute_mpas_transect_mask": 126, "represent": 126, "distort": 126, "becaus": [126, 127, 130, 132, 136, 142], "design": [126, 127], "plane": [126, 142], "care": [126, 132, 142], "taken": [126, 128], "handl": [126, 142], "datelin": 126, "antimeridian": 126, "issu": [126, 142], "close": 126, "worth": 126, "modif": 126, "transectcellmask": 126, "ntransect": 126, "transectedgemask": 126, "transectvertexmask": 126, "transectnam": 126, "don": [126, 133, 136], "transectcellglobalid": 126, "could": [126, 127, 128, 130, 142], "demand": 126, "transectedgemasksign": 126, "sinc": [126, 129, 140, 142], "someth": [126, 136], "add_edge_sign": 126, "compute_mpas_flood_fill_mask": 126, "scatter": 126, "cellseedmask": [126, 131], "propag": 126, "elsewher": [126, 127, 140], "compute_lon_lat_region_mask": 126, "serv": 126, "grid_file_nam": 126, "albani": 126, "mali": 126, "greenland": [126, 128], "antarctica": [126, 127], "dsmesh1": 126, "dsmesh2": 126, "20000": 126, "mesh1": 126, "mesh2": 126, "merged_mesh": 126, "perhap": [126, 132], "apart": 126, "done": [126, 128, 139], "split_grid": 126, "split_mesh1": 126, "split_mesh2": 126, "filename1": 126, "filename2": 126, "maxedges1": 126, "maxedges2": 126, "meshfil": 126, "2000": 126, "inplac": 126, "contrast": [126, 130], "center_on_mesh": 126, "three": [126, 127, 128, 142], "translate_planar_grid": 126, "gather": 126, "invok": 126, "choos": [126, 136], "arbirari": 126, "datafil": 126, "shift_valu": 126, "jigsawpi": [126, 127], "triangle_to_netcdf": 126, "mpas_to_triangl": 126, "from_mpa": 126, "scrip_from_mpa": 126, "l": 126, "landic": 126, "basic": [127, 131, 139, 142], "approach": [127, 139, 142], "periodic_mesh_10x20_1km": 127, "awkwardli": 127, "hurt": 127, "conform": 127, "correctli": 127, "On": [127, 141], "npx": 127, "npy": 127, "mesh_to_cul": 127, "nonperiodic_mesh_10x20_1km": 127, "simpl": 127, "240": [127, 142], "usr": 127, "cellwidthvslatlon": 127, "constantcellwidth": 127, "__main__": 127, "complex": [127, 130, 142], "variat": 127, "higher": [127, 128], "build_planar_mesh": [127, 131], "spehric": 127, "structur": 127, "mesh_definition_tool": 127, "mergecellwidthvslat": 127, "asymptot": 127, "characterist": 127, "about": [127, 142], "arctic": 127, "181": 127, "66": [127, 133], "commonli": 127, "flavor": 127, "mind": 127, "parameter": 127, "pure": 127, "northern": 127, "somewhat": 127, "abrupt": 127, "switch": 127, "nearli": [127, 136, 142], "appreci": 127, "aris": 127, "obtain": 127, "common": 127, "deform": 127, "partial": [127, 142], "resolv": [127, 129], "proport": 127, "finer": 127, "e3smv1": 127, "rrs_cellwidthvslat": 127, "atlanticpacificgrid": 127, "signed_dist": 127, "curv": [127, 136], "equal": [127, 128], "hand": 127, "featurecolleciton": 127, "come": [127, 139, 142], "predefin": 127, "signed_distance_from_geojson": 127, "read_feature_collect": 127, "re": [127, 139], "high_res_region": 127, "so_signed_dist": 127, "25": [127, 128, 133], "1600e3": 127, "500e3": 127, "sometim": [127, 142], "interest": [127, 142], "unsign": 127, "mask_from_geojson": 127, "distance_from_geojson": 127, "complic": 127, "highest": 127, "concentr": 127, "pyplot": [127, 142], "plt": [127, 142], "gaussian": 127, "dcoars": 127, "dfine": 127, "cmin": 127, "cmax": 127, "iter_count": 127, "get_r": 127, "xval": 127, "exp": 127, "x_mid": 127, "01": [127, 142], "properti": [127, 133], "weird": 127, "8232421875000173": 127, "283113991917228": 127, "5600585937500142": 127, "8752158957336085": 127, "9448242187500171": 127, "8453839885731744": 127, "3186035156249841": 127, "8239462091017558": 127, "6372070312500188": 127, "37353251022881745": 127, "3181152343750147": 127, "03295898255728466": 127, "636474609375017": 127, "3405741662837591": 127, "163818359375015": 127, "5159363834516735": 127, "9443359375000164": 127, "9771465537125645": 127, "coastal_tool": 128, "aid": 128, "driver": 128, "coastal_refined_mesh": 128, "repeatedli": 128, "continental_u": 128, "smooth_coastlin": 128, "entire_glob": 128, "60to30": 128, "dx_max_glob": 128, "dx_min_glob": 128, "dx_min_coast": 128, "600": 128, "400": 128, "north_america": 128, "compute_cell_width": 128, "farther": 128, "occur": 128, "action": 128, "hurrican": 128, "usdequ120at30cr10rr2": 128, "success": 128, "delawar": 128, "bai": 128, "ct": 128, "print": 128, "enhanc": 128, "30km": 128, "atlantic_restrict": 128, "western_atlant": 128, "5000": 128, "500": 128, "northeast": 128, "10km": 128, "delaware_bai": 128, "5km": 128, "delaware_region": 128, "175": 128, "75": 128, "2km": 128, "delaware_restrict": 128, "17": [128, 141], "directli": [128, 130, 136, 139, 142], "long": [128, 142], "bathyemtri": 128, "select": [128, 142], "continent": 128, "shelf": [128, 130], "reduc": 128, "cost": 128, "fewer": 128, "withing": 128, "ingredi": 128, "previouli": 128, "decid": 128, "iter": [128, 129], "confin": 128, "restrict": 128, "elimin": 128, "prevent": 128, "appear": 128, "side": [128, 142], "narrow": [128, 129], "piec": 128, "gulf": 128, "mexico": 128, "central": 128, "america": 128, "enforc": 128, "853": 128, "39": [128, 133], "732": 128, "74": [128, 133], "939": 128, "36": 128, "678": 128, "71": 128, "519": 128, "156": 128, "153": 128, "077": 128, "76": 128, "024": 128, "37": [128, 133], "188": 128, "214": 128, "756": 128, "512": 128, "925": 128, "274": 128, "38": 128, "318": 128, "counter": 128, "clockwis": 128, "u": [128, 142], "east": 128, "island": 128, "81": [128, 133], "85": 128, "87": 128, "7": [128, 141], "51": 128, "56": [128, 133], "68": 128, "107": 128, "119": 128, "92": 128, "52": 128, "84": 128, "83": 128, "101": 128, "82": 128, "72": 128, "24": 128, "117": 128, "29": 128, "77": 128, "62": [128, 133], "67": [128, 133], "galveston_bai": 128, "us_east_coast": 128, "us_gulf_coast": 128, "caribbean": 128, "us_west_coast": 128, "hawaii": 128, "alaska": 128, "bering_sea_": 128, "bering_sea_w": 128, "aleutian_islands_": 128, "aleutian_islands_w": 128, "conu": 128, "coastline_alter": 129, "v": [129, 133, 142], "ground": 129, "add_critical_land_blockag": 129, "bridg": 129, "natur": 129, "fccritblockag": 129, "critical_land_blockag": 129, "dscritblockmask": 129, "arakawa": 129, "veloc": 129, "allevi": 129, "add_land_locked_cells_to_mask": 129, "cannot": [129, 142], "advect": 129, "unless": [129, 142], "widen_transect_edge_mask": 129, "critical_passag": 129, "fccritpassag": 129, "dscritpassmask": 129, "add_depth": 130, "star": 130, "correct": [130, 142], "compute_depth": 130, "suitabl": 130, "add_zmid": 130, "caviti": 130, "vari": 130, "slightli": [130, 142], "undul": 130, "account": 130, "compute_zmid": 130, "write_time_varying_zmid": 130, "mention": 130, "amount": 130, "disk": 130, "paraview_extractor": [131, 142], "extract_vtk": [131, 142], "floodplain": 131, "wet": 131, "dry": 131, "inject_preserve_floodplain": 131, "bottomdepthobserv": 131, "inject_bathymetri": 131, "build_moc_basin": 132, "individu": 132, "stabl": [132, 141], "indian": 132, "indo": 132, "fcmoc": 132, "mocadd_moc_southern_boundary_transect": 132, "dsmasksandtransect": 132, "add_moc_southern_boundary_transect": 132, "moc_southern_boundary_extractor": 132, "foreseen": 132, "22": 132, "backward": 132, "compat": 132, "make_moc_basins_and_transect": 132, "mesh_nam": [132, 136], "ec30to60kml60e3smv2r03": 132, "_moc_mask": 132, "_moc_masks_and_transect": 132, "moc_basin": 132, "plot_ocean_transect": 133, "drake": 133, "milena": 133, "veneziani": 133, "linestr": 133, "63": 133, "02": [133, 142], "65": 133, "46": 133, "64": 133, "42": 133, "04": 133, "28": 133, "54": 133, "44": 133, "minlevelcel": 133, "visualizaiton": 133, "your": [133, 136, 139, 142], "blob": 133, "_plot_transect": 133, "dpi": 133, "colorbar": 133, "extend_seaice_mask": 134, "presenc": [134, 136], "seaice_partit": [134, 137, 138], "make_mpas_scripfile_on_cel": 135, "make_mpas_scripfile_on_vertic": 135, "write_scrip_fil": 135, "write_2d_scripfil": 135, "files_for_e3sm": 136, "version": [136, 142], "esmf": 136, "unfamiliar": 136, "learn": 136, "mambaforg": 136, "activ": [136, 139], "profil": 136, "sh": 136, "mamba": 136, "11": [136, 141], "nompi": 136, "mpi": 136, "necessari": [136, 140], "hpc": 136, "fix_regrid_output": 136, "ex": 136, "built": [136, 142], "theses": 136, "prepare_seaice_partit": 136, "create_seaice_partit": 136, "outputdir": 136, "inputmesh": 136, "outputmesh": 136, "destin": 136, "had": [136, 139], "standalon": 136, "preprocess": 136, "significantli": [136, 142], "nproc": 136, "nprocsfil": 136, "cullerdir": 136, "execut": 136, "diagnost": 136, "onto": 136, "gpmeti": 136, "partition_": 136, "simplifi": 136, "primarili": [136, 142], "lcrc": 136, "machin": [136, 142], "anvil": 136, "chrysali": 136, "simple_seaice_partit": 136, "datadir": 136, "seaice_qu60km_polar": 136, "icepresent_qu60km_polar": 136, "inputdata": 136, "share": [136, 140], "condit": [136, 142], "matter": 136, "230313": 136, "todai": 136, "task_count": 136, "suffix": 136, "task": 136, "group": [136, 142], "public_html": 136, "wc14to60e2r3": 136, "210210": 136, "468": 136, "helper": 136, "gen_seaice_mesh_partit": 136, "make_regions_fil": 137, "regrid_to_other_mesh": 138, "prepar": 138, "clone": 139, "instruct": 139, "miniconda": 139, "beyond": [139, 142], "scope": 139, "strict": 139, "channel_prior": 139, "notic": 139, "them": [139, 142], "mpas_tools_dev": 139, "pip": 139, "rush": 139, "dev_environ": 139, "suggest": 139, "deactiv": 139, "dual": 140, "detect": 140, "subdivide_great_circl": 140, "subdivide_planar": 140, "sequenc": 140, "lon_lat_to_cartesian": 140, "back": 140, "cartesian_to_lon_lat": 140, "arc": 140, "angular_dist": 140, "13": 141, "14": 141, "19": 141, "21": 141, "hodg": 142, "podg": 142, "unrel": 142, "conceiv": 142, "repositori": 142, "who": 142, "basi": 142, "monthli": 142, "wherea": 142, "slice": 142, "suffic": 142, "quit": 142, "therefor": 142, "prohibit": 142, "transfer": 142, "practic": 142, "paraview_vtk_field_extractor": 142, "interfac": 142, "subset": 142, "fairli": 142, "mpaso": 142, "timeseriesstatsmonthli": 142, "restart": 142, "rst": 142, "0001": 142, "01_00000": 142, "daili": 142, "analysis_memb": 142, "am": 142, "timeseriesstatsdaili": 142, "timedaily_avg_activetracers_temperatur": 142, "init": 142, "xtime_startdaili": 142, "instanc": 142, "xtime_enddaili": 142, "fieldsoncel": 142, "tip": 142, "contin": 142, "areacel": 142, "demonstr": 142, "explicitli": 142, "vtk_files2": 142, "sesson": 142, "easili": 142, "necess": 142, "vtk_files3": 142, "special": 142, "allonedg": 142, "allonvertic": 142, "edgesoncel": 142, "nvertlevelsp1": 142, "vtk_files4": 142, "saw": 142, "deepest": 142, "salin": 142, "timedaily_avg_activetracers_salin": 142, "timedaily_avg_layerthick": 142, "vtk_files5": 142, "timedaily_avg_activetracers_temperature_0": 142, "timedaily_avg_activetracers_temperature_maxlevelcel": 142, "timedaily_avg_activetracers_salinity_0": 142, "timedaily_avg_activetracers_salinity_maxlevelcel": 142, "timedaily_avg_layerthickness_0": 142, "timedaily_avg_layerthickness_maxlevelcel": 142, "probabl": 142, "stride": 142, "continu": 142, "vtk_files6": 142, "complain": 142, "rag": 142, "vtk_files7": 142, "li": 142, "propos": 142, "fix": 142, "duplic": 142, "transform": 142, "uncheck": 142, "hit": 142, "disappear": 142, "click": 142, "ey": 142, "icon": 142, "reappear": 142, "crop": 142, "groupdataset1": 142, "item": 142, "clip": 142, "clip1": 142, "clean": 142, "behind": 142, "leav": 142, "vtk_files8": 142, "bit": 142, "simpler": 142, "1e": 142, "khat": 142, "focus": 142, "situat": 142, "vtk_files9": 142, "add_earth_spher": 142, "annotate_d": 142, "hole": 142, "anim": 142, "thu": 142, "pentagon": 142, "trinagl": 142, "tri": 142, "triangul": 142, "0501": 142, "sst": 142, "isel": 142, "ssttri": 142, "sstnode": 142, "ninterp": 142, "ntriangl": 142, "reshap": 142, "ravel": 142, "shade": 142, "gouraud": 142, "xlim": 142, "ylim": 142, "flat": 142, "snapshot": 142, "handi": 142, "unfortun": 142, "cmocean": 142, "register_sci_viz_colormap": 142, "No": 142, "xml": 142, "3wbgy5": 142}, "objects": {"mpas_tools.cime": [[5, 0, 0, "-", "constants"]], "mpas_tools.config": [[6, 1, 1, "", "MpasConfigParser"]], "mpas_tools.config.MpasConfigParser": [[7, 2, 1, "", "__getitem__"], [6, 2, 1, "", "__init__"], [8, 2, 1, "", "add_from_file"], [9, 2, 1, "", "add_from_package"], [10, 2, 1, "", "add_user_config"], [11, 2, 1, "", "copy"], [12, 2, 1, "", "get"], [13, 2, 1, "", "getboolean"], [14, 2, 1, "", "getexpression"], [15, 2, 1, "", "getfloat"], [16, 2, 1, "", "getint"], [17, 2, 1, "", "getlist"], [18, 2, 1, "", "has_option"], [19, 2, 1, "", "has_section"], [20, 2, 1, "", "set"], [21, 2, 1, "", "write"]], "mpas_tools.io": [[22, 3, 1, "", "write_netcdf"]], "mpas_tools.logging": [[23, 1, 1, "", "LoggingContext"], [24, 3, 1, "", "check_call"]], "mpas_tools.logging.LoggingContext": [[23, 2, 1, "", "__init__"]], "mpas_tools.merge_grids": [[25, 3, 1, "", "merge_grids"]], "mpas_tools.mesh.conversion": [[26, 3, 1, "", "convert"], [27, 3, 1, "", "cull"], [28, 3, 1, "", "mask"]], "mpas_tools.mesh.creation": [[29, 0, 0, "-", "build_mesh"], [34, 0, 0, "-", "mesh_definition_tools"], [40, 0, 0, "-", "signed_distance"]], "mpas_tools.mesh.creation.build_mesh": [[30, 3, 1, "", "build_planar_mesh"], [31, 3, 1, "", "build_spherical_mesh"]], "mpas_tools.mesh.creation.jigsaw_driver": [[32, 3, 1, "", "jigsaw_driver"]], "mpas_tools.mesh.creation.jigsaw_to_netcdf": [[33, 3, 1, "", "jigsaw_to_netcdf"]], "mpas_tools.mesh.creation.mesh_definition_tools": [[35, 3, 1, "", "AtlanticPacificGrid"], [36, 3, 1, "", "EC_CellWidthVsLat"], [37, 3, 1, "", "RRS_CellWidthVsLat"], [38, 3, 1, "", "mergeCellWidthVsLat"]], "mpas_tools.mesh.creation.mpas_to_triangle": [[39, 3, 1, "", "mpas_to_triangle"]], "mpas_tools.mesh.creation.signed_distance": [[41, 3, 1, "", "distance_from_geojson"], [42, 3, 1, "", "mask_from_geojson"], [43, 3, 1, "", "signed_distance_from_geojson"]], "mpas_tools.mesh.creation.triangle_to_netcdf": [[44, 3, 1, "", "triangle_to_netcdf"]], "mpas_tools.mesh.interpolation": [[45, 3, 1, "", "interp_bilin"]], "mpas_tools.mesh.mask": [[46, 3, 1, "", "compute_lon_lat_region_masks"], [47, 3, 1, "", "compute_mpas_flood_fill_mask"], [48, 3, 1, "", "compute_mpas_region_masks"], [49, 3, 1, "", "compute_mpas_transect_masks"]], "mpas_tools.ocean": [[50, 0, 0, "-", "build_mesh"], [53, 0, 0, "-", "coastal_tools"], [67, 0, 0, "-", "coastline_alteration"], [81, 0, 0, "-", "moc"]], "mpas_tools.ocean.build_mesh": [[51, 3, 1, "", "build_planar_mesh"], [52, 3, 1, "", "build_spherical_mesh"]], "mpas_tools.ocean.coastal_tools": [[54, 3, 1, "", "CPP_projection"], [55, 3, 1, "", "coastal_refined_mesh"], [56, 3, 1, "", "compute_cell_width"], [57, 3, 1, "", "create_background_mesh"], [58, 3, 1, "", "distance_to_coast"], [59, 3, 1, "", "extract_coastlines"], [60, 3, 1, "", "get_convex_hull_coordinates"], [61, 3, 1, "", "get_data_inside_box"], [62, 3, 1, "", "get_indices_inside_quad"], [63, 3, 1, "", "plot_coarse_coast"], [64, 3, 1, "", "plot_region_box"], [65, 3, 1, "", "save_matfile"], [66, 3, 1, "", "smooth_coastline"]], "mpas_tools.ocean.coastline_alteration": [[68, 3, 1, "", "add_critical_land_blockages"], [69, 3, 1, "", "add_land_locked_cells_to_mask"], [70, 3, 1, "", "widen_transect_edge_masks"]], "mpas_tools.ocean.depth": [[71, 3, 1, "", "add_depth"], [72, 3, 1, "", "add_zmid"], [73, 3, 1, "", "compute_depth"], [74, 3, 1, "", "compute_zmid"], [75, 3, 1, "", "write_time_varying_zmid"]], "mpas_tools.ocean.inject_bathymetry": [[76, 3, 1, "", "inject_bathymetry"]], "mpas_tools.ocean.inject_meshDensity": [[77, 3, 1, "", "inject_meshDensity_from_file"], [78, 3, 1, "", "inject_planar_meshDensity"], [79, 3, 1, "", "inject_spherical_meshDensity"]], "mpas_tools.ocean.inject_preserve_floodplain": [[80, 3, 1, "", "inject_preserve_floodplain"]], "mpas_tools.ocean.moc": [[82, 3, 1, "", "add_moc_southern_boundary_transects"], [83, 3, 1, "", "make_moc_basins_and_transects"]], "mpas_tools.ocean.transects": [[84, 3, 1, "", "find_transect_levels_and_weights"], [85, 3, 1, "", "get_outline_segments"], [86, 3, 1, "", "interp_mpas_to_transect_triangle_nodes"], [87, 3, 1, "", "interp_mpas_to_transect_triangles"], [88, 3, 1, "", "interp_transect_grid_to_transect_triangle_nodes"]], "mpas_tools.ocean.viz": [[89, 3, 1, "", "add_inset"], [90, 3, 1, "", "plot_ocean_transects"]], "mpas_tools.parallel": [[91, 3, 1, "", "create_pool"]], "mpas_tools.planar_hex": [[92, 3, 1, "", "make_planar_hex_mesh"]], "mpas_tools.scrip.from_mpas": [[93, 3, 1, "", "scrip_from_mpas"]], "mpas_tools.seaice.mask": [[94, 3, 1, "", "extend_seaice_mask"]], "mpas_tools.seaice.mesh": [[95, 3, 1, "", "make_mpas_scripfile_on_cells"], [96, 3, 1, "", "make_mpas_scripfile_on_vertices"], [97, 3, 1, "", "write_2D_scripfile"], [98, 3, 1, "", "write_scrip_file"]], "mpas_tools.seaice.partition": [[99, 3, 1, "", "create_partitions"], [100, 3, 1, "", "gen_seaice_mesh_partition"], [101, 3, 1, "", "prepare_partitions"]], "mpas_tools.seaice.regions": [[102, 3, 1, "", "make_regions_file"]], "mpas_tools.seaice.regrid": [[103, 3, 1, "", "regrid_to_other_mesh"]], "mpas_tools.split_grids": [[104, 3, 1, "", "split_grids"]], "mpas_tools.tests.test_cime_constants": [[105, 3, 1, "", "test_cime_constants"]], "mpas_tools.transects": [[106, 1, 1, "", "Vector"], [107, 3, 1, "", "angular_distance"], [108, 3, 1, "", "cartesian_to_great_circle_distance"], [109, 3, 1, "", "cartesian_to_lon_lat"], [110, 3, 1, "", "lon_lat_to_cartesian"], [111, 3, 1, "", "subdivide_great_circle"], [112, 3, 1, "", "subdivide_planar"]], "mpas_tools.transects.Vector": [[106, 2, 1, "", "__init__"]], "mpas_tools.translate": [[113, 3, 1, "", "center"], [114, 3, 1, "", "center_on_mesh"], [115, 3, 1, "", "translate"]], "mpas_tools.viz.colormaps": [[116, 3, 1, "", "register_sci_viz_colormaps"]], "mpas_tools.viz.mesh_to_triangles": [[117, 3, 1, "", "mesh_to_triangles"]], "mpas_tools.viz.paraview_extractor": [[118, 3, 1, "", "extract_vtk"]], "mpas_tools.viz.transects": [[119, 3, 1, "", "find_planar_transect_cells_and_weights"], [120, 3, 1, "", "find_transect_cells_and_weights"], [121, 3, 1, "", "make_triangle_tree"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "function", "Python function"]}, "titleterms": {"api": 0, "refer": 0, "mpa": [0, 122, 126, 135, 138, 142], "mesh": [0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 95, 96, 97, 98, 126, 127, 128, 131, 135, 138, 142], "tool": [0, 122, 127, 128, 136], "creation": [0, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 126, 127, 131], "convers": [0, 26, 27, 28, 126], "config": [0, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], "i": 0, "o": 0, "parallel": [0, 91], "interpol": [0, 45, 123], "cime": [0, 3, 5], "constant": [0, 3, 5], "ocean": [0, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 122, 131, 133], "sea": [0, 122], "ic": [0, 122], "log": [0, 23, 24, 124], "transect": [0, 84, 85, 86, 87, 88, 106, 107, 108, 109, 110, 111, 112, 119, 120, 121, 126, 129, 132, 133, 140], "visual": [0, 133, 142], "test": [0, 105, 139], "main": 1, "author": [1, 122], "contributor": 1, "build": [2, 127, 132], "document": 2, "file": [4, 135], "comment": 4, "mpas_tool": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 125, 139], "mpasconfigpars": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], "__getitem__": 7, "add_from_fil": 8, "add_from_packag": 9, "add_user_config": 10, "copi": 11, "get": 12, "getboolean": 13, "getexpress": 14, "getfloat": 15, "getint": 16, "getlist": 17, "has_opt": 18, "has_sect": 19, "set": 20, "write": [21, 130], "io": 22, "write_netcdf": 22, "loggingcontext": 23, "check_cal": 24, "merge_grid": 25, "convert": [26, 126], "cull": 27, "mask": [28, 46, 47, 48, 49, 94, 126, 129, 134, 137], "build_mesh": [29, 30, 31, 50, 51, 52], "build_planar_mesh": [30, 51], "build_spherical_mesh": [31, 52], "jigsaw_driv": 32, "jigsaw_to_netcdf": 33, "mesh_definition_tool": [34, 35, 36, 37, 38], "atlanticpacificgrid": 35, "ec_cellwidthvslat": 36, "rrs_cellwidthvslat": 37, "mergecellwidthvslat": 38, "mpas_to_triangl": 39, "signed_dist": [40, 41, 42, 43], "distance_from_geojson": 41, "mask_from_geojson": 42, "signed_distance_from_geojson": 43, "triangle_to_netcdf": 44, "interp_bilin": 45, "compute_lon_lat_region_mask": 46, "compute_mpas_flood_fill_mask": 47, "compute_mpas_region_mask": 48, "compute_mpas_transect_mask": 49, "coastal_tool": [53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66], "cpp_project": 54, "coastal_refined_mesh": 55, "compute_cell_width": 56, "create_background_mesh": 57, "distance_to_coast": 58, "extract_coastlin": 59, "get_convex_hull_coordin": 60, "get_data_inside_box": 61, "get_indices_inside_quad": 62, "plot_coarse_coast": 63, "plot_region_box": 64, "save_matfil": 65, "smooth_coastlin": 66, "coastline_alter": [67, 68, 69, 70], "add_critical_land_blockag": 68, "add_land_locked_cells_to_mask": 69, "widen_transect_edge_mask": 70, "depth": [71, 72, 73, 74, 75, 130], "add_depth": 71, "add_zmid": 72, "compute_depth": 73, "compute_zmid": 74, "write_time_varying_zmid": 75, "inject_bathymetri": 76, "inject_meshdens": [77, 78, 79], "inject_meshdensity_from_fil": 77, "inject_planar_meshdens": 78, "inject_spherical_meshdens": 79, "inject_preserve_floodplain": 80, "moc": [81, 82, 83, 132], "add_moc_southern_boundary_transect": 82, "make_moc_basins_and_transect": 83, "find_transect_levels_and_weight": 84, "get_outline_seg": 85, "interp_mpas_to_transect_triangle_nod": 86, "interp_mpas_to_transect_triangl": 87, "interp_transect_grid_to_transect_triangle_nod": 88, "viz": [89, 90, 116, 117, 118, 119, 120, 121], "add_inset": 89, "plot_ocean_transect": 90, "create_pool": 91, "planar_hex": 92, "make_planar_hex_mesh": 92, "scrip": [93, 126, 135], "from_mpa": 93, "scrip_from_mpa": 93, "seaic": [94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 135, 138], "extend_seaice_mask": 94, "make_mpas_scripfile_on_cel": 95, "make_mpas_scripfile_on_vertic": 96, "write_2d_scripfil": 97, "write_scrip_fil": 98, "partit": [99, 100, 101, 136, 137], "create_partit": 99, "gen_seaice_mesh_partit": 100, "prepare_partit": 101, "region": [102, 126, 128, 137, 142], "make_regions_fil": 102, "regrid": [103, 138], "regrid_to_other_mesh": 103, "split_grid": 104, "test_cime_const": 105, "vector": 106, "angular_dist": 107, "cartesian_to_great_circle_dist": 108, "cartesian_to_lon_lat": 109, "lon_lat_to_cartesian": 110, "subdivide_great_circl": 111, "subdivide_planar": 112, "translat": [113, 114, 115, 126], "center": 113, "center_on_mesh": 114, "colormap": [116, 142], "register_sci_viz_colormap": 116, "mesh_to_triangl": 117, "paraview_extractor": 118, "extract_vtk": 118, "find_planar_transect_cells_and_weight": 119, "find_transect_cells_and_weight": 120, "make_triangle_tre": 121, "user": 122, "": 122, "guid": 122, "develop": 122, "indic": 122, "tabl": 122, "version": [122, 125, 141], "us": 124, "subprocess": 124, "call": 124, "make": [125, 137], "chang": [125, 139], "entri": 125, "point": 125, "depend": [125, 130], "updat": 125, "cell": [126, 127, 128, 129], "culler": 126, "creator": 126, "python": 126, "multiprocess": 126, "comput": [126, 128], "flood": 126, "fill": 126, "lon": [126, 142], "lat": [126, 142], "merg": [126, 127], "split": 126, "between": [126, 138], "format": 126, "msh": 126, "netcdf": 126, "triangl": [126, 142], "uniform": 127, "planar": 127, "jigsaw": 127, "spheric": 127, "driver": 127, "definit": 127, "width": [127, 128], "defin": 127, "an": 127, "eddi": 127, "closur": 127, "rossbi": 127, "radiu": 127, "atlant": 127, "pacif": 127, "sign": 127, "distanc": [127, 128], "function": [127, 136, 140], "coastal": 128, "refin": 128, "creat": 128, "background": 128, "extract": [128, 142], "coastlin": [128, 129], "coast": 128, "blend": 128, "alter": 129, "ad": [129, 130, 132], "land": 129, "blockag": 129, "lock": 129, "widen": 129, "coordin": [130, 142], "1d": 130, "3d": 130, "zmid": 130, "time": [130, 142], "variabl": 130, "meridion": 132, "overturn": 132, "circul": 132, "basin": 132, "southern": 132, "togeth": 132, "plot": 133, "extend": 134, "2d": 135, "grid": 135, "graph": 136, "run": 136, "from": 136, "compass": 136, "conda": 136, "environ": [136, 139], "remov": 139, "subdivid": 140, "low": 140, "level": 140, "paraview": 142, "vtk": 142, "extractor": 142, "temperatur": 142, "seri": 142, "multipl": 142, "field": 142, "all": 142, "index": 142, "dimens": 142, "ignor": 142, "topograph": 142, "data": 142, "macro": 142}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1, "sphinx": 57}, "alltitles": {"API reference": [[0, "api-reference"]], "MPAS mesh tools": [[0, "mpas-mesh-tools"]], "Mesh creation": [[0, "mesh-creation"]], "Mesh conversion": [[0, "mesh-conversion"]], "Config": [[0, "config"]], "I/O": [[0, "i-o"]], "Parallelism": [[0, "parallelism"]], "Interpolation": [[0, "interpolation"], [123, "interpolation"]], "CIME constants": [[0, "cime-constants"]], "Ocean Tools": [[0, "ocean-tools"], [122, null]], "Sea-ice Tools": [[0, "sea-ice-tools"], [122, null]], "Logging": [[0, "logging"], [124, "logging"]], "Transects": [[0, "transects"], [140, "transects"]], "Visualization": [[0, "visualization"], [133, "visualization"], [142, "visualization"]], "Tests": [[0, "tests"]], "Main Authors": [[1, "main-authors"]], "Contributors": [[1, "contributors"]], "Building the Documentation": [[2, "building-the-documentation"]], "CIME Constants": [[3, "cime-constants"]], "Config files": [[4, "config-files"]], "Comments in config files": [[4, "comments-in-config-files"]], "mpas_tools.cime.constants": [[5, "module-mpas_tools.cime.constants"]], "mpas_tools.config.MpasConfigParser": [[6, "mpas-tools-config-mpasconfigparser"]], "mpas_tools.config.MpasConfigParser.__getitem__": [[7, "mpas-tools-config-mpasconfigparser-getitem"]], "mpas_tools.config.MpasConfigParser.add_from_file": [[8, "mpas-tools-config-mpasconfigparser-add-from-file"]], "mpas_tools.config.MpasConfigParser.add_from_package": [[9, "mpas-tools-config-mpasconfigparser-add-from-package"]], "mpas_tools.config.MpasConfigParser.add_user_config": [[10, "mpas-tools-config-mpasconfigparser-add-user-config"]], "mpas_tools.config.MpasConfigParser.copy": [[11, "mpas-tools-config-mpasconfigparser-copy"]], "mpas_tools.config.MpasConfigParser.get": [[12, "mpas-tools-config-mpasconfigparser-get"]], "mpas_tools.config.MpasConfigParser.getboolean": [[13, "mpas-tools-config-mpasconfigparser-getboolean"]], "mpas_tools.config.MpasConfigParser.getexpression": [[14, "mpas-tools-config-mpasconfigparser-getexpression"]], "mpas_tools.config.MpasConfigParser.getfloat": [[15, "mpas-tools-config-mpasconfigparser-getfloat"]], "mpas_tools.config.MpasConfigParser.getint": [[16, "mpas-tools-config-mpasconfigparser-getint"]], "mpas_tools.config.MpasConfigParser.getlist": [[17, "mpas-tools-config-mpasconfigparser-getlist"]], "mpas_tools.config.MpasConfigParser.has_option": [[18, "mpas-tools-config-mpasconfigparser-has-option"]], "mpas_tools.config.MpasConfigParser.has_section": [[19, "mpas-tools-config-mpasconfigparser-has-section"]], "mpas_tools.config.MpasConfigParser.set": [[20, "mpas-tools-config-mpasconfigparser-set"]], "mpas_tools.config.MpasConfigParser.write": [[21, "mpas-tools-config-mpasconfigparser-write"]], "mpas_tools.io.write_netcdf": [[22, "mpas-tools-io-write-netcdf"]], "mpas_tools.logging.LoggingContext": [[23, "mpas-tools-logging-loggingcontext"]], "mpas_tools.logging.check_call": [[24, "mpas-tools-logging-check-call"]], "mpas_tools.merge_grids.merge_grids": [[25, "mpas-tools-merge-grids-merge-grids"]], "mpas_tools.mesh.conversion.convert": [[26, "mpas-tools-mesh-conversion-convert"]], "mpas_tools.mesh.conversion.cull": [[27, "mpas-tools-mesh-conversion-cull"]], "mpas_tools.mesh.conversion.mask": [[28, "mpas-tools-mesh-conversion-mask"]], "mpas_tools.mesh.creation.build_mesh": [[29, "module-mpas_tools.mesh.creation.build_mesh"]], "mpas_tools.mesh.creation.build_mesh.build_planar_mesh": [[30, "mpas-tools-mesh-creation-build-mesh-build-planar-mesh"]], "mpas_tools.mesh.creation.build_mesh.build_spherical_mesh": [[31, "mpas-tools-mesh-creation-build-mesh-build-spherical-mesh"]], "mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver": [[32, "mpas-tools-mesh-creation-jigsaw-driver-jigsaw-driver"]], "mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf": [[33, "mpas-tools-mesh-creation-jigsaw-to-netcdf-jigsaw-to-netcdf"]], "mpas_tools.mesh.creation.mesh_definition_tools": [[34, "module-mpas_tools.mesh.creation.mesh_definition_tools"]], "mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid": [[35, "mpas-tools-mesh-creation-mesh-definition-tools-atlanticpacificgrid"]], "mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat": [[36, "mpas-tools-mesh-creation-mesh-definition-tools-ec-cellwidthvslat"]], "mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat": [[37, "mpas-tools-mesh-creation-mesh-definition-tools-rrs-cellwidthvslat"]], "mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat": [[38, "mpas-tools-mesh-creation-mesh-definition-tools-mergecellwidthvslat"]], "mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle": [[39, "mpas-tools-mesh-creation-mpas-to-triangle-mpas-to-triangle"]], "mpas_tools.mesh.creation.signed_distance": [[40, "module-mpas_tools.mesh.creation.signed_distance"]], "mpas_tools.mesh.creation.signed_distance.distance_from_geojson": [[41, "mpas-tools-mesh-creation-signed-distance-distance-from-geojson"]], "mpas_tools.mesh.creation.signed_distance.mask_from_geojson": [[42, "mpas-tools-mesh-creation-signed-distance-mask-from-geojson"]], "mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson": [[43, "mpas-tools-mesh-creation-signed-distance-signed-distance-from-geojson"]], "mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf": [[44, "mpas-tools-mesh-creation-triangle-to-netcdf-triangle-to-netcdf"]], "mpas_tools.mesh.interpolation.interp_bilin": [[45, "mpas-tools-mesh-interpolation-interp-bilin"]], "mpas_tools.mesh.mask.compute_lon_lat_region_masks": [[46, "mpas-tools-mesh-mask-compute-lon-lat-region-masks"]], "mpas_tools.mesh.mask.compute_mpas_flood_fill_mask": [[47, "mpas-tools-mesh-mask-compute-mpas-flood-fill-mask"]], "mpas_tools.mesh.mask.compute_mpas_region_masks": [[48, "mpas-tools-mesh-mask-compute-mpas-region-masks"]], "mpas_tools.mesh.mask.compute_mpas_transect_masks": [[49, "mpas-tools-mesh-mask-compute-mpas-transect-masks"]], "mpas_tools.ocean.build_mesh": [[50, "module-mpas_tools.ocean.build_mesh"]], "mpas_tools.ocean.build_mesh.build_planar_mesh": [[51, "mpas-tools-ocean-build-mesh-build-planar-mesh"]], "mpas_tools.ocean.build_mesh.build_spherical_mesh": [[52, "mpas-tools-ocean-build-mesh-build-spherical-mesh"]], "mpas_tools.ocean.coastal_tools": [[53, "module-mpas_tools.ocean.coastal_tools"]], "mpas_tools.ocean.coastal_tools.CPP_projection": [[54, "mpas-tools-ocean-coastal-tools-cpp-projection"]], "mpas_tools.ocean.coastal_tools.coastal_refined_mesh": [[55, "mpas-tools-ocean-coastal-tools-coastal-refined-mesh"]], "mpas_tools.ocean.coastal_tools.compute_cell_width": [[56, "mpas-tools-ocean-coastal-tools-compute-cell-width"]], "mpas_tools.ocean.coastal_tools.create_background_mesh": [[57, "mpas-tools-ocean-coastal-tools-create-background-mesh"]], "mpas_tools.ocean.coastal_tools.distance_to_coast": [[58, "mpas-tools-ocean-coastal-tools-distance-to-coast"]], "mpas_tools.ocean.coastal_tools.extract_coastlines": [[59, "mpas-tools-ocean-coastal-tools-extract-coastlines"]], "mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates": [[60, "mpas-tools-ocean-coastal-tools-get-convex-hull-coordinates"]], "mpas_tools.ocean.coastal_tools.get_data_inside_box": [[61, "mpas-tools-ocean-coastal-tools-get-data-inside-box"]], "mpas_tools.ocean.coastal_tools.get_indices_inside_quad": [[62, "mpas-tools-ocean-coastal-tools-get-indices-inside-quad"]], "mpas_tools.ocean.coastal_tools.plot_coarse_coast": [[63, "mpas-tools-ocean-coastal-tools-plot-coarse-coast"]], "mpas_tools.ocean.coastal_tools.plot_region_box": [[64, "mpas-tools-ocean-coastal-tools-plot-region-box"]], "mpas_tools.ocean.coastal_tools.save_matfile": [[65, "mpas-tools-ocean-coastal-tools-save-matfile"]], "mpas_tools.ocean.coastal_tools.smooth_coastline": [[66, "mpas-tools-ocean-coastal-tools-smooth-coastline"]], "mpas_tools.ocean.coastline_alteration": [[67, "module-mpas_tools.ocean.coastline_alteration"]], "mpas_tools.ocean.coastline_alteration.add_critical_land_blockages": [[68, "mpas-tools-ocean-coastline-alteration-add-critical-land-blockages"]], "mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask": [[69, "mpas-tools-ocean-coastline-alteration-add-land-locked-cells-to-mask"]], "mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks": [[70, "mpas-tools-ocean-coastline-alteration-widen-transect-edge-masks"]], "mpas_tools.ocean.depth.add_depth": [[71, "mpas-tools-ocean-depth-add-depth"]], "mpas_tools.ocean.depth.add_zmid": [[72, "mpas-tools-ocean-depth-add-zmid"]], "mpas_tools.ocean.depth.compute_depth": [[73, "mpas-tools-ocean-depth-compute-depth"]], "mpas_tools.ocean.depth.compute_zmid": [[74, "mpas-tools-ocean-depth-compute-zmid"]], "mpas_tools.ocean.depth.write_time_varying_zmid": [[75, "mpas-tools-ocean-depth-write-time-varying-zmid"]], "mpas_tools.ocean.inject_bathymetry.inject_bathymetry": [[76, "mpas-tools-ocean-inject-bathymetry-inject-bathymetry"]], "mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file": [[77, "mpas-tools-ocean-inject-meshdensity-inject-meshdensity-from-file"]], "mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity": [[78, "mpas-tools-ocean-inject-meshdensity-inject-planar-meshdensity"]], "mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity": [[79, "mpas-tools-ocean-inject-meshdensity-inject-spherical-meshdensity"]], "mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain": [[80, "mpas-tools-ocean-inject-preserve-floodplain-inject-preserve-floodplain"]], "mpas_tools.ocean.moc": [[81, "module-mpas_tools.ocean.moc"]], "mpas_tools.ocean.moc.add_moc_southern_boundary_transects": [[82, "mpas-tools-ocean-moc-add-moc-southern-boundary-transects"]], "mpas_tools.ocean.moc.make_moc_basins_and_transects": [[83, "mpas-tools-ocean-moc-make-moc-basins-and-transects"]], "mpas_tools.ocean.transects.find_transect_levels_and_weights": [[84, "mpas-tools-ocean-transects-find-transect-levels-and-weights"]], "mpas_tools.ocean.transects.get_outline_segments": [[85, "mpas-tools-ocean-transects-get-outline-segments"]], "mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes": [[86, "mpas-tools-ocean-transects-interp-mpas-to-transect-triangle-nodes"]], "mpas_tools.ocean.transects.interp_mpas_to_transect_triangles": [[87, "mpas-tools-ocean-transects-interp-mpas-to-transect-triangles"]], "mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes": [[88, "mpas-tools-ocean-transects-interp-transect-grid-to-transect-triangle-nodes"]], "mpas_tools.ocean.viz.add_inset": [[89, "mpas-tools-ocean-viz-add-inset"]], "mpas_tools.ocean.viz.plot_ocean_transects": [[90, "mpas-tools-ocean-viz-plot-ocean-transects"]], "mpas_tools.parallel.create_pool": [[91, "mpas-tools-parallel-create-pool"]], "mpas_tools.planar_hex.make_planar_hex_mesh": [[92, "mpas-tools-planar-hex-make-planar-hex-mesh"]], "mpas_tools.scrip.from_mpas.scrip_from_mpas": [[93, "mpas-tools-scrip-from-mpas-scrip-from-mpas"]], "mpas_tools.seaice.mask.extend_seaice_mask": [[94, "mpas-tools-seaice-mask-extend-seaice-mask"]], "mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells": [[95, "mpas-tools-seaice-mesh-make-mpas-scripfile-on-cells"]], "mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices": [[96, "mpas-tools-seaice-mesh-make-mpas-scripfile-on-vertices"]], "mpas_tools.seaice.mesh.write_2D_scripfile": [[97, "mpas-tools-seaice-mesh-write-2d-scripfile"]], "mpas_tools.seaice.mesh.write_scrip_file": [[98, "mpas-tools-seaice-mesh-write-scrip-file"]], "mpas_tools.seaice.partition.create_partitions": [[99, "mpas-tools-seaice-partition-create-partitions"]], "mpas_tools.seaice.partition.gen_seaice_mesh_partition": [[100, "mpas-tools-seaice-partition-gen-seaice-mesh-partition"]], "mpas_tools.seaice.partition.prepare_partitions": [[101, "mpas-tools-seaice-partition-prepare-partitions"]], "mpas_tools.seaice.regions.make_regions_file": [[102, "mpas-tools-seaice-regions-make-regions-file"]], "mpas_tools.seaice.regrid.regrid_to_other_mesh": [[103, "mpas-tools-seaice-regrid-regrid-to-other-mesh"]], "mpas_tools.split_grids.split_grids": [[104, "mpas-tools-split-grids-split-grids"]], "mpas_tools.tests.test_cime_constants.test_cime_constants": [[105, "mpas-tools-tests-test-cime-constants-test-cime-constants"]], "mpas_tools.transects.Vector": [[106, "mpas-tools-transects-vector"]], "mpas_tools.transects.angular_distance": [[107, "mpas-tools-transects-angular-distance"]], "mpas_tools.transects.cartesian_to_great_circle_distance": [[108, "mpas-tools-transects-cartesian-to-great-circle-distance"]], "mpas_tools.transects.cartesian_to_lon_lat": [[109, "mpas-tools-transects-cartesian-to-lon-lat"]], "mpas_tools.transects.lon_lat_to_cartesian": [[110, "mpas-tools-transects-lon-lat-to-cartesian"]], "mpas_tools.transects.subdivide_great_circle": [[111, "mpas-tools-transects-subdivide-great-circle"]], "mpas_tools.transects.subdivide_planar": [[112, "mpas-tools-transects-subdivide-planar"]], "mpas_tools.translate.center": [[113, "mpas-tools-translate-center"]], "mpas_tools.translate.center_on_mesh": [[114, "mpas-tools-translate-center-on-mesh"]], "mpas_tools.translate.translate": [[115, "mpas-tools-translate-translate"]], "mpas_tools.viz.colormaps.register_sci_viz_colormaps": [[116, "mpas-tools-viz-colormaps-register-sci-viz-colormaps"]], "mpas_tools.viz.mesh_to_triangles.mesh_to_triangles": [[117, "mpas-tools-viz-mesh-to-triangles-mesh-to-triangles"]], "mpas_tools.viz.paraview_extractor.extract_vtk": [[118, "mpas-tools-viz-paraview-extractor-extract-vtk"]], "mpas_tools.viz.transects.find_planar_transect_cells_and_weights": [[119, "mpas-tools-viz-transects-find-planar-transect-cells-and-weights"]], "mpas_tools.viz.transects.find_transect_cells_and_weights": [[120, "mpas-tools-viz-transects-find-transect-cells-and-weights"]], "mpas_tools.viz.transects.make_triangle_tree": [[121, "mpas-tools-viz-transects-make-triangle-tree"]], "MPAS-Tools": [[122, "mpas-tools"]], "User's Guide": [[122, null]], "Developer's Guide": [[122, null]], "Indices and tables": [[122, "indices-and-tables"]], "Authors": [[122, null]], "Versions": [[122, null], [141, "versions"]], "Using logging": [[124, "using-logging"]], "Logging subprocess calls": [[124, "logging-subprocess-calls"]], "Making Changes to mpas_tools": [[125, "making-changes-to-mpas-tools"]], "Entry Points": [[125, "entry-points"]], "Dependencies": [[125, "dependencies"]], "Updating the Version": [[125, "updating-the-version"]], "Mesh Conversion": [[126, "mesh-conversion"]], "Mesh Converter": [[126, "mesh-converter"]], "Cell Culler": [[126, "cell-culler"]], "Mask Creator": [[126, "mask-creator"]], "Mask Creation with Python Multiprocessing": [[126, "mask-creation-with-python-multiprocessing"]], "Computing MPAS Region Masks": [[126, "computing-mpas-region-masks"]], "Computing Transect Masks": [[126, "computing-transect-masks"]], "Computing a Flood-fill Mask": [[126, "computing-a-flood-fill-mask"]], "Computing Lon/Lat Region Masks": [[126, "computing-lon-lat-region-masks"]], "Merging and Splitting": [[126, "merging-and-splitting"]], "Translation": [[126, "translation"]], "Converting Between Mesh Formats": [[126, "converting-between-mesh-formats"]], "MSH to MPAS NetCDF": [[126, "msh-to-mpas-netcdf"]], "Triangle to MPAS NetCDF": [[126, "triangle-to-mpas-netcdf"]], "MPAS NetCDF to Triangle": [[126, "mpas-netcdf-to-triangle"]], "MPAS NetCDF to SCRIP": [[126, "mpas-netcdf-to-scrip"]], "Mesh Creation": [[127, "id1"]], "Uniform, Planar Meshes": [[127, "uniform-planar-meshes"]], "Building a JIGSAW Mesh": [[127, "building-a-jigsaw-mesh"]], "Spherical Meshes": [[127, "spherical-meshes"]], "Planar Meshes": [[127, "planar-meshes"]], "JIGSAW Driver": [[127, "jigsaw-driver"]], "Mesh Definition Tools": [[127, "mesh-definition-tools"]], "Merging Cell Widths": [[127, "merging-cell-widths"]], "Defining an Eddy-closure Mesh": [[127, "defining-an-eddy-closure-mesh"]], "Defining a Rossby-radius Mesh": [[127, "defining-a-rossby-radius-mesh"]], "Defining an Atlantic/Pacific Mesh": [[127, "defining-an-atlantic-pacific-mesh"]], "Signed Distance Functions": [[127, "signed-distance-functions"]], "Coastal Tools": [[128, "coastal-tools"]], "Refining a Mesh": [[128, "refining-a-mesh"]], "Creating a Background Mesh": [[128, "creating-a-background-mesh"]], "Extracting Coastlines": [[128, "extracting-coastlines"]], "Computing Distance to Coast": [[128, "computing-distance-to-coast"]], "Blending Cell Widths": [[128, "blending-cell-widths"]], "Regions": [[128, "regions"]], "Coastline Alteration": [[129, "coastline-alteration"]], "Adding Land Blockages": [[129, "adding-land-blockages"]], "Masking Land-locked Cells": [[129, "masking-land-locked-cells"]], "Widening Transects": [[129, "widening-transects"]], "Adding a Depth Coordinate": [[130, "adding-a-depth-coordinate"]], "Adding a 1D depth coordinate": [[130, "adding-a-1d-depth-coordinate"]], "Adding a 3D zMid coordinate": [[130, "adding-a-3d-zmid-coordinate"]], "Writing a time-dependent, 3D zMid variable": [[130, "writing-a-time-dependent-3d-zmid-variable"]], "Ocean Mesh Creation": [[131, "ocean-mesh-creation"]], "Meridional Overturning Circulation": [[132, "meridional-overturning-circulation"]], "Building MOC Basins": [[132, "building-moc-basins"]], "Adding Southern Transects": [[132, "adding-southern-transects"]], "Building MOC Basins and Transects Together": [[132, "building-moc-basins-and-transects-together"]], "Plotting Ocean Transects": [[133, "plotting-ocean-transects"]], "Mask": [[134, "mask"]], "Extending a Mask": [[134, "extending-a-mask"]], "Mesh": [[135, "mesh"]], "MPAS-Seaice SCRIP files": [[135, "mpas-seaice-scrip-files"]], "SCRIP files for 2D grids": [[135, "scrip-files-for-2d-grids"]], "Graph partitioning": [[136, "graph-partitioning"]], "Running from compass": [[136, "running-from-compass"]], "Conda environment": [[136, "conda-environment"]], "Graph partition tools": [[136, "graph-partition-tools"]], "Graph partition function": [[136, "graph-partition-function"]], "Region masks": [[137, "region-masks"]], "Make a region mask for partitioning": [[137, "make-a-region-mask-for-partitioning"]], "Regrid": [[138, "regrid"]], "Regridding between MPAS-Seaice meshes": [[138, "regridding-between-mpas-seaice-meshes"]], "Testing Changes to mpas_tools": [[139, "testing-changes-to-mpas-tools"]], "Removing the test environment": [[139, "removing-the-test-environment"]], "Subdividing transects": [[140, "subdividing-transects"]], "Low-level functions": [[140, "low-level-functions"]], "ParaView VTK Extractor": [[142, "paraview-vtk-extractor"]], "Extracting a Temperature Time-series": [[142, "extracting-a-temperature-time-series"]], "Extracting Multiple Fields": [[142, "extracting-multiple-fields"]], "Extracting \u201cAll\u201d Fields": [[142, "extracting-all-fields"]], "Indexing Dimensions": [[142, "indexing-dimensions"]], "Indexing Time": [[142, "indexing-time"]], "Ignoring Time": [[142, "ignoring-time"]], "Lon/Lat Coordinates": [[142, "lon-lat-coordinates"]], "Topographic Data": [[142, "topographic-data"]], "Extracting a Region": [[142, "extracting-a-region"]], "ParaView Macros": [[142, "paraview-macros"]], "MPAS Mesh to Triangles": [[142, "mpas-mesh-to-triangles"]], "Colormaps": [[142, "colormaps"]]}, "indexentries": {"module": [[5, "module-mpas_tools.cime.constants"], [29, "module-mpas_tools.mesh.creation.build_mesh"], [34, "module-mpas_tools.mesh.creation.mesh_definition_tools"], [40, "module-mpas_tools.mesh.creation.signed_distance"], [50, "module-mpas_tools.ocean.build_mesh"], [53, "module-mpas_tools.ocean.coastal_tools"], [67, "module-mpas_tools.ocean.coastline_alteration"], [81, "module-mpas_tools.ocean.moc"]], "mpas_tools.cime.constants": [[5, "module-mpas_tools.cime.constants"]], "mpasconfigparser (class in mpas_tools.config)": [[6, "mpas_tools.config.MpasConfigParser"]], "__init__() (mpas_tools.config.mpasconfigparser method)": [[6, "mpas_tools.config.MpasConfigParser.__init__"]], "__getitem__() (mpas_tools.config.mpasconfigparser method)": [[7, "mpas_tools.config.MpasConfigParser.__getitem__"]], "add_from_file() (mpas_tools.config.mpasconfigparser method)": [[8, "mpas_tools.config.MpasConfigParser.add_from_file"]], "add_from_package() (mpas_tools.config.mpasconfigparser method)": [[9, "mpas_tools.config.MpasConfigParser.add_from_package"]], "add_user_config() (mpas_tools.config.mpasconfigparser method)": [[10, "mpas_tools.config.MpasConfigParser.add_user_config"]], "copy() (mpas_tools.config.mpasconfigparser method)": [[11, "mpas_tools.config.MpasConfigParser.copy"]], "get() (mpas_tools.config.mpasconfigparser method)": [[12, "mpas_tools.config.MpasConfigParser.get"]], "getboolean() (mpas_tools.config.mpasconfigparser method)": [[13, "mpas_tools.config.MpasConfigParser.getboolean"]], "getexpression() (mpas_tools.config.mpasconfigparser method)": [[14, "mpas_tools.config.MpasConfigParser.getexpression"]], "getfloat() (mpas_tools.config.mpasconfigparser method)": [[15, "mpas_tools.config.MpasConfigParser.getfloat"]], "getint() (mpas_tools.config.mpasconfigparser method)": [[16, "mpas_tools.config.MpasConfigParser.getint"]], "getlist() (mpas_tools.config.mpasconfigparser method)": [[17, "mpas_tools.config.MpasConfigParser.getlist"]], "has_option() (mpas_tools.config.mpasconfigparser method)": [[18, "mpas_tools.config.MpasConfigParser.has_option"]], "has_section() (mpas_tools.config.mpasconfigparser method)": [[19, "mpas_tools.config.MpasConfigParser.has_section"]], "set() (mpas_tools.config.mpasconfigparser method)": [[20, "mpas_tools.config.MpasConfigParser.set"]], "write() (mpas_tools.config.mpasconfigparser method)": [[21, "mpas_tools.config.MpasConfigParser.write"]], "write_netcdf() (in module mpas_tools.io)": [[22, "mpas_tools.io.write_netcdf"]], "loggingcontext (class in mpas_tools.logging)": [[23, "mpas_tools.logging.LoggingContext"]], "__init__() (mpas_tools.logging.loggingcontext method)": [[23, "mpas_tools.logging.LoggingContext.__init__"]], "check_call() (in module mpas_tools.logging)": [[24, "mpas_tools.logging.check_call"]], "merge_grids() (in module mpas_tools.merge_grids)": [[25, "mpas_tools.merge_grids.merge_grids"]], "convert() (in module mpas_tools.mesh.conversion)": [[26, "mpas_tools.mesh.conversion.convert"]], "cull() (in module mpas_tools.mesh.conversion)": [[27, "mpas_tools.mesh.conversion.cull"]], "mask() (in module mpas_tools.mesh.conversion)": [[28, "mpas_tools.mesh.conversion.mask"]], "mpas_tools.mesh.creation.build_mesh": [[29, "module-mpas_tools.mesh.creation.build_mesh"]], "build_planar_mesh() (in module mpas_tools.mesh.creation.build_mesh)": [[30, "mpas_tools.mesh.creation.build_mesh.build_planar_mesh"]], "build_spherical_mesh() (in module mpas_tools.mesh.creation.build_mesh)": [[31, "mpas_tools.mesh.creation.build_mesh.build_spherical_mesh"]], "jigsaw_driver() (in module mpas_tools.mesh.creation.jigsaw_driver)": [[32, "mpas_tools.mesh.creation.jigsaw_driver.jigsaw_driver"]], "jigsaw_to_netcdf() (in module mpas_tools.mesh.creation.jigsaw_to_netcdf)": [[33, "mpas_tools.mesh.creation.jigsaw_to_netcdf.jigsaw_to_netcdf"]], "mpas_tools.mesh.creation.mesh_definition_tools": [[34, "module-mpas_tools.mesh.creation.mesh_definition_tools"]], "atlanticpacificgrid() (in module mpas_tools.mesh.creation.mesh_definition_tools)": [[35, "mpas_tools.mesh.creation.mesh_definition_tools.AtlanticPacificGrid"]], "ec_cellwidthvslat() (in module mpas_tools.mesh.creation.mesh_definition_tools)": [[36, "mpas_tools.mesh.creation.mesh_definition_tools.EC_CellWidthVsLat"]], "rrs_cellwidthvslat() (in module mpas_tools.mesh.creation.mesh_definition_tools)": [[37, "mpas_tools.mesh.creation.mesh_definition_tools.RRS_CellWidthVsLat"]], "mergecellwidthvslat() (in module mpas_tools.mesh.creation.mesh_definition_tools)": [[38, "mpas_tools.mesh.creation.mesh_definition_tools.mergeCellWidthVsLat"]], "mpas_to_triangle() (in module mpas_tools.mesh.creation.mpas_to_triangle)": [[39, "mpas_tools.mesh.creation.mpas_to_triangle.mpas_to_triangle"]], "mpas_tools.mesh.creation.signed_distance": [[40, "module-mpas_tools.mesh.creation.signed_distance"]], "distance_from_geojson() (in module mpas_tools.mesh.creation.signed_distance)": [[41, "mpas_tools.mesh.creation.signed_distance.distance_from_geojson"]], "mask_from_geojson() (in module mpas_tools.mesh.creation.signed_distance)": [[42, "mpas_tools.mesh.creation.signed_distance.mask_from_geojson"]], "signed_distance_from_geojson() (in module mpas_tools.mesh.creation.signed_distance)": [[43, "mpas_tools.mesh.creation.signed_distance.signed_distance_from_geojson"]], "triangle_to_netcdf() (in module mpas_tools.mesh.creation.triangle_to_netcdf)": [[44, "mpas_tools.mesh.creation.triangle_to_netcdf.triangle_to_netcdf"]], "interp_bilin() (in module mpas_tools.mesh.interpolation)": [[45, "mpas_tools.mesh.interpolation.interp_bilin"]], "compute_lon_lat_region_masks() (in module mpas_tools.mesh.mask)": [[46, "mpas_tools.mesh.mask.compute_lon_lat_region_masks"]], "compute_mpas_flood_fill_mask() (in module mpas_tools.mesh.mask)": [[47, "mpas_tools.mesh.mask.compute_mpas_flood_fill_mask"]], "compute_mpas_region_masks() (in module mpas_tools.mesh.mask)": [[48, "mpas_tools.mesh.mask.compute_mpas_region_masks"]], "compute_mpas_transect_masks() (in module mpas_tools.mesh.mask)": [[49, "mpas_tools.mesh.mask.compute_mpas_transect_masks"]], "mpas_tools.ocean.build_mesh": [[50, "module-mpas_tools.ocean.build_mesh"]], "build_planar_mesh() (in module mpas_tools.ocean.build_mesh)": [[51, "mpas_tools.ocean.build_mesh.build_planar_mesh"]], "build_spherical_mesh() (in module mpas_tools.ocean.build_mesh)": [[52, "mpas_tools.ocean.build_mesh.build_spherical_mesh"]], "mpas_tools.ocean.coastal_tools": [[53, "module-mpas_tools.ocean.coastal_tools"]], "cpp_projection() (in module mpas_tools.ocean.coastal_tools)": [[54, "mpas_tools.ocean.coastal_tools.CPP_projection"]], "coastal_refined_mesh() (in module mpas_tools.ocean.coastal_tools)": [[55, "mpas_tools.ocean.coastal_tools.coastal_refined_mesh"]], "compute_cell_width() (in module mpas_tools.ocean.coastal_tools)": [[56, "mpas_tools.ocean.coastal_tools.compute_cell_width"]], "create_background_mesh() (in module mpas_tools.ocean.coastal_tools)": [[57, "mpas_tools.ocean.coastal_tools.create_background_mesh"]], "distance_to_coast() (in module mpas_tools.ocean.coastal_tools)": [[58, "mpas_tools.ocean.coastal_tools.distance_to_coast"]], "extract_coastlines() (in module mpas_tools.ocean.coastal_tools)": [[59, "mpas_tools.ocean.coastal_tools.extract_coastlines"]], "get_convex_hull_coordinates() (in module mpas_tools.ocean.coastal_tools)": [[60, "mpas_tools.ocean.coastal_tools.get_convex_hull_coordinates"]], "get_data_inside_box() (in module mpas_tools.ocean.coastal_tools)": [[61, "mpas_tools.ocean.coastal_tools.get_data_inside_box"]], "get_indices_inside_quad() (in module mpas_tools.ocean.coastal_tools)": [[62, "mpas_tools.ocean.coastal_tools.get_indices_inside_quad"]], "plot_coarse_coast() (in module mpas_tools.ocean.coastal_tools)": [[63, "mpas_tools.ocean.coastal_tools.plot_coarse_coast"]], "plot_region_box() (in module mpas_tools.ocean.coastal_tools)": [[64, "mpas_tools.ocean.coastal_tools.plot_region_box"]], "save_matfile() (in module mpas_tools.ocean.coastal_tools)": [[65, "mpas_tools.ocean.coastal_tools.save_matfile"]], "smooth_coastline() (in module mpas_tools.ocean.coastal_tools)": [[66, "mpas_tools.ocean.coastal_tools.smooth_coastline"]], "mpas_tools.ocean.coastline_alteration": [[67, "module-mpas_tools.ocean.coastline_alteration"]], "add_critical_land_blockages() (in module mpas_tools.ocean.coastline_alteration)": [[68, "mpas_tools.ocean.coastline_alteration.add_critical_land_blockages"]], "add_land_locked_cells_to_mask() (in module mpas_tools.ocean.coastline_alteration)": [[69, "mpas_tools.ocean.coastline_alteration.add_land_locked_cells_to_mask"]], "widen_transect_edge_masks() (in module mpas_tools.ocean.coastline_alteration)": [[70, "mpas_tools.ocean.coastline_alteration.widen_transect_edge_masks"]], "add_depth() (in module mpas_tools.ocean.depth)": [[71, "mpas_tools.ocean.depth.add_depth"]], "add_zmid() (in module mpas_tools.ocean.depth)": [[72, "mpas_tools.ocean.depth.add_zmid"]], "compute_depth() (in module mpas_tools.ocean.depth)": [[73, "mpas_tools.ocean.depth.compute_depth"]], "compute_zmid() (in module mpas_tools.ocean.depth)": [[74, "mpas_tools.ocean.depth.compute_zmid"]], "write_time_varying_zmid() (in module mpas_tools.ocean.depth)": [[75, "mpas_tools.ocean.depth.write_time_varying_zmid"]], "inject_bathymetry() (in module mpas_tools.ocean.inject_bathymetry)": [[76, "mpas_tools.ocean.inject_bathymetry.inject_bathymetry"]], "inject_meshdensity_from_file() (in module mpas_tools.ocean.inject_meshdensity)": [[77, "mpas_tools.ocean.inject_meshDensity.inject_meshDensity_from_file"]], "inject_planar_meshdensity() (in module mpas_tools.ocean.inject_meshdensity)": [[78, "mpas_tools.ocean.inject_meshDensity.inject_planar_meshDensity"]], "inject_spherical_meshdensity() (in module mpas_tools.ocean.inject_meshdensity)": [[79, "mpas_tools.ocean.inject_meshDensity.inject_spherical_meshDensity"]], "inject_preserve_floodplain() (in module mpas_tools.ocean.inject_preserve_floodplain)": [[80, "mpas_tools.ocean.inject_preserve_floodplain.inject_preserve_floodplain"]], "mpas_tools.ocean.moc": [[81, "module-mpas_tools.ocean.moc"]], "add_moc_southern_boundary_transects() (in module mpas_tools.ocean.moc)": [[82, "mpas_tools.ocean.moc.add_moc_southern_boundary_transects"]], "make_moc_basins_and_transects() (in module mpas_tools.ocean.moc)": [[83, "mpas_tools.ocean.moc.make_moc_basins_and_transects"]], "find_transect_levels_and_weights() (in module mpas_tools.ocean.transects)": [[84, "mpas_tools.ocean.transects.find_transect_levels_and_weights"]], "get_outline_segments() (in module mpas_tools.ocean.transects)": [[85, "mpas_tools.ocean.transects.get_outline_segments"]], "interp_mpas_to_transect_triangle_nodes() (in module mpas_tools.ocean.transects)": [[86, "mpas_tools.ocean.transects.interp_mpas_to_transect_triangle_nodes"]], "interp_mpas_to_transect_triangles() (in module mpas_tools.ocean.transects)": [[87, "mpas_tools.ocean.transects.interp_mpas_to_transect_triangles"]], "interp_transect_grid_to_transect_triangle_nodes() (in module mpas_tools.ocean.transects)": [[88, "mpas_tools.ocean.transects.interp_transect_grid_to_transect_triangle_nodes"]], "add_inset() (in module mpas_tools.ocean.viz)": [[89, "mpas_tools.ocean.viz.add_inset"]], "plot_ocean_transects() (in module mpas_tools.ocean.viz)": [[90, "mpas_tools.ocean.viz.plot_ocean_transects"]], "create_pool() (in module mpas_tools.parallel)": [[91, "mpas_tools.parallel.create_pool"]], "make_planar_hex_mesh() (in module mpas_tools.planar_hex)": [[92, "mpas_tools.planar_hex.make_planar_hex_mesh"]], "scrip_from_mpas() (in module mpas_tools.scrip.from_mpas)": [[93, "mpas_tools.scrip.from_mpas.scrip_from_mpas"]], "extend_seaice_mask() (in module mpas_tools.seaice.mask)": [[94, "mpas_tools.seaice.mask.extend_seaice_mask"]], "make_mpas_scripfile_on_cells() (in module mpas_tools.seaice.mesh)": [[95, "mpas_tools.seaice.mesh.make_mpas_scripfile_on_cells"]], "make_mpas_scripfile_on_vertices() (in module mpas_tools.seaice.mesh)": [[96, "mpas_tools.seaice.mesh.make_mpas_scripfile_on_vertices"]], "write_2d_scripfile() (in module mpas_tools.seaice.mesh)": [[97, "mpas_tools.seaice.mesh.write_2D_scripfile"]], "write_scrip_file() (in module mpas_tools.seaice.mesh)": [[98, "mpas_tools.seaice.mesh.write_scrip_file"]], "create_partitions() (in module mpas_tools.seaice.partition)": [[99, "mpas_tools.seaice.partition.create_partitions"]], "gen_seaice_mesh_partition() (in module mpas_tools.seaice.partition)": [[100, "mpas_tools.seaice.partition.gen_seaice_mesh_partition"]], "prepare_partitions() (in module mpas_tools.seaice.partition)": [[101, "mpas_tools.seaice.partition.prepare_partitions"]], "make_regions_file() (in module mpas_tools.seaice.regions)": [[102, "mpas_tools.seaice.regions.make_regions_file"]], "regrid_to_other_mesh() (in module mpas_tools.seaice.regrid)": [[103, "mpas_tools.seaice.regrid.regrid_to_other_mesh"]], "split_grids() (in module mpas_tools.split_grids)": [[104, "mpas_tools.split_grids.split_grids"]], "test_cime_constants() (in module mpas_tools.tests.test_cime_constants)": [[105, "mpas_tools.tests.test_cime_constants.test_cime_constants"]], "vector (class in mpas_tools.transects)": [[106, "mpas_tools.transects.Vector"]], "__init__() (mpas_tools.transects.vector method)": [[106, "mpas_tools.transects.Vector.__init__"]], "angular_distance() (in module mpas_tools.transects)": [[107, "mpas_tools.transects.angular_distance"]], "cartesian_to_great_circle_distance() (in module mpas_tools.transects)": [[108, "mpas_tools.transects.cartesian_to_great_circle_distance"]], "cartesian_to_lon_lat() (in module mpas_tools.transects)": [[109, "mpas_tools.transects.cartesian_to_lon_lat"]], "lon_lat_to_cartesian() (in module mpas_tools.transects)": [[110, "mpas_tools.transects.lon_lat_to_cartesian"]], "subdivide_great_circle() (in module mpas_tools.transects)": [[111, "mpas_tools.transects.subdivide_great_circle"]], "subdivide_planar() (in module mpas_tools.transects)": [[112, "mpas_tools.transects.subdivide_planar"]], "center() (in module mpas_tools.translate)": [[113, "mpas_tools.translate.center"]], "center_on_mesh() (in module mpas_tools.translate)": [[114, "mpas_tools.translate.center_on_mesh"]], "translate() (in module mpas_tools.translate)": [[115, "mpas_tools.translate.translate"]], "register_sci_viz_colormaps() (in module mpas_tools.viz.colormaps)": [[116, "mpas_tools.viz.colormaps.register_sci_viz_colormaps"]], "mesh_to_triangles() (in module mpas_tools.viz.mesh_to_triangles)": [[117, "mpas_tools.viz.mesh_to_triangles.mesh_to_triangles"]], "extract_vtk() (in module mpas_tools.viz.paraview_extractor)": [[118, "mpas_tools.viz.paraview_extractor.extract_vtk"]], "find_planar_transect_cells_and_weights() (in module mpas_tools.viz.transects)": [[119, "mpas_tools.viz.transects.find_planar_transect_cells_and_weights"]], "find_transect_cells_and_weights() (in module mpas_tools.viz.transects)": [[120, "mpas_tools.viz.transects.find_transect_cells_and_weights"]], "make_triangle_tree() (in module mpas_tools.viz.transects)": [[121, "mpas_tools.viz.transects.make_triangle_tree"]]}}) \ No newline at end of file diff --git a/0.22.0rc4/testing_changes.html b/0.22.0rc4/testing_changes.html new file mode 100644 index 000000000..0a5626b8c --- /dev/null +++ b/0.22.0rc4/testing_changes.html @@ -0,0 +1,196 @@ + + + + + + + Testing Changes to mpas_tools — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Testing Changes to mpas_tools

+

Here, we describe the workflow for creating a development conda environment +that points to mpas_tools in a branch from a local clone of the repo. +This approach works both for calling functions from the package within a python +script or another python package and for calling the “entry points” +(command-line tools; see Making Changes to mpas_tools).

+

Basic instructions on how to install Miniconda +are beyond the scope of this documentation. Make sure the conda-forge channel +is added and that channel priority is “strict”, meaning packages will +definitely come from conda-forge if they are available there.

+
conda config --add channels conda-forge
+conda config --set channel_priority strict
+
+
+

To make a conda environment and install the current mpas_tools in a way that +it will be used out of the repo directly (i.e. it will notice changes as you +make them in your branch), run:

+
cd conda_package
+conda env create -y -n mpas_tools_dev --file dev-spec.txt
+conda activate mpas_tools_dev
+python -m pip install -e .
+
+
+

You should now find that mpas_tools can be imported in python codes and the +various scripts and entry points are available in the path.

+

If you have already created the mpas_tools_dev environment, it may be best +to remove it (see below) and create it again. If you are in a rush, you can +use:

+
conda env update -f ./dev_environment
+conda activate mpas_tools_dev
+python -m pip install -e .
+
+
+

to update the existing environment and make sure mpas_tools in the +environment points to your current branch.

+

There is no need to build a conda package, as previous instructions had +suggested.

+
+

Removing the test environment

+

If you’re done with testing, you can remove the test environment

+
conda deactivate
+conda remove --all -n mpas_tools_dev
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/transects.html b/0.22.0rc4/transects.html new file mode 100644 index 000000000..fb3f76488 --- /dev/null +++ b/0.22.0rc4/transects.html @@ -0,0 +1,183 @@ + + + + + + + Transects — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Transects

+

The mpas_tools.transects module contains functions used to define +transects through MPAS meshes. These transects can be used to create masks +of the cells, edges or dual-mesh cells (in some sense “vertices”) that +intersect the transect. They can also be used for visualization such as +plotting vertical cross-sections of MPAS data along the transect.

+
+

Subdividing transects

+

For both visualization and intersection detection, it is often useful to +subdivide a transect into smaller segments. This is performed with the +function mpas_tools.transects.subdivide_great_circle() for spherical +meshes and with mpas_tools.transects.subdivide_planar() for planar +meshes.

+

For spherical meshes, subdivision is performed in Cartesian coordinates. Since +transects are typically provided as a sequence of longitude/latitude points, +it is typically necessary to convert to Cartesian coordinates using +mpas_tools.transects.lon_lat_to_cartesian() and then back to +longitude/latitude coordinates using +mpas_tools.transects.cartesian_to_lon_lat().

+
+
+

Low-level functions

+

The module also shares some lower-level functions used elsewhere in the +package.

+

The arc length (in radians) along a transect can be found with +mpas_tools.transects.angular_distance().

+

The function mpas_tools.transects.intersects() can be used to +determine if 2 arcs on the sphere intersect one another and +mpas_tools.transects.intersection() can be used to find the +intersection point of 2 intersecting arcs.

+
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/versions.html b/0.22.0rc4/versions.html new file mode 100644 index 000000000..d3aa95367 --- /dev/null +++ b/0.22.0rc4/versions.html @@ -0,0 +1,240 @@ + + + + + + + Versions — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Versions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Documentation

On GitHub

stable

master

v0.0.11

0.0.11

v0.0.12

0.0.12

v0.0.13

0.0.13

v0.0.14

0.0.14

v0.0.15

0.0.15

v0.1.0

0.1.0

v0.2.0

0.2.0

v0.2.1

0.2.1

v0.3.0

0.3.0

v0.4.0

0.4.0

v0.5.0

0.5.0

v0.6.0

0.6.0

v0.7.0

0.7.0

v0.8.0

0.8.0

v0.9.0

0.9.0

v0.10.0

0.10.0

v0.11.0

0.11.0

v0.12.0

0.12.0

v0.13.0

0.13.0

v0.14.0

0.14.0

v0.15.0

0.15.0

v0.16.0

0.16.0

v0.17.0

0.17.0

v0.18.0

0.18.0

v0.19.0

0.19.0

v0.20.0

0.20.0

v0.21.0

0.21.0

+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/0.22.0rc4/visualization.html b/0.22.0rc4/visualization.html new file mode 100644 index 000000000..0aa824f74 --- /dev/null +++ b/0.22.0rc4/visualization.html @@ -0,0 +1,667 @@ + + + + + + + Visualization — mpas_tools 0.22.0rc4 documentation + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Visualization

+

MPAS-Tools has kind of a hodge-podge of unrelated visualization tools. This is +largely because MPAS-Tools is conceived of primarily as a repository for tools +for manipulating MPAS meshes during their construction and initialization.

+
+

ParaView VTK Extractor

+

Data on MPAS meshes can be viewed directly in +ParaView. However, those of us who work with +output from MPAS components on a regular basis have found that the built-in +capability has a number of significant limitations. These include:

+
    +
  • ParaView visualizes data on MPAS cell centers by connecting them to form +triangles. The data is linearly interpolated within each triangle and +geometry associated with the parts of MPAS cells that are adjacent to +boundaries (e.g. land in the ocean and sea-ice components) are not visualized.

  • +
  • MPAS output may not contain the mesh information needed by ParaView. This is +typical of monthly output files, which do not include the mesh data for +more efficient file storage.

  • +
  • MPAS output files may contain significantly more data that is desired for +visualization. The data may contain full 3D fields, whereas a few slices at +different depths may suffice for visualization. There may also be many more +variables in the output than are of interest. This may be a problem if the +datasets are quite large and therefore prohibitive to transfer to another +machine where visualization may be more practical.

  • +
+

For these reasons and more, we created a Python tool for extracting data on +MPAS meshes in files in VTK format that can be read in by +ParaView. The VTK files provide the data as “cell”, rather than “point” data in +ParaVeiw, meaning each cell has the correct polygonal geometry and will be +visualized with a single, constant value for a given field. The extractor, +which is available either through the +mpas_tools.viz.paraview_extractor.extract_vtk() function or the +paraview_vtk_field_extractor.py command-line interface, can also be used to +visualize data on MPAS vertices (visualized on triangles) and edges (visualized +on quadrilaterals).

+

The extractor also allows the user to select a subset of the indices along +dimensions other than Time, nCells, nVertices and nEdges. This +can be useful for selecting, for example, only the top layer of a 3D field. +This capability can also be used to ignore fields with a given dimension by +selecting no indices along that dimension.

+

By default, time-independent fields on cells are written to a file

+
vtk_files/staticFieldsOnCells.vtp
+
+
+

and time-dependent fields on cells are written to a series of files

+
vtk_files/timeDependentFieldsOnCells.pvd
+vtk_files/time_series/timeDependentFieldsOnCells.0.vtp
+vtk_files/time_series/timeDependentFieldsOnCells.1.vtp
+...
+
+
+

and similarly for edges and vertices. Time-independent fields can be +included in each time step of the time-dependent fields for with +combine=True. This allows time-dependent and -independent fields +to be combined in filters within Paraview at the expense of considerable +additional storage space.

+

Since the extractor is fairly complex with a lot of possible use cases, we will +describe its functionality in several examples.

+
+

Extracting a Temperature Time-series

+

To extract fields across multiple files, passing in a regular expression +for the filename pattern, for example +filename_pattern="hist.mpaso.timeSeriesStatsMonthly.*.nc". Since the mesh +data is often excluded from time series output, you may need to supply a +different file with mesh information, such as an initial condition or a restart +file: mesh_filename='mpaso.rst.0001-02-01_00000.nc'.

+

In the following example, we extract the temperature field from a time series +of daily output from the MPAS-Ocean model:

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list='timeDaily_avg_activeTracers_temperature',
+    dimension_list=['nVertLevels=0'], mesh_filename='init.nc',
+    out_dir='vtk_files', xtime='xtime_startDaily')
+
+
+

The top index (nVertLevels=0) is extracted from the temperature time series. +The output directory is 'vtk_files'. MPAS output typically includes time +information in string format in a variable called xtime. In this instance, +we have time-averaged data and the output instead includes a start time +xtime_startDaily that we need to supply instead. (We could also supply the +end time xtime_endDaily if that were preferred for some reason.)

+

The result is:

+
vtk_files/fieldsOnCells.pvd
+vtk_files/time_series/fieldsOnCells.0.vtp
+...
+
+
+

These files can be opened in ParaView with:

+
$ paraview vtk_files/fieldsOnCells.pvd
+
+
+

This will open all of the files in the vtk_files/time_series directory as +they are requested within ParaView. See ParaView Macros for some tips +on filling in the continents and displaying the current date in ParaView.

+

The same extraction could be accomplished with the command-line tool as follows:

+
$ paraview_vtk_field_extractor.py \
+     -f "analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc" \
+     -v timeDaily_avg_activeTracers_temperature -d nVertLevels=0 \
+     -m init.nc -o vtk_files --xtime=xtime_startDaily
+
+
+
+
+

Extracting Multiple Fields

+

In this next example, we will extract areaCell in addition to temperature. +First, we will extract it into a separate VTK file for time-independent +variables, then we will demonstrate combining it with the time-dependent data.

+

In the first instance, we add areaCell to the variable_list and +explicitly include combine=False, the default, to indicate that we want to +keep time-independent and time-dependent variables separate:

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list=['timeDaily_avg_activeTracers_temperature', 'areaCell'],
+    dimension_list=['nVertLevels=0'], mesh_filename='init.nc',
+    combine=False, out_dir='vtk_files2', xtime='xtime_startDaily')
+
+
+

The result is:

+
vtk_files2/staticFieldsOnCells.vtp
+vtk_files2/timeDependentFieldsOnCells.pvd
+vtk_files2/time_series/timeDependentFieldsOnCells.0.vtp
+  ...
+
+
+

We can open both vtk_files/staticFieldsOnCells.vtp and +vtk_files/timeDependentFieldsOnCells.pvd in the same ParaVeiw sesson and +plot them as we like. But we cannot perform calculations involving both +temperature and cell area very easily. If this were a necessity, it might be +convenient to combine them into the same files:

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list=['timeDaily_avg_activeTracers_temperature', 'areaCell'],
+    dimension_list=['nVertLevels=0'], mesh_filename='init.nc',
+    combine=True, out_dir='vtk_files3', xtime='xtime_startDaily')
+
+
+

Now, the result is that areaCell is included in the time-series files

+
vtk_files3/fieldsOnCells.pvd
+vtk_files3/time_series/fieldsOnCells.0.vtp
+...
+
+
+
+
+

Extracting “All” Fields

+

Sometimes, you want all of the fields from your input files to be extracted. +For this purpose there is a special “variable” called 'all' that gets +translated into the full list of available variables. More often, you want to +extract all the variables on cells, edges or vertices, so there are special +“variables” for this, too: 'allOnCells', 'allOnEdges', and +'allOnVertices'. By default, only variables from the files found by +filename_pattern are expanded by these special variables. If you also want +to include variables from the mesh file, you need to specify +include_mesh_vars=True.

+

The following example extracts all the variables on cells for both the +time-series and the mesh data. It specifies maxEdges= so that variables +(such as edgesOnCell and cellsOnCell) that include this dimension are +excluded:

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list=['allOnCells'],
+    dimension_list=['nVertLevels=0', 'nVertLevelsP1=0', 'maxEdges='],
+    mesh_filename='init.nc', combine=True, include_mesh_vars=True,
+    out_dir='vtk_files4', xtime='xtime_startDaily')
+
+
+
+
+

Indexing Dimensions

+

In the previous examples, we saw a basic example of indexing the “extra” +dimensions (i.e. dimensions other than Time, nCells, nVertices and +nEdges) from MPAS output. Here, we show some slightly more involved +examples.

+

Indices for extra dimensions can either be supplied at runtime at a prompt (if +dimension_list=None) or via a list of strings with the dimensions and +associated indices. For each extra dimension, you can specify nothing for the +indices (an empty string, meaning skip any fields with this dimension), a single +index, a comma-separated list of indices, or a range of indices (separated by 1 +or 2 colons). For example,

+
dimension_list=['maxEdges=', 'nVertLeves=0:10:2', 'nParticles=0,2,4,6,8']
+
+
+

will ignore any fields with dimension maxEdges, extract every other +layer from the first 10 vertical levels (each into its own field) and +extract the 5 specified particles.

+

An index array can also be specified in this way (and these can be mixed +with integer indices in a comma-separated list but not in a colon-separated +range):

+
dimension_list=['nVertLeves=0,maxLevelCell']
+
+
+

This will extract fields from the first vertical level and the vertical level +with index given by maxLevelCell (the deepest layer in each ocean column).

+

Here is a more complete example that extracts the temperature, salinity and +layer thickness at the sea surface and seafloor.

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list=['timeDaily_avg_activeTracers_temperature',
+                   'timeDaily_avg_activeTracers_salinity',
+                   'timeDaily_avg_layerThickness'],
+    dimension_list=['nVertLevels=0,maxLevelCell'], mesh_filename='init.nc',
+    out_dir='vtk_files5', xtime='xtime_startDaily')
+
+
+

The resulting fields are named:

+
timeDaily_avg_activeTracers_temperature_0
+timeDaily_avg_activeTracers_temperature_maxLevelCell
+timeDaily_avg_activeTracers_salinity_0
+timeDaily_avg_activeTracers_salinity_maxLevelCell
+timeDaily_avg_layerThickness_0
+timeDaily_avg_layerThickness_maxLevelCell
+
+
+
+
+

Indexing Time

+

Time can also be indexed like the other dimensions, but it is not passed to the +dimension_list argument but instead to the time argument. The time +index string can have any of the following formats:

+
    +
  • '' - no times are to be extracted (probably not useful for time)

  • +
  • 'n' - the index n is to be extracted

  • +
  • 'm,n,p' - the list of indices is to be extracted

  • +
  • 'm:n' - all indices from m to n are to be extracted (including m but +excluding n, in the typical python indexing convention)

  • +
  • 'm:n:s' - all indices from m to n are to be extracted (including m but +excluding n, in the typical python indexing convention) with stride s between +indices

  • +
+

In this example, we extract every 6 days from the daily data set starting with +the beginning fo the data set and continuing to the end (by not specifying the +end index n):

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list=['timeDaily_avg_activeTracers_temperature'],
+    dimension_list=['nVertLevels=0'], mesh_filename='init.nc',
+    time='0::6', out_dir='vtk_files6', xtime='xtime_startDaily')
+
+
+
+
+

Ignoring Time

+

Some MPAS files, for example mesh files and initial conditions, contain a +Time dimension but no xtime variable. The extractor will complain about +this unless you specify ignore_time=True. In this case, only the first time +index is used and all fields are considered to be time-independent, ending +up in staticFieldsOnCells.vtp, etc.

+
+
+

Lon/Lat Coordinates

+

The extractor can produce files in lon/lat coordinates instead of 3D Cartesian +space if lonlat=True. Polygons near the prime meridian (0 or 360 degrees +longitude) will end up on one side or the other based on the location of the +cell center. This leads to a “ragged” edge a the prime meridian, particularly +for coarse-resolution meshes:

+_images/ragged.png +

Below, we will provide a method for handling this issue in ParaView.

+

Here, we extract the temperature field as in Extracting a Temperature Time-series, but +this time in lon/lat coordinates.

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list='timeDaily_avg_activeTracers_temperature',
+    dimension_list=['nVertLevels=0'], mesh_filename='init.nc',
+    lonlat=True, out_dir='vtk_files7', xtime='xtime_startDaily')
+
+
+

In ParaView, the data lies approximately 0 and 360 degrees long the x axis but +with some polygons extending partially beyond these bounds. Since we typically +wish to see the data between -180 and 180 degrees longitude, the proposed fix +will take care of both the longitude range and the ragged edges in one go.

+

First, we make a duplicate copy of the data, translated by -360 degrees. Open +a Transform Filter in ParaView and enter -360 in the first Translate cell +(the x axis). Uncheck “Show Box” and hit “Apply”. The original data will +disappear but you can simply click the eye icon next to it to make it reappear.

+

Next, we want to combine the original and translated versions of the mesh into +a single dataset. Use the shift key to select both, then open the Group +Datasets Filter, then hit “Apply”.

+

Finally, we will crop the grouped dataset to the range of -180 to 180 degrees:

+
    +
  • Select the final of the three “GroupDataset1” items,

  • +
  • open a Clip Filter,

  • +
  • select “Plane” as the Clip Type,

  • +
  • set the Origin to -180, 0, 0,

  • +
  • set the Normal to -1, 0, 0

  • +
+

This has clipped the extra data off the left edge. Now for the right edge:

+
    +
  • Select the “Clip1” item,

  • +
  • open a Clip Filter again,

  • +
  • select “Plane” as the Clip Type,

  • +
  • set the Origin to 180, 0, 0,

  • +
  • set the Normal to 1, 0, 0,

  • +
  • uncheck “Show Plane”

  • +
+

Now, the data should have clean edges. If you want, you can put a plane behind +it to fill in the land:

+_images/clipped.png +
+
+

Topographic Data

+

The extractor includes optional support for extracting geometry appropriate +for displaying variables at the depth of a topographic feature (typically +the top or bottom of the domain) for MPAS components with a spatially +variable top or bottom index (e.g. maxLevelCell in MPAS-Ocean). This is +accomplished with arguments such as:

+
topo_dim='nVertLevels', topo_cell_index='maxLevelCell'
+
+
+

Fields on cells are sampled at the topographic index and the geometry +includes polygons corresponding to edges so that vertical faces between +adjacent cells can be displayed. Fields are extracted as normal except +that they are sampled as point data rather than cell data, allowing +computations in ParaView to display the topography. A mask field is also +included, indicating which parts of edge polygons correspond to the boundary +of the domain (boundaryMask == 1) and which parts of cell and edge +polygons are interior (boundaryMask == 0).

+

In the following, we make sure to use combine=True and +include_mesh_vars=True because we need bottomDepth from the mesh file +to be included in the time-dependent output files. We are not interested in +variables with dimensions nVertLevelsP1 or maxEdges so we remove those +dimensions by leaving their index strings blank.

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list='allOnCells',
+    dimension_list=['nVertLevelsP1=', 'maxEdges='],
+    topo_dim='nVertLevels', topo_cell_index='maxLevelCell',
+    combine=True, include_mesh_vars=True, mesh_filename='init.nc',
+    out_dir='vtk_files8', xtime='xtime_startDaily')
+
+
+

Together, this can be used to plot topography by using a Calculator Filter in +ParaView, checking the “Coordinate Result” box, and entering the following:

+
coords*(1.0 + 100.0/mag(coords)*((1 - boundaryMask)*(-bottomDepth)
+                                 + 10.0*boundaryMask))
+
+
+

The result is that the MPAS-Ocean topography is displayed with a vertical +exaggeration of 100 and with a value equivalent to 10 m along boundary points of +edge polygons (a “water-tight” surface).

+

Here is what that looks like for a 240-km (very coarse) ocean mesh:

+_images/qu240_topo.png +

The same approach can be used with lonlat=True. In this case, the +Calculator Filter is a bit simpler:

+
coords + 1e-3*(1 - boundaryMask)*(-bottomDepth)*kHat + 1.0*boundaryMask*kHat
+
+
+

Here is the bottom temperature in such a plot:

+_images/qu240_topo_lonlat.png +
+
+

Extracting a Region

+

Some simulations are focused on a small region, even though the entire globe is +included in the mesh. For such situations, we provide a way to extract a +subset of the data over a region before converting it to VTK format. The user +specifies a +FeatureCollection +from the geometric_features package as an argument. The regions in this +feature collection are used to define a mask, and the MPAS data is culled to +lie within the mask before conversion to VTK proceeds.

+
+

Note

+

The region should indicate the parts of the mesh to keep, not those to +remove.

+
+

In this example, we extract sea surface temperature only in the Southern Ocean:

+
from mpas_tools.viz.paraview_extractor import extract_vtk
+from geometric_features import GeometricFeatures
+
+
+gf = GeometricFeatures()
+fc = gf.read(componentName='ocean', objectType='region',
+             featureNames=['Southern Ocean'])
+
+extract_vtk(
+    filename_pattern='analysis_members/mpaso.hist.am.timeSeriesStatsDaily.*.nc',
+    variable_list='timeDaily_avg_activeTracers_temperature',
+    dimension_list=['nVertLevels=0'], mesh_filename='init.nc',
+    fc_region_mask=fc, out_dir='vtk_files9', xtime='xtime_startDaily')
+
+
+_images/so_cropped.png +
+
+

ParaView Macros

+

We also provide two macros that can be imported into ParaView, +add_earth_sphere.py +and +annotate_date.py. +Download them and then go to Macros > Add New Macro, and select each file.

+

The first of these adds a sphere that is just a bit smaller than the MPAS data +on the sphere so that continents are not holes in the data. The second can +be used to display the current time (extracted from the xtime variable) in +a ParaVeiw animation.

+
+
+
+

MPAS Mesh to Triangles

+

A relatively new and under-explored functionality in MPAS-Tools is the +capability to extract a triangle mesh for visualization from an MPAS mesh. +This functionality comes from the function +mpas_tools.viz.mesh_to_triangles.mesh_to_triangles(). The function +takes an MPAS mesh as an xarray.Dataset object as its only required input +and produces another xarray.Dataset with the triangle mesh that connects +pairs of adjacent vertices to cell centers as its output. Thus, each hexagon +becomes 6 triangles, each pentagon becomes 5, and so on.

+

In addition to the points and connectivity data for defining these trinagles, +the output dataset, dsTris, also includes the cell index that each triangle +is in and cell indices and weights for interpolating data defined at cell +centers to triangle nodes. dsTris includes variables triCellIndices, +the cell that each triangle is part of; nodeCellIndices and +nodeCellWeights, the indices and weights used to interpolate from MPAS cell +centers to triangle nodes; Cartesian coordinates xNode, yNode, and +zNode; and lonNode` and latNode in radians. lonNode is +guaranteed to be within 180 degrees of the cell center corresponding to +triCellIndices. Nodes always have a counterclockwise winding.

+

Here is an example workflow for using this function:

+
import xarray
+import numpy
+import matplotlib.pyplot as plt
+from matplotlib.tri import Triangulation
+
+from mpas_tools.viz import mesh_to_triangles
+
+
+dsMesh = xarray.open_dataset('mpaso.rst.0501-01-01_00000.nc')
+dsTris = mesh_to_triangles(dsMesh, periodicCopy=True)
+
+sst = dsMesh.temperature.isel(Time=0, nVertLevels=0).values
+
+sstTri = sst[dsTris.triCellIndices]
+
+sstNode = (sst[dsTris.nodeCellIndices]*dsTris.nodeCellWeights).sum('nInterp')
+
+nTriangles = dsTris.sizes['nTriangles']
+tris = numpy.arange(3*nTriangles).reshape(nTriangles, 3)
+
+lonNode = numpy.rad2deg(dsTris.lonNode.values).ravel()
+latNode = numpy.rad2deg(dsTris.latNode.values).ravel()
+sstNode = sstNode.values.ravel()
+
+triangles = Triangulation(lonNode, latNode, tris)
+
+plt.figure(1)
+plt.tripcolor(triangles, sstNode, shading='gouraud')
+plt.xlim([0., 360.])
+plt.ylim([-90., 90.])
+
+plt.figure(2)
+plt.tripcolor(triangles, sstTri, shading='flat')
+plt.xlim([0., 360.])
+plt.ylim([-90., 90.])
+
+plt.show()
+
+
+

In this example, mpaso.rst.0501-01-01_00000.nc is a restart file from a +simulation with an EC at the default 30 to 60 km resolution (see +Defining an Eddy-closure Mesh); the restart file contains both mesh information and a snapshot +of the 3D temperature field.

+

Here are the resulting plots (which look nearly identical at this resolution):

+_images/ec60to30_tris_gouraud.png +_images/ec60to30_tris_flat.png +
+
+

Colormaps

+

Some MPAS-Tools routines include plots of mesh resolution and related variables. +We have found it handy to use the +SciVisColor Colormaps for some of these plots. +Unfortunately, there is not a standard python package for adding these +colormaps to matplotlib (as is the case for +cmocean, for example). To add the +SciVisColor colormaps, call the function +mpas_tools.viz.colormaps.register_sci_viz_colormaps(). No arguments +are required, as the XML files for defining the colormaps are included in the +package.

+

In this example, we use the 3Wbgy5 colormap:

+_images/so60to12_res.png +
+
+ + +
+
+
+ +
+ +
+

© Copyright This software is open source software available under the BSD-3license. Copyright (c) 2019 Triad National Security, LLC. All rights reserved. Copyright (c) 2019 Lawrence Livermore National Security, LLC. All rights reserved. Copyright (c) 2019 UT-Battelle, LLC. All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file