diff --git a/conda/gridTools_export-linux-64-RTD.yml b/conda/gridTools_export-linux-64-RTD.yml index c80dd0f..8d827b1 100644 --- a/conda/gridTools_export-linux-64-RTD.yml +++ b/conda/gridTools_export-linux-64-RTD.yml @@ -1,4 +1,4 @@ -name: gridTools +name: stable channels: - pyviz - conda-forge @@ -6,307 +6,214 @@ channels: dependencies: - _libgcc_mutex=0.1=conda_forge - _openmp_mutex=4.5=1_gnu - - alabaster=0.7.12=py_0 - - alsa-lib=1.2.3=h516909a_0 - - anyio=3.2.1=py37h89c1867_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - argon2-cffi=20.1.0=py37h5e8e339_2 - - async_generator=1.10=py_0 - - attrs=21.2.0=pyhd8ed1ab_0 - - babel=2.9.1=pyh44b312d_0 - - backcall=0.2.0=pyh9f0ad1d_0 - - backports=1.0=py_2 - - backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0 - - bleach=3.3.0=pyh44b312d_0 - - bokeh=2.3.2=py37h89c1867_0 - - boost-cpp=1.74.0=hc6e9bd1_3 - - brotlipy=0.7.0=py37h5e8e339_1001 - bzip2=1.0.8=h7f98852_4 - - c-ares=1.17.1=h7f98852_1 - - ca-certificates=2021.5.30=ha878542_0 - - cairo=1.16.0=h6cf1ce9_1008 - - cartopy=0.19.0.post1=py37h0c48da3_0 - - certifi=2021.5.30=py37h89c1867_0 - - cf_xarray=0.5.2=pyh6c4a22f_0 - - cffi=1.14.5=py37hc58025e_0 - - cfitsio=3.470=hb418390_7 - - cftime=1.5.0=py37h6f94858_0 - - chardet=4.0.0=py37h89c1867_1 - - click=7.1.2=pyh9f0ad1d_0 - - click-plugins=1.1.1=py_0 - - cligj=0.7.2=pyhd8ed1ab_0 - - cloudpickle=1.6.0=py_0 - - colorama=0.4.4=pyh9f0ad1d_0 - - colorcet=2.0.6=py_0 - - conda=4.10.1=py37h89c1867_0 - - conda-package-handling=1.7.3=py37h5e8e339_0 - - coverage=5.5=py37h5e8e339_0 - - cryptography=3.4.7=py37h5d9358c_0 - - curl=7.77.0=hea6ffbf_0 - - cycler=0.10.0=py_2 - - cython=0.29.23=py37hcd2ae1e_1 - - cytoolz=0.11.0=py37h5e8e339_3 - - dask=2021.6.2=pyhd8ed1ab_0 - - dask-core=2021.6.2=pyhd8ed1ab_0 - - dataclasses=0.8=pyhc8e2a94_1 - - datashader=0.13.0=py_0 - - datashape=0.5.4=py_1 - - dbus=1.13.6=h48d8840_2 - - decorator=5.0.9=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distributed=2021.6.2=py37h89c1867_0 - - docrep=0.2.7=py_0 - - docutils=0.16=py37h89c1867_3 - - entrypoints=0.3=pyhd8ed1ab_1003 - - esmf=8.1.0=nompi_hed08645_0 - - esmpy=8.1.0=nompi_py37hff16fce_0 - - expat=2.4.1=h9c3ff4c_0 - - fiona=1.8.18=py37h17d6ad9_1 - - fontconfig=2.13.1=hba837de_1005 + - c-ares=1.18.1=h7f98852_0 + - ca-certificates=2021.10.8=ha878542_0 + - cartopy=0.20.1=py37h7f4ca2d_3 + - certifi=2021.10.8=py37h89c1867_1 + - cftime=1.5.1.1=py37hb1e94ed_1 + - curl=7.80.0=h2574ce0_0 + - cycler=0.11.0=pyhd8ed1ab_0 + - esmf=8.1.0=mpi_mpich_h3dcaa78_101 + - esmpy=8.1.0=mpi_mpich_py37hf719a8e_100 - freetype=2.10.4=h0708190_1 - - freexl=1.0.6=h7f98852_0 - - fsspec=2021.6.1=pyhd8ed1ab_0 - - future=0.18.2=py37h89c1867_3 - - gdal=3.2.1=py37hc5bc4e4_7 - - geopandas=0.9.0=pyhd8ed1ab_0 - - geos=3.9.1=h9c3ff4c_2 - - geotiff=1.6.0=h2b14fbe_4 - - geoviews=1.9.1=py_0 - - geoviews-core=1.9.1=py_0 - - gettext=0.19.8.1=h0b5b191_1005 - - giflib=5.2.1=h36c2ea0_2 - - glib=2.68.3=h9c3ff4c_0 - - glib-tools=2.68.3=h9c3ff4c_0 - - gst-plugins-base=1.18.4=hf529b03_2 - - gstreamer=1.18.4=h76c114f_2 + - geos=3.10.0=h9c3ff4c_0 - hdf4=4.2.15=h10796ff_3 - - hdf5=1.10.6=nompi_h6a2412b_1114 - - heapdict=1.0.1=py_0 - - holoviews=1.14.4=py_0 - - hvplot=0.7.2=py_0 - - icu=68.1=h58526e2_0 - - idna=2.10=pyh9f0ad1d_0 - - imagesize=1.2.0=py_0 - - importlib-metadata=4.5.0=py37h89c1867_0 - - importlib_metadata=4.5.0=hd8ed1ab_0 - - iniconfig=1.1.1=pyh9f0ad1d_0 - - ipykernel=5.5.5=py37h085eea5_0 - - ipython=7.24.1=py37h085eea5_0 - - ipython_genutils=0.2.0=py_1 - - ipywidgets=7.6.3=pyhd3deb0d_0 - - jedi=0.18.0=py37h89c1867_2 - - jinja2=3.0.1=pyhd8ed1ab_0 + - hdf5=1.10.6=mpi_mpich_h996c276_1014 + - jbig=2.1=h7f98852_2003 - jpeg=9d=h36c2ea0_0 - - json-c=0.15=h98cffda_0 - - json5=0.9.5=pyh9f0ad1d_0 - - jsonschema=3.2.0=pyhd8ed1ab_3 - - jupyter=1.0.0=py37h89c1867_6 - - jupyter_client=6.1.12=pyhd8ed1ab_0 - - jupyter_console=6.4.0=pyhd8ed1ab_0 - - jupyter_core=4.7.1=py37h89c1867_0 - - jupyter_server=1.9.0=pyhd8ed1ab_0 - - jupyterlab=3.0.16=pyhd8ed1ab_0 - - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0 - - jupyterlab_server=2.6.0=pyhd8ed1ab_0 - - jupyterlab_widgets=1.0.0=pyhd8ed1ab_1 - - kealib=1.4.14=hcc255d8_2 - - kiwisolver=1.3.1=py37h2527ec5_1 - - krb5=1.19.1=hcc1bbae_0 - - latexcodec=2.0.1=pyh9f0ad1d_0 + - kiwisolver=1.3.2=py37h2527ec5_1 + - krb5=1.19.2=hcc1bbae_3 - lcms2=2.12=hddcbb42_0 - - ld_impl_linux-64=2.35.1=hea4e1c9_2 - - libblas=3.9.0=9_openblas - - libcblas=3.9.0=9_openblas - - libclang=11.1.0=default_ha53f305_1 - - libcurl=7.77.0=h2574ce0_0 - - libdap4=3.20.6=hd7c4107_2 + - ld_impl_linux-64=2.36.1=hea4e1c9_2 + - lerc=3.0=h9c3ff4c_0 + - libblas=3.9.0=12_linux64_openblas + - libcblas=3.9.0=12_linux64_openblas + - libcurl=7.80.0=h2574ce0_0 + - libdeflate=1.8=h7f98852_0 - libedit=3.1.20191231=he28a2e2_2 - libev=4.33=h516909a_1 - - libevent=2.1.10=hcdb4288_3 - - libffi=3.3=h58526e2_2 - - libgcc-ng=9.3.0=h2828fa1_19 - - libgdal=3.2.1=h38ff51b_7 - - libgfortran-ng=9.3.0=hff62375_19 - - libgfortran5=9.3.0=hff62375_19 - - libglib=2.68.3=h3e27bee_0 - - libgomp=9.3.0=h2828fa1_19 - - libiconv=1.16=h516909a_0 - - libkml=1.3.0=h238a007_1013 - - liblapack=3.9.0=9_openblas - - libllvm10=10.0.1=he513fc3_3 - - libllvm11=11.1.0=hf817b99_2 - - libnetcdf=4.7.4=nompi_h56d31a8_107 - - libnghttp2=1.43.0=h812cca2_0 - - libogg=1.3.4=h7f98852_1 - - libopenblas=0.3.15=pthreads_h8fe5266_1 - - libopus=1.3.1=h7f98852_1 + - libffi=3.4.2=h7f98852_5 + - libgcc-ng=11.2.0=h1d223b6_11 + - libgfortran-ng=11.2.0=h69a702a_11 + - libgfortran5=11.2.0=h5c6108e_11 + - libgomp=11.2.0=h1d223b6_11 + - liblapack=3.9.0=12_linux64_openblas + - libnetcdf=4.8.0=mpi_mpich_hfc250a3_0 + - libnghttp2=1.43.0=h812cca2_1 + - libnsl=2.0.0=h7f98852_0 + - libopenblas=0.3.18=pthreads_h8fe5266_0 - libpng=1.6.37=h21135ba_2 - - libpq=13.3=hd57d9b9_0 - - librttopo=1.1.0=h1185371_6 - - libsodium=1.0.18=h36c2ea0_1 - - libspatialindex=1.9.3=h9c3ff4c_3 - - libspatialite=5.0.1=he52d314_3 - - libssh2=1.9.0=ha56f1ee_6 - - libstdcxx-ng=9.3.0=h6de172a_19 - - libtiff=4.2.0=hbd63e13_2 + - libssh2=1.10.0=ha56f1ee_2 + - libstdcxx-ng=11.2.0=he4da1e4_11 + - libtiff=4.3.0=h6f004c6_2 - libuuid=2.32.1=h7f98852_1000 - - libuv=1.41.0=h7f98852_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp-base=1.2.0=h7f98852_2 - - libxcb=1.13=h7f98852_1003 - - libxkbcommon=1.0.3=he3ba5ed_0 - - libxml2=2.9.12=h72842e0_0 - - llvmlite=0.36.0=py37h9d7f4d0_0 - - locket=0.2.0=py_2 - - lz4-c=1.9.3=h9c3ff4c_0 - - m2r2=0.2.8=pyhd8ed1ab_0 - - markdown=3.3.4=pyhd8ed1ab_0 - - markupsafe=2.0.1=py37h5e8e339_0 - - matplotlib=3.4.2=py37h89c1867_0 - - matplotlib-base=3.4.2=py37hdd32ed1_0 - - matplotlib-inline=0.1.2=pyhd8ed1ab_2 - - mistune=0.8.4=py37h5e8e339_1003 - - more-itertools=8.8.0=pyhd8ed1ab_0 - - msgpack-python=1.0.2=py37h2527ec5_1 - - multipledispatch=0.6.0=py_0 - - munch=2.5.0=py_0 - - mysql-common=8.0.25=ha770c72_0 - - mysql-libs=8.0.25=h935591d_0 - - nbclassic=0.3.1=pyhd8ed1ab_1 - - nbclient=0.5.3=pyhd8ed1ab_0 - - nbconvert=6.1.0=py37h89c1867_0 - - nbformat=5.1.3=pyhd8ed1ab_0 + - libwebp-base=1.2.1=h7f98852_0 + - libzlib=1.2.11=h36c2ea0_1013 + - lz4-c=1.9.3=h9c3ff4c_1 + - mpi=1.0=mpich + - mpi4py=3.1.2=py37h1e5cb63_0 + - mpich=3.4.2=h846660c_100 - ncurses=6.2=h58526e2_4 - - nest-asyncio=1.5.1=pyhd8ed1ab_0 - - netcdf-fortran=4.5.3=nompi_h996563d_103 - - netcdf4=1.5.6=nompi_py37hf7b6e46_102 - - notebook=6.4.0=pyha770c72_0 - - nspr=4.30=h9c3ff4c_0 - - nss=3.67=hb5efdd6_0 - - numba=0.53.1=py37hb11d6e1_1 - - numpy=1.21.0=py37h038b26d_0 + - netcdf-fortran=4.5.3=mpi_mpich_h196b126_4 - olefile=0.46=pyh9f0ad1d_1 - openjpeg=2.4.0=hb52868f_1 - - openssl=1.1.1k=h7f98852_0 - - owslib=0.24.1=pyhd8ed1ab_0 - - packaging=20.9=pyh44b312d_0 - - pandas=1.2.5=py37h219a48f_0 - - pandoc=2.14.0.3=h7f98852_0 - - pandocfilters=1.4.2=py_1 - - panel=0.11.3=py_0 - - param=1.10.1=py_0 - - parso=0.8.2=pyhd8ed1ab_0 - - partd=1.2.0=pyhd8ed1ab_0 - - pcre=8.45=h9c3ff4c_0 - - pexpect=4.8.0=pyh9f0ad1d_2 - - pickleshare=0.7.5=py_1003 - - pillow=8.2.0=py37h4600e1f_1 - - pip=21.1.2=pyhd8ed1ab_0 - - pixman=0.40.0=h36c2ea0_0 - - pluggy=0.13.1=py37h89c1867_4 - - pooch=1.4.0=pyhd8ed1ab_0 - - poppler=0.89.0=h2de54a5_5 - - poppler-data=0.4.10=0 - - postgresql=13.3=h2510834_0 - - proj=7.2.0=h277dcde_2 - - prometheus_client=0.11.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.19=pyha770c72_0 - - prompt_toolkit=3.0.19=hd8ed1ab_0 - - psutil=5.8.0=py37h5e8e339_1 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - py=1.10.0=pyhd3deb0d_0 - - pybtex=0.24.0=py37h89c1867_0 - - pybtex-docutils=1.0.0=py37h89c1867_0 - - pycosat=0.6.3=py37h5e8e339_1006 - - pycparser=2.20=pyh9f0ad1d_2 - - pyct=0.4.8=py_0 - - pyct-core=0.4.8=py_0 - - pygments=2.9.0=pyhd8ed1ab_0 - - pykdtree=1.3.4=py37ha21ca33_0 - - pyopenssl=20.0.1=pyhd8ed1ab_0 - - pyparsing=2.4.7=pyh9f0ad1d_0 - - pyproj=3.1.0=py37h20b8899_3 - - pyqt=5.12.3=py37h89c1867_7 - - pyqt-impl=5.12.3=py37he336c9b_7 - - pyqt5-sip=4.19.18=py37hcd2ae1e_7 - - pyqtchart=5.12=py37he336c9b_7 - - pyqtwebengine=5.12.1=py37he336c9b_7 - - pyrsistent=0.17.3=py37h5e8e339_2 + - openssl=1.1.1l=h7f98852_0 + - pillow=8.4.0=py37h0f21c89_0 + - pip=21.3.1=pyhd8ed1ab_0 + - proj=8.2.0=h277dcde_0 + - pyproj=3.2.1=py37hb589d83_5 - pyshp=2.1.3=pyh44b312d_0 - - pysocks=1.7.1=py37h89c1867_3 - - pytest=6.2.4=py37h89c1867_0 - - python=3.7.10=hffdb5ce_100_cpython - - python-dateutil=2.8.1=py_0 + - python=3.7.12=hb7a2778_100_cpython + - python-dateutil=2.8.2=pyhd8ed1ab_0 - python_abi=3.7=1_cp37m - - pytz=2021.1=pyhd8ed1ab_0 - - pyviz_comms=2.0.2=py_0 - - pyyaml=5.4.1=py37h5e8e339_0 - - pyzmq=22.1.0=py37h336d617_0 - - qt=5.12.9=hda022c4_4 - - qtconsole=5.1.0=pyhd8ed1ab_0 - - qtpy=1.9.0=py_0 - readline=8.1=h46c0cb4_0 - - requests=2.25.1=pyhd3deb0d_0 - - requests-unixsocket=0.2.0=py_0 - - rtree=0.9.7=py37h0b55af0_1 - - ruamel_yaml=0.15.80=py37h5e8e339_1004 - - scipy=1.6.3=py37h29e03ee_0 - - send2trash=1.7.1=pyhd8ed1ab_0 - - setuptools=49.6.0=py37h89c1867_3 - - shapely=1.7.1=py37h2d1e849_5 + - scipy=1.7.2=py37hf2a6cf1_0 + - setuptools=59.1.1=py37h89c1867_0 + - shapely=1.8.0=py37ha79c7d7_2 - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.2.0=py37h89c1867_1 - - snowballstemmer=2.1.0=pyhd8ed1ab_0 - - sortedcontainers=2.4.0=pyhd8ed1ab_0 - - sphinx=4.0.2=pyh6c4a22f_1 - - sphinx_rtd_theme=0.5.2=pyhd8ed1ab_1 - - sphinxcontrib-applehelp=1.0.2=py_0 - - sphinxcontrib-bibtex=2.3.0=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.2=py_0 - - sphinxcontrib-htmlhelp=2.0.0=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=py_0 - - sphinxcontrib-qthelp=1.0.3=py_0 - - sphinxcontrib-serializinghtml=1.1.5=pyhd8ed1ab_0 - - sqlite=3.36.0=h9cd32fc_0 - - tblib=1.7.0=pyhd8ed1ab_0 - - terminado=0.10.1=py37h89c1867_0 - - testpath=0.5.0=pyhd8ed1ab_0 - - tiledb=2.2.9=h91fcb0e_0 - - tk=8.6.10=h21135ba_1 - - toml=0.10.2=pyhd8ed1ab_0 - - toolz=0.11.1=py_0 - - tornado=6.1=py37h5e8e339_1 - - tqdm=4.61.1=pyhd8ed1ab_0 - - traitlets=5.0.5=py_0 - - typing_extensions=3.10.0.0=pyha770c72_0 - - tzcode=2021a=h7f98852_1 - - tzdata=2021a=he74cb21_0 - - urllib3=1.26.5=pyhd8ed1ab_0 - - wcwidth=0.2.5=pyh9f0ad1d_2 - - webencodings=0.5.1=py_1 - - websocket-client=0.57.0=py37h89c1867_4 - - wheel=0.36.2=pyhd3deb0d_0 - - widgetsnbextension=3.5.1=py37h89c1867_4 - - xarray=0.19.0=pyhd8ed1ab_1 - - xerces-c=3.2.3=h9d8b166_2 - - xesmf=0.5.3=pyhd8ed1ab_0 - - xgcm=0.5.2=pyhd8ed1ab_0 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.0.10=h7f98852_0 - - xorg-libsm=1.2.3=hd9c2040_1000 - - xorg-libx11=1.7.2=h7f98852_0 - - xorg-libxau=1.0.9=h7f98852_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h7f98852_1 - - xorg-libxrender=0.9.10=h7f98852_1003 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 + - sqlite=3.36.0=h9cd32fc_2 + - tk=8.6.11=h27826a3_1 + - tornado=6.1=py37h5e8e339_2 + - tzdata=2021e=he74cb21_0 + - wheel=0.37.0=pyhd8ed1ab_1 - xz=5.2.5=h516909a_1 - - yaml=0.2.5=h516909a_0 - - zeromq=4.3.4=h9c3ff4c_0 - - zict=2.0.0=py_0 - - zipp=3.4.1=pyhd8ed1ab_0 - - zlib=1.2.11=h516909a_1010 - - zstd=1.4.9=ha95c52a_0 + - zlib=1.2.11=h36c2ea0_1013 + - zstd=1.5.0=ha95c52a_0 + - pip: + - alabaster==0.7.12 + - anyio==3.3.4 + - argcomplete==1.12.3 + - argon2-cffi==21.1.0 + - attrs==21.2.0 + - babel==2.9.1 + - backcall==0.2.0 + - bleach==4.1.0 + - bokeh==2.3.3 + - cf-xarray==0.6.1 + - cffi==1.15.0 + - charset-normalizer==2.0.7 + - click==8.0.3 + - cloudpickle==2.0.0 + - colorama==0.4.4 + - colorcet==2.0.6 + - coverage==6.1.2 + - cython==0.29.24 + - dask==2021.11.1 + - datashader==0.13.0 + - datashape==0.5.2 + - debugpy==1.5.1 + - decorator==5.1.0 + - defusedxml==0.7.1 + - distributed==2021.11.1 + - docrep==0.2.7 + - docutils==0.16 + - entrypoints==0.3 + - fonttools==4.28.1 + - fsspec==2021.11.0 + - future==0.18.2 + - geoviews==1.9.1 + - heapdict==1.0.1 + - holoviews==1.14.6 + - hvplot==0.7.2 + - idna==3.3 + - imagesize==1.3.0 + - importlib-metadata==4.8.2 + - importlib-resources==5.4.0 + - iniconfig==1.1.1 + - ipykernel==6.5.0 + - ipython==7.29.0 + - ipython-genutils==0.2.0 + - jedi==0.18.1 + - jinja2==3.0.3 + - json5==0.9.6 + - jsonschema==4.2.1 + - jupyter-client==7.0.6 + - jupyter-core==4.9.1 + - jupyter-server==1.11.2 + - jupyterlab==3.2.4 + - jupyterlab-pygments==0.1.2 + - jupyterlab-server==2.8.2 + - latexcodec==2.0.1 + - llvmlite==0.37.0 + - locket==0.2.1 + - markdown==3.3.6 + - markupsafe==2.0.1 + - matplotlib==3.5.0 + - matplotlib-inline==0.1.3 + - mistune==0.8.4 + - msgpack==1.0.2 + - multipledispatch==0.6.0 + - nbclassic==0.3.4 + - nbclient==0.5.8 + - nbconvert==6.3.0 + - nbformat==5.1.3 + - nest-asyncio==1.5.1 + - netcdf4==1.5.8 + - notebook==6.4.6 + - numba==0.54.1 + - numpy==1.20.3 + - owslib==0.25.0 + - packaging==21.2 + - pandas==1.3.4 + - pandocfilters==1.5.0 + - panel==0.12.1 + - param==1.12.0 + - parso==0.8.2 + - partd==1.2.0 + - pexpect==4.8.0 + - pickleshare==0.7.5 + - pluggy==1.0.0 + - prometheus-client==0.12.0 + - prompt-toolkit==3.0.22 + - psutil==5.8.0 + - ptyprocess==0.7.0 + - py==1.11.0 + - pybtex==0.24.0 + - pybtex-docutils==1.0.1 + - pycparser==2.21 + - pyct==0.4.8 + - pygments==2.10.0 + - pykdtree==1.3.4 + - pyparsing==2.4.7 + - pyqt5==5.15.6 + - pyqt5-qt5==5.15.2 + - pyqt5-sip==12.9.0 + - pyrsistent==0.18.0 + - pytest==6.2.5 + - pytz==2021.3 + - pyviz-comms==2.1.0 + - pyyaml==6.0 + - pyzmq==22.3.0 + - requests==2.26.0 + - send2trash==1.8.0 + - setuptools-scm==6.3.2 + - sniffio==1.2.0 + - snowballstemmer==2.2.0 + - sortedcontainers==2.4.0 + - sphinx==4.3.0 + - sphinx-rtd-theme==1.0.0 + - sphinxcontrib-applehelp==1.0.2 + - sphinxcontrib-bibtex==2.4.1 + - sphinxcontrib-devhelp==1.0.2 + - sphinxcontrib-htmlhelp==2.0.0 + - sphinxcontrib-jsmath==1.0.1 + - sphinxcontrib-qthelp==1.0.3 + - sphinxcontrib-serializinghtml==1.1.5 + - tblib==1.7.0 + - terminado==0.12.1 + - testpath==0.5.0 + - toml==0.10.2 + - tomli==1.2.2 + - toolz==0.11.2 + - tqdm==4.62.3 + - traitlets==5.1.1 + - typing-extensions==4.0.0 + - urllib3==1.26.7 + - wcwidth==0.2.5 + - webencodings==0.5.1 + - websocket-client==1.2.1 + - xarray==0.20.1 + - xgcm==0.5.2 + - zict==2.0.0 + - zipp==3.6.0 diff --git a/docs/development/CHANGELOG.md b/docs/development/CHANGELOG.md index cb8ed8d..8945162 100644 --- a/docs/development/CHANGELOG.md +++ b/docs/development/CHANGELOG.md @@ -1,6 +1,255 @@ # Changelog -# 2021-08-12 +## 2021-11-24 + +Commit dev to main to release 0.3.2. + +## 2021-11-22 + +Working towards release 0.3.2 + + - Fixed some formatting in documentation + - Updated operational pathways graphic + - Working through release tasks + +## 2021-11-17 + +Working towards release 0.3.2 + + - Documentation cleanup for gridutils.extendGrid() + - RTD is working! + - Remove pip requirements that snuck into `gridTools_export-linux-64-RTD.yml`. + - Modify `roms_io.py` to mandate netcdf4 or netcdf3. Do not fall back to `pyroms`. + - Remove `cartopy` from requirements.txt; this triggers a lot of dependency checks. + Include in user installation instructions that a combination of conda, pip and manual + installation of `cartopy` might be necessary. + - The RTD installation does not need to be fully functional. It only needs to be able + to load the modules by import. The `gridTools_export-linux-64-RTD.yml` has been pared + down to a minimal installation to be overlaid by the `requirements.txt` file using pip. + - RTD with conda performs a two stage install: + - `conda env create --quiet --name stable --file conda/gridTools_export-linux-64-RTD.yml` + - `python -m pip install -U -r requirements.txt` + - Current failure is in the first stage. + - Try to rebuild with a minimal RTD stack. + - Current conda configuration has a peak memory footprint of 1489580 kB + - Just python=3 uses 409452 kB + - Remove `m2r2` from software stack. + +## 2021-11-16 + +Testing for release 0.3.2 + + - RTD is failing. We need to shift some items out of + `gridTools_export-linux-64-RTD.yml` and into + requirements.txt. + Try: `/usr/bin/time -v conda env create --quiet --name stable --file conda/gridTools_export-linux-64-RTD.yml` + - Writing release documentation; need to check on RTD. + - Testing completed on chinook node + - Updated README for examples directory + - Show i vertex in yellow for python script example 5a and 6. + - Testing on chinook node + - Update API for Example 3 for computeBathymetricRoughness() + +## 2021-11-15 + +Testing for release 0.3.2 + + - Tested app at mybinder.org + - Update API for python script 7 for + computeBathymetricRoughness(); add informational + message to say if REusing an existing bathymetry. + - Begin testing on aarch64 platform + - Fix GitHub CI (currently passes) + - Completed testing on local Ubuntu node with 64GB + - Python script example 3 and 8 now demonstrates use of + an extended grid with the function regridTopo() to + eliminate grid artifacts. + - Fix grid axis for generation of IBCAO grid in python + script for Example 5 and 5a. Show expected answers for + grid corners. + +## 2021-11-14 + +Working towards release 0.3.2, testing examples: + + - Show how to fix the artifact using extended grids with + the function regridTopo() in example 3. + - Update meshutils.writeLandMask() and meshutils.writeOceanMask() + to search for x and y coordinates if not provided by the supplied + variable. + - Further fix to updateGridMetadata(). + - Notebook example 7a and 7b did not save an + example land and ocean mask. They should now work + independently of the python script example 7 now. + - Scan all examples for API call change to computeBathymetricRoughness() + - FixByOverlapQHGridShift => useQHGridShift, useOverlap + - Example 7 should create three separate sets of example + files. + - Create another example 07b that demonstrates extending + the grid for use in the bathymetric roughness routine. + - API update for computing metrics for mkGridsExmaple04a. + Set i grid lines yellow to show grid orientation. + - Fix variable axis in mkGridsExample04 to match the + gridtools library. Results are the same. + - Adjust stereographic southern hemisphere example + in mkGridItereative. + - Gridtools app would not launch with IP. It comes up + with IP=0.0.0.0 and browsing to IP. + +## 2021-11-12 + +Gridtools updates working towards release 0.3.2 + + - Finished initial update to global metadata attributes. + - Implement showGridPoints keyword attribute for plotGrid(). + +## 2021-11-10 + +Progress on global metadata updates. + +## 2021-11-06 + +Work towards release 0.3.2 with current fixes and improvements. + - Work on adding or appending to history global variable. + - Move to generic routine for adding/appending/updating + global variables. + - Global `history` values are separated by a `\n` according + to netCDF kitchen sink tools. + +## 2021-10-27 + + - Finally fixed the "stereographic" grid generation. + The grids cannot be rotated yet, but patterns for + doing so are emerging. + - Developed some examples showing grid generation in + available projections. Additional examples should + be created for other projections. + +## 2021-10-25 + + - gridtools applications do not display properly when + jupyter is started with `--ip=0.0.0.0`. + +## 2021-10-23 + + - Adding support for different variable output types for + FMS/MOM6 grid files. The FMS coupler will die if the + integer part of the mosaic tile files contain 64-bit + integers. Reducing that size to 32-bit (i4/int32). + +## 2021-10-22 + + - First implementation of ice-9 algorithm derived from + example software written by Alistair Adcroft and + Niki Zadeh. Added as bathyutils.ice9(). + - Added citations for ice-9 algorithm as best we have + them for now. + +## 2021-10-20 + + - Software development around subsetting existing grids. + - Upgrades to computeBathymetricRoughness() to allow it to + diagnose roughness using serveral grid options. + Reworking options to useSupergrid, useOverlap and + useQHGridShift replacing prior options. + - Add more important documentation links from matplotlib. + - Noted that original ROMS to MOM6 conversion script uses + a different default earth radius. + - Save the global projection attribute only if available. + - If the global projection attribute is not set, try to + set it from the projection grid parameters. Use the + global projection attribute, if it is available. + - When computing grid metrics, clamp `angle_dx` to zero + as is done in the original convertion from ROMS to MOM6 + code. + +## 2021-10-13 + + - Develop gridutils.subsetGrid() to allow subsetting of + grids evenly divisble by the specified scale factor. + +## 2021-10-11 + + - Fix a few spellings of vertices and note the singular of + "vertices" is "vertex". + - Spherical grid fix (rel 0.3.1) for southern hemisphere broke + the northern hemispheric grids. Need to further investigate + creation and extension of various spherical grids. + - Start marking i vertex lines as yellow in examples to ensure + proper grid generation. + - Add option to plotGrid to allow plotting of one or more + specified grid points. + - Initial clipping code added to extendGrid function. + +## 2021-10-07 + + - Example 12 shows mercator, lambert conformal conic and + stereographic grid extensions. + - Finished generation of extended grid. Need to + finish clipping of grid back to requested size. + - Added support for extending sterographic grids. + - Grid extension development. Keeping routine + very simple. Initial implementation was somewhat + more complex. + - Extending lat/lon grids works. + - Found a bug in gridutils.findLineFromPoints(), off + by one error for computing new points. + - Spurious breakpoint() in gridutils.readGrid() with + no documentation. Seems to be a condition with + reading ROMS grids. + +## 2021-10-06 + + - Add a reference for Niki Zadah's grid generation tools. + - Continue grid extension development. + - Auto detect method and projection for grid to extend. + +## 2021-10-05 + + - Fix return in function (CI:113) + +## 2021-10-01 + + - BUG: app: fix latitude range for grid center. Range should be + -90 to +90 instead of 0 to 90. The 0 to 90 range would be + important if we chose to stick with two separate hemispheric + projections. Dealing with a separate southern hemisphere would + introduce additional complications. Resolves #12. + - Begin work on grid extension for spherical and lat/lon based + grids. Create example 12 to exercise new features. + +## 2021-08-23 + + - Finish task of creating a roughness field from an extended + MOM6 grid so we have useful data for the entire grid. + - Example 07 formatting. + - `undo_break_array_to_blocks` change argument from + useSupergrid to useOverlap to better reflect technique + being used. + - `undo_break_array_to_blocks` the grid returned is the + untrimmed grid for useOverlap. + - `computeBathymetricRoughness` add extendedGrid option + to tell the routine that an extended grid is being used. + When this is true, the grid shift is skipped if used + with useFixByOverlapQHGridShift. + - `computeBathymetricRoughness` add more user messages + indicating what it is doing based on specified options. + - add `findLineFromPoints()` needs to be improved to + allow specification of additional points on the grid. + +## 2021-08-16 + + - Add a southern hemispheric example to `mkGridIterative.ipynb`. + - BUG in `gridtools.generate_regional_spherical_meters`, the + INVERSE should use (xx,yy) NOT (yy,xx). Thanks to the bug + report from Olga Sergienko. + +## 2021-08-13 + + - Begin exp/rel032 branch + - Fix gridtools pydoc/ref for computeBathymetricRoughness() + +## 2021-08-12 - Begin release cycle for 0.3.1 - Add github templates @@ -12,7 +261,7 @@ - Script tests on triton ok - Add contributors to release notes -# 2021-08-11 +## 2021-08-11 - Example 3 is broken - xarray=0.19.0 @@ -29,14 +278,14 @@ - Add a guide to the API manual for the gridtools and FRE-NCtools comparison which is partially complete. -# 2021-08-04 +## 2021-08-04 - PR#11 can be applied via merge of remote branch, proceeding with 0.3.1 update - PyCNAL: Grabbing a copy of SODA 3.3.1/1980 for OBC/IC work - PyCNAL: Grabbing a copy of WOA13 for OBC/IC work -# 2021-08-03 +## 2021-08-03 - Looking at how to apply PR#11 - Example 07a; note that the selection of the 1000 meter depth is @@ -47,7 +296,7 @@ in the PATH. - Create dataset subset/preparer for `make_topog` executables. -# 2021-07-22 +## 2021-07-22 - Remove unneeded import from example 09b - Documentation updates @@ -61,16 +310,16 @@ - In xarray dataset .sel statements, slice requires the shape location and the dimension wants the array location. -# 2021-07-20 +## 2021-07-20 - Documentation updates -# 2021-07-16 +## 2021-07-16 - Add some borders to the grid editor. Have to work on the 4th side. - Continue with documentation -# 2021-07-15 +## 2021-07-15 - Large files take a long time to save. Makes the application appear hung or unresponsive. @@ -83,7 +332,7 @@ - Continue with documentation updates to RTD. - Fixed RTD by moving import gridtools after adding ".." to path. -# 2021-07-14 +## 2021-07-14 - Adding RTD documentation about the grid generation application. - Learned how to add page breaks in rst for latex/PDF. @@ -92,7 +341,7 @@ - Fix message for detached logging from application. - Add missing last section to RTD tutorial. -# 2021-07-13 +## 2021-07-13 - Add references from GridUtils to bathyutils functions. - Fix citation tags for pyroms references. @@ -104,12 +353,12 @@ - Nearly completed a tutorial showing how to create and edit a MOM6 model grid. -# 2021-07-12 +## 2021-07-12 - Discovered we can manually force showing a figure using display(figure). - Started a broad tutorial for creating and modifying a grid in Jupyter. -# 2021-07-11 +## 2021-07-11 - Started some work on syncing MD files into source directory for sphinx. Might have to rethink this a bit. @@ -119,30 +368,30 @@ FRE-NCtools test 13. Still need to increase MAXXGRID to 1e8 in `create_xgrid.h` to succeed with using GEBCO 2020. -# 2021-07-10 +## 2021-07-10 - Working through deployment checklist. - Fix a spelling mistake in release notes. -# 2021-07-09 +## 2021-07-09 - For UAF/chinook with old glibc, it is best to bootstrap with python and geoviews up front and then load all the other packages. All examples and editors work. -# 2021-07-08 +## 2021-07-08 - Example 8: Update plot parameter - Example 3: fix a bug; change log file name - Update docs/conda/README.md -# 2021-07-07 +## 2021-07-07 - Begin testing on chinook@UAF. - Chinook has an older glibc that requires a different set of packages for gridtools. -# 2021-07-06 +## 2021-07-06 - Try to save an artifact to github actions: conda dump - All examples are functional on aarch64 @@ -158,14 +407,14 @@ to missing pyqt support for pylab. The conda package manager provides sufficient pyqt support. -# 2021-07-05 +## 2021-07-05 - Rename a few of the examples so they sort nicely in UNIX `ls`. - Hashes match between github `x86_64` and `aarch64`. Good! - Change pytest grid example to match Example 1 for platform comparisons (LLC grid tilt 30 degrees). -# 2021-07-04 +## 2021-07-04 - Cause an error if a ROMS gridid.txt file cannot be found. - Ocean and land masks did not have a hash created. Added to meshutils @@ -188,12 +437,12 @@ - Packages versions are typically seen only at the root element, so optimize on that. -# 2021-07-03 +## 2021-07-03 - Rework sysinfo and utils modules to allow more flexible software and detection in different environments. -# 2021-07-02 +## 2021-07-02 - RTD is fixed. - Add roms modules to RTD docs. @@ -209,7 +458,7 @@ against the `MINIMUM_DEPTH` for points that need to be capped as well. - Update some MOM6 notes about bathymetry and related parameters. -# 2021-07-01 +## 2021-07-01 - Set undefined depth of ocean to -99999.0 - Refactor codes to use utils.sha256sum() @@ -223,20 +472,20 @@ - Revising mask modification for bathyutils.applyExistingLandmask() and bathyutils.applyExistingOceanmask(). -# 2021-06-30 +## 2021-06-30 - MOM6 PR#1428 `MASKING_DEPTH` may be unspecified or shallower than `MINIMUM_DEPTH`. - Allow modification of a MOM6 grid. - Now need to work on save and application of edited grid. -# 2021-06-29 +## 2021-06-29 - Continue configuration of jupyter mask editer. - Integration of ROMS grids into openGrid/readGrid infrastructure. - Rename variable `PYROMS_GRIDID_FILE` to `ROMS_GRIDID_FILE`. - Move to more generic keywarg arguments to openDataset, openGrid and readGrid. -# 2021-06-28 +## 2021-06-28 - Add controls to jupyter mask editor - Jupyter mask editor is now wrapped in a class @@ -246,7 +495,7 @@ that calls `%pylab` first. - fix typo in example for gridutils.plotGrid() -# 2021-06-27 +## 2021-06-27 - map() does not work well with numpy/xarray - pyplot will require a rewrite to optimize speed; the full map is rendered and @@ -254,12 +503,12 @@ - need to add a control to jupyter editor to enable/disable mask edits but still allow moving the subgrid on each click. -# 2021-06-26 +## 2021-06-26 - Working on trying to get jupyter and pyplot displays to be more similar to each other. -# 2021-06-25 +## 2021-06-25 - Added an adaptive method to the mask editor. User can specify size of grid subset. Subset grid is centered over the last mouse click. @@ -270,7 +519,7 @@ - Make sure to reset the kernel and wipe out any cells on notebooks to keep the repository size down. -# 2021-06-24 +## 2021-06-24 - Experimenting with hvplot quadmesh. With a large grid, it takes a long time. May want to consider partitioning the grid for plotting? Sliding views? @@ -282,7 +531,7 @@ - The coordinate system is a little different in cartopy. Found a reference that helped fix the issue. -# 2021-06-23 +## 2021-06-23 - Copied needed modules from pyroms and made some modifications - Added new modules to `__init__` for grids module @@ -298,11 +547,11 @@ - bibtex authors are separated by and and not commas - Add citation for pyroms -# 2021-06-22 +## 2021-06-22 - PR#8 submitted to main. Making final checks of CI, RTD and mybinder. -# 2021-06-21 +## 2021-06-21 - Add more environment infomation - Show stdout for pytests (-rA) @@ -318,7 +567,7 @@ - Updated some documentation in the sanity module. - Add reference to `gridutils.generate_regional_spherical_meters()` -# 2021-06-20 +## 2021-06-20 - Add keyword arguments to GridUtils.plotGrid() for control over plotting elements. @@ -341,7 +590,7 @@ - xarray tutorial data requires python module pooch - Create mkGridsExample7a notebook to experiment with xarray plotting methods. -# 2021-06-19 +## 2021-06-19 - Add generic plotting demonstration to Example 7. Will add more options in later releases. Not quite working yet. @@ -364,7 +613,7 @@ - Add `*_DEPTH` specified options to metadata for topography and masking files. - Restructure plotGrid to enable plotting of model grid or other variables. -# 2021-06-18 +## 2021-06-18 - conda export environments should not include special pip packages - Remove pip definitions from binder/environment.yml @@ -375,7 +624,7 @@ - Rename LandMask to Landmask - Rename OceanMask to Oceanmask -# 2021-06-17 +## 2021-06-17 - Adopt use of colorama for optional coloring of text output - Debug gridtools.grids.mom6 @@ -383,7 +632,7 @@ - Fixes for at least when git commands fail attempting to grab git related information. -# 2021-06-16 +## 2021-06-16 - Initial coding of ROMS to MOM6 converter and writing out a solo mosaic for a new grid is complete. Now to begin testing. @@ -393,7 +642,7 @@ - Add proper string encoding to gridutils.removeFillValueAttributes. - Continue adding routines to mom6 and roms modules. -# 2021-06-15 +## 2021-06-15 - Replace {} with dict() - Porting of ROMS to MOM6 grids will go hand in hand with general @@ -412,7 +661,7 @@ if ds:/GEBCO_2020 == ds:GEBCO_2020. - Simplify Example 8 a little bit with file spec discovery. -# 2021-06-14 +## 2021-06-14 - Add remaining modules to RTD documentation. - RTD docstrings: https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html @@ -426,19 +675,19 @@ - Add bibtex to sphinx documentation process. - bibliography.rst: Sample entry for a paper and a github repo. -# 2021-06-13 +## 2021-06-13 - computeGridMetrics comes in two forms: spherical and cartesian. - Begin construction of makeSoloMosaic that does similar work to `make_solo_mosaic`. - Attempts to build FRE-nctools on chinook have failed so far. -# 2021-06-12 +## 2021-06-12 - Numpy has a method to access the indexes that match grid points for any value test. -# 2021-06-11 +## 2021-06-11 - BUG: Relative paths do not work in the new filespec scheme. - Remove old Documentation.md file. @@ -455,7 +704,7 @@ - Adding sphinx/doxygen to documentation proceedures. The documentation will utilize a separate enviornmnet to keep things simple. -# 2021-06-10 +## 2021-06-10 - More TODOs. - Added Example8 to demonstrate construction of depth/ocean mask grid @@ -488,7 +737,7 @@ - Allow chunks option to be passed for grid and data sources. - openGrid now uses openDataset again -# 2021-06-09 +## 2021-06-09 - Implement saving of ocean and land masks using a specified `MASKING_DEPTH`. @@ -505,7 +754,7 @@ for at the moment. The first routines are writing a land and ocean mask file based on a supplied field. -# 2021-06-08 +## 2021-06-08 - Integration of bathymetric roughness to allow for internal tide parameterization to be used in a model run. @@ -536,7 +785,7 @@ - Add LICENSE.md similar to MOM6 - Noted quirk for xesmf -# 2021-06-03 +## 2021-06-03 - Release 0.1.1 - Installation and tutorial (PR#3) @@ -553,7 +802,7 @@ - Update tutorial links so they will work after publication to main branch - Update todos -# 2021-05-30 +## 2021-05-30 - Consolidate requirements lists again - github CI: use quiet mode for conda and pip to make output less verbose @@ -563,7 +812,7 @@ - libtiff is required by proj - Do not use python setup.py: this is a legacy installation method -# 2021-05-28 +## 2021-05-28 - The answer is use python -m pip; do not use python setup.py - Revamped requirements for possibly a two stage install for pip? @@ -574,7 +823,7 @@ - Add other dependencies: dask, colorcet and datashape - Add a hack for supporting differences in package requirements for pip vs. setup.py -# 2021-05-26 +## 2021-05-26 - Fix remote saving to correct directory as shown in the application - Improve gridtools metadata output; add hashes to certain variables @@ -588,13 +837,13 @@ - Begin construction of topoutils.py based on ocean_model_topog_generator - Begin construction of datasource.py that will manage data sources -# 2021-05-20 +## 2021-05-20 - Add netCDF4 to gridTools.yml base packages; xarray needs it to read netcdf version 4 files - Add a few informational links - Update to push exp/bathyV1 -# 2021-05-18 +## 2021-05-18 - Add info on running dask in a cluster environment - Delete duplicate conda/docs directory; not sure how that got there @@ -602,7 +851,7 @@ - Merge https://github.com/ESMG/gridtools/pull/1 - Finish out documentation updates for PR#1 -# 2021-05-17 +## 2021-05-17 - Merge updates (PR#2) - Add netcdf metadata: grid\*, conda\_env, package\_versions and software\_version. @@ -611,13 +860,13 @@ - Indicate some pitfalls in maintaining exported configurations for conda - Resync binder/environment.yml with conda/gridTools\_export.yml -# 2021-05-15 +## 2021-05-15 - Aggregate mybinder.org into its binder directory to further clean up the repository - Add numpypi to setup.py for automatic installation - Update binder to only install gridtools(+datashader+numpypi) -# 2021-05-14 +## 2021-05-14 - Delete conda/xesmfTest.yml; this used for testing a conda install environment for the reworked repo - Start on continuous integration (CI) and testing of repo code to help check for inadvertant bugs @@ -633,7 +882,7 @@ - Add gridtool module import tests - Add a couple more tests (incomplete) -# 2021-05-13 +## 2021-05-13 - Add datashader dependency to setup.py - Remove duplicate logging example @@ -648,7 +897,7 @@ - Fix mybinder.org detection in application - Fix mybinder.org installation paths -# 2021-05-11 +## 2021-05-11 - Finish out 0.1 milestones - Add more TODOs including reproducibility goals @@ -662,11 +911,11 @@ - Modify setuptools import to model that of the sphinx setup.py - Refactoring likely broke a lot of stuff...have to check -# 2021-05-10 +## 2021-05-10 - Establish 0.2 milestones -# 2021-05-06 +## 2021-05-06 - BUG(app): Stereographic grid generation does not work when dx/dy is not evenly divisible by grid resolution. TODO @@ -684,13 +933,13 @@ - app: erase debug cell at the bottom of mkGridInteractive.ipynb - publish to ESMG:dev branch and test mybinder.org -# 2021-05-05 +## 2021-05-05 - This day in history. SpaceX launches and lands starship prototype number 15. - Add wish list task for delta method import of boundary conditions and forcing fields. - Add/update documentation for the application. -# 2021-05-04 +## 2021-05-04 - Merge PR#1 into robTest - Provide user with more descriptive plotting failure whether it is due to a non-existent grid or really a plotting error. @@ -709,7 +958,7 @@ - Add a grid "Center" tab - Expand ranges of dx, dy, gridResolutionX and gridResolutionY to also support meters -# 2021-05-03 +## 2021-05-03 - WARNING: This commit leaves the Application broken (temporarily). - API CHANGES @@ -724,7 +973,7 @@ - Update app:make_plot for various projection inputs - Remove an unneeded string expansion for Mercator. -# 2021-05-02 +## 2021-05-02 - API CHANGES - Performing parameter checks upfront and converting some to float for use later. @@ -737,7 +986,7 @@ different options. - Adding code guards for MOM6 specific operations. -# 2021-05-01 +## 2021-05-01 - Move generic API demonstrations into mkGridsExample2.py so it does not detract from specific grid generation demonstrations @@ -753,7 +1002,7 @@ projection information. All details should be specifically documented. -# 2021-04-30 +## 2021-04-30 - API CHANGES - gridResolution is now units based instead of scale based as Niki defined it in his notebook example. @@ -776,7 +1025,7 @@ grid generator for units in meters. This routine will have to construct the proj string early. - Build out of Spherical grid generator begins (not complete) -# 2021-04-29 +## 2021-04-29 - Unify user manual. The user manual will hold the bulk of the operational details. Application details will be a small subset enough to explain the operational details of the graphical user interface. @@ -793,7 +1042,7 @@ - Change user specification of grid center to "centerX" and "centerY" and specify those units in "centerUnits". - BUG: Updating grid or plot parameter nested arguments will get clobbered. Queued to be fixed later. -# 2021-04-28 +## 2021-04-28 - Raphael pointed us code he wrote that allows conversion from XY to LATLON over a 2D field. It was exactly what we needed to get the IBCAO grid working in the polar projection. @@ -817,7 +1066,7 @@ - Added a plotting demo for illustrating unstructured grid interpolation and differences between using grid edges and grid center points for plotting. -# 2021-04-26 +## 2021-04-26 - Avoid use of xesmf 0.5.2 - split xesmfTools environment and move xgcm into its own environment @@ -833,7 +1082,7 @@ - Update message if regular lat lon grid is being built on the equator or not - Move plotBathyArctic6.py into pyroms directory -# 2021-04-22 +## 2021-04-22 - The supergrid plotting would fail if grid type was two(2) and resolution was 0.5. When multiplied together, it results in 1.0 which confused the current system. @@ -847,7 +1096,7 @@ - Separate refine inputs to grid functions that use gridResolution and gridMode - Update some messaging -# 2021-04-10 +## 2021-04-10 - Shore up messaging and debugging code in GridUtils(). A lot of missing level= in 2nd arguments calls to printMsg and debugMsg. @@ -862,7 +1111,7 @@ - lcc_grid.gpd almost replicates Niki's example grid; degress vs meters - Create a 3rd example that generates a 1x1 grid for testing -# 2021-04-09 +## 2021-04-09 - Fix warning in GridUtils.plotGrid() - Change warnings to logging.WARNING messages @@ -888,7 +1137,7 @@ - Use the setter functions in mkGridScripts and examples instead of setting the object variables directly. - TODO: consider moving important variables to private/hidden variables. -# 2021-04-08 +## 2021-04-08 - Experimentation with panel.pane.HTML did not work pan out. No great control over width and height. Text updates did not automatically resize the window. The TextAreaInput automatically adds a @@ -899,12 +1148,12 @@ - Testing of new printMsg facility is working. - Added a clear information button to clear the inforamtion window. -# 2021-04-07 +## 2021-04-07 - Move Spherical.py to spherical.py to match coding standards - Use R from GridUtils class in spherical -# 2021-04-03 +## 2021-04-03 - BUG: add ccrs.SouthPolarStereo() to projCarto - Remove plotExtentX0,X1 checks for lon>180 @@ -915,7 +1164,7 @@ - BUG(migration): Saving local files are fixed - BUG(migration): Call the showManual method with () -# 2021-04-02 +## 2021-04-02 - combined xgcmTools with xecmfTools configuration - added nbserverproxy to xecmfTools diff --git a/docs/development/DEPLOY.md b/docs/development/DEPLOY.md index cba0c41..3b0be61 100644 --- a/docs/development/DEPLOY.md +++ b/docs/development/DEPLOY.md @@ -30,7 +30,7 @@ and the DEPLOYMENT TEMPLATE header above. - [ ] Ensure `binder/environment.yml` is in sync with `conda/gridTools_export-linux-64.yml` - [ ] Ensure release/version is properly updated in `gridtools/__init__.py` - - [ ] Modify any test CI Github Actions + - [ ] Modify any test CI GitHub Actions - [ ] Update any tests performed by pytest - [ ] Update TODOs.md, archiving completed TODOs and milestones - [ ] Add contributors in their own section below for contributions via the pull request or related issues @@ -43,14 +43,18 @@ and the DEPLOYMENT TEMPLATE header above. - [ ] Merge "Release x.y.z" to main - [ ] Reverify mybinder.org operation - [ ] Ensure CI/Actions continue to pass (requires manual request) - - [ ] Ensure MDs on github renders correctly - - [ ] Add and commit a tag with x.y.z + - [ ] Check CI/Actions Artifacts for proper results + - [ ] Ensure MDs on GitHub renders correctly + - [ ] Add and commit a tag with x.y.z; add commit hash to archive/x.y.z.md - [ ] Ensure Read the Docs renders correctly for `stable` (triggered after new tag is pushed) - - [ ] Run through a Release on the github site + - [ ] Run through a Release on the GitHub site - [ ] Place a release notice on the MOM6 forum + # General Release Notes # Bug Fixes +# API Changes + # Contributors diff --git a/docs/development/ImportantReferences.md b/docs/development/ImportantReferences.md index a2222c6..b93372d 100644 --- a/docs/development/ImportantReferences.md +++ b/docs/development/ImportantReferences.md @@ -35,6 +35,7 @@ * https://github.com/pydata/xarray/issues/2899 * https://github.com/rabernat/intro_to_physical_oceanography * https://github.com/SciTools/cartopy/issues/787 + * https://gitlab.com/remikz/nccmp * https://guides.github.com/features/mastering-markdown/ * http://holoviews.org/user_guide/Dashboards.html * https://math.libretexts.org/Bookshelves/Calculus/Book%3A_Calculus_(OpenStax)/12%3A_Vectors_in_Space/12.7%3A_Cylindrical_and_Spherical_Coordinates#:~:text=In%20the%20Cartesian%20coordinate%20system%2C%20the%20location%20of%20a%20point,an%20angle%20measure%20(%CE%B8). @@ -42,8 +43,10 @@ * https://matplotlib.org/stable/gallery/images_contours_and_fields/image_masked.html * https://matplotlib.org/stable/gallery/images_contours_and_fields/pcolormesh_levels.html#sphx-glr-gallery-images-contours-and-fields-pcolormesh-levels-py * https://matplotlib.org/stable/gallery/images_contours_and_fields/pcolormesh_grids.html#sphx-glr-gallery-images-contours-and-fields-pcolormesh-grids-py - * https://matplotlib.org/stable/tutorials/colors/colormaps.html * https://matplotlib.org/stable/tutorials/colors/colorbar_only.html#sphx-glr-tutorials-colors-colorbar-only-py + * https://matplotlib.org/stable/tutorials/colors/colormaps.html + * https://matplotlib.org/stable/tutorials/colors/colormap-manipulation.html + * https://matplotlib.org/stable/tutorials/colors/colors.html * https://matplotlib.org/stable/users/event_handling.html * https://matplotlib.org/stable/users/interactive.html * https://matthewrocklin.com/blog/work/2017/07/03/scaling @@ -67,6 +70,7 @@ * https://scitools.org.uk/cartopy/docs/latest/index.html * https://scitools.org.uk/cartopy/docs/latest/crs/projections.html * https://scitools.org.uk/cartopy/docs/latest/gallery/effects_of_the_ellipse.html + * https://scitools.org.uk/cartopy/docs/latest/matplotlib/gridliner.html * https://softwareengineering.stackexchange.com/questions/329348/classes-vs-modules-in-python * https://www.sphinx-doc.org/en/master/latex.html#latexsphinxsetup * https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html @@ -82,6 +86,7 @@ * https://stackoverflow.com/questions/12575421/convert-a-1d-array-to-a-2d-array-in-numpy * https://stackoverflow.com/questions/13530489/adding-background-color-of-notes-to-sphinx-generated-pdf-files * https://stackoverflow.com/questions/15411967/how-can-i-check-if-code-is-executed-in-the-ipython-notebook + * https://stackoverflow.com/questions/18717877/prevent-plot-from-showing-in-jupyter-notebook * https://stackoverflow.com/questions/20180543/how-to-check-version-of-python-modules * https://stackoverflow.com/questions/20288711/post-install-script-with-python-setuptools * https://stackoverflow.com/questions/20961287/what-is-pylab diff --git a/docs/development/TODO.md b/docs/development/TODO.md index daed1df..876e844 100644 --- a/docs/development/TODO.md +++ b/docs/development/TODO.md @@ -2,22 +2,24 @@ ## Milestones - - [ ] Release 0.3.2 - - [ ] Add dataset subset/preparer function that will satisfy - FRE-NCtools `make_topog`. + - [ ] Release 0.3.x + - [ ] Release 0.x + - [ ] Additional metadata for tile variable: `standard_name`, `tile_spec_version`, + `geometry`, `discretization` and `conformal`. - [ ] Side by side comparison of bathymetric fields as generated by current set of tools and FRE-NCtools. - - [ ] Release 0.x - - [ ] Auto extending known grid types to allow flexible calculations. - - [ ] Fix GridUtils.regridTopo() halo effect on outer grid edge - - [ ] Improvements to roughness calculation. + - [ ] Add dataset subset/preparer function that will satisfy + FRE-NCtools `make_topog`. + - [ ] Improvements to roughness calculation - [ ] Finish port ROMS mask editor as-is to gridtools for MOM6/ROMS grids (pylab) - [ ] Rewrite/Optimize pylab mask editor - [ ] Application improvements - [ ] Boundery condition grid creation and support (OBCs) - [ ] Save only the points we need instead of the whole supergrid - [ ] Sponge data preparation - - [ ] Subset existing grids and infrastructure + - [ ] Subsetting + - [ ] Add more flexibility for handling model grids + - [ ] Boundary files - [ ] Leverage dask (for users that lack access to large memory nodes) - [ ] More graceful handling of periodic grid edges: +0,+360 vs -180,+180 - [ ] Enhanced grid/plot projection options (non-map based; @@ -25,11 +27,12 @@ - [ ] Enhanced plotting support - [ ] Allow export of MOM6 grid to ROMS - [ ] implement ROMS.extend_ROMS_grid() - - [ ] Grid filling options (flooding) (ice9) - [ ] Enable gridtools library to be installable via conda # BUGS + - [ ] gridtools applications do not start up properly when jupyter is + started with `--ip=0.0.0.0` - [ ] Investigate reliably of produced grids between platforms - [ ] A nested dictionary will clobber other nested elements instead of updating elements. Recode `setPlotParameters` and @@ -39,9 +42,18 @@ # TASKS + - [ ] Generic tool to subset a MOM6 grid for a given area for debugging. + - [X] Name this function subsetGrid(). + - [ ] Allow selection of offset, spacing and range. + - [ ] Show example of original roughness calculation + - [ ] grid extension and other operations for `GNOMONIC_ED` grid (FRE) + - [ ] gridutils.readGrid() ROMS grid; spurious breakpoint() removed; missing + condition in if statement + - [ ] Add tile metadata `geometry`; move global `grid_version` into tile + variable - [ ] Create our own conda repository since there is now a name conflict with at least PyPi. - - [ ] Sponge data preparation + - [ ] Boundary/sponge data preparation - [ ] Current scripts generate u,v fields on h-points; this needs to be changed to C-grid u/v-points instead - [ ] general documentation @@ -59,8 +71,6 @@ - [ ] having tilt may not produce conformal grids - [X] Niki''s example added; but it may not be correct - [ ] Niki might have solved lat lon tilt? - - [ ] make Stereographic grids - - [ ] user testing - [ ] grid generation in other projections (tri-polar, etc) - [ ] on saveGrid(): - [X] convert lon [+0,+360] to [-180,+180] @@ -79,7 +89,7 @@ - [ ] MOM6: Obey `MASKING_DEPTH`, `MINIMUM_DEPTH`, `ALLOW_LANDMASK_CHANGES`, `MAXIMUM_DEPTH`, `TOPO_EDITS_FILE` MOM6/src/initialization parameters - [ ] show outline of full grid - - [ ] Example 09a has a wierd artifact showing grid boundary + - [ ] Example 09a has a weird artifact showing grid boundary - [ ] show other underlying fields - topo? - [ ] ROMS: write edited mask - [X] MOM6: write edited mask @@ -94,10 +104,10 @@ - [ ] MOM6: write edited mask - [X] ROMS: write edited mask - [ ] integration of data sources + - [ ] Using xesmf regridder and other tools to create bathymetry and + other forcing and boundary files - [ ] generic regridder for creating boundary files (OBCs) from data sources - [ ] xesmf regridder for bathymetry sources - - [X] option to create ocean mask fraction - - [ ] investigate artifact generated in the grid corners - [ ] option to use source grid as a supergrid for coarsening - [ ] refactor function arguments into kwargs - [ ] refactor print statements to use gridtools logging facility @@ -127,14 +137,22 @@ - [ ] update any tool metadata that is appropriate for that grid - [ ] parse and utilize any available proj string; must be a global or variable attribute - - [ ] Using xesmf regridder and other tools to create bathymetry and - other forcing and boundary files - - [ ] Develop a field "flood" routine similar to pyroms - [ ] Perform checks for ensureEvenI and ensureEvenJ everywhere. This applies only to the grid not the supergrid. # TODO + - [ ] Improve gridutils.getXYDist() to maybe look at other + derivatives to improve accuracy of appending points along + a non-regularly spaced line. + - [X] Incorporate grid extension (extending) code + - [X] initial automatic grid detection code + - [X] spherical coords + - [ ] test northern hemispheric grids + - [ ] test southern hemispheric grids + - [ ] test grids that overlap the equator + - [X] lat/lon coord + - [X] clip grid to specified size - [ ] Update operational paths graphic - [ ] Interoperability with FRE-NCtools - [ ] Generic plotting of figures @@ -165,11 +183,12 @@ - [X] Create a message buffer/system for information. - [ ] Create a way to monitor a log file; https://discourse.holoviz.org/t/scrollable-log-text-viewer/317 - - [ ] log/display github revision of gridtools used by mybinder.org instances + - [ ] log/display github revision of gridtools used by mybinder.org instances/application - [ ] For now, the gridParameters are always in reference to a center point in a grid in the future, one may fix a side or point of the grid and grow out from that point instead of the center. - [ ] Grid generation application + - [ ] add option to turn on/off gridline labels - [ ] enable user configurable plot and widget sizes (hardcoded in __init__) - [ ] enable user to change ellipsoid, R, `x_0` and `y_0` grid and plot parameters @@ -184,7 +203,6 @@ - [ ] Develop additional GridUtils() functions - [ ] Run `proj -le` and return the names or display the details - [ ] Populates the ellps field for the application - - [ ] Detect grid types and auto extend grids to deal with data artifacts - [ ] Create routine to handle periodic conditions; automatically extend needed points to cover zero degree and dateline issues. - [ ] Deploy use of self.gridMade (robTest:PR#1) @@ -195,6 +213,8 @@ - [ ] a test fails in `test_trunc.py` - [ ] CI/Actions test harnesses - [ ] pytest: Setup some simple projection tests: IBCAO, .... + - [ ] pytest: Test other spherical grids not centered over the pole; + add graphics to artifacts for viewing. - [ ] pytest: Refactor numpypi into structured tests under pytest - [ ] pytest: allow certain tests to fail if a module is not available (issue warnings instead) @@ -202,6 +222,11 @@ # WISH + - [ ] Show difference fields for python script examples 3 and 8. + - [ ] Add more features to the ice-9 algorithm + - [ ] zEdits + - [ ] Multiple seed points + - [ ] Periodic grid support - [ ] Update gridTools.yml with some pinned versions to help package resolution - [ ] Write example program(s) - [ ] Example 04 : DASK: mkGridsEample4a.ipynb is incomplete diff --git a/docs/development/archive/0.3.1.md b/docs/development/archive/0.3.1.md index 1d34434..8a1c0e6 100644 --- a/docs/development/archive/0.3.1.md +++ b/docs/development/archive/0.3.1.md @@ -1,7 +1,7 @@ # Retired TODO and Milestones ## Release 0.3.1 - * https://github.com/ESMG/gridtools/commit/... + * https://github.com/ESMG/gridtools/commit/194d7b2e73e9365799a25977de6e84f5aaeae20c * August 12, 2021 ### Milestones diff --git a/docs/development/archive/0.3.2.md b/docs/development/archive/0.3.2.md new file mode 100644 index 0000000..3c29574 --- /dev/null +++ b/docs/development/archive/0.3.2.md @@ -0,0 +1,34 @@ +# Retired TODO and Milestones + +## Release 0.3.2 + * https://github.com/ESMG/gridtools/commit/... + * November 16, 2021 + +### Milestones + + - [X] Update meshutils.writeLandMask() and meshutils.writeOceanMask() to search for x and y + coordinates if not provided by the supplied variable. + - [X] GridUtils.plotGrid() allow plotting of one or more grid points. + - [X] Grid filling options (flooding; ice-9 algorithm) + - [X] Plotting model grid: include option to show grid points on the grid. + - [X] Fix GridUtils.regridTopo() halo effect on outer grid edge + - [X] option to create ocean mask fraction + - [X] investigate artifact generated in the grid corners; fix by extending grid and clipping result + - [X] Implemented metadata functions: gridutils.updateGridMetadata(); gridutils.checkGridMetadata() + - [X] Add or append to 'history' global variable. + - [X] Auto extending known grid types to allow workarounds for calculations + with artifacts around the edges. + - [X] Add reference for Niki's `ocean_model_grid_generator`! + - [X] Core model grid generic subsetting is available via gridutils.subsetGrid(); does not subset + boundary conditions + +### TODOs + + - [X] able to make and create stereographic grids + - [X] Develop a field "flood" routine similar to pyroms; ported ice9 routine + +### BUGS + + - [X] BUG: Fix example7 scripts so they can run independently of each other as examples. + - [X] BUG: `gridtools.generate_regional_spherical_meters` fix spherical grid generation. Resolves #16 + - [X] BUG: app: adjust grid center latitude bounds to -90 to +90. Resolves #16. diff --git a/docs/development/netCDF.md b/docs/development/netCDF.md new file mode 100644 index 0000000..65235a4 --- /dev/null +++ b/docs/development/netCDF.md @@ -0,0 +1,9 @@ +# netCDF + +The netCDF kitchen sink tools append to the global history element by +separating the inserted strings by a linefeed (`\n`). + +For example: +``` +:history = "Sat Nov 6 15:45:29 2021: ncrename -v xx,x land_mask_Example3.nc\nSat Nov 6 15:45:11 2021: ncrename -v x,xx land_mask_Example3.nc" ; +``` diff --git a/docs/development/releases/0.3.2.md b/docs/development/releases/0.3.2.md new file mode 100644 index 0000000..946f37e --- /dev/null +++ b/docs/development/releases/0.3.2.md @@ -0,0 +1,70 @@ +# Release 0.3.2 + +## Previous Release + +Tag: 0.3.1 `194d7b2e73e9365799a25977de6e84f5aaeae20c` + +# Checklist + + - [X] Operating system checks + - [X] `x86_64`: Ubuntu 20.04.2 LTS (64 GB) + - [ ] `x86_64`: Ubuntu 20.04.2 LTS (12 GB VM) **Skipped** + - [X] `aarch64`: Raspberry Pi 4 (8 GB) + - [ ] `x86_64`: triton node (64 GB) **Cluster offline** + - [X] `x86_64`: chinook node (128 GB) + - [X] Verify operation of example notebooks + - [X] Verify operation of example scripts + - [X] Resync environments + - [X] Pip requirements.txt should closely mirror gridTools.yml + - [X] Update any special needs in requirements.txt + - [X] Resync `gridTools_export-linux-64.yml` without pip modules + - [X] Resync `gridTools_export-linux-64-RTD.yml` without nodejs and pip modules + - [X] Ensure `binder/environment.yml` is in sync + with `conda/gridTools_export-linux-64.yml` + - [X] Ensure release/version is properly updated in `gridtools/__init__.py` + - [X] Modify any test CI GitHub Actions + - [X] Update any tests performed by pytest + - [X] Update TODOs.md, archiving completed TODOs and milestones + - [X] Add contributors in their own section below for contributions via the pull request or related issues + - [X] After submission of PR to main + - [X] Review commit as necessary + - [X] Verify CI/Actions pass + - [X] Verify Read the Docs render correctly + - [X] Verify mybinder.org is functional + - [X] Review, update and/or close any issues + - [X] Merge "Release 0.3.2" to main + - [X] Reverify mybinder.org operation + - [X] Ensure CI/Actions continue to pass (requires manual request) + - [X] Check CI/Actions Artifacts for proper results + - [X] Ensure MDs on GitHub renders correctly + - [X] Add and commit a tag with 0.3.2; add commit hash to archive/0.3.2.md + - [X] Ensure Read the Docs renders correctly for `stable` (triggered after new tag is pushed) + - [X] Run through a Release on the GitHub site + - [X] Place a release notice on the MOM6 forum + +# General Release Notes + + - This release resolves issues #15 and #16 with fixes to spherical grid support and + the ability to extend a model grid for use in routines that generate artifacts on + the boundaries. + - ReadtheDocs resources were moved around such that the conda environment is a + small subset of packages to get around a memory issue. The remaining resources + are loaded via pip. + +# Bug Fixes + + - Fix example7 scripts so they can run independently of each other as examples. + - `gridtools.generate_regional_spherical_meters` fix spherical grid generation. Resolves #16 + - app: adjust grid center latitude bounds to -90 to +90. Resolves #16. + +# API Changes + + - For some examples, the **i** verticies are now shown in yellow to show orientation of the grid and + to make sure the grid orientation is correct as requested. + - Updates to computeBathymeticRoughness() + - Option FixByOverlapQHGridShift replaced with two boolean arguments: useQHGridShift, useOverlap + +# Contributors + + - Jessica Garwood, Kate Hedstrom: debugging and confirmation of problems generating MOM6 exchange + grids using xarray or gridtools. diff --git a/docs/grids/Examples.md b/docs/grids/Examples.md index c5d7341..f3ebb94 100644 --- a/docs/grids/Examples.md +++ b/docs/grids/Examples.md @@ -3,6 +3,11 @@ Grid examples have been provided to demonstrate the utility of the grid generation software. +The python gridtools library uses a default radius of GRS80 +or 6.378137e6 meters. The ROMS grids are based on a radius +of 6370.e3 meters if passed through the pyroms conversion +script. + # Lambert Conformal Conic ## NEP7 @@ -17,6 +22,8 @@ The LCC attributes are: Central latitude: unknown (seems ok for plotting) Corner points: (-130,0N) (-220,70N) +PROJ: `+proj=lcc +lat_1=40.0 +lat_2=60.0 +lon_0=-91.0` + ## Pacific The code creates a grid in spherical coordinates. It appears the final @@ -34,9 +41,11 @@ This grid description was provided by Kate Hedstrom. This grid is in the North Polar Stereo projection. This grid has a central longitude of 160.0 West. -The true scale latitude is unknown. Kate thinks it might be 90N? +The true scale latitude is unknown. Kate thinks it might be 90N? Having true scale latitude unset for plotting seems to work. +PROJ: `+proj=stere +lat_0=90 +lon_0=-160.0 +R=6370000` + ## IBCAO IBCAO is a North Polar Stero projection grid. The @@ -45,7 +54,7 @@ describes the grid in full detail. See page 9 for grid format. A Polarstereographic projection with the true scale at 75 °N is “preserved” in the Cartesian grid. The horizontal -datum is World Geodetic System (WGS 84). +datum is World Geodetic System (WGS84). The center of the grid is the North Pole. @@ -58,3 +67,5 @@ Grid corners: -2902500 -2902500 -45.0 +53:49:1.4687 +2902500 -2902500 +45.0 +53:49:1.4687 ``` + +PROJ: `+proj=stere +lat_0=90 +lat_ts=75.0 +lon_0=0.0 +ellps=WGS84` diff --git a/docs/grids/MOM6.md b/docs/grids/MOM6.md index 84dd7b9..67cbfcb 100644 --- a/docs/grids/MOM6.md +++ b/docs/grids/MOM6.md @@ -60,3 +60,11 @@ variables and dimensions: * Dimensions * nx, ny : grid centers * nxp, nxp : grid verticies + +### Nomenclature + + * The supergrid is twice the horizonal resolution. + * The supergrid contains all the staggered points, but the model only + solves equations for the actual grid. + * When talking about the resolution of a MOM6 grid, the convention is + to talk about the resolution of the grid not the supergrid. diff --git a/examples/README.md b/examples/README.md index c3cd9c5..fcb7e11 100644 --- a/examples/README.md +++ b/examples/README.md @@ -51,12 +51,6 @@ This script demonstrates some of the logging and debugging methods integrated into the gridtools library. -## mkGridsShowLoggers.py - -This scripts demonstrates how to access logging -from other python modules should it become -necessary for debugging problems. - ## mkGridsExample03.py This example generates a Mercator grid off @@ -65,6 +59,10 @@ grid is constructed in FRE-NCtools, in example [03FRE](mkGridsExample03FRE.py), for comparison. +This also demonstrates the use of an extended +grid to overcome the outer boundary artifacts +generated by the regridTopo() routine. + Please see the [API](https://mom6gridtools.readthedocs.io/en/latest/guides/index.html) manual for a guide @@ -216,6 +214,24 @@ script copy and pasted to start the editor. Once editing is complete, there are more commands required to save the edited grid. +## mkGridsExample11.ipynb + +NOTE: INCOMPLETE EXAMPLE + +This example might be replaced by example 12. + +## mkGridsExample12.ipynb + +This shows the grid extension capabilities for various grid +projections. It shows how model grid can be grown in any +direction. + +## mkGridsShowLoggers.py + +This scripts demonstrates how to access logging +from other python modules should it become +necessary for debugging problems. + ## NewGridMOM6.ipynb This is all the code from a fully written tutorial about diff --git a/examples/mkGridIterative.ipynb b/examples/mkGridIterative.ipynb index e4b304d..6f0d679 100644 --- a/examples/mkGridIterative.ipynb +++ b/examples/mkGridIterative.ipynb @@ -199,7 +199,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': \"Nearside Perspective: 20x30 with 30 degree tilt\",\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")\n", @@ -227,7 +227,13 @@ "# Axes object - you can further fine tune plot parameters, \n", "# titles, axis, etc prior to the final plotting of the figure.\n", "# Some items may be configured via the figure object.\n", - "(figure, axes) = grd.plotGrid()" + "# Additional parameters can be passed to plotGrid()\n", + "# showGridPoints = [] tuples of (j,i) to show grid points on the\n", + "# plotted grid. The tuple may include color, (j,i,'b') and point\n", + "# size (j,i,'b',20.0). The default point size is 5.0.\n", + "# NOTE: The points refer to the supergrid. To line up with the regular\n", + "# grid, the points have to be multiples of two.\n", + "(figure, axes) = grd.plotGrid(showGridPoints=[(0,0),(10,0,'g'),(0,10,'b',20.0)])" ] }, { @@ -275,7 +281,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': \"Mercator: 20x30 with 30 degree tilt\",\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -323,7 +329,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': 'Lambert Conformal Conic: 20x30 with 30 degree tilt',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -439,7 +445,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': 'North Polar Stereo: 120x120',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -485,7 +491,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': \"Nearside Perspective: 60x60\",\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -517,11 +523,120 @@ "metadata": {}, "source": [ "## Meters\n", - "This grid is generated using grid distances specified in meters. Grid tilt is not a valid option.However, grid rotation may be achieved using the lon_0 projection parameter.\n", + "This grid is generated using grid distances specified in meters. Grid tilt is not a valid option. However, grid rotation may be achieved using the lon_0 projection parameter.\n", "\n", - "The example notebook, mkGridsExample4.ipynb, demonstrates how a spherical grid can be created outside\n", - "the grid generation library and plotted. The notebook also shows how to obtain the same grid using\n", - "the library." + "The example notebook, mkGridsExample04.ipynb, demonstrates how a spherical grid can be created outside the grid generation library and plotted. The notebook also shows how to obtain the same grid using the library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "443652e2-a566-473e-852d-baf1a937260f", + "metadata": {}, + "outputs": [], + "source": [ + "# South Polar Stereo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f048413e-3f48-43c5-bd01-5ecaf8d56ef2", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3d70563-b681-42f8-a9fa-3fcaec42409f", + "metadata": {}, + "outputs": [], + "source": [ + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': \"Stereographic\",\n", + " 'ellps': 'WGS84',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'lat_ts': -60.0,\n", + " },\n", + " 'centerX': 90.0,\n", + " 'centerY': -60.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 300000.0,\n", + " 'dy': 200000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dyUnits': 'meters',\n", + " 'gridResolution': 4000.0,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True\n", + "})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b579275-fe74-4321-8a57-9f7a0dfc9881", + "metadata": {}, + "outputs": [], + "source": [ + "grd.makeGrid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c225d0e0-1553-407d-a01b-9f1e760ece82", + "metadata": {}, + "outputs": [], + "source": [ + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (12,12),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'ellps': 'WGS84',\n", + " 'lon_0': -90.0,\n", + " 'lat_0': -90.0,\n", + " 'lat_ts': -60.0,\n", + " },\n", + " 'extent': [80, 100, -68, -58],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Stereographic: Southern Hemisphere\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d52a009-c043-4192-844f-62ee187507df", + "metadata": {}, + "outputs": [], + "source": [ + "(figure, axes) = grd.plotGrid()\n", + "axes.gridlines(draw_labels=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d5d65e7-6d97-426d-bd9d-2aa86a756824", + "metadata": {}, + "outputs": [], + "source": [ + "figure" ] }, { @@ -617,7 +732,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': \"Mercator projection: 20x30 with 30 degree tilt\",\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -664,7 +779,7 @@ " 'jLinewidth': 1.0,\n", " 'showGridCells': True,\n", " 'title': \"Nearside Perspective: 20x30 with 30 degree tilt\",\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -740,7 +855,7 @@ " 'jLinewidth': 1.0,\n", " 'showGrid': True,\n", " 'title': 'North Polar Stereo: Arctic6',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -796,7 +911,7 @@ " 'jLinewidth': 1.0,\n", " 'showGrid': True,\n", " 'title': 'Lambert Conformal Conic: NEP7',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" diff --git a/examples/mkGridsExample03.py b/examples/mkGridsExample03.py index 62f2327..ca6eb06 100644 --- a/examples/mkGridsExample03.py +++ b/examples/mkGridsExample03.py @@ -7,6 +7,9 @@ # grid should be comparable to a similar # grid created by FRE-NCtools. +# NOTE: This script takes a VERY long time +# to run. + import sys, os, logging, cartopy import xarray as xr from gridtools.gridutils import GridUtils @@ -191,7 +194,7 @@ # Data sources cannot be in chunked mode for use in this routine bathyGrids = grd.computeBathymetricRoughness('ds:GEBCO_2020', maxMb=99, superGrid=False, useClipping=False, - FixByOverlapQHGridShift=True, + useQHGridShift=True, useOverlap=True, auxVariables=['hStd', 'hMin', 'hMax', 'depth'], ) @@ -221,7 +224,7 @@ plotVariables={ 'depth': { 'values': bathyGrids['depth'], - 'title': 'GEBCO 2020 applied with computeBathyRoughness()', + 'title': 'GEBCO 2020: computeBathyRoughness()', 'cbar_kwargs': { 'orientation': 'horizontal', } @@ -246,7 +249,7 @@ plotVariables={ 'depth': { 'values': resultGrids['depth'], - 'title': 'GEBCO 2020 applied with GridUtils.regridTopo()', + 'title': 'GEBCO 2020: GridUtils.regridTopo()', 'cbar_kwargs': { 'orientation': 'horizontal', } @@ -257,3 +260,43 @@ figure.savefig(os.path.join(wrkDir, 'MERC_20x30_Bathy_Example3_regridTopo.png'), dpi=None, facecolor='w', edgecolor='w', orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) + +# The original routine leaves an artifact around the grid edge. This can +# be fixed by extending the grid by one grid point, recomputing and +# then clipping the extended result. + +extGrd = grd.extendGrid(2, 2, 2, 2) + +# Put the extended grid into a gridtools grid. Attach it to +# the same data source as above. +grd2 = GridUtils() +grd2.useDataSource(ds) +grd2.readGrid(local=extGrd) + +resultGridsExt = grd2.regridTopo('ds:GEBCO_2020', topoVarName='depth', periodic=False) + +# Subset the result grid back to the original grid +resultGrids2 = xr.Dataset() +resultGrids2['depth'] = resultGridsExt['depth'][1:-1,1:-1] +resultGrids2['ocean_mask'] = resultGridsExt['ocean_mask'][1:-1,1:-1] + +resultGrids2.to_netcdf(os.path.join(wrkDir, 'ocean_topog_Example3_regridTopo_ext.nc'), + encoding=grd2.removeFillValueAttributes(data=resultGrids2)) + +# Plot the new bathy grid +(figure, axes) = grd.plotGrid( + showModelGrid=False, + plotVariables={ + 'depth': { + 'values': resultGrids2['depth'], + 'title': 'GEBCO 2020: GridUtils.regridTopo() with an extended grid', + 'cbar_kwargs': { + 'orientation': 'horizontal', + } + } + }, +) + +figure.savefig(os.path.join(wrkDir, 'MERC_20x30_Bathy_Example3_regridTopo_ext.png'), + dpi=None, facecolor='w', edgecolor='w', + orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) diff --git a/examples/mkGridsExample04.ipynb b/examples/mkGridsExample04.ipynb index 20468e1..f367fc8 100644 --- a/examples/mkGridsExample04.ipynb +++ b/examples/mkGridsExample04.ipynb @@ -96,7 +96,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Create cartesian grid (y, x)\n", + "# Create cartesian grid (x, y)\n", "# Confirm grid points and x, y coordinates" ] }, @@ -107,7 +107,7 @@ "metadata": {}, "outputs": [], "source": [ - "yy, xx = np.meshgrid(y, x)" + "xx, yy = np.meshgrid(x, y)" ] }, { @@ -131,7 +131,7 @@ "proj = Transformer.from_crs(crs.geodetic_crs, crs)\n", "\n", "# compute the lon/lat\n", - "lon, lat = proj.transform(yy, xx, direction='INVERSE')" + "lon, lat = proj.transform(xx, yy, direction='INVERSE')" ] }, { @@ -142,6 +142,10 @@ "outputs": [], "source": [ "# Confirm we have the correct grid points and lat lon values\n", + "# Expected answers:\n", + "# -2902500.0 -2902500.0 53.8170746379705 -45.0\n", + "# 2902500.0 2902500.0 53.8170746379705 135.0\n", + "# REF: https://www.ngdc.noaa.gov/mgg/bathymetry/arctic/IBCAO_TechnicalReference.PDF\n", "print(yy[0,0], xx[0,0], lat[0,0], lon[0,0])\n", "print(yy[y.shape[0]-1, x.shape[0]-1], xx[y.shape[0]-1, x.shape[0]-1], lat[y.shape[0]-1, x.shape[0]-1], lon[y.shape[0]-1, x.shape[0]-1])" ] @@ -242,7 +246,7 @@ " 'jLinewidth': 1,\n", " 'showGrid': True,\n", " 'title': 'Stereographic: IBCAO',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -391,7 +395,7 @@ " 'jLinewidth': 1,\n", " 'showGrid': True,\n", " 'title': 'Stereographic: IBCAO',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" diff --git a/examples/mkGridsExample04a.ipynb b/examples/mkGridsExample04a.ipynb index a124bc5..17f8b2b 100644 --- a/examples/mkGridsExample04a.ipynb +++ b/examples/mkGridsExample04a.ipynb @@ -112,7 +112,7 @@ "metadata": {}, "outputs": [], "source": [ - "yy, xx = da.meshgrid(y, x)" + "xx, yy = da.meshgrid(x, y)" ] }, { @@ -140,9 +140,9 @@ "#lon, lat = proj.transform(yy, xx, direction='INVERSE')\n", "\n", "# DASK\n", - "def gufoo(yy, xx):\n", - " return proj.transform(yy, xx, direction='INVERSE')\n", - "lon, lat = da.apply_gufunc(gufoo, \"(i),(j)->(i),(j)\", yy, xx, vectorize=True, allow_rechunk=True)" + "def gufoo(xx, yy):\n", + " return proj.transform(xx, yy, direction='INVERSE')\n", + "lon, lat = da.apply_gufunc(gufoo, \"(j),(i)->(j),(i)\", xx, yy, vectorize=True, allow_rechunk=True)" ] }, { @@ -153,6 +153,10 @@ "outputs": [], "source": [ "# Confirm we have the correct grid points and lat lon values\n", + "# Expected answers:\n", + "# -2902500.0 -2902500.0 53.8170746379705 -45.0\n", + "# 2902500.0 2902500.0 53.8170746379705 135.0\n", + "# REF: https://www.ngdc.noaa.gov/mgg/bathymetry/arctic/IBCAO_TechnicalReference.PDF\n", "print(float(yy[0,0]), float(xx[0,0]), float(lat[0,0]), float(lon[0,0]))\n", "print(float(yy[y.shape[0]-1, x.shape[0]-1]), float(xx[y.shape[0]-1, x.shape[0]-1]), float(lat[y.shape[0]-1, x.shape[0]-1]), float(lon[y.shape[0]-1, x.shape[0]-1]))" ] @@ -164,7 +168,8 @@ "metadata": {}, "outputs": [], "source": [ - "from gridtools.gridutils import GridUtils" + "from gridtools.gridutils import GridUtils\n", + "%matplotlib inline" ] }, { @@ -242,7 +247,7 @@ " 'jLinewidth': 1,\n", " 'showGrid': True,\n", " 'title': 'Stereographic: IBCAO',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -276,7 +281,7 @@ "outputs": [], "source": [ "# Compute grid metrics\n", - "grd.computeGridMetrics()" + "grd.computeGridMetricsSpherical()" ] }, { @@ -390,7 +395,7 @@ " 'jLinewidth': 1,\n", " 'showGrid': True,\n", " 'title': 'Stereographic: IBCAO',\n", - " 'iColor': 'k',\n", + " 'iColor': 'y',\n", " 'jColor': 'k'\n", " }\n", ")" @@ -415,6 +420,14 @@ "source": [ "figure" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7a8a96b-5a4e-493c-b1d8-6296ff72910c", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/examples/mkGridsExample05.py b/examples/mkGridsExample05.py index f0cfa27..6e940f0 100644 --- a/examples/mkGridsExample05.py +++ b/examples/mkGridsExample05.py @@ -18,7 +18,7 @@ x = np.arange(-2902500., 2902500. + dx, dx, dtype=np.float32) y = np.arange(-2902500., 2902500. + dy, dy, dtype=np.float32) -yy, xx = np.meshgrid(y, x) +xx, yy = np.meshgrid(x, y) from pyproj import CRS, Transformer @@ -30,9 +30,14 @@ proj = Transformer.from_crs(crs.geodetic_crs, crs) # compute the lon/lat -lon, lat = proj.transform(yy, xx, direction='INVERSE') +lon, lat = proj.transform(xx, yy, direction='INVERSE') # Confirm we have the correct grid points and lat lon values +print(''' +Expected answers: +-2902500.0 -2902500.0 53.8170746379705 -45.0 +2902500.0 2902500.0 53.8170746379705 135.0 +---''') print(yy[0,0], xx[0,0], lat[0,0], lon[0,0]) print(yy[y.shape[0]-1, x.shape[0]-1], xx[y.shape[0]-1, x.shape[0]-1],\ lat[y.shape[0]-1, x.shape[0]-1], lon[y.shape[0]-1, x.shape[0]-1]) @@ -85,7 +90,7 @@ 'jLinewidth': 1.0, 'showGrid': True, 'title': 'Stereographic: IBCAO', - 'iColor': 'k', + 'iColor': 'y', 'jColor': 'k' } ) diff --git a/examples/mkGridsExample05a.py b/examples/mkGridsExample05a.py index 3e3674f..a58be81 100644 --- a/examples/mkGridsExample05a.py +++ b/examples/mkGridsExample05a.py @@ -21,7 +21,7 @@ x = np.arange(-2902500., 2902500. + dx, dx, dtype=np.float32) y = np.arange(-2902500., 2902500. + dy, dy, dtype=np.float32) -yy, xx = np.meshgrid(y, x) +xx, yy = np.meshgrid(x, y) # From the command line we can convert single points # gdaltransform -s_srs "+proj=stere +lat_0=90 +lat_ts=75" -t_srs EPSG:4326 @@ -37,9 +37,14 @@ proj = Transformer.from_crs(crs.geodetic_crs, crs) # compute the lon/lat -lon, lat = proj.transform(yy, xx, direction='INVERSE') +lon, lat = proj.transform(xx, yy, direction='INVERSE') # Confirm we have the correct grid points and lat lon values +print(''' +Expected answers: +-2902500.0 -2902500.0 53.746468618592075 -45.0 +2902500.0 2902500.0 53.746468618592075 135.0 +---''') print(yy[0,0], xx[0,0], lat[0,0], lon[0,0]) print(yy[y.shape[0]-1, x.shape[0]-1], xx[y.shape[0]-1, x.shape[0]-1], lat[y.shape[0]-1, x.shape[0]-1], lon[y.shape[0]-1, x.shape[0]-1]) @@ -91,7 +96,7 @@ 'jLinewidth': 1.0, 'showGrid': True, 'title': 'Stereographic: IBCAO', - 'iColor': 'k', + 'iColor': 'y', 'jColor': 'k' } ) diff --git a/examples/mkGridsExample06.py b/examples/mkGridsExample06.py index 47501e5..99a993f 100644 --- a/examples/mkGridsExample06.py +++ b/examples/mkGridsExample06.py @@ -59,7 +59,7 @@ 'showGrid': False, 'showGridCells': True, 'title': 'Stereographic: mini IBCAO', - 'iColor': 'k', + 'iColor': 'y', 'jColor': 'k' } ) diff --git a/examples/mkGridsExample07.py b/examples/mkGridsExample07.py index 564938e..7008801 100644 --- a/examples/mkGridsExample07.py +++ b/examples/mkGridsExample07.py @@ -18,7 +18,7 @@ # We can turn on extra output from the module grd.printMsg("Setting print and logging messages to the DEBUG level.") -logFilename = os.path.join(wrkDir, 'LCC_20x30.log') +logFilename = os.path.join(wrkDir, 'LCC_20x30_7.log') grd.setVerboseLevel(logging.DEBUG) grd.setDebugLevel(0) grd.setLogLevel(logging.DEBUG) @@ -103,12 +103,13 @@ # it. If you want to test the routine again, erase the output # file. if os.path.isfile(bathyGridFilename): + grd.printMsg("Using existing bathymetry file: %s" % (bathyGridFilename)) bathyGrids = xr.open_dataset(bathyGridFilename) else: # Data sources cannot be in chunked mode for use in this routine bathyGrids = grd.computeBathymetricRoughness('ds:GEBCO_2020', maxMb=99, superGrid=False, useClipping=False, - FixByOverlapQHGridShift=True, + useQHGridShift=True, useOverlap=True, auxVariables=['hStd', 'hMin', 'hMax', 'depth'], ) @@ -148,7 +149,7 @@ inputDirectory=inputDir, overwrite=True, ) -grd.saveGrid(filename=os.path.join(inputDir, "ocean_hgrid.nc")) +grd.saveGrid(filename=os.path.join(inputDir, "ocean_hgrid_7.nc")) # Do some plotting! @@ -187,8 +188,9 @@ } }, ) -figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OrigBathy.png'), dpi=None, facecolor='w', edgecolor='w', - orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) +figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OrigBathy_7.png'), dpi=None, + facecolor='w', edgecolor='w', orientation='landscape', + transparent=False, bbox_inches=None, pad_inches=0.1) # Plot depth grid after we apply an existing landmask with minimum # depth set to 1000 meters @@ -204,7 +206,7 @@ } }, ) -figure.savefig(os.path.join(wrkDir, 'LCC_20x30_MinBathy.png'), dpi=None, facecolor='w', edgecolor='w', +figure.savefig(os.path.join(wrkDir, 'LCC_20x30_MinBathy_7.png'), dpi=None, facecolor='w', edgecolor='w', orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) # Plot original gebco just using the grid extent, not the model grid points diff --git a/examples/mkGridsExample07a.ipynb b/examples/mkGridsExample07a.ipynb index 269b9e1..dc93dad 100644 --- a/examples/mkGridsExample07a.ipynb +++ b/examples/mkGridsExample07a.ipynb @@ -81,7 +81,7 @@ "source": [ "# We can turn on extra output from the module\n", "grd.printMsg(\"Setting print and logging messages to the DEBUG level.\")\n", - "logFilename = os.path.join(wrkDir, 'LCC_20x30.log')\n", + "logFilename = os.path.join(wrkDir, 'LCC_20x30_7a.log')\n", "grd.setVerboseLevel(logging.DEBUG)\n", "grd.setDebugLevel(0)\n", "grd.setLogLevel(logging.DEBUG)\n", @@ -201,21 +201,32 @@ "# We do not need to compute bathymetric roughness if we have an existing file\n", "# Increase the memory footprint (maxMb) to allow more mesh refinements to\n", "# be used from the topography.\n", - "bathyGridFilename = os.path.join(wrkDir, 'ocean_topog_Example7.nc')\n", + "bathyGridFilename = os.path.join(wrkDir, 'ocean_topog_Example7a.nc')\n", "\n", "if os.path.isfile(bathyGridFilename):\n", + " grd.printMsg(\"Using existing bathymetry file: %s\" % (bathyGridFilename))\n", " bathyGrids = xr.open_dataset(bathyGridFilename)\n", "else:\n", - " # Data sources cannot be in chunked mode for use in this routine\n", + " # This routine cannont use data sources that are in chunked mode (dask)\n", " bathyGrids = grd.computeBathymetricRoughness('ds:GEBCO_2020',\n", " maxMb=99, superGrid=False, useClipping=False,\n", - " FixByOverlapQHGridShift=True,\n", + " useQHGridShift=True, useOverlap=True,\n", " auxVariables=['hStd', 'hMin', 'hMax', 'depth'],\n", " )\n", "\n", " # This is needed to really convert the elevation field to depth\n", " # The 'depth' field has to be requested as an auxVariables\n", " grd.applyEvalMap('ds:GEBCO_2020', bathyGrids)\n", + "\n", + " # Write ocean_mask and land_mask based on existing field with\n", + " # a standard MASKING_DEPTH of 0.0 meters. The next part of this\n", + " # example will set a MINIMUM_DEPTH of 1000.0 meters for comparison.\n", + " grd.writeOceanmask(bathyGrids, 'depth', 'mask',\n", + " os.path.join(wrkDir, 'ocean_mask_Example7a.nc'),\n", + " MASKING_DEPTH=0.0)\n", + " grd.writeLandmask(bathyGrids, 'depth', 'mask',\n", + " os.path.join(wrkDir, 'land_mask_Example7a.nc'),\n", + " MASKING_DEPTH=0.0) \n", " \n", " # Apply existing land mask which should not change anything\n", " # The minimum depth will modify a couple points. We save the\n", @@ -228,14 +239,14 @@ " # * Any ocean points that become land will have a depth of 0.0 meters\n", " \n", " bathyGrids['newDepth'] = grd.applyExistingLandmask(bathyGrids, 'depth',\n", - " os.path.join(wrkDir, 'land_mask_Example7.nc'), 'mask',\n", + " os.path.join(wrkDir, 'land_mask_Example7a.nc'), 'mask',\n", " MASKING_DEPTH=0.0, MINIMUM_DEPTH=1000.0, MAXIMUM_DEPTH=-99999.0)\n", " bathyGrids['newDepth'].attrs['units'] = 'meters'\n", " bathyGrids['newDepth'].attrs['standard_name'] = 'topographic depth at Arakawa C h-points'\n", "\n", " # Write grid variables out to a file\n", " # TODO: provide a data source service hook?\n", - " bathyGrids.to_netcdf(os.path.join(wrkDir, 'ocean_topog_Example7.nc'),\n", + " bathyGrids.to_netcdf(os.path.join(wrkDir, 'ocean_topog_Example7a.nc'),\n", " encoding=grd.removeFillValueAttributes(data=bathyGrids))" ] }, @@ -246,7 +257,7 @@ "metadata": {}, "outputs": [], "source": [ - "grd.saveGrid(filename=os.path.join(wrkDir, \"LCC_20x30_Example7.nc\"))" + "grd.saveGrid(filename=os.path.join(wrkDir, \"LCC_20x30_Example7a.nc\"))" ] }, { @@ -264,7 +275,7 @@ " inputDirectory=inputDir,\n", " overwrite=True,\n", ")\n", - "grd.saveGrid(filename=os.path.join(inputDir, \"ocean_hgrid.nc\"))" + "grd.saveGrid(filename=os.path.join(inputDir, \"ocean_hgrid_7a.nc\"))" ] }, { @@ -336,7 +347,7 @@ "metadata": {}, "outputs": [], "source": [ - "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelGrid.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelGrid_7a.png'), dpi=None, facecolor='w', edgecolor='w',\n", " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" ] }, @@ -369,7 +380,7 @@ "metadata": {}, "outputs": [], "source": [ - "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelGridCells.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelGridCells_7a.png'), dpi=None, facecolor='w', edgecolor='w',\n", " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" ] }, @@ -445,7 +456,7 @@ "metadata": {}, "outputs": [], "source": [ - "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OrigBathy.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OrigBathy_7a.png'), dpi=None, facecolor='w', edgecolor='w',\n", " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" ] }, @@ -489,7 +500,7 @@ "metadata": {}, "outputs": [], "source": [ - "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_MinBathy.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_MinBathy_7a.png'), dpi=None, facecolor='w', edgecolor='w',\n", " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" ] }, @@ -532,7 +543,7 @@ "metadata": {}, "outputs": [], "source": [ - "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_BathyDelta.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_BathyDelta_7a.png'), dpi=None, facecolor='w', edgecolor='w',\n", " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" ] }, @@ -575,7 +586,7 @@ "metadata": {}, "outputs": [], "source": [ - "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_h2.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_h2_7a.png'), dpi=None, facecolor='w', edgecolor='w',\n", " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" ] } diff --git a/examples/mkGridsExample07b.ipynb b/examples/mkGridsExample07b.ipynb new file mode 100644 index 0000000..86d10e7 --- /dev/null +++ b/examples/mkGridsExample07b.ipynb @@ -0,0 +1,640 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "830f737b-90bf-4121-bcff-8c8982c897db", + "metadata": {}, + "outputs": [], + "source": [ + "# This notebook is similar to the python script Example 7\n", + "# This notebook also uses extended grids as a workaround\n", + "# to overcome quirks with the bathymetric roughness routine." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45ea4f07-0894-4ca2-8421-531a7cebedc3", + "metadata": {}, + "outputs": [], + "source": [ + "# conda: gridTools" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "950e9cea-e786-446a-9c86-2ec307fff543", + "metadata": {}, + "outputs": [], + "source": [ + "# We utilize the 20x30 example grid along the\n", + "# California coast." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2027415-da36-430b-94d4-9b74ab430470", + "metadata": {}, + "outputs": [], + "source": [ + "import sys, os, logging\n", + "from gridtools.gridutils import GridUtils\n", + "from gridtools.datasource import DataSource\n", + "\n", + "import cartopy\n", + "import xarray as xr\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f1d21c9-8533-4c14-9483-2726b8137084", + "metadata": {}, + "outputs": [], + "source": [ + "# Setup a work directory\n", + "#wrkDir = '/home/cermak/mom6/configs/zOutput'\n", + "wrkDir = '/import/AKWATERS/jrcermakiii/configs/zOutput'\n", + "inputDir = os.path.join(wrkDir, \"INPUT\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecd6a367-3a24-4c1b-a99e-e070944863be", + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize a grid object\n", + "grd = GridUtils()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36e63977-ade1-4326-8538-9a2a6ae81bcf", + "metadata": {}, + "outputs": [], + "source": [ + "# We can turn on extra output from the module\n", + "grd.printMsg(\"Setting print and logging messages to the DEBUG level.\")\n", + "logFilename = os.path.join(wrkDir, 'LCC_20x30_7b.log')\n", + "grd.setVerboseLevel(logging.DEBUG)\n", + "grd.setDebugLevel(0)\n", + "grd.setLogLevel(logging.DEBUG)\n", + "grd.deleteLogfile(logFilename)\n", + "grd.enableLogging(logFilename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00dfc67f-98b6-431a-9bae-74a81045ba47", + "metadata": {}, + "outputs": [], + "source": [ + "# Make sure we erase any previous grid, grid parameters and plot parameters.\n", + "grd.clearGrid()\n", + "\n", + "# Specify the grid parameters\n", + "# gridMode should be 2.0 for supergrid\n", + "# Normally 30.0; 0.0 for debugging\n", + "gtilt = 30.0\n", + "grd.printMsg(\"Set grid parameters.\")\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'LambertConformalConic',\n", + " 'lon_0': 230.0,\n", + " 'lat_0': 40.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 230.0,\n", + " 'centerY': 40.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 20.0,\n", + " 'dxUnits': 'degrees',\n", + " 'dy': 30.0,\n", + " 'dyUnits': 'degrees',\n", + " 'tilt': gtilt,\n", + " 'gridResolutionX': 1.0,\n", + " 'gridResolutionY': 1.0,\n", + " 'gridResolution': 1.0,\n", + " 'gridResolutionXUnits': 'degrees',\n", + " 'gridResolutionYUnits': 'degrees',\n", + " 'gridResolutionUnits': 'degrees',\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True,\n", + " 'tileName': 'tile1',\n", + "})\n", + "grd.printMsg(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e16fee6-6b2c-4cc5-9efd-74a4bd1ca79f", + "metadata": {}, + "outputs": [], + "source": [ + "# This forms a grid in memory using the specified grid parameters\n", + "grd.makeGrid()\n", + "grd.printMsg(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f85ea2a8-d530-4aa8-ac61-66fba26d309f", + "metadata": {}, + "outputs": [], + "source": [ + "# External data sources are required\n", + "# This creates an empty data source catalog\n", + "ds = DataSource()\n", + "\n", + "# Connect the catalog to the grid object\n", + "grd.useDataSource(ds)\n", + "\n", + "# For variableMap, matching variable values will be renamed to the\n", + "# variable key. For evalMap, variables in the expression need\n", + "# to be in brackets. If the key is new, a new field will be\n", + "# created with the given expression.\n", + "ds.addDataSource({\n", + " 'GEBCO_2020': {\n", + " 'url' : 'file:/import/AKWATERS/jrcermakiii/bathy/gebco/GEBCO_2020.nc',\n", + " 'variableMap' : {\n", + " 'lat': 'lat',\n", + " 'lon': 'lon',\n", + " 'depth' : 'elevation'\n", + " },\n", + " 'evalMap': {\n", + " 'depth' : '-[depth]'\n", + " }\n", + " }\n", + "})\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b91fe4ad-f3b8-4e95-880c-6dd7f7a2ed6e", + "metadata": {}, + "outputs": [], + "source": [ + "# Save the catalog just for demonstration\n", + "ds.saveCatalog(os.path.join(wrkDir, 'catalog.json'))\n", + "ds.saveCatalog(os.path.join(wrkDir, 'catalog.yaml'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f82fa522-4c0f-413d-b3a8-22e202a626ba", + "metadata": {}, + "outputs": [], + "source": [ + "# We do not need to compute bathymetric roughness if we have an existing file\n", + "# Increase the memory footprint (maxMb) to allow more mesh refinements to\n", + "# be used from the topography.\n", + "bathyGridFilename = os.path.join(wrkDir, 'ocean_topog_Example7b.nc')\n", + "\n", + "if os.path.isfile(bathyGridFilename):\n", + " grd.printMsg(\"Using existing bathymetry file: %s\" % (bathyGridFilename))\n", + " bathyGrids = xr.open_dataset(bathyGridFilename)\n", + "else:\n", + " # This routine cannont use data sources that are in chunked mode (dask)\n", + " \n", + " # The grid is extended to provide additional points for the\n", + " # roughness routine to utilize. The bathymetric and roughness\n", + " # grid is on the regular grid, so the underlying supergrid has to\n", + " # be extended by two points.\n", + " extGrd = grd.extendGrid(2, 2, 2, 2)\n", + " \n", + " # Put the extended grid into a gridtools grid. Attach it to\n", + " # the same data source as above.\n", + " grd2 = GridUtils()\n", + " grd2.useDataSource(ds)\n", + " grd2.readGrid(local=extGrd)\n", + " \n", + " # Bathymetric roughness is computed on the extended grid\n", + " requestedVariables = ['hStd', 'hMin', 'hMax', 'depth']\n", + " bathyGrids2 = grd2.computeBathymetricRoughness('ds:GEBCO_2020',\n", + " maxMb=99, superGrid=False, useClipping=False,\n", + " useOverlap=True, useQHGridShift=False, extendedGrid=True,\n", + " auxVariables=requestedVariables\n", + " )\n", + "\n", + " # This is needed to really convert the elevation field to depth\n", + " # The 'depth' field has to be requested as an auxVariables\n", + " grd.applyEvalMap('ds:GEBCO_2020', bathyGrids2)\n", + " \n", + " # The extended grid is reduced back to the original size.\n", + " # Information needs to be placed in a new xarray so variables\n", + " # have dimensional consistency. The field h2 is implicitly\n", + " # provided above, so it needs to be added to the list.\n", + " requestedVariables.append('h2')\n", + " bathyGrids = xr.Dataset()\n", + " for vrb in requestedVariables:\n", + " bathyGrids[vrb] = bathyGrids2[vrb][1:-1,1:-1].copy()\n", + " \n", + " # Write ocean_mask and land_mask based on existing field with\n", + " # a standard MASKING_DEPTH of 0.0 meters. The next part of this\n", + " # example will set a MINIMUM_DEPTH of 1000.0 meters for comparison.\n", + " grd.writeOceanmask(bathyGrids, 'depth', 'mask',\n", + " os.path.join(wrkDir, 'ocean_mask_Example7b.nc'),\n", + " MASKING_DEPTH=0.0)\n", + " grd.writeLandmask(bathyGrids, 'depth', 'mask',\n", + " os.path.join(wrkDir, 'land_mask_Example7b.nc'),\n", + " MASKING_DEPTH=0.0)\n", + " \n", + " # Apply existing land mask which should not change anything\n", + " # The minimum depth will modify a couple points. We save the\n", + " # new field as 'newDepth' to allow comparison with 'depth'.\n", + " \n", + " # Argument notes:\n", + " # * NOTE: The selection of the 1000.0 meter depth is arbitrary is for the purpose of demonstration.\n", + " # * Any ocean mask points shallower than a depth of 1000.0 meters will be set to 1000.0 meters\n", + " # * Any land mask points that become ocean will be set to a depth of 1000.0 meters\n", + " # * Any ocean points that become land will have a depth of 0.0 meters\n", + " \n", + " bathyGrids['newDepth'] = grd.applyExistingLandmask(bathyGrids, 'depth',\n", + " os.path.join(wrkDir, 'land_mask_Example7b.nc'), 'mask',\n", + " MASKING_DEPTH=0.0, MINIMUM_DEPTH=1000.0, MAXIMUM_DEPTH=-99999.0)\n", + " bathyGrids['newDepth'].attrs['units'] = 'meters'\n", + " bathyGrids['newDepth'].attrs['standard_name'] = 'topographic depth at Arakawa C h-points'\n", + "\n", + " # Write grid variables out to a file\n", + " # TODO: provide a data source service hook?\n", + " bathyGrids.to_netcdf(os.path.join(wrkDir, 'ocean_topog_Example7b.nc'),\n", + " encoding=grd.removeFillValueAttributes(data=bathyGrids))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f10f546-555b-4c59-9f21-a8484b2a08f0", + "metadata": {}, + "outputs": [], + "source": [ + "grd.saveGrid(filename=os.path.join(wrkDir, \"LCC_20x30_Example7b.nc\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7a201e6-9e01-4423-85e3-9b34505d0300", + "metadata": {}, + "outputs": [], + "source": [ + "# Write out FMS related support files\n", + "grd.makeSoloMosaic(\n", + " topographyGrid=bathyGrids['newDepth'],\n", + " writeLandmask=True,\n", + " writeOceanmask=True,\n", + " inputDirectory=inputDir,\n", + " overwrite=True,\n", + ")\n", + "grd.saveGrid(filename=os.path.join(inputDir, \"ocean_hgrid_7b.nc\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d39a35f4-7efb-438d-97da-9acf17d92db3", + "metadata": {}, + "outputs": [], + "source": [ + "# Do some plotting!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55087c90-a7ef-45db-9617-2df5c8d8a16e", + "metadata": {}, + "outputs": [], + "source": [ + "# Set plot parameters for the grid and topography\n", + "\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'NearsidePerspective',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': False,\n", + " 'title': \"Nearside Perspective: 20x30 with %.1f degree tilt\" % (gtilt),\n", + " 'iColor': 'k',\n", + " 'jColor': 'k',\n", + " 'transform': cartopy.crs.PlateCarree(),\n", + " 'satelliteHeight': 35785831.0,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6076604-408b-4de0-b30e-92adc997ac37", + "metadata": {}, + "outputs": [], + "source": [ + "# Show the model grid only\n", + "grd.setPlotParameters({'showGridCells': False})\n", + "(figure, axes) = grd.plotGrid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6882d187-c7b3-4e76-be9d-fc6d60c4647d", + "metadata": {}, + "outputs": [], + "source": [ + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "325a2501-6f0d-495a-8282-612d436564c2", + "metadata": {}, + "outputs": [], + "source": [ + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelGrid_7b.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ddbe37c-05e1-4bfc-93d7-a3a884e904c1", + "metadata": {}, + "outputs": [], + "source": [ + "# Show the model grid cells\n", + "grd.setPlotParameters({'showGridCells': True})\n", + "(figure, axes) = grd.plotGrid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d04fc49-ce87-498d-aba8-ac7165e85854", + "metadata": {}, + "outputs": [], + "source": [ + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3334670e-273e-4770-8c06-a7c23e8fec7e", + "metadata": {}, + "outputs": [], + "source": [ + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelGridCells_7b.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67e0f4fb-eb5f-4045-afd1-6d2f48e8f370", + "metadata": {}, + "outputs": [], + "source": [ + "# Show the model grid cells (TODO: Future feature)\n", + "# grd.setPlotParameters({'showSupergrid': True, 'showGridCells': False})\n", + "# (figure, axes) = grd.plotGrid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cea271d2-5335-40f5-9f7e-f395a4c91e99", + "metadata": {}, + "outputs": [], + "source": [ + "#figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e9591d4-1202-4d2e-92b8-f9d904cbb977", + "metadata": {}, + "outputs": [], + "source": [ + "#figure.savefig(os.path.join(wrkDir, 'LCC_20x30_ModelSupergrid.png'), dpi=None, facecolor='w', edgecolor='w',\n", + "# orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e18abe97-54cb-4567-90f4-e2eaa4ec38ea", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot original depth grid after running computeBathyRoughness()\n", + "(figure, axes) = grd.plotGrid(\n", + " showModelGrid=False,\n", + " plotVariables={\n", + " 'depth': {\n", + " 'values': bathyGrids['depth'],\n", + " 'title': 'Original diagnosed bathymetric field',\n", + " 'cbar_kwargs': {\n", + " 'orientation': 'horizontal',\n", + " }\n", + " }\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bc7c212-678d-423e-95f8-5ffdbb0fb90d", + "metadata": {}, + "outputs": [], + "source": [ + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2087cd42-af74-49c5-9ebf-fd193df581d6", + "metadata": {}, + "outputs": [], + "source": [ + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OrigBathy_7b.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fc9433e-cae3-4a2f-9601-32bc7a28f339", + "metadata": {}, + "outputs": [], + "source": [ + "# Plot depth grid after we apply an existing landmask with minimum\n", + "# depth set to 1000 meters\n", + "(figure, axes) = grd.plotGrid(\n", + " showModelGrid=False,\n", + " plotVariables={\n", + " 'depth': {\n", + " 'values': bathyGrids['newDepth'],\n", + " 'title': 'Bathymetric grid with 1000 meter minimum depth',\n", + " 'cbar_kwargs': {\n", + " 'orientation': 'horizontal',\n", + " }\n", + " }\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c3f8a33-7e84-4849-8291-30efb59eef63", + "metadata": {}, + "outputs": [], + "source": [ + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75861994-563e-4a62-bddd-68aa4e1813bb", + "metadata": {}, + "outputs": [], + "source": [ + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_MinBathy_7b.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6dea6b03-aa13-46f2-ba5b-1ac94f117000", + "metadata": {}, + "outputs": [], + "source": [ + "# Show the difference between 'newDepth' and 'depth'\n", + "(figure, axes) = grd.plotGrid(\n", + " showModelGrid=False,\n", + " plotVariables={\n", + " 'depth': {\n", + " 'values': bathyGrids['newDepth'] - bathyGrids['depth'],\n", + " 'title': 'Bathymetric depth difference',\n", + " 'cbar_kwargs': {\n", + " 'orientation': 'horizontal',\n", + " }\n", + " }\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3334b5fc-a1e2-41ac-8930-ff724f3d4abd", + "metadata": {}, + "outputs": [], + "source": [ + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5e9d0c3-e2ec-4a1a-bd98-fb8d924d6cdd", + "metadata": {}, + "outputs": [], + "source": [ + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_BathyDelta_7b.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47a6b630-ce80-40b2-af23-714a54f2790c", + "metadata": {}, + "outputs": [], + "source": [ + "# Show h2 diagnosed parameter\n", + "(figure, axes) = grd.plotGrid(\n", + " showModelGrid=False,\n", + " plotVariables={\n", + " 'h2': {\n", + " 'values': bathyGrids['h2'],\n", + " 'title': 'Bathymetric roughness (h2)',\n", + " 'cbar_kwargs': {\n", + " 'orientation': 'horizontal',\n", + " }\n", + " }\n", + " },\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad244823-06a6-49e9-84b7-b933dee416dd", + "metadata": {}, + "outputs": [], + "source": [ + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ca460ac-18c2-40c2-aaf5-d8506d2b9992", + "metadata": {}, + "outputs": [], + "source": [ + "figure.savefig(os.path.join(wrkDir, 'LCC_20x30_h2_7b.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/mkGridsExample08.py b/examples/mkGridsExample08.py index 81021ee..f546db4 100644 --- a/examples/mkGridsExample08.py +++ b/examples/mkGridsExample08.py @@ -3,6 +3,7 @@ # conda: gridTools import sys, os, logging +import xarray as xr import cartopy from gridtools.gridutils import GridUtils from gridtools.datasource import DataSource @@ -136,7 +137,7 @@ plotVariables={ 'depth': { 'values': resultGrids['depth'], - 'title': 'GEBCO 2020 applied to GridUtils.regridTopo()', + 'title': 'GEBCO 2020: GridUtils.regridTopo(): depth', 'cbar_kwargs': { 'orientation': 'horizontal', } @@ -153,7 +154,7 @@ plotVariables={ 'oceanMask': { 'values': resultGrids['ocean_mask'], - 'title': 'GEBCO 2020 applied to GridUtils.regridTopo()', + 'title': 'GEBCO 2020: GridUtils.regridTopo(): ocean_mask', 'cbar_kwargs': { 'orientation': 'horizontal', } @@ -163,3 +164,88 @@ figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OceanMask_Example8.png'), dpi=None, facecolor='w', edgecolor='w', orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) + +# Do the same thing again but with an extended grid to eliminate the corner grid +# point artifacts. + +# Create an extended grid +extGrd = grd.extendGrid(2, 2, 2, 2) + +# Put the extended grid into a gridtools grid. Attach it to +# the same data source as above. +grd2 = GridUtils() +grd2.useDataSource(ds) +grd2.readGrid(local=extGrd) + +# Use topoutils.TopoUtils.regridTopo() function on extended grid +resultGridsExt = grd2.regridTopo('ds:GEBCO_2020', topoVarName='depth', periodic=False) + +# Subset the result grid back to the original grid +resultGrids2 = xr.Dataset() +resultGrids2['depth'] = resultGridsExt['depth'][1:-1,1:-1] +resultGrids2['ocean_mask'] = resultGridsExt['ocean_mask'][1:-1,1:-1] + +# Write fields out to a file +# TODO: provide a data source service hook? +resultGrids2.to_netcdf(os.path.join(wrkDir, 'ocean_topog_Example8_ext.nc'), + encoding=grd.removeFillValueAttributes(data=resultGrids2)) + +# Do some plotting! + +# Set plot parameters for the grid and topography + +grd.setPlotParameters( + { + 'figsize': (8,8), + 'projection': { + 'name': 'NearsidePerspective', + 'lat_0': 40.0, + 'lon_0': 230.0 + }, + 'extent': [-160.0 ,-100.0, 20.0, 60.0], + 'iLinewidth': 1.0, + 'jLinewidth': 1.0, + 'showGridCells': True, + 'title': "Nearside Perspective: 20x30 with %.1f degree tilt" % (gtilt), + 'iColor': 'k', + 'jColor': 'k', + 'transform': cartopy.crs.PlateCarree(), + 'satelliteHeight': 35785831.0, + } +) + +# Plot the new bathy grid +(figure, axes) = grd.plotGrid( + showModelGrid=False, + plotVariables={ + 'depth': { + 'values': resultGrids2['depth'], + 'title': 'GEBCO 2020: GridUtils.regridTopo(): depth_ext', + 'cbar_kwargs': { + 'orientation': 'horizontal', + } + } + }, +) + +figure.savefig(os.path.join(wrkDir, 'LCC_20x30_Bathy_Example8_ext.png'), dpi=None, + facecolor='w', edgecolor='w', + orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) + +# Plot the fractional ocean mask +(figure, axes) = grd.plotGrid( + showModelGrid=False, + plotVariables={ + 'oceanMask': { + 'values': resultGrids2['ocean_mask'], + 'title': 'GEBCO 2020: GridUtils.regridTopo(): ocean_mask_ext', + 'cbar_kwargs': { + 'orientation': 'horizontal', + } + } + }, +) + +figure.savefig(os.path.join(wrkDir, 'LCC_20x30_OceanMask_Example8_ext.png'), dpi=None, + facecolor='w', edgecolor='w', + orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1) diff --git a/examples/mkGridsExample09b.ipynb b/examples/mkGridsExample09b.ipynb index bd4bd67..ecbf43b 100644 --- a/examples/mkGridsExample09b.ipynb +++ b/examples/mkGridsExample09b.ipynb @@ -8,7 +8,10 @@ "outputs": [], "source": [ "# This example allows editing of the 20x30 sample grid off the\n", - "# coast of California\n", + "# coast of California.\n", + "\n", + "# NOTICE: This requires that the python script\n", + "# mkGridsExample07.py was run BEFORE this notebook can be run.\n", "\n", "import os, sys\n", "from gridtools.gridutils import GridUtils\n", @@ -68,7 +71,16 @@ "\n", "# Create the mask editor\n", "appObj = maskEditor(crs=crs, ds=oceanMask['mask'])\n", - "app = appObj.createMaskEditorApp()\n", + "app = appObj.createMaskEditorApp()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f83c0120-eb32-46f6-aa8d-599a80cf9432", + "metadata": {}, + "outputs": [], + "source": [ "display(app)" ] }, diff --git a/examples/mkGridsExample12.ipynb b/examples/mkGridsExample12.ipynb new file mode 100644 index 0000000..ef1bc36 --- /dev/null +++ b/examples/mkGridsExample12.ipynb @@ -0,0 +1,858 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "9b16579e-353e-43bc-9bc5-256c613511ff", + "metadata": {}, + "outputs": [], + "source": [ + "# Example 12:\n", + "#\n", + "# This example creates two simple grids in cartesian and lat/lon space and\n", + "# demonstrates the use of the extendGrid() routine on two simple 5x5 grids.\n", + "\n", + "# NOTE: The i grid lines are shown in yellow. This helps see that for the\n", + "# stereographic grid, that the grid is actually rotated 90 degrees from\n", + "# the nominal view of the grid where (J,I) (0,0) is at the bottom left\n", + "# and J grows upwards and I grows rightwards." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3caefa2-f550-4f8d-a909-a49cdd62f601", + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize library\n", + "# conda: gridTools\n", + "import os\n", + "from gridtools.gridutils import GridUtils\n", + "%matplotlib inline\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3c6e2d5-d15f-4060-86c1-fd4c2a339960", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a grid in spherical space using the LCC projection\n", + "# NOTE: Specification of the grid is in degrees, but\n", + "# the computation is spherical coordinates using meters.\n", + "grd = GridUtils()\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'LambertConformalConic',\n", + " 'lon_0': 230.0,\n", + " 'lat_0': 40.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 230.0,\n", + " 'centerY': 40.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 20.0,\n", + " 'dxUnits': 'degrees',\n", + " 'dy': 20.0,\n", + " 'dyUnits': 'degrees',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 4.0,\n", + " 'gridResolutionUnits': 'degrees',\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True,\n", + " 'tileName': 'tile1',\n", + "})\n", + "grd.makeGrid()\n", + "\n", + "# Define plot parameters so we can see what the grid looks like\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'NearsidePerspective',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Lambert Conformal Conic: 5x5\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d362a8d3-1d3a-4d83-b4d1-62a22200610b", + "metadata": {}, + "outputs": [], + "source": [ + "(figure, axes) = grd.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56ec0b9d-896d-465a-aae0-4a65fc835bc6", + "metadata": {}, + "outputs": [], + "source": [ + "# Extend this grid one regular cell (two cells in the supergrid) using meters\n", + "extGrid = grd.extendGrid(2,2,2,2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f8c73e2-5a73-488e-a980-78079d18a421", + "metadata": {}, + "outputs": [], + "source": [ + "eGridLCC = GridUtils()\n", + "eGridLCC.readGrid(local=extGrid)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2dd52472-7420-42cf-a36e-fc9560c13e10", + "metadata": {}, + "outputs": [], + "source": [ + "eGridLCC.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'NearsidePerspective',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Lambert Conformal Conic: 5x5 extended by 1 regular grid point to 7x7\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cd5b8aa-ff3c-403e-b04e-163f558e4a3e", + "metadata": {}, + "outputs": [], + "source": [ + "(figure, axes) = eGridLCC.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0331708d-f6ee-4667-8cb8-54405c30cafd", + "metadata": {}, + "outputs": [], + "source": [ + "eGridLCC.grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7b2710-3ee6-42a8-b03b-cfa00ff79a2d", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a mercator grid in lat/lon space\n", + "grd = GridUtils()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9b9b370-c9e7-49f6-857c-187d65e65950", + "metadata": {}, + "outputs": [], + "source": [ + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Mercator',\n", + " 'lon_0': 230.0,\n", + " 'lat_0': 40.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 230.0,\n", + " 'centerY': 40.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 20.0,\n", + " 'dxUnits': 'degrees',\n", + " 'dy': 20.0,\n", + " 'dyUnits': 'degrees',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 4.0,\n", + " 'gridResolutionUnits': 'degrees',\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True,\n", + " 'tileName': 'tile1',\n", + "})\n", + "grd.makeGrid()\n", + "\n", + "# Define plot parameters so we can see what the grid looks like\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'NearsidePerspective',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Mercator: 5x5\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3cac5524-2a33-44f9-b600-fd7b53e23188", + "metadata": {}, + "outputs": [], + "source": [ + "(figure, axes) = grd.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77db29f7-71e4-44d2-bb4e-19e8ac19da96", + "metadata": {}, + "outputs": [], + "source": [ + "# Extend this grid one regular cell (two cells in the supergrid) using degrees\n", + "extGrid = grd.extendGrid(2,2,2,2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1198cab1-7c98-432b-9168-e23899ed7355", + "metadata": {}, + "outputs": [], + "source": [ + "eGridMercator = GridUtils()\n", + "eGridMercator.readGrid(local=extGrid)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6a9b540-093b-424f-b46c-837566927fa2", + "metadata": {}, + "outputs": [], + "source": [ + "# Define plot parameters so we can see what the grid looks like\n", + "eGridMercator.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'NearsidePerspective',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Mercator: 5x5 extended by 1 regular grid point to 7x7\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6759833-fcbc-487c-8034-12a57d803261", + "metadata": {}, + "outputs": [], + "source": [ + "(figure, axes) = eGridMercator.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4427c871-7ed1-4bd1-bb31-eef72cf145d5", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a 5x5 Stereographic grid for testing\n", + "grd = GridUtils()\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': \"Stereographic\",\n", + " 'ellps': 'WGS84',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'lat_ts': 75.0,\n", + " },\n", + " 'centerX': 0.0,\n", + " 'centerY': 90.0,\n", + " 'cneterUnits': 'degrees',\n", + " 'dx': 2500000.0,\n", + " 'dy': 2500000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dyUnits': 'meters',\n", + " 'gridResolution': 500000.0,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True\n", + "})\n", + "\n", + "grd.makeGrid()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "becd19ed-ffc7-4c3b-8327-ba54eb291360", + "metadata": {}, + "outputs": [], + "source": [ + "# Define plot parameters so we can see what the grid looks like\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = grd.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36218729-8e74-4b2d-925f-fde34cc5dcfb", + "metadata": {}, + "outputs": [], + "source": [ + "# Extend this grid one regular cell (two cells in the supergrid) using meters\n", + "extGrid = grd.extendGrid(2,2,2,2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a4dd38a-9251-4cd5-abde-bdd09531e1c1", + "metadata": {}, + "outputs": [], + "source": [ + "eGridStereographic = GridUtils()\n", + "eGridStereographic.readGrid(local=extGrid)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3bbf6fbf-b1b6-45e6-94a5-a5509aeeb658", + "metadata": {}, + "outputs": [], + "source": [ + "eGridStereographic.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point to 7x7',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridStereographic.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9744662d-a47b-430c-ac8d-fabb623a5301", + "metadata": {}, + "outputs": [], + "source": [ + "# Grid clipping tests" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41d54e1f-665d-48cc-bedc-58ba6070b597", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep sides of the grid (jstart)\n", + "# Row along the bottom\n", + "extGrid = grd.extendGrid(2,0,0,0)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (jstart)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d9de7be-1ccf-4da0-a264-713281aaba54", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep sides of the grid (jend)\n", + "# Row across the top\n", + "extGrid = grd.extendGrid(0,2,0,0)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (jend)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44c5e41c-0b7b-43b7-807d-16d89c7abc07", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep sides of the grid (istart)\n", + "# Row on the left\n", + "extGrid = grd.extendGrid(0,0,2,0)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (istart)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ac69401-617c-4a9d-b4b0-f5023d7687d3", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep sides of the grid (iend)\n", + "# Row along the right\n", + "extGrid = grd.extendGrid(0,0,0,2)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (iend)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81d368de-613c-44ba-bfb0-42d70acfab2f", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep two sides of the grid (i/j start)\n", + "# Row on the left and bottom\n", + "extGrid = grd.extendGrid(2,0,2,0)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (i/j start)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b4f6931-5a74-48ad-a241-fe070f7ab33c", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep two sides of the grid (i/j end)\n", + "# Row on the top and right\n", + "extGrid = grd.extendGrid(0,2,0,2)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (i/j end)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "065adba5-881b-4900-bb18-259a5db7506c", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep two sides of the grid (jstart and iend)\n", + "# Row along bottom and right\n", + "extGrid = grd.extendGrid(2,0,0,2)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0\n", + " },\n", + " 'extent': [-180, 180, 60, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic: 5x5 extended by 1 regular grid point (istart and jend)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d612e99a-d29e-439e-98ba-1c8608f30b13", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a 1x3 mercator grid for an asymmetric test\n", + "grd = GridUtils()\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Mercator',\n", + " 'lon_0': 230.0,\n", + " 'lat_0': 40.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 230.0,\n", + " 'centerY': 40.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 12.0,\n", + " 'dxUnits': 'degrees',\n", + " 'dy': 4.0,\n", + " 'dyUnits': 'degrees',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 4.0,\n", + " 'gridResolutionUnits': 'degrees',\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True,\n", + " 'tileName': 'tile1',\n", + "})\n", + "grd.makeGrid()\n", + "\n", + "# Define plot parameters so we can see what the grid looks like\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Mercator',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Mercator: 1x3\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = grd.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d01b956-4454-4ed7-959e-a7e2ef5ff73c", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a 3x1 mercator grid for an asymmetric test\n", + "grd = GridUtils()\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Mercator',\n", + " 'lon_0': 230.0,\n", + " 'lat_0': 40.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 230.0,\n", + " 'centerY': 40.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 4.0,\n", + " 'dxUnits': 'degrees',\n", + " 'dy': 12.0,\n", + " 'dyUnits': 'degrees',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 4.0,\n", + " 'gridResolutionUnits': 'degrees',\n", + " 'gridMode': 2,\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True,\n", + " 'tileName': 'tile1',\n", + "})\n", + "grd.makeGrid()\n", + "\n", + "# Define plot parameters so we can see what the grid looks like\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Mercator',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': \"Mercator: 3x1\",\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = grd.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba51367e-03d2-4148-b89c-654c59c93c83", + "metadata": {}, + "outputs": [], + "source": [ + "# Repeat last example, but only keep sides of the grid (jstart)\n", + "# Row along the bottom\n", + "extGrid = grd.extendGrid(2,0,0,0)\n", + "eGridClip = GridUtils()\n", + "eGridClip.readGrid(local=extGrid)\n", + "eGridClip.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Mercator',\n", + " 'lat_0': 40.0,\n", + " 'lon_0': 230.0\n", + " },\n", + " 'extent': [-160.0 ,-100.0, 20.0, 60.0],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGrid': False,\n", + " 'showGridCells': True,\n", + " 'title': 'Mercator: 3x1 extended by 1 regular grid point (jstart)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "\n", + "(figure, axes) = eGridClip.plotGrid()\n", + "figure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f23a3e6-c9c9-4776-9a5b-23ffebb242a4", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/projection/stereographic/otherNorthHemisphere.ipynb b/examples/projection/stereographic/otherNorthHemisphere.ipynb new file mode 100644 index 0000000..86fa6a7 --- /dev/null +++ b/examples/projection/stereographic/otherNorthHemisphere.ipynb @@ -0,0 +1,153 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "fec2bf13-8861-46d8-8507-c4605f77ba90", + "metadata": {}, + "outputs": [], + "source": [ + "# conda: gridTools\n", + "import os\n", + "from gridtools.gridutils import GridUtils\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58803eba-7c47-43d8-aa49-051968abdd17", + "metadata": {}, + "outputs": [], + "source": [ + "# Define a place to write example files\n", + "wrkDir = '/import/AKWATERS/jrcermakiii/configs/projection/stereographic'\n", + "inputDir = os.path.join(wrkDir, \"INPUT\")\n", + "plotDir = os.path.join(wrkDir,\"PLOTS\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69010a73-02a8-42bd-851a-e438312cf68e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Instantiate a grid tools library object\n", + "# Adjust message levels from the library\n", + "grd = GridUtils()\n", + "grd.setVerboseLevel('INFO')\n", + "grd.setDebugLevel(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75298636-2108-4e92-8aa9-e65090751843", + "metadata": {}, + "outputs": [], + "source": [ + "# NORTHERN HEMISPHERE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ce33d7d-684a-4226-adb9-68dac22c4cae", + "metadata": {}, + "outputs": [], + "source": [ + "# More complex projection parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d5fd088-7b43-43ee-9cea-51a2044a73d9", + "metadata": {}, + "outputs": [], + "source": [ + "# Zoom in on the USA, using a projection of lon_0=270.0000\n", + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 270.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 270.0,\n", + " 'centerY': 45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,6),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 270.0,\n", + " 'lat_0': 90,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-140, -40, 20, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45N/270E(-90W) lon_0=270.0',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_nh_45n_270e_270lon0.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='landscape', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6190a55-d70f-42f2-b88e-a4468efae74a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/projection/stereographic/pointTests.ipynb b/examples/projection/stereographic/pointTests.ipynb new file mode 100644 index 0000000..a598624 --- /dev/null +++ b/examples/projection/stereographic/pointTests.ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "fec2bf13-8861-46d8-8507-c4605f77ba90", + "metadata": {}, + "outputs": [], + "source": [ + "# conda: gridTools\n", + "import os\n", + "from gridtools.gridutils import GridUtils\n", + "from pyproj import CRS, Transformer\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58803eba-7c47-43d8-aa49-051968abdd17", + "metadata": {}, + "outputs": [], + "source": [ + "# Define a place to write example files\n", + "wrkDir = '/import/AKWATERS/jrcermakiii/configs/projection/stereographic'\n", + "inputDir = os.path.join(wrkDir, \"INPUT\")\n", + "plotDir = os.path.join(wrkDir,\"PLOTS\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69010a73-02a8-42bd-851a-e438312cf68e", + "metadata": {}, + "outputs": [], + "source": [ + "# Instantiate a grid tools library object\n", + "# Adjust message levels from the library\n", + "grd = GridUtils()\n", + "grd.setVerboseLevel('INFO')\n", + "grd.setDebugLevel(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d87dcab-9824-4a19-9c72-061a0730534c", + "metadata": {}, + "outputs": [], + "source": [ + "# Simple coordinate tests\n", + "PROJSTRING = \"+proj=stere +lat_0=90.000000 +ellps=WGS84\"\n", + "# create the coordinate reference system\n", + "crs = CRS.from_proj4(PROJSTRING)\n", + "\n", + "# create the projection from lon/lat to x/y\n", + "prj = Transformer.from_crs(crs.geodetic_crs, crs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75298636-2108-4e92-8aa9-e65090751843", + "metadata": {}, + "outputs": [], + "source": [ + "# NORTHERN HEMISPHERE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8820e10-9a3c-4ccc-af5b-cc1f39921032", + "metadata": {}, + "outputs": [], + "source": [ + "# All the pole points should end up back at the pole (90.0 N)\n", + "# When transformed back, the actual location of longitude is lost.\n", + "# Lon, Lat / X(east), Y(north)\n", + "locations = [(0.0, 90.0), (90.0, 90.0), (180.0, 90.0), (270.0, 90.0)]\n", + "\n", + "for loc in locations:\n", + " (lon, lat) = loc\n", + " # Transform to X, Y\n", + " east, north = prj.transform(lon, lat)\n", + " # Back to Lon, Lat\n", + " lon2, lat2 = prj.transform(east, north, direction='INVERSE')\n", + " # Show result\n", + " print(\"(lon=%s, lat=%s) -> (east=%s, north=%s) -> (lon=%s, lat=%s)\" %\n", + " (lon, lat, east, north, lon2, lat2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8bcbe09-0b50-41a5-9597-9b7727503135", + "metadata": {}, + "outputs": [], + "source": [ + "# Testing all the quadrants at 45.0 N\n", + "# Lon, Lat / X(east), Y(north)\n", + "locations = [(0.0, 45.0), (90.0, 45.0), (180.0, 45.0), (270.0, 45.0)]\n", + "# locations = [(0.0, 45.0), (90.0, 45.0), (180.0, 45.0), (-90.0, 45.0)]\n", + "\n", + "for loc in locations:\n", + " (lon, lat) = loc\n", + " # Transform to X, Y\n", + " east, north = prj.transform(lon, lat)\n", + " # Back to Lon, Lat\n", + " lon2, lat2 = prj.transform(east, north, direction='INVERSE')\n", + " # Show result\n", + " print(\"(lon=%s, lat=%s) -> (east=%s, north=%s) -> (lon=%s, lat=%s)\" %\n", + " (lon, lat, east, north, lon2, lat2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d590adf-7734-4cfa-bfa9-18f703a2a7e8", + "metadata": {}, + "outputs": [], + "source": [ + "# SOUTHERN HEMISPHERE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d52e00c8-0185-4d2a-b0dc-3903803aca06", + "metadata": {}, + "outputs": [], + "source": [ + "# All the pole points should end up back at the pole (90.0 S)\n", + "# When transformed back, the actual location of longitude is lost.\n", + "# Lon, Lat / X(east), Y(north)\n", + "locations = [(0.0, -90.0), (90.0, -90.0), (180.0, -90.0), (270.0, -90.0)]\n", + "\n", + "for loc in locations:\n", + " (lon, lat) = loc\n", + " # Transform to X, Y\n", + " east, north = prj.transform(lon, lat)\n", + " # Back to Lon, Lat\n", + " lon2, lat2 = prj.transform(east, north, direction='INVERSE')\n", + " # Show result\n", + " print(\"(lon=%s, lat=%s) -> (east=%s, north=%s) -> (lon=%s, lat=%s)\" %\n", + " (lon, lat, east, north, lon2, lat2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1472353e-de25-41bd-a15e-17bc55aecd96", + "metadata": {}, + "outputs": [], + "source": [ + "# Testing all the quadrants at 45.0 S\n", + "# Lon, Lat / X(east), Y(north)\n", + "locations = [(0.0, -45.0), (90.0, -45.0), (180.0, -45.0), (270.0, -45.0)]\n", + "# locations = [(0.0, -45.0), (90.0, -45.0), (180.0, -45.0), (-90.0, -45.0)]\n", + "\n", + "for loc in locations:\n", + " (lon, lat) = loc\n", + " # Transform to X, Y\n", + " east, north = prj.transform(lon, lat)\n", + " # Back to Lon, Lat\n", + " lon2, lat2 = prj.transform(east, north, direction='INVERSE')\n", + " # Show result\n", + " print(\"(lon=%s, lat=%s) -> (east=%s, north=%s) -> (lon=%s, lat=%s)\" %\n", + " (lon, lat, east, north, lon2, lat2))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/projection/stereographic/simpleNorthHemisphere.ipynb b/examples/projection/stereographic/simpleNorthHemisphere.ipynb new file mode 100644 index 0000000..6fa3506 --- /dev/null +++ b/examples/projection/stereographic/simpleNorthHemisphere.ipynb @@ -0,0 +1,372 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "fec2bf13-8861-46d8-8507-c4605f77ba90", + "metadata": {}, + "outputs": [], + "source": [ + "# conda: gridTools\n", + "import os\n", + "from gridtools.gridutils import GridUtils\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58803eba-7c47-43d8-aa49-051968abdd17", + "metadata": {}, + "outputs": [], + "source": [ + "# Define a place to write example files\n", + "wrkDir = '/import/AKWATERS/jrcermakiii/configs/projection/stereographic'\n", + "inputDir = os.path.join(wrkDir, \"INPUT\")\n", + "plotDir = os.path.join(wrkDir,\"PLOTS\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69010a73-02a8-42bd-851a-e438312cf68e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Instantiate a grid tools library object\n", + "# Adjust message levels from the library\n", + "grd = GridUtils()\n", + "grd.setVerboseLevel('INFO')\n", + "grd.setDebugLevel(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75298636-2108-4e92-8aa9-e65090751843", + "metadata": {}, + "outputs": [], + "source": [ + "# NORTHERN HEMISPHERE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ce33d7d-684a-4226-adb9-68dac22c4cae", + "metadata": {}, + "outputs": [], + "source": [ + "# Test pole location" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da6deb67-1ca1-423f-b921-710d5c5b4ae7", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 0.0,\n", + " 'centerY': 90.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, 20, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=90N/0E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_nh_90n_0e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0fc18dd-8078-4fc2-aeea-b2cec8057728", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 0.0,\n", + " 'centerY': 45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, 20, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45N/0E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_nh_45n_0e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6e8f5b8-d1b2-47a9-ae14-75de15c67a78", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 90.0,\n", + " 'centerY': 45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, 20, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45N/90E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_nh_45n_90e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f40f1534-91fa-4164-8e29-074ed71c2832", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 180.0,\n", + " 'centerY': 45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, 20, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45N/180E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_nh_45n_180e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7d06c01-b8c6-4555-80c3-90becb6ea839", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 270.0,\n", + " 'centerY': 45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': 90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, 20, 90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45N/270E(-90W)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_nh_45n_270e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/projection/stereographic/simpleSouthHemisphere.ipynb b/examples/projection/stereographic/simpleSouthHemisphere.ipynb new file mode 100644 index 0000000..820d36b --- /dev/null +++ b/examples/projection/stereographic/simpleSouthHemisphere.ipynb @@ -0,0 +1,372 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "fec2bf13-8861-46d8-8507-c4605f77ba90", + "metadata": {}, + "outputs": [], + "source": [ + "# conda: gridTools\n", + "import os\n", + "from gridtools.gridutils import GridUtils\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58803eba-7c47-43d8-aa49-051968abdd17", + "metadata": {}, + "outputs": [], + "source": [ + "# Define a place to write example files\n", + "wrkDir = '/import/AKWATERS/jrcermakiii/configs/projection/stereographic'\n", + "inputDir = os.path.join(wrkDir, \"INPUT\")\n", + "plotDir = os.path.join(wrkDir,\"PLOTS\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69010a73-02a8-42bd-851a-e438312cf68e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Instantiate a grid tools library object\n", + "# Adjust message levels from the library\n", + "grd = GridUtils()\n", + "grd.setVerboseLevel('INFO')\n", + "grd.setDebugLevel(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75298636-2108-4e92-8aa9-e65090751843", + "metadata": {}, + "outputs": [], + "source": [ + "# SOUTHERN HEMISPHERE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ce33d7d-684a-4226-adb9-68dac22c4cae", + "metadata": {}, + "outputs": [], + "source": [ + "# Test pole location" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da6deb67-1ca1-423f-b921-710d5c5b4ae7", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 0.0,\n", + " 'centerY': -90.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, -20, -90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=90S/0E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_sh_90s_0e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0fc18dd-8078-4fc2-aeea-b2cec8057728", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 0.0,\n", + " 'centerY': -45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, -20, -90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45S/0E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_sh_45s_0e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6e8f5b8-d1b2-47a9-ae14-75de15c67a78", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 90.0,\n", + " 'centerY': -45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, -20, -90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45S/90E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_sh_45s_90e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f40f1534-91fa-4164-8e29-074ed71c2832", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 180.0,\n", + " 'centerY': -45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, -20, -90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45S/180E',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_sh_45s_180e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7d06c01-b8c6-4555-80c3-90becb6ea839", + "metadata": {}, + "outputs": [], + "source": [ + "grd.clearGrid()\n", + "# Specify the grid parameters\n", + "grd.setGridParameters({\n", + " 'projection': {\n", + " 'name': 'Stereographic',\n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'centerX': 270.0,\n", + " 'centerY': -45.0,\n", + " 'centerUnits': 'degrees',\n", + " 'dx': 6000000.0,\n", + " 'dxUnits': 'meters',\n", + " 'dy': 6000000.0,\n", + " 'dyUnits': 'meters',\n", + " 'tilt': 0.0,\n", + " 'gridResolution': 1000000.0,\n", + " 'gridMode': 2,\n", + " 'gridResolutionUnits': 'meters',\n", + " 'gridType': 'MOM6',\n", + " 'ensureEvenI': True,\n", + " 'ensureEvenJ': True \n", + "})\n", + "grd.makeGrid()\n", + "# Show the new grid\n", + "grd.setPlotParameters(\n", + " {\n", + " 'figsize': (8,8),\n", + " 'projection': {\n", + " 'name': 'Stereographic', \n", + " 'lon_0': 0.0,\n", + " 'lat_0': -90.0,\n", + " 'ellps': 'WGS84'\n", + " },\n", + " 'extent': [-180, 180, -20, -90],\n", + " 'iLinewidth': 1.0,\n", + " 'jLinewidth': 1.0,\n", + " 'showGridCells': True,\n", + " 'title': 'Stereographic 6x6: Center=45S/270E(-90W)',\n", + " 'iColor': 'y',\n", + " 'jColor': 'k'\n", + " }\n", + ")\n", + "(figure, axes) = grd.plotGrid()\n", + "display(figure)\n", + "figure.savefig(os.path.join(plotDir, '6x6_sh_45s_270e.png'), dpi=None, facecolor='w', edgecolor='w',\n", + " orientation='portrait', transparent=False, bbox_inches=None, pad_inches=0.1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/gridtools/__init__.py b/gridtools/__init__.py index f52c669..0801262 100644 --- a/gridtools/__init__.py +++ b/gridtools/__init__.py @@ -27,8 +27,8 @@ # DeprecationWarning, module='docutils.io') # For __version__ add + to check if we are installing from a github repo -__version__ = '0.3.1+' -__released__ = '0.3.1' # used when Sphinx builds its own docs +__version__ = '0.3.2+' +__released__ = '0.3.2' # used when Sphinx builds its own docs #: Version info for better programmatic use. #: @@ -38,7 +38,7 @@ #: #: .. versionadded:: 1.2 #: Before version 1.2, check the string ``sphinx.__version__``. -version_info = (0, 3, 1, 'alpha', 0) +version_info = (0, 3, 2, 'alpha', 0) package_dir = path.abspath(path.dirname(__file__)) diff --git a/gridtools/app.py b/gridtools/app.py index 9803c88..e6f534d 100644 --- a/gridtools/app.py +++ b/gridtools/app.py @@ -671,7 +671,7 @@ def initializeWidgets(self): self.glatts = pn.widgets.Spinner(name="Latitude of True Scale(lat_ts) (-90 to 90)", value=40.0, step=1.0, start=-90.0, end=90.0, width=100) self.gtilt = pn.widgets.Spinner(name="Tilt (-90 to 90)", value=30.0, step=0.1, start=-90.0, end=90.0, width=100) self.gridCenterX = pn.widgets.Spinner(name='Grid Center(Longitude or X)', value=230.0, step=0.1, start=0.0, end=360.0, width=100) - self.gridCenterY = pn.widgets.Spinner(name='Grid Center(Latitude or Y)', value=40.0, step=0.1, start=0.0, end=90.0, width=100) + self.gridCenterY = pn.widgets.Spinner(name='Grid Center(Latitude or Y)', value=40.0, step=0.1, start=-90.0, end=90.0, width=100) self.gridCenterUnits = pn.widgets.Select(name='Grid Center Units', options=self.unitNames, value=self.unitNames[0]) self.gridControlUpdateButton = pn.widgets.Button(name='Make Grid', button_type='primary') self.gridControlUpdateButton.on_click(self.make_grid) diff --git a/gridtools/bathyutils.py b/gridtools/bathyutils.py index 684a918..7af9621 100644 --- a/gridtools/bathyutils.py +++ b/gridtools/bathyutils.py @@ -1,5 +1,5 @@ # Bathymetric tools -# Implementations of bathometric grid generators +# Implementation of bathometric grid generators and other utilities # - https://github.com/nikizadehgfdl/ocean_model_topog_generator # - compute_bathymetric_roughness_h2(**opts) @@ -315,10 +315,84 @@ def applyExistingOceanmask(grd, dsData, dsVariable, maskFile, maskVariable, **kw return workData['newDepth'] +def ice9(grd, **kwargs): + ''' + This is a implementation of the ice-9 algorithm for filling in disconnected ocean + bodies (lakes) for a given ocean grid. Be sure to specify anticipated + MINIMUM_DEPTH, MASKING_DEPTH and MAXIMUM_DEPTH that will be used for the + model run. + + :param grd: class object + :type grd: GridUtils + :param \**kwargs: + See below + + **Keyword arguments**: + + * *ocean_seeds* (``[(int, int)]``) -- + Provide ice-9 algorithm with one or more (j,i) ocean body grid points to designate + as areas that should be treated as areas of continuous ocean points. + If more than one seed is given, all the discovered wet points will be + merged together to form the final grid minus any detached ocean points (lakes). + NOTE: Only the first seed is used! Future releases will allow multiple seeds. + * *depth* (``grid``) -- + The depth grid to use for ice-9 algorithm. This should be the same size as + the provided latitude and logitude points defining the grid. Values are + positive for depth (water) and negative for height (land). + * *periodic* (``boolean``) -- + Tells the algorithm that the grid is periodic and should + check wrap points. Default: False + NOTE: Not implemented! + * *returnFields* (``list``) -- + List of fields to be returned in the grd object. Default: ['wetMask'] + * *MINIMUM_DEPTH* (``float``) -- minimum depth of ocean in meters. Default: 0.0 + * *MASKING_DEPTH* (``float``) -- masking depth of ocean in meters. Default: 0.0 + * *MAXIMUM_DEPTH* (``float``) -- maximum depth of ocean in meters. Default: -99999.0 + * *zEdits* (``boolean``) -- + Utilize zEdits for the provided depth field. Store any updates to the depth field + in zEdits as well. Default: False + NOTE: Not implemented! + + The ice-9 algorithm was first mentioned in a program written by Niki Zadeh in the + `ocean_model_topog_generator` repository. :cite:p:`Zadeh_2020_ocean_model_topog_generator` + + Another reference to the ice-9 algorithm is metioned in the + repository `regrid_runoff` by Alistair Adcroft. :cite:p:`Adcroft_2020_regrid_runoff`. + ''' + + # Run through each ocean_seed provided + # TODO: This only runs through the first seed + for oceanSeed in kwargs['ocean_seeds']: + depth = kwargs['depth'] + (nj, ni) = depth.shape + wetMask = xr.DataArray(data = np.zeros((nj, ni)), dims = ("ny", "nx")) + stack = set() + stack.add( oceanSeed ) + while stack: + (j,i) = stack.pop() + # If we are already marked wet or see a land point + # skip to the next point. + if wetMask[j,i] or depth[j,i] <= kwargs['MASKING_DEPTH']: continue + wetMask[j,i] = 1 + + # Check surrounding points + # For periodic boundaries, check wrap points + if i>0: stack.add( (j,i-1) ) + #else: stack.add( (j,ni-1) ) + if i0: stack.add( (j-1,i) ) + if j package_versions.txt") - # #self.grid.attrs['package_versions'] = str(pd.read_csv("package_versions.txt")) - # sysObj = sysinfo.SysInfo(grd=self) - # cmd = "conda list --explicit" - # (out, err, rc) = sysObj.runCommand(cmd) - # self.grid.attrs['package_versions'] = out - # #self.grid.attrs['package_versions'] = "/n".join(out) + # self.grid.attrs['projection'] = self.gridInfo['gridParameters']['projection']['name'] #except: - # #raise - # try: - # self.grid.attrs['conda_env'] = os.environ['CONDA_PREFIX'] - # except: - # self.grid.attrs['conda_env'] = "Conda environment not found." - # - # self.grid.attrs['package_versions'] = os.environ['CONDA_PREFIX'] + # pass - #try: - # response = requests.get("https://api.github.com/ESMG/gridtools/releases/latest") - # self.grid.attrs['software_version'] = print(response.json()["name"]) - #except: - # self.grid.attrs['software_version'] = "" + # Add additional metadata if available + #addMetadata = ['centerX', 'centerY', 'centerUnits', 'dx', 'dxUnits', 'dy', 'dyUnits', 'tilt'] + #for metaTag in addMetadata: + # if metaTag in self.gridInfo['gridParameters'].keys(): + # self.grid.attrs['grid_%s' % (metaTag)] = self.gridInfo['gridParameters'][metaTag] # Collect system metadata - sysObj = sysinfo.SysInfo(grd=self) - sysObj.loadVersionData() - self.grid.attrs['software_version'] = sysObj.dumpVersionData() + #sysObj = sysinfo.SysInfo(grd=self) + #sysObj.loadVersionData() + #self.grid.attrs['software_version'] = sysObj.dumpVersionData() - try: - self.grid.attrs['proj'] = self.gridInfo['gridParameters']['projection']['proj'] - except: - projString = self.formProjString(self.gridInfo['gridParameters']) - if projString: - self.grid.attrs['proj'] = projString - self.gridInfo['gridParameters']['projection']['proj'] = projString - else: - msg = "WARNING: Projection string could not be determined from grid parameters." - self.printMsg(msg, level=logging.WARNING) - self.debugMsg('') + # If the global attribute 'proj' is not set, try to set it using + # provided gridParameters. Use the global 'proj' attribute if + # already set. - #R = 6370.e3 # Radius of sphere - # TODO: get ellipse setting - #R = self._default_Re + #try: + # if not('proj' in self.grid.attrs.keys()): + # self.grid.attrs['proj'] = self.gridInfo['gridParameters']['projection']['proj'] + #except: + # projString = self.formProjString(self.gridInfo['gridParameters']) + # if projString: + # self.grid.attrs['proj'] = projString + # self.gridInfo['gridParameters']['projection']['proj'] = projString + # else: + # msg = "WARNING: Projection string could not be determined from grid parameters." + # self.printMsg(msg, level=logging.WARNING) + # self.debugMsg('') + + # Determine radius from provided metadata + # R = 6370.e3 # Radius of sphere (from original pyroms ROMS to MOM6 grid conversion script) + # R = self._default_Re # (GRS80 is the default for the proj python package) R = self.getRadius(self.gridInfo['gridParameters']) # Make a copy of the lon grid as values are changed for computation # xarray=0.19.0 requires unpacking of Dataset variables by using .data lon = self.grid.x.copy().data - lat = self.grid.y.data + lat = self.grid.y.copy().data # Approximate edge lengths as great arcs self.grid['dx'] = (('nyp', 'nx'), R * spherical.angle_through_center( (lat[ :,1:],lon[ :,1:]), (lat[: ,:-1],lon[: ,:-1]) )) @@ -582,12 +567,19 @@ def computeGridMetricsSpherical(self): # Presize the angle_dx array angle_dx = np.zeros(lat.shape) + angle2_dx = np.zeros(lat.shape) + + # This was commented out in the original conversion code? + #angle_dx[:,1:-1] = np.arctan2( (lat[:,2:] - lat[:,:-2]) , ((lon[:,2:] - lon[:,:-2]) * cos_lat[:,1:-1]) ) + #angle_dx[:, 0 ] = np.arctan2( (lat[:, 1] - lat[:, 0 ]) , ((lon[:, 1] - lon[:, 0 ]) * cos_lat[:, 0 ]) ) + #angle_dx[:,-1 ] = np.arctan2( (lat[:,-1] - lat[:,-2 ]) , ((lon[:,-1] - lon[:,-2 ]) * cos_lat[:,-1 ]) ) + # Fix lon so they are 0 to 360 for computation of angle_dx lon = np.where(lon < 0., lon+360, lon) - angle_dx[:,1:-1] = np.arctan2( (lat[:,2:] - lat[:,:-2]) , ((lon[:,2:] - lon[:,:-2]) * cos_lat[:,1:-1]) ) - angle_dx[:, 0 ] = np.arctan2( (lat[:, 1] - lat[:, 0 ]) , ((lon[:, 1] - lon[:, 0 ]) * cos_lat[:, 0 ]) ) - angle_dx[:,-1 ] = np.arctan2( (lat[:,-1] - lat[:,-2 ]) , ((lon[:,-1] - lon[:,-2 ]) * cos_lat[:,-1 ]) ) - self.grid['angle_dx'] = (('nyp', 'nxp'), angle_dx) + angle2_dx[:,1:-1] = np.arctan2( (lat[:,2:] - lat[:,:-2]) , ((lon[:,2:] - lon[:,:-2]) * cos_lat[:,1:-1]) ) + angle2_dx[:, 0 ] = np.arctan2( (lat[:, 1] - lat[:, 0 ]) , ((lon[:, 1] - lon[:, 0 ]) * cos_lat[:, 0 ]) ) + angle2_dx[:,-1 ] = np.arctan2( (lat[:,-1] - lat[:,-2 ]) , ((lon[:,-1] - lon[:,-2 ]) * cos_lat[:,-1 ]) ) + self.grid['angle_dx'] = (('nyp', 'nxp'), np.maximum(angle_dx, angle2_dx)) #self.grid.angle_dx.attrs['standard_name'] = 'grid_vertex_x_angle_WRT_geographic_east' #self.grid.angle_dx.attrs['units'] = 'degrees_east' self.grid['angle_dx'].attrs['units'] = 'radians' @@ -640,13 +632,20 @@ def formProjString(self, param): if 'R' in param['projection']: projString = "+R=%s %s" % (param['projection']['R'], projString) - if projString == None: + if projString is None: msg = "Unable to set projection string." self.printMsg(msg, level=logging.WARNING) self.debugMsg(msg) return projString + def getXYDist(self, x1, y1, x2, y2): + '''Compute distance between two points in x/y space.''' + + dst = math.sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2))) + + return dst + def makeGrid(self, setFilename=None): '''Using supplied grid parameters, populate a grid in memory.''' @@ -1020,6 +1019,10 @@ def makeGrid(self, setFilename=None): newGridCreated = True if newGridCreated: + # Show an informational message here + msg = "INFO: A new grid has been created." + self.printMsg(msg, level=logging.INFO) + # Fill in a tile name and geometry self.grid['tile'] = tileName self.grid.tile['geometry'] = geometryType @@ -1035,7 +1038,7 @@ def makeGrid(self, setFilename=None): except: msg = "WARNING: Projection string could not be determined from grid parameters." self.printMsg(msg, level=logging.WARNING) - self.debugMsg('') + self.debugMsg('') # Declare the xarray dataset open even though it is really only in memory at this point self.xrOpen = True @@ -1122,7 +1125,7 @@ def mesh_plot(self, lon, lat, lon0=0., lat0=90.): ax.coastlines() ax.gridlines() (nj,ni) = lon.shape - # plotting verticies + # plotting vertices for i in range(0,ni+1,2): ax.plot(lon[:,i], lat[:,i], 'k', transform=cartopy.crs.Geodetic()) for j in range(0,nj+1,2): @@ -1351,17 +1354,18 @@ def generate_regional_spherical_meters(self, cUnits, cX, cY, dx, dxU, dy, dyU, t if 'R' in pD.keys(): PROJSTRING = "%s +R=%f" % (PROJSTRING, pD['R']) - msg = 'Transformation proj string(%s)' % (PROJSTRING) + msg = 'Transformation PROJ (%s)' % (PROJSTRING) self.printMsg(msg, level=logging.INFO) # create the coordinate reference system crs = CRS.from_proj4(PROJSTRING) + # create the projection from lon/lat to x/y proj = Transformer.from_crs(crs.geodetic_crs, crs) - # compute (y, x) from (lon, lat) + # compute (x, y) from (lon, lat) gX, gY = proj.transform(cX, cY) - msg = 'Computing center point in meters: (%f, %f) to (%f, %f)' % (cY, cX, gX, gY) + msg = 'Computing center point in meters: (lat=%f, lon=%f) to (%f, %f)' % (cY, cX, gX, gY) self.printMsg(msg, level=logging.INFO) gMode = 1 @@ -1383,11 +1387,10 @@ def generate_regional_spherical_meters(self, cUnits, cX, cY, dx, dxU, dy, dyU, t x = np.arange(gX - halfDX, (gX + halfDX) + grX, grX, dtype=np.float32) y = np.arange(gY - halfDY, (gY + halfDY) + grY, grY, dtype=np.float32) - yy, xx = np.meshgrid(y, x) - - # compute (y, x) from (lon, lat) - lon, lat = proj.transform(yy, xx, direction='INVERSE') + xx, yy = np.meshgrid(x, y) + # compute (lon, lat) from (x, y) + lon, lat = proj.transform(xx, yy, direction='INVERSE') lam_ = lon phi_ = lat @@ -1433,7 +1436,7 @@ def generate_regional_spherical_degrees(self, cUnits, cX, cY, dx, dxU, dy, dyU, # xarray grid operations grid functions # Xarray Grid Operations Grid Functions - + def closeGrid(self): '''Closes and open dataset file pointer.''' if self.xrOpen: @@ -1449,11 +1452,11 @@ def convertGrid(self, target, **kwargs): :rtype: none Supported grid conversions: - +--------+--------+---------------------------------------------------+ - | SOURCE | TARGET | CODE CITATIONS | - +--------+--------+---------------------------------------------------+ - | ROMS | MOM6 | :cite:p:`Ilicak_2020_ROMS_to_MOM6` | - +--------+--------+---------------------------------------------------+ + +--------+--------+-----------------------------------------------------------------+ + | SOURCE | TARGET | CODE CITATIONS | + +--------+--------+-----------------------------------------------------------------+ + | ROMS | MOM6 | convert_ROMS_grid_to_MOM6.py :cite:p:`Ilicak_2020_ROMS_to_MOM6` | + +--------+--------+-----------------------------------------------------------------+ **Keyword arguments**: @@ -1744,7 +1747,7 @@ def readGrid(self, **kwargs): self.grid = self.grid.set_coords(['lon', 'lat']) else: - breakpoint() + pass @@ -1792,7 +1795,7 @@ def removeFillValueAttributes(self, data=None, stringVars=None): return ncEncoding - def saveGrid(self, filename=None, directory=None): + def saveGrid(self, filename=None, directory=None, enc=None): ''' This operation is destructive using the last known filename which can be overridden. ''' @@ -1815,13 +1818,160 @@ def saveGrid(self, filename=None, directory=None): # Save the grid here try: - self.grid.to_netcdf(self.xrFilename, encoding=self.removeFillValueAttributes()) + gridEncoding = self.removeFillValueAttributes() + if enc: + for vrb in ['x', 'y', 'dx', 'dy', 'angle_dx', 'area']: + gridEncoding[vrb] = {'dtype': enc} + self.grid.to_netcdf(self.xrFilename, encoding = gridEncoding) msg = "Successfully wrote netCDF file to %s" % (self.xrFilename) self.printMsg(msg, level=logging.INFO) except: msg = "Failed to write netCDF file to %s" % (self.xrFilename) self.printMsg(msg, level=logging.INFO) + def checkGridMetadata(self, kwargs, varKey, defaultValue, append=False): + ''' + Update or overwrite global metadata values based on keyword arguments. + + **Keyword arguments** + + * *append* (``boolean``) -- Updated metadata is appended to any + existing metadata. If the attribute does not exist, it is + added. + ''' + + returnValue = defaultValue + kwKeys = kwargs.keys() + gridKeys = self.grid.attrs.keys() + + # Use the submitted keyword value, otherwise use the default + if varKey in kwargs.keys(): + returnValue = kwargs[varKey] + + # If we are not to update the metadata, then we use + # the existing grid metadata value. If the existing + # value is None or empty, replace it with the new value. + currentValue = None + if varKey in gridKeys: + currentValue = self.grid.attrs[varKey] + + if kwargs['updateMetadata']: + if append: + if currentValue is not None: + if len(currentValue) == 0: + returnValue = "%s" % (returnValue) + else: + returnValue = "%s\n%s" % (currentValue, returnValue) + else: + if currentValue is not None: + if len(currentValue) > 0: + returnValue = self.grid.attrs[varKey] + else: + # No update permitted unless the existing global attribute + # is empty or missing + if currentValue is not None: + if len(currentValue) > 0: + returnValue = currentValue + + return returnValue + + def updateGridMetadata(self, **kwargs): + ''' + Generic routine to apply metadata to appropriate entries to the existing grid + loaded into the gridutils object. This also checks any existing gridParameters. + This attempts to set several attributes. If only setting one or two attributes, + consider using :func:`gridtools.gridutils.checkGridMetadata()`. + + **Keyword arguments**: + + * *updateMetadata* (``boolean``) -- Allow updates to metadata global attributes. + If False, existing metadata is not overwritten. If an attribute is missing, + the global attribute is added. Default: True + ''' + # If any keyword argument is unset, set to the default + utils.checkArgument(kwargs, 'updateMetadata', True) + + #self.grid.attrs['grid_version'] = "0.2" + self.grid.attrs['grid_version'] = self.checkGridMetadata(kwargs, 'grid_version', "0.2") + msg = "GridTools: %s" % (self.getVersion()) + self.grid.attrs['code_version'] = self.checkGridMetadata(kwargs, 'code_version', msg) + historyMsg = "%s: created grid with GridTools library" %\ + (datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) + #utils.checkArgument(kwargs, 'historyMsg', historyMsg) + #if 'history' in self.grid.attrs.keys(): + # self.grid.attrs['history'] = "%s\n%s" % (self.grid.attrs['history'], kwargs['historyMsg']) + #else: + # self.grid.attrs['history'] = kwargs['historyMsg'] + self.grid.attrs['history'] = self.checkGridMetadata(kwargs, 'history', historyMsg, append=True) + + if hasattr(self, 'gridInfo'): + if 'gridParameters' in self.gridInfo: + if 'projection' in self.gridInfo['gridParameters']: + if 'name' in self.gridInfo['gridParameters']['projection']: + self.grid.attrs['projection'] =\ + self.checkGridMetadata(kwargs, 'projection', self.gridInfo['gridParameters']['projection']['name']) + #try: + # self.grid.attrs['projection'] = self.gridInfo['gridParameters']['projection']['name'] + #except: + # pass + + # Add additional metadata if available + addMetadata = ['centerX', 'centerY', 'centerUnits', 'dx', 'dxUnits', 'dy', 'dyUnits', 'tilt'] + for metaTag in addMetadata: + if metaTag in self.gridInfo['gridParameters'].keys(): + #self.grid.attrs['grid_%s' % (metaTag)] = self.gridInfo['gridParameters'][metaTag] + globAttr = 'grid_%s' % (metaTag) + self.grid.attrs[globAttr] = self.checkGridMetadata(kwargs, globAttr, self.gridInfo['gridParameters'][metaTag]) + + # Collect system metadata + sysObj = sysinfo.SysInfo(grd=self) + sysObj.loadVersionData() + #self.grid.attrs['software_version'] = sysObj.dumpVersionData() + self.grid.attrs['software_version'] = self.checkGridMetadata(kwargs, 'software_version', sysObj.dumpVersionData()) + + # If the global attribute 'proj' is not set, try to set it using + # provided gridParameters. Use the global 'proj' attribute if + # already set. + + projString = None + + # If the grid has a 'proj' use it as the authority + if hasattr(self, 'grid'): + if 'proj' in self.grid.attrs.keys(): + projString = self.grid.attrs['proj'] + + # If 'proj' was not set, attempt to use a defined 'proj' in the + # projection parameters + if projString is None and hasattr(self, 'gridInfo'): + if 'gridParameters' in self.gridInfo: + if 'projection' in self.gridInfo['gridParameters']: + if 'proj' in self.gridInfo['gridParameters']['projection']: + projString = self.gridInfo['gridParameters']['projection']['proj'] + + # Last attempt to define projString + if projString is None: + projString = self.formProjString(self.gridInfo['gridParameters']) + + if projString is None: + msg = "WARNING: Grid metadata: grid projection could not be determined." + self.printMsg(msg, level=logging.WARNING) + else: + # If we get to this point, set the 'proj' parameters above + self.grid.attrs['proj'] = self.checkGridMetadata(kwargs, 'proj', projString) + self.gridInfo['gridParameters']['projection']['proj'] = projString + + #try: + # if not('proj' in self.grid.attrs.keys()): + # self.grid.attrs['proj'] = self.gridInfo['gridParameters']['projection']['proj'] + #except: + # projString = self.formProjString(self.gridInfo['gridParameters']) + # if projString: + # self.grid.attrs['proj'] = projString + # self.gridInfo['gridParameters']['projection']['proj'] = projString + # else: + # msg = "WARNING: Projection string could not be determined from grid parameters." + # self.printMsg(msg, level=logging.WARNING) + def makeSoloMosaic(self, **kwargs): ''' This replicates some of the processes of ``make_solo_mosaic`` from :cite:p:`GFDL_MSG_2021_FRE_nctools`. @@ -1853,6 +2003,8 @@ def makeSoloMosaic(self, **kwargs): * *relativeToINPUTDir* (``string``) -- absolute or relative path for mosaic files to the INPUT directory. Default: "./" .. note:: + Integers stored in the mosaic tiles must be 32 bit integers. If 64 bit integers are used, + the FMS coupler will die with invalid netcdf variable type. Using the defaults, this routine will write the following files to the ``INPUT`` directory with one tile named ``tile1``: @@ -1961,6 +2113,11 @@ def plotGrid(self, **kwargs): * *showModelGrid* (``boolean``) -- set False to hide the model grid. Default: True * *plotVariables* (``dict()``) -- one or more variables and plot parameters. Default: None + * *showGridPoints* (``list()``) -- list of grid points to show on the plot. The list contains + tuples of `(j,i)`, `(j,i,c)` or `(j,i,c,s)`. The default color (c) is `red` with a size + (s) of 5. To change just the size of the point, the color must also be specified. + NOTE: For MOM6 grids, the (j,i) refer to points on the supergrid. Points on the + regular grid should be multiples of two. **Keyword arguments for plotVariables**: @@ -1982,6 +2139,8 @@ def plotGrid(self, **kwargs): kwargs['showModelGrid'] = True if not('plotVariables' in kwargs.keys()): kwargs['plotVariables'] = dict() + if not('showGridPoints' in kwargs.keys()): + kwargs['showGridPoints'] = list() plotProjection = self.getPlotParameter('name', subKey='projection', default=None) @@ -2084,6 +2243,21 @@ def plotGrid(self, **kwargs): if j <= nj-1: ax.plot(self.grid['x'][j,:], self.grid['y'][j,:], jColor, linewidth=jLinewidth, transform=transform) + # Overplot specified grid points + for pts in kwargs['showGridPoints']: + jpt = pts[0] + ipt = pts[1] + defaultColor = "red" + defaultSize = 5.0 + ptlen = len(pts) + if ptlen == 3: + defaultColor = pts[2] + if ptlen == 4: + defaultColor = pts[2] + defaultSize = pts[3] + ax.scatter(self.grid['x'][jpt,ipt], self.grid['y'][jpt,ipt], + color=defaultColor, s=defaultSize, transform=transform, zorder=3.0) + # Loop through provided variables if kwargs['plotVariables']: for pVar in kwargs['plotVariables'].keys(): @@ -2118,8 +2292,6 @@ def plotGrid(self, **kwargs): # Configure plot parameters, title is covered up by the plot? ax = self.updateAxes(ax, kwargs['plotVariables'][pVar]) - #breakpoint() - return f, ax def setPlotCMap(self, varArgs): @@ -2182,6 +2354,360 @@ def deleteGridParameters(self, gList, subKey=None): self.gridInfo['gridParameterKeys'] = self.gridInfo['gridParameters'].keys() + def extendGrid(self, jStart, jEnd, iStart, iEnd, gridMethod='auto', gridProj='auto'): + '''Extend the current grid by jStart, jEnd, iStart, iEnd points using + the specified method. The grid can be extended using 'spherical' space + or 'latlon' space. If the method is 'auto', the routine tries to + determine which to use. The grid is extended in all directions + using the maximum of provided parameters and then clipped to + the proper dimensions. Grids extended using 'spherical' space + require the projection used when the grid was created to perform + forward and reverse transformation of coordinates. + + This function assumes an existing grid is present and that + the variables x and y are longitude and latitude. + + This function returns the extended grid. + + .. note:: + + Since MOM6 grids are defined with a supergrid, to extend + the regular grid one point in all directions, this routine + should specify to extend the grid two points in all + directions. + + **Grid Extension Technique**:: + + This description shows the extension of a grid by one point. This + also applies to any requested grid size. + + Process + + # Original grid (o); Points to fill (.) + # . . . . . + # . o o o . + # . o o o . + # . o o o . + # . . . . . + + # Step 1: Extend grid along j-direction + # New points shown by (A) + # . . . . . + # A o o o A + # A o o o A + # A o o o A + # . . . . . + # + + # Step 2: Extend grid along the i-direction + # New points shown by (B) + # B B B B B + # A o o o A + # A o o o A + # A o o o A + # B B B B B + + # Step 3: Clip grid back to requested size + # given by iStart, iEnd, jStart, jEnd. + + # To prepend one column of points, + # please specify extendGrid(0,0,1,0). + # The grid returned should look like: + # A o o o + # A o o o + # A o o o + + # To prepend one column of points and + # append a row of points to the end, + # please specify extendGrid(0,1,1,0). + # The grid returned should look like: + # B B B B + # A o o o + # A o o o + # A o o o + + ''' + + # Local variables + maxIncrease = max(jStart, jEnd, iStart, iEnd) + x = None + y = None + extGrid = xr.Dataset() + + # If gridMethod='auto' try to determine if we should extend + # the grid via 'spherical' or 'latlon'. + + if gridMethod == 'auto': + gridMethod = self.extendGridDetectMethod() + if not(gridMethod in ('spherical','latlon')): + msg = "ERROR: Unable to automatically detect grid type. Returning an empty grid." + self.printMsg(msg, level=logging.ERROR) + self.debugMsg(msg) + return extGrid + + # INFO + msg = ("INFO: Auto detected gridding method (%s)." % (gridMethod)) + self.printMsg(msg, level=logging.INFO) + + if gridProj == 'auto': + if hasattr(self.grid, 'attrs'): + gridAttr = self.grid.attrs.keys() + if 'proj' in gridAttr: + gridProj = self.grid.attrs['proj'] + + # INFO + msg = ("INFO: Auto detected projection details (%s)." % (gridProj)) + self.printMsg(msg, level=logging.INFO) + + # An existing grid should be present + try: + extGrid['x'] = self.grid['x'].copy() + extGrid['y'] = self.grid['y'].copy() + except: + msg = "ERROR: Existing grid not found. Returning an empty grid." + self.printMsg(msg, level=logging.ERROR) + self.debugMsg(msg) + return extGrid + + extGrid.attrs['extendedGrid'] = False + if gridMethod == 'spherical': + extGrid = self.extendGridSpherical(extGrid, maxIncrease, gridProj) + if gridMethod == 'latlon': + extGrid = self.extendGridLatLon(extGrid, maxIncrease) + + if extGrid.attrs['extendedGrid']: + # No need to do anything if requested size equals maxIncrease + if maxIncrease == iStart and maxIncrease == iEnd and maxIncrease == jStart and maxIncrease == jEnd: + return extGrid + # Clip extended grid to requested size + (ny, nx) = extGrid['x'].shape + clipGrid = xr.Dataset() + # Y/lat + jjStart = maxIncrease - jStart + jjEnd = ny - (maxIncrease - jEnd) + # X/lon + iiStart = maxIncrease - iStart + iiEnd = nx - (maxIncrease - iEnd) + print("Request:",jStart,jEnd,iStart,iEnd) + print("MaxIncrease:",maxIncrease) + print("Grid shape:",ny,nx) + print("Grid clip:",jjStart,jjEnd,iiStart,iiEnd) + clipGrid['x'] = extGrid['x'][jjStart:jjEnd,iiStart:iiEnd] + clipGrid['y'] = extGrid['y'][jjStart:jjEnd,iiStart:iiEnd] + extGrid = clipGrid + print("Grid shape:", extGrid['x'].shape) + else: + msg = "ERROR: Extending grid failed. Returning incomplete grid." + self.printMsg(msg, level=logging.ERROR) + self.debugMsg(msg) + + return extGrid + + def extendGridSpherical(self, inputGrid, maxIncrease, gridProj): + ''' + This uniformly extends the input grid by maxIncrease points using spherical coordinates + in meters. This function requires a grid projection to accurately perform the forward + and reverse transformation of grid points. + + To increase the grid size we need maxIncrease points on either size (twice as big). + ''' + + # create the coordinate reference system + crs = CRS.from_proj4(gridProj) + + # create the projection from lon/lat to x/y + projObj = Transformer.from_crs(crs.geodetic_crs, crs) + + # Transform lat/lon to spherical coordinates + gX, gY = projObj.transform(inputGrid['x'], inputGrid['y']) + + # Start with an empty grid + extGrd = xr.Dataset() + extGrd.attrs['extendedGrid'] = True + + # Get current size of input grid + (nyp, nxp) = inputGrid['x'].shape + + # Create extended grid with new size + x = np.zeros((nyp+(maxIncrease*2), nxp+(maxIncrease*2))) + y = np.zeros((nyp+(maxIncrease*2), nxp+(maxIncrease*2))) + + # Place array and dimensions into the new grid + # Copy input grid into the center of the new grid + extGrd['x'] = (('nyp', 'nxp'), x) + extGrd['y'] = (('nyp', 'nxp'), y) + extGrd['x'][maxIncrease:nyp+maxIncrease,maxIncrease:nxp+maxIncrease] = inputGrid['x'][:,:] + extGrd['y'][maxIncrease:nyp+maxIncrease,maxIncrease:nxp+maxIncrease] = inputGrid['y'][:,:] + # Get the shape of the new grid + (extyp, extxp) = x.shape + + # Extend grid along j-direction using meters and transform back to + # latitude and longitude. + for j in range(0, nyp): + (newY, newX) = self.findLineFromPoints(gY[j,:], gX[j,:], maxIncrease, maxIncrease) + newLon, newLat = projObj.transform(newX, newY, direction='INVERSE') + ind = maxIncrease + for newPt in range(0, maxIncrease): + extGrd['x'][j+maxIncrease,ind-1] = newLon[(newPt*2)] + extGrd['y'][j+maxIncrease,ind-1] = newLat[(newPt*2)] + extGrd['x'][j+maxIncrease,extxp-ind] = newLon[(newPt*2)+1] + extGrd['y'][j+maxIncrease,extxp-ind] = newLat[(newPt*2)+1] + ind = ind - 1 + + # Extend grid along i-direction using meters and transform back to + # latitude and longitude coordinates. Need to include + # the extended points in the j-direction to find + # the corners. + for i in range(0, extxp): + lon = extGrd['x'][maxIncrease:extyp-maxIncrease,i].data + lat = extGrd['y'][maxIncrease:extyp-maxIncrease,i].data + gXX, gYY = projObj.transform(lon, lat) + (newY, newX) = self.findLineFromPoints(gYY, gXX, maxIncrease, maxIncrease) + newLon, newLat = projObj.transform(newX, newY, direction='INVERSE') + ind = maxIncrease + for newPt in range(0, maxIncrease): + extGrd['x'][ind-1,i] = newLon[(newPt*2)] + extGrd['y'][ind-1,i] = newLat[(newPt*2)] + extGrd['x'][extyp-ind,i] = newLon[(newPt*2)+1] + extGrd['y'][extyp-ind,i] = newLat[(newPt*2)+1] + ind = ind - 1 + + return extGrd + + def extendGridLatLon(self, inputGrid, maxIncrease): + ''' + This uniformly extends the input grid by maxIncrease points using latitude and longitude + coordinates in degrees. + + To increase the grid size we need maxIncrease points on either size (twice as big). + ''' + + # Start with an empty grid + extGrd = xr.Dataset() + extGrd.attrs['extendedGrid'] = True + + # Get shape of the input grid + (nyp, nxp) = inputGrid['x'].shape + + # Create extended grid with new size + x = np.zeros((nyp+(maxIncrease*2), nxp+(maxIncrease*2))) + y = np.zeros((nyp+(maxIncrease*2), nxp+(maxIncrease*2))) + + # Place array and dimensions into the new grid + # Copy input grid into the center of the new grid + extGrd['x'] = (('nyp', 'nxp'), x) + extGrd['y'] = (('nyp', 'nxp'), y) + extGrd['x'][maxIncrease:nyp+maxIncrease,maxIncrease:nxp+maxIncrease] = inputGrid['x'][:,:] + extGrd['y'][maxIncrease:nyp+maxIncrease,maxIncrease:nxp+maxIncrease] = inputGrid['y'][:,:] + # Get the shape of the new grid + (extyp, extxp) = x.shape + + # Extend grid along j-direction using latitude + # and longitude coordinates. + for j in range(0, nyp): + (newLat, newLon) = self.findLineFromPoints(inputGrid['y'][j,:], inputGrid['x'][j,:], maxIncrease, maxIncrease) + ind = maxIncrease + for newPt in range(0, maxIncrease): + # jStart (head) + extGrd['x'][j+maxIncrease,ind-1] = newLon[(newPt*2)] + extGrd['y'][j+maxIncrease,ind-1] = newLat[(newPt*2)] + # jEnd (tail) + extGrd['x'][j+maxIncrease,extxp-ind] = newLon[(newPt*2)+1] + extGrd['y'][j+maxIncrease,extxp-ind] = newLat[(newPt*2)+1] + ind = ind - 1 + + # Extend grid along i-direction using latitude + # and longitude coordinates. Need to include + # the extended points in the j-direction to find + # the corners. + for i in range(0, extxp): + xpts = extGrd['x'][maxIncrease:extyp-maxIncrease,i].data + ypts = extGrd['y'][maxIncrease:extyp-maxIncrease,i].data + (newLat, newLon) = self.findLineFromPoints(ypts, xpts, maxIncrease, maxIncrease) + ind = maxIncrease + for newPt in range(0, maxIncrease): + extGrd['x'][ind-1,i] = newLon[(newPt*2)] + extGrd['y'][ind-1,i] = newLat[(newPt*2)] + extGrd['x'][extyp-ind,i] = newLon[(newPt*2)+1] + extGrd['y'][extyp-ind,i] = newLat[(newPt*2)+1] + ind = ind - 1 + + return extGrd + + def extendGridDetectMethod(self): + ''' + This function looks at the grid metadata and searches for hints + to see how the grid should be extended. + + **Sources probed for information**: + + * Global attribute: projection + * Variable 'tile' attribute: geometry + ''' + + # Simple cases + if hasattr(self.grid, 'attrs'): + gridAttr = self.grid.attrs.keys() + if 'projection' in gridAttr: + gridProjection = self.grid.attrs['projection'] + if gridProjection == 'Mercator': + return 'latlon' + if gridProjection in ('LambertConformalConic','Stereographic'): + return 'spherical' + if 'proj' in gridAttr: + projString = self.grid.attrs['proj'] + if projString.find('proj=lcc') >=0 or projString.find('proj=stere') >=0: + return 'spherical' + if projString.find('proj=merc') >=0: + return 'latlon' + + if hasattr(self.grid, 'variables'): + gridVars = self.grid.variables.keys() + if 'tile' in gridVars: + tileAttr = self.grid.variables['tile'].attrs.keys() + if 'geometry' in tileAttr: + gridGeometry = self.grid.variables['tile'].attrs['geometry'] + if gridGeometry == 'spherical': + return 'spherical' + # This may not be right + return 'latlon' + + return None + + + def findLineFromPoints(self, ptsY, ptsX, nY, nX): + '''Find the extension points at the end of given set of points. + This routine assumes a nearly linear regularly spaced array of points + is provided. + + Returned are the new points on the given line. + + ([y1, y2], [x1, x2]) where (y1, x1) is the head of + the line and (y2, x2) is the tail of the line. + + NOTE: Number of points to extend should be the same nY = nX. If + the points are not regularly spaced, extension of a line with + a large number of points is not going to work very well. + ''' + + newy = [] + newx = [] + + diffY = np.diff(ptsY) + diffX = np.diff(ptsX) + + # lat + for ind in range(1, nY+1): + newy.append(ptsY[0] - (diffY[0]*ind)) + newy.append(ptsY[-1] + (diffY[-1]*ind)) + + # lon + for ind in range(1, nX+1): + newx.append(ptsX[0] - (diffX[0]*ind)) + newx.append(ptsX[-1] + (diffX[-1]*ind)) + + return (newy, newx) + def getGridParameter(self, gkey, subKey=None, default=None, inform=True): '''Return the requested grid parameter or the default if none is available. The routine will emit a message by default. Use inform=False to suppress @@ -2290,6 +2816,37 @@ def showGridParameters(self): self.printMsg("%20s: %s" % (k,self.gridInfo['gridParameters'][k]), level=logging.INFO) else: self.printMsg("No grid parameters found.", level=logging.ERROR) + + def subsetGrid(self, scaleFactor): + """Subsets current grid by the specified scale factor. Scale factor must + be an integer and be evenly divisble into the regular grid. A subsetted + grid is returned or None on any error. + """ + + # Get regular grid size + (nyp, nxp) = self.grid['x'].shape + ny = int((nyp - 1) / 2) + nx = int((nxp - 1) / 2) + + # Check for grids that are not divisible by the scale factor + if ny % scaleFactor != 0 or nx % scaleFactor != 0: + self.printMsg(".", level=logging.ERROR) + return None + + newGrd = gridtools.gridutils.GridUtils() + newGrd.grid['x'] = self.grid['x'][::scaleFactor,::scaleFactor] + newGrd.grid['y'] = self.grid['y'][::scaleFactor,::scaleFactor] + + # Copy global level metadata + for attr in self.grid.attrs.keys(): + newGrd.grid.attrs[attr] = self.grid.attrs[attr] + + # Recompute metrics + history = "%s: subset grid with GridTools.subsetGrid() using scale factor %d" %\ + (datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), scaleFactor) + newGrd.computeGridMetricsSpherical(history=history) + + return newGrd # plot parameter operations plot parameter routines # Plot Parameter Operations Plot Parameter Routines @@ -2453,7 +3010,7 @@ def setPlotParameters(self, plotParameters, subKey=None): self.gridInfo['plotParameterKeys'] = self.gridInfo['plotParameters'].keys() # data source operations data source routines - # Data source operations Data source routines + # Data Source Operations Data Source Routines def addDataSource(self, dataSource, delete=False): '''Add a data source to the catalog. See: datasource.addDataSource()''' @@ -2742,9 +3299,22 @@ def applyExistingOceanmask(self, dsData, dsVariable, maskFile, maskVariable, **k return bathyutils.applyExistingOceanmask(self, dsData, dsVariable, maskFile, maskVariable, **kwargs) def computeBathymetricRoughness(self, dsName, **kwargs): - '''This generates h2 and other fields. See: bathytools.computeBathymetricRoughness()''' + '''This generates h2 and other fields. + See: :func:`gridtools.bathyutils.computeBathymetricRoughness()`''' from . import bathyutils - return bathyutils.computeBathymetricRoughness(self, dsName, **kwargs) + roughnessGrids = bathyutils.computeBathymetricRoughness(self, dsName, **kwargs) + + # Add history metadata + return roughnessGrids + + def ice9(self, **kwargs): + '''This calls the ice-9 algorithm from bathyutils. + See: :func:`gridtools.bathyutils.ice9()`''' + from . import bathyutils + ice9Grids = bathyutils.ice9(self, **kwargs) + + # Add history metadata + return ice9Grids # meshutils routines diff --git a/gridtools/meshutils.py b/gridtools/meshutils.py index e99b763..8b3df3b 100644 --- a/gridtools/meshutils.py +++ b/gridtools/meshutils.py @@ -21,8 +21,16 @@ def writeLandmask(grd, dsData, dsVariable, outVariable, outFile, **kwargs): dsDataset = xr.Dataset() dsDataset[outVariable] = xr.where(dsData[dsVariable] <= masking_depth, 1.0, 0.0) dsDataset[outVariable].attrs['sha256'] = utils.sha256sum(dsDataset[outVariable]) - dsDataset['x'] = dsData['x'] - dsDataset['y'] = dsData['y'] + # Try to copy coordinates from the supplied variable otherwise, try + # the supplied grid. + copyCoords = ['x', 'y'] + for varCoord in copyCoords: + if hasattr(dsData, varCoord): + dsDataset[varCoord] = dsData[varCoord] + else: + if hasattr(grd, varCoord): + dsDataset[varCoord] = grd[varCoord] + dsDataset.to_netcdf(outFile, encoding=grd.removeFillValueAttributes(data=dsDataset)) return @@ -45,6 +53,14 @@ def writeOceanmask(grd, dsData, dsVariable, outVariable, outFile, **kwargs): dsDataset = xr.Dataset() dsDataset[outVariable] = xr.where(dsData[dsVariable] > masking_depth, 1.0, 0.0) dsDataset[outVariable].attrs['sha256'] = utils.sha256sum(dsDataset[outVariable]) - dsDataset['x'] = dsData['x'] - dsDataset['y'] = dsData['y'] + # Try to copy coordinates from the supplied variable otherwise, try + # the supplied grid. + copyCoords = ['x', 'y'] + for varCoord in copyCoords: + if hasattr(dsData, varCoord): + dsDataset[varCoord] = dsData[varCoord] + else: + if hasattr(grd, varCoord): + dsDataset[varCoord] = grd[varCoord] + dsDataset.to_netcdf(outFile, encoding=grd.removeFillValueAttributes(data=dsDataset)) diff --git a/requirements.txt b/requirements.txt index c536eca..7ae4f08 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,16 +1,14 @@ -cartopy colorama colorcet coverage cython dask -datashader +datashader==0.13.0 docutils==0.16 -geoviews -hvplot +geoviews==1.9.1 +hvplot==0.7.2 jupyterlab matplotlib -m2r2 netCDF4 numba numpy diff --git a/source/references.bib b/source/references.bib index ded8de4..a5e0f40 100644 --- a/source/references.bib +++ b/source/references.bib @@ -48,6 +48,17 @@ @article{IBCAO_Version_3 journal = {Geophysical Research Letters}, } +@misc{Adcroft_2020_regrid_runoff, + author = {A. Adcroft}, + title = "Conservatively re-grids runoff data to the nearest coastal wet-point of a MOM6 ocean grid", + organization = {adcroft}, + commit = {ea890c0625a747320b17053e0196df0822347d45}, + branch = {master}, + URL = "https://github.com/adcroft/regrid_runoff", + month = {Jun}, + year = 2020, +} + @misc{Adcroft_2019_numpypi, author = {A. Adcroft}, title = "Quick test of how portable intrinsics can be", @@ -80,6 +91,16 @@ @misc{Zadeh_2020_ocean_model_topog_generator year = 2020, } +@misc{Zadeh_2020_grid_generation, + author = {N. Zadeh}, + title = "A collection of tools and documents for creating finite element tripolar grids for MOM based ocean models", + organization = {nikizadehgfdl}, + commit = {136ffe549c8d9039d50a806833de839474b208e0}, + URL = "https://github.com/nikizadehgfdl/grid_generation/commit/136ffe549c8d9039d50a806833de839474b208e0", + month = {Feb}, + year = 2020, +} + @misc{Ilicak_2020_ROMS_to_MOM6, author = {M. Ilicak and A. Adcroft and M. Harrison}, title = "ROMS to MOM6 grid converter", diff --git a/source/tutorials/GridtoolsOperationalPaths.png b/source/tutorials/GridtoolsOperationalPaths.png new file mode 100644 index 0000000..e6cb874 Binary files /dev/null and b/source/tutorials/GridtoolsOperationalPaths.png differ diff --git a/source/tutorials/GridtoolsOperationalPaths_0.3.0.png b/source/tutorials/GridtoolsOperationalPaths_0.3.0.png deleted file mode 100644 index 0880878..0000000 Binary files a/source/tutorials/GridtoolsOperationalPaths_0.3.0.png and /dev/null differ diff --git a/source/tutorials/index.rst b/source/tutorials/index.rst index a19e6bf..c2cc132 100644 --- a/source/tutorials/index.rst +++ b/source/tutorials/index.rst @@ -4,7 +4,7 @@ Tutorials The tutorials in this section explore some of the operational pathways provided by the gridtools library. -.. image:: GridtoolsOperationalPaths_0.3.0.png +.. image:: GridtoolsOperationalPaths.png .. toctree:: :maxdepth: 2