├── .github
└── workflows
│ └── publish-to-test-pypi.yml
├── .gitignore
├── .idea
├── .gitignore
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── modules.xml
├── stompy.iml
└── vcs.xml
├── .readthedocs.yaml
├── LICENSE
├── MANIFEST
├── README.md
├── docs
├── .gitignore
├── Makefile
├── conf.py
├── images
│ ├── composite-shp-table.png
│ ├── composite-shp-zoom.png
│ ├── composite-shp.png
│ ├── dcc-dredged.png
│ └── dcc-original.png
├── index.rst
├── make.bat
├── stompy.filters.rst
├── stompy.grid.rst
├── stompy.harm_decomp.rst
├── stompy.io.local.rst
├── stompy.io.rst
├── stompy.model.delft.rst
├── stompy.model.pypart.rst
├── stompy.model.rst
├── stompy.model.suntans.rst
├── stompy.nanpsd.rst
├── stompy.parse_interval.rst
├── stompy.plot.rst
├── stompy.priority_queue.rst
├── stompy.rst
├── stompy.scriptable.rst
├── stompy.spatial.rst
├── stompy.tidal_datum.rst
├── stompy.tide_consts.rst
├── stompy.undoer.rst
├── stompy.utils.rst
├── stompy.weighted_kde.rst
└── stompy.xr_utils.rst
├── examples
├── .gitignore
├── Stream Quiver.ipynb
├── convert_sun_to_dfm.py
├── curvilinear_grids.py
├── dev_openfoam.py
├── dfm_dwaq
│ ├── .gitignore
│ ├── README.md
│ ├── basic_test.py
│ ├── dflow-template.mdu
│ ├── local_config.py.in
│ └── sample_output.png
├── dwaq_adjust_bc_fluxes.py
├── dwaq_data_handling.ipynb
├── dwaq_map_to_nc.py
├── filtering.ipynb
├── filtering.pdf
├── openfoam.ipynb
├── plot_dflow_map.ipynb
├── plot_dwaq_output.py
├── shp_lines_to_polygons.py
├── transects_0.ipynb
└── unstructured_grid_plotting.ipynb
├── pyproject.toml
├── requirements-rtd.txt
├── requirements.txt
├── setup.py
├── stompy
├── .gitignore
├── __init__.py
├── filters.py
├── grid
│ ├── __init__.py
│ ├── cgal_line_walk.py
│ ├── cli.py
│ ├── depth_connectivity.py
│ ├── exact_delaunay.py
│ ├── extrude_openfoam.py
│ ├── front.py
│ ├── geom_types.py
│ ├── gmsh_scale_helper.py
│ ├── live_dt.py
│ ├── merge_ugrid_subgrids.py
│ ├── multi_ugrid.py
│ ├── optimize_grid.py
│ ├── orthogonalize.py
│ ├── orthomaker.py
│ ├── paver.py
│ ├── paver_opt_mixin.py
│ ├── quad_grower.py
│ ├── quad_laplacian.py
│ ├── quad_refine.py
│ ├── rebay.py
│ ├── sample_to_rectilinear.py
│ ├── shadow_cdt.py
│ ├── smoother.py
│ ├── tom.py
│ ├── topojson.py
│ ├── triangulate_hole.py
│ ├── trigrid.py
│ ├── ugrid.py
│ └── unstructured_grid.py
├── harm_decomp.py
├── io
│ ├── __init__.py
│ ├── dss.py
│ ├── landxml.py
│ ├── local
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── asos.py
│ │ ├── cdec.py
│ │ ├── cdip_mop.py
│ │ ├── cimis.py
│ │ ├── coamps.py
│ │ ├── common.py
│ │ ├── hycom.py
│ │ ├── jodc_mooring.py
│ │ ├── ndbc.py
│ │ ├── noaa_coops.py
│ │ ├── polaris.py.old
│ │ ├── sfsu_wind.py
│ │ ├── uk_tides.py
│ │ ├── usgs_nwis.py
│ │ ├── usgs_sfbay.py
│ │ └── usgs_sfbay_station_locations.csv
│ ├── match_datasets.py
│ ├── nmea.py
│ ├── qnc.py
│ ├── rbr.py
│ ├── rdb.py
│ ├── rdb_codes.py
│ ├── rdb_datadescriptors.py
│ ├── rdradcp.py
│ ├── rdradcp_xr.py
│ ├── seaduck.py
│ ├── sontek.py
│ ├── usgs_parm_codes.tsv
│ ├── vtk.py
│ └── wocss
│ │ ├── .gitignore
│ │ ├── GSwoxB1.f
│ │ ├── Makefile
│ │ ├── NOTES
│ │ ├── plots.py
│ │ ├── raob_soundings25653.cdf
│ │ ├── rundat.dat
│ │ ├── terrain.dat
│ │ └── winds.dat
├── memoize.py
├── model
│ ├── __init__.py
│ ├── data_comparison.py
│ ├── delft
│ │ ├── .gitignore
│ │ ├── CODE_GUIDE.txt
│ │ ├── __init__.py
│ │ ├── custom_process.py
│ │ ├── data
│ │ │ ├── defaults-2021.03.mdu
│ │ │ ├── defaults-2023.02.mdu
│ │ │ ├── defaults-r53925.mdu
│ │ │ ├── trim-tut_fti_waq.dat
│ │ │ ├── trim-tut_fti_waq.def
│ │ │ ├── tut_fti_waq-bal.his
│ │ │ ├── tut_fti_waq.hda
│ │ │ └── tut_fti_waq.hdf
│ │ ├── dflow_grid.py
│ │ ├── dflow_model.py
│ │ ├── dfm_bc.py
│ │ ├── dfm_grid.py
│ │ ├── dfm_to_ptm.py
│ │ ├── hydro_utils.py
│ │ ├── io.py
│ │ ├── map_merge.py
│ │ ├── map_merge_ondemand.py
│ │ ├── nefis.py
│ │ ├── nefis_dev.py
│ │ ├── nefis_nc.py
│ │ ├── paradelft.py
│ │ ├── process_diagram.py
│ │ ├── splice_waq.py
│ │ ├── sundwaq.py
│ │ ├── test_agg.py
│ │ ├── test_dflow_grid.py
│ │ ├── test_nefis.py
│ │ ├── test_waq_process.py
│ │ ├── test_waq_scenario.py
│ │ ├── waq_hydro_editor.py
│ │ ├── waq_process.py
│ │ ├── waq_scenario.py
│ │ └── z_layer_aggregator.py
│ ├── dem_to_csgraph.py
│ ├── dsm2.py
│ ├── fish_ptm
│ │ ├── ptm_config.py
│ │ ├── ptm_tools.py
│ │ └── shp2polygons.py
│ ├── fvcom
│ │ ├── __init__.py
│ │ └── fvcom.py
│ ├── hydro_model.py
│ ├── openfoam
│ │ ├── cli.py
│ │ ├── depth_average.py
│ │ └── mesh_ops.py
│ ├── otps
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── otps_model.py
│ │ └── read_otps.py
│ ├── pypart
│ │ ├── __init__.py
│ │ ├── basic.py
│ │ └── ketefian.py
│ ├── ras
│ │ ├── ras.py
│ │ └── result_reader.py
│ ├── schism
│ │ ├── data
│ │ │ ├── param.nml
│ │ │ └── sediment.nml
│ │ └── schism_model.py
│ ├── slurm_mixin.py
│ ├── stream_tracer.py
│ ├── suntans
│ │ ├── __init__.py
│ │ ├── data
│ │ │ └── suntans.dat
│ │ ├── depender.py
│ │ ├── domain.py
│ │ ├── forcing.py
│ │ ├── store_file.py
│ │ ├── sun_driver.py
│ │ ├── sunreader.py
│ │ ├── timeseries.py
│ │ └── transect.py
│ ├── unstructured_diffuser.py
│ └── water_column.py
├── nanpsd.py
├── parse_interval.py
├── plot
│ ├── __init__.py
│ ├── cmap.py
│ ├── cmaps
│ │ ├── 001-fire.cpt
│ │ ├── 00_bw_linear.cpt
│ │ ├── BkBlAqGrYeOrReViWh200.cpt
│ │ ├── BlueYellowRed.cpt
│ │ ├── Blue_Cyan_Yellow.cpt
│ │ ├── Blue_Yellow_CCW.cpt
│ │ ├── DEM_screen.cpt
│ │ ├── GMT_cyclic.cpt
│ │ ├── GMT_drywet.cpt
│ │ ├── Primary_04.cpt
│ │ ├── RdYlGn.ggr
│ │ ├── Spectral.ggr
│ │ ├── Split_Complementary_01a.cpt
│ │ ├── Split_Complementary_07.cpt
│ │ ├── StepSeq25.cpt
│ │ ├── Tertiary_01b.cpt
│ │ ├── ViBlGrWhYeOrRe.cpt
│ │ ├── WhViBlGrYeOrReWh.cpt
│ │ ├── YlOrRd_09.ggr
│ │ ├── __init__.py
│ │ ├── arctic.cpt
│ │ ├── aspectcolr.cpt
│ │ ├── bath_114.cpt
│ │ ├── brightsong2.cpt
│ │ ├── butterflyfairy.cpt
│ │ ├── caleblack.cpt
│ │ ├── cbcSpectral.cpt
│ │ ├── cequal.cpt
│ │ ├── colormaps.png
│ │ ├── cyanotype_01.cpt
│ │ ├── diverging.cpt
│ │ ├── dkbluered.cpt
│ │ ├── es_platinum_06.cpt
│ │ ├── f-30-31-32.cpt
│ │ ├── haxby.cpt
│ │ ├── hot_and_cold.cpt
│ │ ├── hot_desaturated.cpt
│ │ ├── iris1.cpt
│ │ ├── ncview_banded.cpt
│ │ ├── nonlinear_gray01.ggr
│ │ ├── nrl_sirkes.cpt
│ │ ├── nrl_sirkes_nowhite.cpt
│ │ ├── oc-sst.cpt
│ │ ├── parrot.cpt
│ │ ├── pm3d14.cpt
│ │ ├── poison.cpt
│ │ ├── saga-01.cpt
│ │ ├── saga-02.cpt
│ │ ├── saga-13.cpt
│ │ ├── saga-16.cpt
│ │ ├── salinity_bgy1.ggr
│ │ ├── salinity_bgy2.ggr
│ │ ├── salinity_bgy3.ggr
│ │ ├── scoutie.cpt
│ │ ├── slyphide.cpt
│ │ ├── srtGreys05.cpt
│ │ ├── temperature.cpt
│ │ ├── turbo.cpt
│ │ └── wave.cpt
│ ├── contour_transect.py
│ ├── ggr.py
│ ├── mkanim.py
│ ├── mpl15.py
│ ├── nbviz.py
│ ├── plot_utils.py
│ ├── plot_wkb.py
│ └── stream_quiver.py
├── priority_queue.py
├── scriptable.py
├── spatial
│ ├── __init__.py
│ ├── algorithms.py
│ ├── constrained_delaunay.py
│ ├── field.py
│ ├── gen_spatial_index.py
│ ├── generate_dem.py
│ ├── geom_types.py
│ ├── interpXYZ.py
│ ├── interp_4d.py
│ ├── interp_concentric.py
│ ├── interp_coverage.py
│ ├── interp_nn.py
│ ├── interp_orthogonal.py
│ ├── join_features.py
│ ├── kdtree_spatialindex.py
│ ├── linestring_utils.py
│ ├── medial_axis.py
│ ├── proj_utils.py
│ ├── qgis_spatialindex.py
│ ├── rasterize_stl.py
│ ├── robust_predicates.py
│ └── wkb2shp.py
├── tidal_datum.py
├── tide_consts.py
├── tide_consts.txt
├── undoer.py
├── utils.py
├── weighted_kde.py
├── xr_transect.py
└── xr_utils.py
└── test
├── .gitignore
├── data
├── .gitignore
├── Ex1.g01.hdf
├── WET.grd
├── WET_DEM.dep
├── coyote.rdb
├── dem_sources.dbf
├── dem_sources.prj
├── dem_sources.qpj
├── dem_sources.shp
├── dem_sources.shx
├── depth.xyz
├── dumbarton.dbf
├── dumbarton.prj
├── dumbarton.shp
├── dumbarton.shx
├── lsb_combined_v14_net.nc
├── scale-lines.dbf
├── scale-lines.prj
├── scale-lines.qpj
├── scale-lines.shp
├── scale-lines.shx
├── scale.dbf
├── scale.prj
├── scale.qpj
├── scale.shp
├── scale.shx
├── section_hydro.txt
├── sfbay
│ ├── cells.dat
│ ├── edges.dat
│ └── points.dat
├── temp-transect.nc
└── test_rdb.rdb
├── dev_cgal_shadow.py
├── dev_cost.py
├── dev_crash.py
├── dev_dfm_to_ptm.py
├── dev_front.py
├── dev_grayscott.py
├── dev_mpi_ugrid.py
├── dev_sms.py
├── dev_tidal_fill.py
├── dev_waq_hydro_editor.py
├── dflow-template.mdu
├── test_cgal_line_walk.py
├── test_cgal_triangulation.py
├── test_cimis.py
├── test_cmap.py
├── test_coamps.py
├── test_constrained_delaunay.py
├── test_dfm.py
├── test_dfm_grid.py
├── test_dfm_to_ptm.py
├── test_exact_delaunay.py
├── test_exact_delaunay2.py
├── test_field.py
├── test_filters.py
├── test_front.py
├── test_front_speed.py
├── test_gen_spatial_index.py
├── test_harm_decomp.py
├── test_lag.py
├── test_live_dt.py
├── test_merge_grids.py
├── test_noaa_coops.py
├── test_otps.py
├── test_paver.py
├── test_paver_purepy.py
├── test_py_apollonius.py
├── test_quad_front.py
├── test_rbr.py
├── test_rdb.py
├── test_read_ras.py
├── test_shadow_cdt.py
├── test_tom.sh
├── test_transect.py
├── test_transect_contour.py
├── test_trigrid.py
├── test_uk_tides.py
├── test_unstructured_grid.py
├── test_unstructured_grid_plot.py
├── test_usgs_nwis.py
├── test_utils.py
├── test_waq_hydro_editor.py
├── test_waq_scenario.py
├── test_wkb2shp.py
└── test_xr_transect.py
/.github/workflows/publish-to-test-pypi.yml:
--------------------------------------------------------------------------------
1 | name: Publish Python distribution to PyPI and TestPyPI
2 |
3 | on: push
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | dist
3 | build
4 | *~
5 | dev
6 | .ipynb_checkpoints
7 | /stompy_ocean.egg-info/
8 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/stompy.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | #build:
4 | # tools:
5 |
6 |
7 | sphinx:
8 | configuration: docs/conf.py
9 |
10 | python:
11 | install:
12 | - requirements-rtd.txt
13 |
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Rusty Holleman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/MANIFEST:
--------------------------------------------------------------------------------
1 | # file GENERATED by distutils, do NOT edit
2 | setup.py
3 | stompy/__init__.py
4 | stompy/filters.py
5 | stompy/harm_decomp.py
6 | stompy/nanpsd.py
7 | stompy/parse_interval.py
8 | stompy/priority_queue.py
9 | stompy/scriptable.py
10 | stompy/tidal_datum.py
11 | stompy/tide_consts.py
12 | stompy/undoer.py
13 | stompy/utils.py
14 | stompy/weighted_kde.py
15 | stompy/xr_utils.py
16 | stompy/grid/__init__.py
17 | stompy/grid/depth_connectivity.py
18 | stompy/grid/exact_delaunay.py
19 | stompy/grid/front.py
20 | stompy/grid/merge_ugrid_subgrids.py
21 | stompy/grid/orthogonalize.py
22 | stompy/grid/orthomaker.py
23 | stompy/grid/paver.py
24 | stompy/grid/tom.py
25 | stompy/grid/trigrid.py
26 | stompy/grid/ugrid.py
27 | stompy/grid/unstructured_grid.py
28 | stompy/io/__init__.py
29 | stompy/io/match_datasets.py
30 | stompy/io/qnc.py
31 | stompy/io/rbr.py
32 | stompy/io/rdb.py
33 | stompy/io/rdb_codes.py
34 | stompy/io/rdb_datadescriptors.py
35 | stompy/io/rdradcp.py
36 | stompy/io/local/__init__.py
37 | stompy/io/local/noaa_coops.py
38 | stompy/io/local/usgs_sfbay.py
39 | stompy/model/__init__.py
40 | stompy/model/unstructured_diffuser.py
41 | stompy/model/delft/__init__.py
42 | stompy/model/delft/dflow_grid.py
43 | stompy/model/delft/dfm_grid.py
44 | stompy/model/delft/hydro_utils.py
45 | stompy/model/delft/io.py
46 | stompy/model/delft/nefis.py
47 | stompy/model/delft/nefis_dev.py
48 | stompy/model/delft/nefis_nc.py
49 | stompy/model/delft/paradelft.py
50 | stompy/model/delft/paraview_prof.py
51 | stompy/model/delft/process_diagram.py
52 | stompy/model/delft/splice_waq.py
53 | stompy/model/delft/sundwaq.py
54 | stompy/model/delft/test_agg.py
55 | stompy/model/delft/test_dflow_grid.py
56 | stompy/model/delft/test_nefis.py
57 | stompy/model/delft/test_waq_process.py
58 | stompy/model/delft/test_waq_scenario.py
59 | stompy/model/delft/waq_process.py
60 | stompy/model/delft/waq_scenario.py
61 | stompy/model/delft/z_layer_aggregator.py
62 | stompy/model/fvcom/__init__.py
63 | stompy/model/fvcom/fvcom.py
64 | stompy/model/pypart/__init__.py
65 | stompy/model/pypart/basic.py
66 | stompy/model/pypart/ketefian.py
67 | stompy/model/suntans/__init__.py
68 | stompy/model/suntans/domain.py
69 | stompy/model/suntans/forcing.py
70 | stompy/model/suntans/sunreader.py
71 | stompy/model/suntans/transect.py
72 | stompy/plot/__init__.py
73 | stompy/plot/cmap.py
74 | stompy/plot/mpl15.py
75 | stompy/plot/plot_utils.py
76 | stompy/plot/plot_wkb.py
77 | stompy/plot/cmaps/__init__.py
78 | stompy/spatial/__init__.py
79 | stompy/spatial/algorithms.py
80 | stompy/spatial/field.py
81 | stompy/spatial/gen_spatial_index.py
82 | stompy/spatial/geom_types.py
83 | stompy/spatial/interp_4d.py
84 | stompy/spatial/interp_coverage.py
85 | stompy/spatial/join_features.py
86 | stompy/spatial/kdtree_spatialindex.py
87 | stompy/spatial/linestring_utils.py
88 | stompy/spatial/proj_utils.py
89 | stompy/spatial/qgis_spatialindex.py
90 | stompy/spatial/robust_predicates.py
91 | stompy/spatial/wkb2shp.py
92 | test/test_cmap.py
93 | test/test_dfm_grid.py
94 | test/test_exact_delaunay.py
95 | test/test_field.py
96 | test/test_front.py
97 | test/test_gen_spatial_index.py
98 | test/test_harm_decomp.py
99 | test/test_merge_grids.py
100 | test/test_quad_front.py
101 | test/test_rbr.py
102 | test/test_rdb.py
103 | test/test_transect.py
104 | test/test_trigrid.py
105 | test/test_unstructured_grid.py
106 | test/test_waq_scenario.py
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # stompy: spatial tools for ocean modeling in python
2 |
3 | Various python modules related to modeling and oceanographic data analysis.
4 |
5 | ## Prerequisites
6 |
7 | `stompy` requires a Python 3 environment with `gdal` installed. There are many ways to set this up. The recommended method would be creating a `mamba` (or `conda`) environment:
8 |
9 | ```
10 | mamba create -n python "gdal<3.9" "numpy<2.0"
11 | mamba activate
12 | ```
13 |
14 | ## Installation
15 |
16 |
17 | ### Installing with `pip`
18 |
19 | ```
20 | pip install stompy-ocean
21 | ```
22 |
23 | ### Installing with `mamba`/`conda`
24 |
25 | Coming soon
26 |
27 | ## Documentation
28 |
29 | See the [Documentation pages](https://stompy.readthedocs.io/en/latest/) for descriptions of the various modules.
30 |
31 | ## Issues
32 |
33 | If you run into any bugs using `stompy`, you are encouraged to submit an [Issue](https://github.com/rustychris/stompy/issues) or PR to this repo.
34 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _build
2 |
--------------------------------------------------------------------------------
/docs/images/composite-shp-table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/docs/images/composite-shp-table.png
--------------------------------------------------------------------------------
/docs/images/composite-shp-zoom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/docs/images/composite-shp-zoom.png
--------------------------------------------------------------------------------
/docs/images/composite-shp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/docs/images/composite-shp.png
--------------------------------------------------------------------------------
/docs/images/dcc-dredged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/docs/images/dcc-dredged.png
--------------------------------------------------------------------------------
/docs/images/dcc-original.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/docs/images/dcc-original.png
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. stompy documentation master file, created by
2 | sphinx-quickstart on Mon Jun 19 14:24:20 2017.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | stompy
7 | ======
8 |
9 | Spatial Tools for Ocean Modeling in Python
10 |
11 | A collection of tools related to oceanographic data processing with an
12 | emphasis on modeling.
13 |
14 | .. toctree::
15 | :maxdepth: 2
16 | :caption: Contents:
17 |
18 | stompy
19 |
20 |
21 | Indices and tables
22 | ==================
23 |
24 | * :ref:`genindex`
25 | * :ref:`modindex`
26 | * :ref:`search`
27 |
--------------------------------------------------------------------------------
/docs/stompy.filters.rst:
--------------------------------------------------------------------------------
1 | stompy\.filters — Flavors of lowpass filters
2 | =======================
3 |
4 | .. automodule:: stompy.filters
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/stompy.grid.rst:
--------------------------------------------------------------------------------
1 | stompy\.grid — Grid reading, writing and manipulating
2 | ====================
3 |
4 | Modules for generating, converting, plotting, and editing
5 | unstructured grids as used in hydrodynamic models (e.g.
6 | UnTRIM, SUNTANS, DFlow-FM).
7 |
8 | For generating grids, the only stable and robust code for
9 | this is in `tom.py` (triangular orthogonal mesher) and `paver.py`.
10 | `tom.py` is a command line interface to `paver.py`. A simple
11 | example of calling tom is in `stompy/tests/test_tom.sh`, and
12 | invoking `tom.py -h` will show the other options available.
13 |
14 | For most other grid-related tasks, the best module to use
15 | is `unstructured_grid.py`, as it supports non-triangular meshes
16 | (such as mixed triangles/quads), and is actively developed.
17 | Grid generation methods built on unstructured_grid.py are
18 | in front.py, but these are not stable and generally should not
19 | be used.
20 |
21 | Note that for any significant amount of grid modification, the
22 | CGAL python bindings are essential. A backup pure python
23 | implementation is included, but will be orders of magnitude
24 | slower and likely less robust numerically. Watch for error
25 | messages near the start of using tom.py to see whether there
26 | are issues loading CGAL.
27 |
28 | Submodules
29 | ----------
30 |
31 | stompy\.grid\.depth\_connectivity module
32 | ----------------------------------------
33 |
34 | .. automodule:: stompy.grid.depth_connectivity
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | stompy\.grid\.exact\_delaunay module
40 | ------------------------------------
41 |
42 | .. automodule:: stompy.grid.exact_delaunay
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | stompy\.grid\.front module
48 | --------------------------
49 |
50 | .. automodule:: stompy.grid.front
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | stompy\.grid\.merge\_ugrid\_subgrids module
56 | -------------------------------------------
57 |
58 | .. automodule:: stompy.grid.merge_ugrid_subgrids
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 | stompy\.grid\.orthogonalize module
64 | ----------------------------------
65 |
66 | .. automodule:: stompy.grid.orthogonalize
67 | :members:
68 | :undoc-members:
69 | :show-inheritance:
70 |
71 | stompy\.grid\.orthomaker module
72 | -------------------------------
73 |
74 | .. automodule:: stompy.grid.orthomaker
75 | :members:
76 | :undoc-members:
77 | :show-inheritance:
78 |
79 | stompy\.grid\.paver module
80 | --------------------------
81 |
82 | .. automodule:: stompy.grid.paver
83 | :members:
84 | :undoc-members:
85 | :show-inheritance:
86 |
87 | stompy\.grid\.tom module
88 | ------------------------
89 |
90 | .. automodule:: stompy.grid.tom
91 | :members:
92 | :undoc-members:
93 | :show-inheritance:
94 |
95 | stompy\.grid\.trigrid module
96 | ----------------------------
97 |
98 | .. automodule:: stompy.grid.trigrid
99 | :members:
100 | :undoc-members:
101 | :show-inheritance:
102 |
103 | stompy\.grid\.ugrid module
104 | --------------------------
105 |
106 | .. automodule:: stompy.grid.ugrid
107 | :members:
108 | :undoc-members:
109 | :show-inheritance:
110 |
111 | stompy\.grid\.unstructured\_grid module
112 | ---------------------------------------
113 |
114 | .. automodule:: stompy.grid.unstructured_grid
115 | :members:
116 | :undoc-members:
117 | :show-inheritance:
118 |
119 |
120 | Module contents
121 | ---------------
122 |
123 | .. automodule:: stompy.grid
124 | :members:
125 | :undoc-members:
126 | :show-inheritance:
127 |
--------------------------------------------------------------------------------
/docs/stompy.harm_decomp.rst:
--------------------------------------------------------------------------------
1 | stompy\.harm\_decomp — Harmonic decomposition and recomposition
2 | ---------------------------
3 |
4 | .. automodule:: stompy.harm_decomp
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/stompy.io.local.rst:
--------------------------------------------------------------------------------
1 | stompy\.io\.local — Methods for regional and local data sources
2 | =========================
3 |
4 | Submodules
5 | ----------
6 |
7 | stompy\.io\.local\.noaa\_coops module
8 | -------------------------------------
9 |
10 | .. automodule:: stompy.io.local.noaa_coops
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | stompy\.io\.local\.usgs\_sfbay module
16 | -------------------------------------
17 |
18 | .. automodule:: stompy.io.local.usgs_sfbay
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 |
24 | Module contents
25 | ---------------
26 |
27 | .. automodule:: stompy.io.local
28 | :members:
29 | :undoc-members:
30 | :show-inheritance:
31 |
--------------------------------------------------------------------------------
/docs/stompy.io.rst:
--------------------------------------------------------------------------------
1 | stompy\.io — Reading and writing of various formats and data sources
2 | ==================
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 |
9 | stompy.io.local
10 |
11 | Submodules
12 | ----------
13 |
14 | stompy\.io\.match\_datasets module
15 | ----------------------------------
16 |
17 | .. automodule:: stompy.io.match_datasets
18 | :members:
19 | :undoc-members:
20 | :show-inheritance:
21 |
22 | stompy\.io\.qnc module
23 | ----------------------
24 |
25 | .. automodule:: stompy.io.qnc
26 | :members:
27 | :undoc-members:
28 | :show-inheritance:
29 |
30 | stompy\.io\.rbr module
31 | ----------------------
32 |
33 | .. automodule:: stompy.io.rbr
34 | :members:
35 | :undoc-members:
36 | :show-inheritance:
37 |
38 | stompy\.io\.rdb module
39 | ----------------------
40 |
41 | .. automodule:: stompy.io.rdb
42 | :members:
43 | :undoc-members:
44 | :show-inheritance:
45 |
46 | stompy\.io\.rdb\_codes module
47 | -----------------------------
48 |
49 | .. automodule:: stompy.io.rdb_codes
50 | :members:
51 | :undoc-members:
52 | :show-inheritance:
53 |
54 | stompy\.io\.rdb\_datadescriptors module
55 | ---------------------------------------
56 |
57 | .. automodule:: stompy.io.rdb_datadescriptors
58 | :members:
59 | :undoc-members:
60 | :show-inheritance:
61 |
62 | stompy\.io\.rdradcp module
63 | --------------------------
64 |
65 | .. automodule:: stompy.io.rdradcp
66 | :members:
67 | :undoc-members:
68 | :show-inheritance:
69 |
70 |
71 | Module contents
72 | ---------------
73 |
74 | .. automodule:: stompy.io
75 | :members:
76 | :undoc-members:
77 | :show-inheritance:
78 |
--------------------------------------------------------------------------------
/docs/stompy.model.pypart.rst:
--------------------------------------------------------------------------------
1 | stompy\.model\.pypart — Python-based particle tracking
2 | =============================
3 |
4 | Alpha.
5 |
6 | Submodules
7 | ----------
8 |
9 | stompy\.model\.pypart\.basic module
10 | -----------------------------------
11 |
12 | .. automodule:: stompy.model.pypart.basic
13 | :members:
14 | :undoc-members:
15 | :show-inheritance:
16 |
17 | stompy\.model\.pypart\.ketefian module
18 | --------------------------------------
19 |
20 | .. automodule:: stompy.model.pypart.ketefian
21 | :members:
22 | :undoc-members:
23 | :show-inheritance:
24 |
25 |
26 | Module contents
27 | ---------------
28 |
29 | .. automodule:: stompy.model.pypart
30 | :members:
31 | :undoc-members:
32 | :show-inheritance:
33 |
--------------------------------------------------------------------------------
/docs/stompy.model.rst:
--------------------------------------------------------------------------------
1 | stompy\.model — Utilities and interfaces to numerical models
2 | =====================
3 |
4 | Subpackages
5 | -----------
6 |
7 | .. toctree::
8 |
9 | stompy.model.delft
10 | stompy.model.pypart
11 | stompy.model.suntans
12 |
13 | Submodules
14 | ----------
15 |
16 | stompy\.model\.unstructured\_diffuser module
17 | --------------------------------------------
18 |
19 | .. automodule:: stompy.model.unstructured_diffuser
20 | :members:
21 | :undoc-members:
22 | :show-inheritance:
23 |
24 |
25 | Module contents
26 | ---------------
27 |
28 | .. automodule:: stompy.model
29 | :members:
30 | :undoc-members:
31 | :show-inheritance:
32 |
--------------------------------------------------------------------------------
/docs/stompy.model.suntans.rst:
--------------------------------------------------------------------------------
1 | stompy\.model\.suntans — Tools and interface for SUNTANS hydrodynamics
2 | ==============================
3 |
4 | N.B.: `Matt Rayson's tools `, are likely more general
5 | purpose and more widely used.
6 |
7 | Submodules
8 | ----------
9 |
10 | stompy\.model\.suntans\.domain module
11 | -------------------------------------
12 |
13 | .. automodule:: stompy.model.suntans.domain
14 | :members:
15 | :undoc-members:
16 | :show-inheritance:
17 |
18 | stompy\.model\.suntans\.forcing module
19 | --------------------------------------
20 |
21 | .. automodule:: stompy.model.suntans.forcing
22 | :members:
23 | :undoc-members:
24 | :show-inheritance:
25 |
26 | stompy\.model\.suntans\.sunreader module
27 | ----------------------------------------
28 |
29 | .. automodule:: stompy.model.suntans.sunreader
30 | :members:
31 | :undoc-members:
32 | :show-inheritance:
33 |
34 | stompy\.model\.suntans\.transect module
35 | ---------------------------------------
36 |
37 | .. automodule:: stompy.model.suntans.transect
38 | :members:
39 | :undoc-members:
40 | :show-inheritance:
41 |
42 |
43 | Module contents
44 | ---------------
45 |
46 | .. automodule:: stompy.model.suntans
47 | :members:
48 | :undoc-members:
49 | :show-inheritance:
50 |
--------------------------------------------------------------------------------
/docs/stompy.nanpsd.rst:
--------------------------------------------------------------------------------
1 | stompy\.nanpsd — A nan-aware power spectral density method
2 | ---------------------
3 |
4 | Uses the correlogram to avoid the widespread nan-contamination of
5 | an FFT.
6 |
7 | .. automodule:: stompy.nanpsd
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 |
--------------------------------------------------------------------------------
/docs/stompy.parse_interval.rst:
--------------------------------------------------------------------------------
1 | stompy\.parse\_interval — Flexible ways of parsing time intervals
2 | ------------------------------
3 |
4 | .. automodule:: stompy.parse_interval
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/stompy.plot.rst:
--------------------------------------------------------------------------------
1 | stompy\.plot — Plotting utilities and enhancements
2 | ====================
3 |
4 | Submodules
5 | ----------
6 |
7 | stompy\.plot\.cmap module
8 | -------------------------
9 |
10 | .. automodule:: stompy.plot.cmap
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | stompy\.plot\.plot\_utils module
16 | --------------------------------
17 |
18 | .. automodule:: stompy.plot.plot_utils
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | stompy\.plot\.plot\_wkb module
24 | ------------------------------
25 |
26 | .. automodule:: stompy.plot.plot_wkb
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 |
32 | Module contents
33 | ---------------
34 |
35 | .. automodule:: stompy.plot
36 | :members:
37 | :undoc-members:
38 | :show-inheritance:
39 |
--------------------------------------------------------------------------------
/docs/stompy.priority_queue.rst:
--------------------------------------------------------------------------------
1 | stompy\.priority\_queue — Python implementation of priority queue data structure
2 | ------------------------------
3 |
4 | .. automodule:: stompy.priority_queue
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/stompy.rst:
--------------------------------------------------------------------------------
1 | stompy
2 | ======
3 |
4 | Spatial Tools for Ocean Modeling in Python
5 |
6 | A collection of tools related to oceanographic data processing with an
7 | emphasis on modeling.
8 |
9 |
10 | Subpackages
11 | -----------
12 |
13 | .. toctree::
14 | :maxdepth: 1
15 |
16 | stompy.grid
17 | stompy.io
18 | stompy.model
19 | stompy.plot
20 | stompy.spatial
21 |
22 | Submodules
23 | ----------
24 |
25 | .. toctree::
26 | :maxdepth: 1
27 |
28 | stompy.filters
29 | stompy.harm_decomp
30 | stompy.nanpsd
31 | stompy.parse_interval
32 | stompy.priority_queue
33 | stompy.scriptable
34 | stompy.tidal_datum
35 | stompy.tidal_consts
36 | stompy.undoer
37 | stompy.utils
38 | stompy.weighted_kde
39 | stompy.xr_utils
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/stompy.scriptable.rst:
--------------------------------------------------------------------------------
1 | stompy\.scriptable — Simple superclass for exposing command-line accessible methods
2 | -------------------------
3 |
4 | .. automodule:: stompy.scriptable
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/stompy.tidal_datum.rst:
--------------------------------------------------------------------------------
1 | stompy\.tidal\_datum — Methods for extracting tidal datums from timeseries
2 | ---------------------------
3 |
4 | .. automodule:: stompy.tidal_datum
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 |
--------------------------------------------------------------------------------
/docs/stompy.tide_consts.rst:
--------------------------------------------------------------------------------
1 | stompy\.tide\_consts — Constants related to tidal constituents
2 | ---------------------------
3 |
4 | .. automodule:: stompy.tide_consts
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 |
--------------------------------------------------------------------------------
/docs/stompy.undoer.rst:
--------------------------------------------------------------------------------
1 | stompy\.undoer — Framework for handling undo history
2 | ---------------------
3 |
4 | Used for grid editing in order to unwind changes to a grid.
5 |
6 | .. automodule:: stompy.undoer
7 | :members:
8 | :undoc-members:
9 | :show-inheritance:
10 |
11 |
--------------------------------------------------------------------------------
/docs/stompy.utils.rst:
--------------------------------------------------------------------------------
1 | stompy\.utils — General utilities
2 | --------------------
3 |
4 | .. automodule:: stompy.utils
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/stompy.weighted_kde.rst:
--------------------------------------------------------------------------------
1 | stompy\.weighted\_kde — Kernel Density Estimate with weights
2 | ----------------------------
3 |
4 | .. automodule:: stompy.weighted_kde
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 |
--------------------------------------------------------------------------------
/docs/stompy.xr_utils.rst:
--------------------------------------------------------------------------------
1 | stompy\.xr\_utils — xarray-related utilities
2 | --------------------------------------------
3 |
4 | .. automodule:: stompy.xr_utils
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints
2 |
--------------------------------------------------------------------------------
/examples/convert_sun_to_dfm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Read a suntans grid in the current directory and write a DFM grid, output_net.nc
5 | """
6 |
7 | from stompy.grid import unstructured_grid
8 | from stompy.model.delft import dfm_grid
9 |
10 | ug=unstructured_grid.SuntansGrid(".")
11 |
12 | dfm_grid.write_dfm(ug,"output_net.nc")
13 |
--------------------------------------------------------------------------------
/examples/curvilinear_grids.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from stompy.grid import front, unstructured_grid
4 | from stompy.plot import plot_wkb
5 | from stompy.spatial import linestring_utils
6 | from stompy import filters
7 | from shapely import geometry
8 |
9 | ##
10 |
11 | # define the domain
12 |
13 |
14 | s=np.linspace(0,6000,200) # along-channel coordinate
15 | amp=700 # amplitude of meanders
16 | lamb=4000 # wave-length of meanders
17 | width=500 # mean channel width
18 | noise_w=50 # amplitude of noise to add to the channel banks
19 | noise_l=1500 # length-scale of noise
20 |
21 | centerline=np.c_[ s, amp*np.cos(2*np.pi*s/lamb)]
22 | pline=geometry.LineString(centerline)
23 | channel=pline.buffer(width/2)
24 | ring=np.array(channel.exterior)
25 | ring_norm=linestring_utils.left_normals(ring)
26 |
27 | noise=(np.random.random(len(ring_norm))-0.5)
28 | winsize=int( noise_l/( channel.exterior.length/len(ring_norm) ) )
29 | noise[:winsize]=0 # so the ends still match up
30 | noise[-winsize:]=0
31 | noise_lp=filters.lowpass_fir(noise,winsize)
32 | noise_lp *= noise_w/np.sqrt(np.mean(noise_lp**2))
33 |
34 | # domain boundary including the random noise
35 | ring_noise=ring+noise_lp[:,None]*ring_norm
36 |
37 | # Create the curvilinear section
38 | thalweg=centerline[50:110]
39 |
40 | plt.figure(1).clf()
41 | plt.plot(centerline[:,0],
42 | centerline[:,1],
43 | 'k-',zorder=2)
44 | plt.axis('equal')
45 |
46 | plot_wkb.plot_wkb(channel,zorder=-2)
47 | plt.plot(ring_noise[:,0],
48 | ring_noise[:,1],
49 | 'm-')
50 |
51 | plt.plot(thalweg[:,0],thalweg[:,1],'r--',lw=3)
52 |
53 | ##
54 |
55 | # First, just the curvilinear section:
56 | g=unstructured_grid.UnstructuredGrid(max_sides=4)
57 |
58 | thalweg_resamp=linestring_utils.resample_linearring(thalweg,50,closed_ring=0)
59 |
60 | g.add_rectilinear_on_line(thalweg_resamp,
61 | profile=lambda x,s,perp: np.linspace(-200,200,20),
62 | add_streamwise=False)
63 | g.plot_edges(zorder=5,color='y')
64 |
--------------------------------------------------------------------------------
/examples/dfm_dwaq/.gitignore:
--------------------------------------------------------------------------------
1 | local_config.py
2 | dfm_run
3 |
--------------------------------------------------------------------------------
/examples/dfm_dwaq/README.md:
--------------------------------------------------------------------------------
1 | This directory shows an example of scripting the creation and execution of a very
2 | simple DFlowFM simulation, and a subsequent scalar simulation using DWAQ.
3 |
4 | The hydrodynamic model is a 500m square grid with a resolution of 10m. The southern
5 | end of the western boundary has a periodic flow. It runs for 48 hours.
6 |
7 | The D-WAQ tracer run includes three tracers:
8 |
9 | - dye1 is initialized as a Gaussian blob in the middle of the domain, and 0 on the flow boundary
10 | - unity is initalized as 1.0, with 0.0 on the flow boundary.
11 | - boundary_dye is initialized as 0.0, with 1.0 on the flow boundary.
12 |
13 | At the end of the simulation the three tracers look like:
14 |
15 | 
16 |
17 | Relevant files:
18 |
19 | `basic_test.py`: The full script
20 |
21 | `local_config.py.in`: Copy this to local_config.py, and edit to set paths to dflowfm, delwaq1, and delwaq2.
22 |
23 | `dflow-template.mdu`: Template values for configuring the DFM run. These can be overwritten in the script,
24 | but for parameters that don't need to change programmatically put them here.
25 |
26 | `dfm_run`: The full DFM output is not in the repository, but some of the key files are here for perusing
27 | without having to run the script.
28 |
29 | `dwaq_run`: The full DWAQ output not in the repository, but some of the key files are here for perusing
30 | without having to run the script.
31 |
--------------------------------------------------------------------------------
/examples/dfm_dwaq/local_config.py.in:
--------------------------------------------------------------------------------
1 | import stompy.model.delft.waq_scenario as dwaq
2 | import stompy.model.delft.dflow_model as dfm
3 |
4 | import os
5 |
6 | DELFT_SRC="/home/rusty/src/dfm/1.5.4/lnx64"
7 | DELFT_SHARE=os.path.join(DELFT_SRC,"share","delft3d")
8 | DELFT_LIB=os.path.join(DELFT_SRC,"lib")
9 |
10 | def install():
11 | os.environ['DELFT_SRC']=DELFT_SRC
12 | os.environ['DELFT_SHARE']=DELFT_SHARE
13 | # not great - really should check what's already in there.
14 | os.environ['LD_LIBRARY_PATH']=DELFT_LIB
15 |
16 | dfm_bin_dir=os.path.join(os.environ['DELFT_SRC'],"bin")
17 | dfm.DFlowModel.dfm_bin_dir=dfm_bin_dir
18 | dfm.DFlowModel.mpi_bin_dir=dfm_bin_dir
19 |
20 |
--------------------------------------------------------------------------------
/examples/dfm_dwaq/sample_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/examples/dfm_dwaq/sample_output.png
--------------------------------------------------------------------------------
/examples/dwaq_adjust_bc_fluxes.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | Command-line tool to infer missing boundary fluxes, and update them
4 | in a flow file.
5 |
6 | This applies to non-flow BCs in DFM, i.e. sea boundary conditions and
7 | discharges.
8 |
9 | """
10 | from __future__ import print_function
11 |
12 | import argparse
13 | import sys,os
14 | import numpy as np
15 |
16 | import stompy.model.delft.waq_scenario as waq
17 |
18 | parser = argparse.ArgumentParser(description='Adjust DFM D-WAQ output to add missing BC fluxes.')
19 |
20 | parser.add_argument('hyd_fn', metavar='dfm_out.hyd', type=str,
21 | help='path to hyd file')
22 |
23 | args = parser.parse_args()
24 |
25 | hyd_fn=args.hyd_fn
26 |
27 | print("Opening hydro from %s"%hyd_fn)
28 | hydro=waq.HydroFiles(hyd_fn)
29 |
30 | print("Adjusting flows, updating %s in place"%hydro.get_path('flows-file'))
31 |
32 | hydro.adjust_boundaries_for_conservation()
33 |
34 | print("Done")
35 |
--------------------------------------------------------------------------------
/examples/dwaq_map_to_nc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | Command-line tool to convert a binary map output to netcdf.
4 | """
5 | from __future__ import print_function
6 |
7 | import argparse
8 | import sys,os
9 | import numpy as np
10 |
11 | import stompy.model.delft.io as dio
12 |
13 | parser = argparse.ArgumentParser(description='Convert D-WAQ binary map output to NetCDF.')
14 |
15 | parser.add_argument('map_fn', metavar='somefile.map', type=str,
16 | help='path to map file output')
17 | parser.add_argument('hyd_fn', metavar='other.hyd', type=str,
18 | help='path to hyd file')
19 | parser.add_argument('--totaldepth',default='TotalDepth',
20 | help='output variable to use as total depth. none to disable sigma coordinate')
21 |
22 | args = parser.parse_args()
23 | # DBG args=parser.parse_args(['--totaldepth','none',"wy2011.map","com-wy2011.hyd"])
24 |
25 | map_fn=args.map_fn
26 | hyd_fn=args.hyd_fn
27 |
28 |
29 | output_fn=map_fn.replace('.map','.nc')
30 | if os.path.exists(output_fn):
31 | print("Output file '%s' exists. Aborting"%output_fn)
32 | sys.exit(1)
33 |
34 | print("Reading map data and grid")
35 | map_ds=dio.read_map(map_fn,hyd_fn)
36 |
37 | if args.totaldepth != 'none':
38 | total_depth=args.totaldepth
39 |
40 | print("Adding minor metadata")
41 |
42 | if total_depth not in map_ds:
43 | print("Fabricating a total-depth variable to allow ugrid-ish output")
44 | map_ds[total_depth]=('time','layer','face'),np.ones( (len(map_ds.time),
45 | len(map_ds.layer),
46 | len(map_ds.face)), '=67.0.0", "wheel"]
5 | build-backend = "setuptools.build_meta"
6 |
7 | [project]
8 | name = "stompy-ocean"
9 | version = "0.0.5"
10 | description = "Various python modules related to modeling and oceanographic data analysis."
11 | readme = {file = "README.md", content-type = "text/markdown"}
12 | authors = [{ name = "Rusty Holleman", email = "rustychris@gmail.com" }]
13 | license = { file = "LICENSE" }
14 | classifiers = [
15 | "License :: OSI Approved :: MIT License",
16 | "Programming Language :: Python",
17 | "Programming Language :: Python :: 3",
18 | ]
19 | keywords = ["modeling", "oceanography", "grid"]
20 | dependencies = ["cmocean",
21 | "matplotlib",
22 | "netCDF4",
23 | "pandas",
24 | "requests",
25 | "scipy",
26 | "Shapely",
27 | "six",
28 | "xarray",
29 | "seawater",
30 | "gdal<3.9",
31 | "numpy<2.0",
32 | "cgal"
33 | ]
34 | requires-python = ">=3.0"
35 |
36 | [tool.setuptools]
37 | packages=['stompy', 'stompy.grid', 'stompy.io', 'stompy.io.local',
38 | 'stompy.model', 'stompy.model.delft', 'stompy.model.fvcom',
39 | 'stompy.model.pypart', 'stompy.model.suntans',
40 | 'stompy.plot', 'stompy.plot.cmaps',
41 | 'stompy.spatial']
42 |
43 | [tool.setuptools.package-data]
44 | stompy = ["tide_consts.txt"]
45 |
46 | [project.urls]
47 | Homepage = "https://github.com/rustychris/stompy"
48 |
--------------------------------------------------------------------------------
/requirements-rtd.txt:
--------------------------------------------------------------------------------
1 | cmocean
2 | future
3 | # GDAL # this is failing the build
4 | matplotlib
5 | netCDF4
6 | numpy
7 | pandas==0.19.2
8 | requests
9 | scipy
10 | Shapely
11 | six
12 | xarray
13 | seawater
14 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | cmocean
2 | gdal
3 | matplotlib
4 | netCDF4
5 | numpy
6 | pandas
7 | requests
8 | scipy
9 | Shapely
10 | six
11 | xarray
12 | seawater
13 | cgal
14 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from distutils.core import setup
2 |
3 | setup(
4 | name='stompy',
5 | version='0.1',
6 | packages=['stompy', 'stompy.grid', 'stompy.io', 'stompy.io.local',
7 | 'stompy.model', 'stompy.model.delft', 'stompy.model.fvcom',
8 | 'stompy.model.pypart', 'stompy.model.suntans',
9 | 'stompy.plot', 'stompy.plot.cmaps',
10 | 'stompy.spatial'],
11 | package_data={'stompy':['tide_consts.txt']},
12 | license='MIT',
13 | url="https://github.com/rustychris/stompy",
14 | author="Rusty Holleman",
15 | author_email="rustychris@gmail.com",
16 | long_description=open('README.md').read(),
17 | )
18 |
--------------------------------------------------------------------------------
/stompy/.gitignore:
--------------------------------------------------------------------------------
1 | wind
2 |
3 |
--------------------------------------------------------------------------------
/stompy/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing to do.
2 |
--------------------------------------------------------------------------------
/stompy/grid/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing
2 |
--------------------------------------------------------------------------------
/stompy/grid/geom_types.py:
--------------------------------------------------------------------------------
1 | from osgeo import ogr
2 |
3 | # map geometry types to names:
4 | ogr2text = {
5 | ogr.wkbGeometryCollection:'GeometryCollection',
6 | ogr.wkbGeometryCollection25D:'GeometryCollection25D',
7 | ogr.wkbLineString:'LineString',
8 | ogr.wkbLineString25D:'LineString25D',
9 | ogr.wkbLinearRing:'LinearRing',
10 | ogr.wkbMultiLineString:'MultiLineString',
11 | ogr.wkbMultiLineString25D:'MultiLineString25D',
12 | ogr.wkbMultiPoint:'MultiPoint',
13 | ogr.wkbMultiPoint25D:'MultiPoint25D',
14 | ogr.wkbMultiPolygon:'MultiPolygon',
15 | ogr.wkbMultiPolygon25D:'MultiPolygon25D',
16 | ogr.wkbPoint:'Point',
17 | ogr.wkbPoint25D:'Point25D',
18 | ogr.wkbPolygon:'Polygon',
19 | ogr.wkbPolygon25D:'Polygon25D',
20 | ogr.wkbUnknown:'Unknown',
21 | }
22 |
23 | text2ogr = dict( [ [ogr2text[k],k] for k in ogr2text.keys()] )
24 |
--------------------------------------------------------------------------------
/stompy/grid/gmsh_scale_helper.py:
--------------------------------------------------------------------------------
1 | """
2 | Handle scale information for a gmsh process.
3 | Expects a single command line argument giving the path to a
4 | pickled Field instance.
5 |
6 | This probably doesn't work with python2 (gmsh docs provide some
7 | additional options needed for python2)
8 | """
9 | from stompy.spatial import field
10 | import pickle
11 | import struct
12 | import sys
13 | import math
14 |
15 | pkl_file=sys.argv[1]
16 | with open(pkl_file,'rb') as fp:
17 | scale=pickle.load(fp)
18 |
19 | while True:
20 | xyz = struct.unpack("ddd", sys.stdin.buffer.read(24))
21 | if math.isnan(xyz[0]):
22 | break
23 | f = scale(xyz[:2])
24 | sys.stdout.buffer.write(struct.pack("d",f))
25 | sys.stdout.flush()
26 |
--------------------------------------------------------------------------------
/stompy/io/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing
2 |
--------------------------------------------------------------------------------
/stompy/io/local/.gitignore:
--------------------------------------------------------------------------------
1 | cache
2 |
--------------------------------------------------------------------------------
/stompy/io/local/__init__.py:
--------------------------------------------------------------------------------
1 | # Various classes for datasources of local or regional use.
2 |
--------------------------------------------------------------------------------
/stompy/io/local/cdip_mop.py:
--------------------------------------------------------------------------------
1 | """
2 | Simple caching layer on THREDDS access to CDIP MOP
3 | wave data. Useful for US West Coast wave climate data,
4 | hourly resolution of many wave parameters.
5 | """
6 |
7 | import os
8 | import numpy as np
9 | from .common import periods
10 | import logging
11 | log=logging.getLogger('cdip_mop')
12 |
13 | import xarray as xr
14 |
15 | def hindcast_dataset(station,start_date,end_date,cache_dir=None,
16 | variables=['waveHs'],clip='True',
17 | days_per_request='M'):
18 | """
19 | station: string, such as 'SM141' (which Pescadero State Beach, San Mateo county)
20 | start_date,end_date: np.datetime64
21 | clip:
22 | False: keep duration of cached blocks
23 | True: clip python-style, exclusive of end date
24 | 'inclusive': clip, but include end date
25 |
26 | variables: which variables to fetch. pass None for all variables.
27 | """
28 | url="http://thredds.cdip.ucsd.edu/thredds/dodsC/cdip/model/MOP_alongshore/%s_hindcast.nc"%station
29 |
30 | ds=None
31 | t=None
32 |
33 | chunks=[]
34 |
35 | for interval_start,interval_end in periods(start_date,end_date,days_per_request):
36 | base_fn="%s_%s_%s_%s.nc"%(station,
37 | "-".join(["%s"%p for p in variables]),
38 | interval_start.strftime('%Y%m%d'),interval_end.strftime('%Y%m%d'))
39 |
40 | if cache_dir is not None:
41 | cache_fn=os.path.join(cache_dir,base_fn)
42 | else:
43 | cache_fn=None
44 |
45 | if (cache_fn is not None) and os.path.exists(cache_fn):
46 | chunk_ds=xr.open_dataset(cache_fn)
47 | chunk_ds.load()
48 | chunks.append(chunk_ds.copy())
49 | chunk_ds.close()
50 | else:
51 | # Fetch it
52 | if ds is None: # open on demand
53 | log.info("Fetching cdip/mop metadta")
54 | ds=xr.open_dataset(url)
55 | t=ds.waveTime.values
56 |
57 | cmip_start,cmip_stop=np.searchsorted(t,
58 | [np.datetime64(interval_start),
59 | np.datetime64(interval_end) ])
60 |
61 | if variables is not None:
62 | ds_sel=ds
63 | else:
64 | ds_sel=ds[variables]
65 |
66 | ds_sel=ds_sel[variables].isel(waveTime=slice(cmip_start,cmip_stop+1))
67 | ds_sel.load()
68 | chunks.append(ds_sel)
69 | if cache_fn is not None:
70 | ds_sel.to_netcdf(cache_fn)
71 | if len(chunks)==0:
72 | return None
73 | elif len(chunks)==1:
74 | ds=chunks[0]
75 | else:
76 | # eliminate any time overlaps:
77 | clipped=[chunks[0]]
78 | for chunk in chunks[1:]:
79 | sel=chunk.waveTime.values>clipped[-1].waveTime.values[-1]
80 | clipped.append( chunk.isel(waveTime=sel) )
81 | ds=xr.concat(clipped,dim='waveTime')
82 |
83 | if not clip:
84 | pass
85 | else:
86 | if clip=='inclusive':
87 | sel=(ds.waveTime.values>=start_date)&(ds.waveTime.values<=end_date)
88 | else:
89 | sel=(ds.waveTime.values>=start_date)&(ds.waveTime.values',
11 | '',
12 | ' ',
13 | f' ',
14 | ' \n']))
15 | # PointData tag can include Scalars="Ve" Vectors="Velocity", etc. but I think this
16 | # is just for selecting an "active" field.
17 |
18 | for vari in df.columns:
19 | if vari in ['x','y','z']:
20 | continue
21 | fp.write(f' \n')
22 | fp.write(" ".join( ("%.4f"%x for x in df[vari].values) ) )
23 | fp.write('\n \n')
24 |
25 | fp.write("\n".join([
26 | ' ',
27 | ' ' # was separate open/close tags
28 | ]))
29 |
30 | fp.write( ' \n')
31 | fp.write( ' \n')
32 | fp.write( " ".join( ("%.3f %.3f %.3f"%(p[0],p[1],p[2]) for p in df[ ['x','y','z'] ].values) ) )
33 |
34 | fp.write('\n\n \n')
35 |
36 | fp.write(' \n')
37 | fp.write('\n')
38 | fp.write( " ".join( ("%d"%x for x in range(len(df))) ) )
39 | fp.write('\n\n')
40 |
41 | fp.write('')
42 | fp.write( " ".join( ("%d"%(x+1) for x in range(len(df))) ) )
43 | fp.write('\n')
44 |
45 | fp.write('')
46 | fp.write( " ".join( ("1" for x in range(len(df))) ) )
47 | fp.write('\n')
48 |
49 | fp.write("\n".join([
50 | ' ',
51 | ' ',
52 | ' ',
53 | '\n'] ))
54 |
--------------------------------------------------------------------------------
/stompy/io/wocss/.gitignore:
--------------------------------------------------------------------------------
1 | windsuv.dat
2 | windsuv.out
3 | windsuv.query
4 | windsuv.stations
5 | outfyl
6 | GSwoxB1
7 |
8 |
--------------------------------------------------------------------------------
/stompy/io/wocss/Makefile:
--------------------------------------------------------------------------------
1 | all: GSwoxB1
2 |
3 | FC=gfortran
4 |
5 | GSwoxB1: GSwoxB1.f
6 | $(FC) -o $@ $<
7 |
--------------------------------------------------------------------------------
/stompy/io/wocss/NOTES:
--------------------------------------------------------------------------------
1 | How available are the necessary data?
2 |
3 | In winds.dat:
4 |
5 | surface wind inputs: 10 stations, fairly broadly distributed.
6 |
7 | then a sounding wind speed ( utm 569000 4173000 )
8 | a sounding at the same location, labeled JU230512.OAK, sounds a lot like
9 | oakland airport? second sounding has temp, Td, and pressure
10 | And the wind data is repeated...
11 |
12 | - http://www.esrl.noaa.gov/ might provide the sounding data
13 |
14 | ds=xr.open_dataset('raob_soundings25653.cdf',decode_times=0)
15 |
16 | - nice! - it has twice daily sondes. just picked a random period in spring 2013,
17 | and got 150 profiles.
18 |
19 | - plotting the wind vectors on top of the terrain, it looks pretty reasonable.
20 |
21 | Questions before this could be put into place for our runs:
22 | - how much wind data can we get, starting with WY2013?
23 | - assume that the sonde profiles can be interpolated in time without too much
24 | trouble.
25 | - would have to downsample the gridded wind for input to suntans. probably
26 | okay. going to be a big dataset.
27 | - aim for 1h winds? 3h? using the sample setup as an example, one realization
28 | of the output wind field is 130kB. So a year at 3h is 194 MB. No sweat.
29 | Possible that 1km is too coarse for a place like Carquinez, but do we
30 | really need perfect wind there?
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/stompy/io/wocss/plots.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import numpy as np
3 | import xarray as xr
4 |
5 | ##
6 |
7 | station_xy=np.loadtxt('windsuv.stations')
8 |
9 | # this has 999 in most places, and a handful of signed values
10 | query=np.loadtxt('windsuv.query') # 246,108
11 | u_query=query[:nrows ]
12 | v_query=query[nrows:]
13 |
14 | # this has a nice smooth field interpolated between stations
15 | output=np.loadtxt('windsuv.out') # 246,108
16 | u_output=output[:nrows]
17 | v_output=output[nrows:]
18 |
19 | # has similar pattern as query, but different values.
20 | dat=np.loadtxt('windsuv.dat')
21 | u_dat=dat[:nrows]
22 | v_dat=dat[nrows:]
23 |
24 | # basic DEM
25 | terrain=np.loadtxt('terrain.dat')
26 |
27 | ##
28 | plt.figure(1).clf()
29 | fig,ax=plt.subplots(num=1)
30 |
31 | ax.plot(station_xy[:,0],
32 | station_xy[:,1],'ko')
33 |
34 | # not sure that came out right
35 | nrows=query.shape[0]//2
36 |
37 | # mostly 999, but with seemingly independent, signed values, in the
38 | # range -100, 176. dm/s ?
39 | # clumping of signs supports this being wind vectors
40 | # ax.imshow(u_query[::-1,:],cmap='jet',origin='lower')
41 |
42 | # ax.imshow(u_dat[::-1,:],cmap='jet',origin='lower')
43 | # ax.imshow(v_output[::-1,:],cmap='jet',origin='lower')
44 |
45 | # ax.imshow( (u_dat-u_query)[::-1,:], cmap='jet',origin='lower')
46 |
47 |
48 | ax.imshow(terrain[::-1,:],cmap='jet',origin='lower')
49 |
50 | ##
51 |
52 | ds=xr.open_dataset('raob_soundings25653.cdf',decode_times=0)
53 |
54 | ##
55 |
56 |
57 | # quiver plot:
58 | x=np.arange(u_output.shape[1])
59 | y=np.arange(u_output.shape[0])[::-1]
60 |
61 | X,Y=np.meshgrid(x,y)
62 |
63 | plt.figure(1).clf()
64 | fig,ax=plt.subplots(num=1)
65 | #ax.imshow(v_output[::-1,:],origin='lower')
66 | ax.imshow(terrain[::-1,:],origin='lower',interpolation='nearest')
67 |
68 | slc=slice(None,None,5)
69 | ax.quiver(X[slc,slc],Y[slc,slc],
70 | u_output[slc,slc],v_output[slc,slc])
71 |
--------------------------------------------------------------------------------
/stompy/io/wocss/raob_soundings25653.cdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/io/wocss/raob_soundings25653.cdf
--------------------------------------------------------------------------------
/stompy/io/wocss/rundat.dat:
--------------------------------------------------------------------------------
1 | **************Sn Francisco Bay area stuff*******************************
2 | 1 * NSKIP ascii option writes every nskip grid pts in x & y.
3 | 10 * NLVL:number of flow surfaces used for calculations
4 | 0.0,0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.8,1.0 * SIGMA(NLVL):sigma values of flow levels
5 | 7 * NFLAT: # of horiz. sfcs for interpol. (includes anemom. lvl)
6 | 10.,50.,100.,200.,400.,800.,1000. * zchooz: heights (m, msl) of horiz sfcs
7 | 200,1,1 * NUMNWS,NUMTMP,numdop: total # sta., # upper wind & t-sondes
8 | 0.515,0.3048 * SPDCNV,HTCNV conv factors input spds to m/s and heights to m
9 | 123,108 * MCRS,NCRS: # rows/cols
10 | 1.0 * DSCRS:dx -- grid spacing (km)
11 | 524.5,4134.0 * UTMAPX,UTMAPY:utms of reference point
12 | 1,1 * kgridx,kgridy, indices of reference point
13 | 1500. * AVTHK -- ht (m) of top sfc over low point
14 | 1.0 * SLFAC slope fact 1st guess top sfc (0=flat,1=terr follow)
15 | 0.2 * CMPRES max compress of space bet sfcs smaller=less rise
16 | 0.001 * DPOTMIN min. theta lapse rate (deg/m) -- low stab lim
17 | 0.05,10.0 * ZZERO,Z10 sfc roughness length (m) & anemometer ht. (m)
18 | 0.1 * D2MIN: min. dist for interp. wts in grid units
19 | 2.0 * DTWT: distance weight power -- wt=1/(Dist**DTWT)
20 | 20 * NITer, iteration limit in subroutine bal5.
21 | 0.2 * ADJMAX: max adj fact near obs 0=no adj & 1=reg adj
22 | 65,12 * lowix & lowiy -- ix & iy indices of a low pt. for t-sonde 1
23 | 41,50 * ditto -- each sonde requires specifying 5 more low pts.
24 | 3,33 * ditto -- there will be 5*numtmp pts
25 | 32,99 * ditto
26 | 42,50 * ditto
27 | 1 * NEND number of cases before stopping.
28 |
--------------------------------------------------------------------------------
/stompy/io/wocss/winds.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/io/wocss/winds.dat
--------------------------------------------------------------------------------
/stompy/model/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing to do.
2 |
--------------------------------------------------------------------------------
/stompy/model/delft/.gitignore:
--------------------------------------------------------------------------------
1 | .svn
2 |
3 |
--------------------------------------------------------------------------------
/stompy/model/delft/CODE_GUIDE.txt:
--------------------------------------------------------------------------------
1 | Just some notes on coding style decisions and rationale (or complaints/quandaries)
2 |
3 | Use tuples for class default values
4 | --
5 | When it's necessary for a class, such as Scenario, to have a default value expressed
6 | as a list, use a tuple rather than a list. This reduces errors in which method
7 | code modifies the classes value. In particular,
8 | class A(object):
9 | x=(1,2,3)
10 | a1=A()
11 | a1.x += (4,)
12 | a2=A()
13 | a2.x != a1.x
14 | is safe, but if x were a list, then a2.x would get the modified value from a1.
15 |
16 |
17 | Constants
18 | --
19 | Make constants available as attributes of the relevant class. This makes
20 | objects self-contained and 'batteries-included'. Otherwise you have to
21 | import the defining module just to use the object.
22 |
--------------------------------------------------------------------------------
/stompy/model/delft/__init__.py:
--------------------------------------------------------------------------------
1 | pass
2 |
--------------------------------------------------------------------------------
/stompy/model/delft/data/trim-tut_fti_waq.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/model/delft/data/trim-tut_fti_waq.dat
--------------------------------------------------------------------------------
/stompy/model/delft/data/trim-tut_fti_waq.def:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/model/delft/data/trim-tut_fti_waq.def
--------------------------------------------------------------------------------
/stompy/model/delft/data/tut_fti_waq-bal.his:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/model/delft/data/tut_fti_waq-bal.his
--------------------------------------------------------------------------------
/stompy/model/delft/data/tut_fti_waq.hda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/model/delft/data/tut_fti_waq.hda
--------------------------------------------------------------------------------
/stompy/model/delft/data/tut_fti_waq.hdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/model/delft/data/tut_fti_waq.hdf
--------------------------------------------------------------------------------
/stompy/model/delft/dflow_grid.py:
--------------------------------------------------------------------------------
1 | # see how involved a NEFIS reader in native python/numpy would be
2 | import os
3 | import sys
4 | import numpy as np
5 | import matplotlib.pyplot as plt
6 | import memoize
7 |
8 | import matplotlib.tri as tri
9 |
10 | class DflowGrid2D(object):
11 | def __init__(self,xcor,ycor,xz,yz,active):
12 | self.xcor=xcor
13 | self.ycor=ycor
14 | self.xz=xz
15 | self.yz=yz
16 | self.active=active
17 | comp=(active==1) # computational cells
18 | self.node_active=comp.copy()
19 | self.node_active[:-1,:-1] = comp[1:,1:] | comp[:-1,1:] | comp[1:,:-1] | comp[:-1,:-1]
20 |
21 | @staticmethod
22 | def from_nef_map(nef):
23 | xcor=nef['map-const'].getelt('XCOR',[0])
24 | ycor=nef['map-const'].getelt('YCOR',[0])
25 | xz=nef['map-const'].getelt('XZ',[0])
26 | yz=nef['map-const'].getelt('YZ',[0])
27 | active=nef['map-const'].getelt('KCS',[0])
28 | return DflowGrid2D(xcor,ycor,xz,yz,active)
29 |
30 | def wireframe(self):
31 | # this method double-draws interior lines.
32 | coll=self.pcolor_face(0*self.xcor)
33 | coll.set_array(None)
34 | coll.set_facecolors('none')
35 | return coll
36 |
37 | def pcolor_face(self,v):
38 | vmsk=np.ma.masked_where(self.active!=1,v)
39 | return plt.pcolor( self.xcor[:-1,:-1],
40 | self.ycor[:-1,:-1],
41 | vmsk[1:-1,1:-1],
42 | edgecolors='k',lw=0.2)
43 |
44 | def pcolormesh_node(self,v):
45 | vmsk=np.ma.masked_where(~self.node_active,v)
46 | return plt.pcolormesh( self.xcor[:-1,:-1],
47 | self.ycor[:-1,:-1],
48 | vmsk[:-1,:-1],
49 | edgecolors='k',lw=0.2,
50 | shading='gouraud')
51 |
52 | @memoize.memoize()
53 | def to_triangulation(self):
54 | # map 2d node index to 1d index - not yet compressed.
55 | idx1d=np.arange(np.prod(self.xcor.shape)).reshape(self.xcor.shape)
56 |
57 | tris=[]
58 | comp=(self.active==1)[1:-1,1:-1]
59 | for row,col in zip(*np.nonzero(comp)):
60 | # may not be CCW
61 | tris.append( [ idx1d[row,col],
62 | idx1d[row,col+1],
63 | idx1d[row+1,col+1] ] )
64 | tris.append( [ idx1d[row+1,col+1],
65 | idx1d[row+1,col],
66 | idx1d[row,col] ] )
67 |
68 | used=np.unique(tris)
69 | x=self.xcor.ravel()[used]
70 | y=self.ycor.ravel()[used]
71 | remap=np.zeros(np.prod(self.xcor.shape))
72 | remap[used] = np.arange(len(used))
73 | orig_tris=tris
74 | tris=remap[tris] # these now index
75 |
76 | T=tri.Triangulation(x,y,tris)
77 | idx_map=used
78 |
79 | return T,idx_map
80 | def pcolor_node(self,v,**kws):
81 | my_kws=dict(shading='gouraud')
82 | my_kws.update(kws)
83 | T,idx_map = self.to_triangulation()
84 | return plt.tripcolor(T,v.ravel()[idx_map],**my_kws)
85 | def contourf_node(self,v,*args,**kws):
86 | T,idx_map = self.to_triangulation()
87 | return plt.tricontourf(T,v.ravel()[idx_map],*args,**kws)
88 |
89 |
90 |
--------------------------------------------------------------------------------
/stompy/model/delft/map_merge.py:
--------------------------------------------------------------------------------
1 | """
2 | Merge DFM map files from multiprocessor to single domain.
3 |
4 | In theory dfmoutput mapmerge infiles...
5 | does this, but experience has shown it is not reliable.
6 |
7 | """
8 |
9 |
10 | class MapMerge(object):
11 | def __init__(self,infiles,outfile,global_grid):
12 | self.global_grid=global_grid
13 | self.outfile=outfile
14 | self.infiles=infiles
15 | def write_merged(self):
16 | self.write_grid()
17 | self.write_data()
18 | def write_grid(self):
19 | # here - could decide on dialect, naming.
20 | ds=self.global_grid.write_to_xarray()
21 | ds.to_netcdf(self.outfile)
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/stompy/model/delft/nefis_nc.py:
--------------------------------------------------------------------------------
1 | """
2 | Converting between nefis and netcdf
3 | In a separate module to separate dependencies
4 |
5 | Relies on the qnc wrapper of netcdf4
6 | """
7 |
8 | from collections import defaultdict
9 | from ...io import qnc
10 |
11 | def nefis_to_nc(nef,squeeze_unl=True,squeeze_element=True,
12 | short_if_unique=True,to_lower=True,unl_name='time',
13 | element_map={},nc_kwargs={},nc=None):
14 | """
15 | nef: an open Nefis object
16 | squeeze_unl: unit length unlimited dimensions in groups are dropped
17 | groups can't be dimensionless, so parameter values are often in
18 | a unit-length group.
19 | short_if_unique: element names which appear in only one group get
20 | just the element name. others are group_element
21 | to_lower: make names lower case
22 | squeeze_element: unit dimensions in elements are also removed
23 | unl_name: if there is a unique unlimited dimension length (ignoring
24 | unit lengths if squeeze_unl is set) - use this name for it.
25 | element_map: map original element names to new names. this matches
26 | against element names before to_lower (but after strip), and the results
27 | will *not* be subject to to_lower.
28 | nc_kwargs: dict of argument to pass to qnc.empty
29 | nc: altenatively, an already open QDataset
30 | """
31 | if nc is None:
32 | nc=qnc.empty(**nc_kwargs)
33 | # required for writing to disk
34 | nc._set_string_mode('fixed')
35 |
36 | # string handling is a little funky -
37 | # still working out whether it should be varlen or fixed.
38 | # fixed makes the string length a new dimension, just annoying
39 | # to get strings back from that.
40 | # varlen ends up having an object dtype, which may not write out
41 | # well with netcdf.
42 |
43 | # check for unique element names
44 | name_count=defaultdict(lambda: 0)
45 | for group in nef.groups():
46 | for elt_name in group.cell.element_names:
47 | name_count[elt_name]+=1
48 |
49 | # check for unique unlimited dimension:
50 | n_unl=0
51 | for group in nef.groups():
52 | if 0 in group.shape and (group.unl_length()>1 or not squeeze_unl):
53 | n_unl+=1
54 |
55 | for group in nef.groups():
56 | # print group.name
57 |
58 | g_shape=group.shape
59 | grp_slices=[slice(None)]*len(g_shape)
60 | grp_dim_names=[None]*len(g_shape)
61 |
62 | if 0 in g_shape: # has an unlimitied dimension
63 | idx=list(g_shape).index(0)
64 | if group.unl_length()==1 and squeeze_unl: # which will be squeezed
65 | grp_slices[idx]=0
66 | elif n_unl==1 and unl_name: # which will be named
67 | grp_dim_names[idx]=unl_name
68 |
69 | for elt_name in group.cell.element_names:
70 | # print elt_name
71 |
72 | if name_count[elt_name]==1 and short_if_unique:
73 | vname=elt_name
74 | else:
75 | vname=group.name + "_" + elt_name
76 |
77 | if vname in element_map:
78 | vname=element_map[vname]
79 | elif to_lower:
80 | vname=vname.lower()
81 |
82 | value=group.getelt(elt_name)
83 | # apply slices
84 | value=value[tuple(grp_slices)]
85 |
86 | if squeeze_element:
87 | # slices specific to this element
88 | val_slices=[slice(None)]*len(value.shape)
89 | # iterate over just the element portion of the shape
90 | for idx in range(len(g_shape),len(val_slices)):
91 | if value.shape[idx]==1:
92 | val_slices[idx]=0
93 | value=value[val_slices]
94 |
95 | # mimics qnc naming.
96 | names=[qnc.anon_dim_name(size=l) for l in value.shape]
97 | for idx,name in enumerate(grp_dim_names):
98 | if name:
99 | names[idx]=name
100 | names.append(Ellipsis)
101 |
102 | nc[vname][names] = value
103 | setattr(nc.variables[vname],'group_name',group.name)
104 | return nc
105 |
106 |
--------------------------------------------------------------------------------
/stompy/model/delft/splice_waq.py:
--------------------------------------------------------------------------------
1 | # invoke with python -m delft.splice_waq
2 | # (assuming that delft is on PYTHONPATH
3 | # use waq_scenario machinery to stitch a bunch of subdomains into
4 | # a single subdomain.
5 | # sort of a repurposing of the DWaqAggregator.
6 |
7 | import os
8 | import logging
9 | import numpy as np
10 |
11 | logger = logging.getLogger()
12 |
13 | from ..suntans import sunreader
14 | from . import waq_scenario
15 | from . import sundwaq
16 | from ... import scriptable
17 |
18 | class SpliceScenario(waq_scenario.Scenario):
19 | pass
20 |
21 | class SunSplicer(scriptable.Scriptable):
22 | def cmd_merge(self,sun_dir,agg_shp="agg-cells.shp",name='global'):
23 | """ sun_dir [agg_shp] [name]
24 | sun_dir: path to directory containing suntans.dat
25 | agg_shp: path, absolute or relative to sun_dir, to shapefile definining
26 | aggregation. Defaults to creating a non-aggregating shapefile.
27 | name: the name under the dwaq directory for the output.
28 |
29 | Combines dwaq-formatted output from multiple processors into a single
30 | domain. Calls suntans_post and make_agg_shp as needed.
31 | """
32 | sun_dir=os.path.abspath(sun_dir)
33 |
34 | self.cmd_suntans_post(sun_dir)
35 | sun=sunreader.SunReader(sun_dir)
36 |
37 | run_prefix="sun"
38 | dwaq_path=os.path.join(sun.datadir,'dwaq')
39 |
40 | agg_shp=os.path.join(sun_dir,agg_shp)
41 | self.cmd_make_agg_shp(sun_dir,agg_shp)
42 |
43 | agg=waq_scenario.HydroMultiAggregator(agg_shp=agg_shp,
44 | run_prefix="sun",
45 | path=os.path.join(sun_dir,'dwaq'))
46 |
47 | scen=SpliceScenario(hydro=agg)
48 | scen.base_path=os.path.join(dwaq_path,"global")
49 | scen.name="spliced"
50 |
51 | scen.write_hydro()
52 |
53 | def cmd_make_agg_shp(self,sun_dir,agg_shp="grid-cells.shp"):
54 | """ sun_dir [agg_shp]
55 | If agg_shp does not exist, write a shapefile which retains all global
56 | cells (i.e. no aggregation)
57 | """
58 | # agg_shp is relative to sun_dir, unless it is an absolute
59 | # path
60 |
61 | agg_shp=os.path.join(sun_dir,agg_shp) # make it absolute
62 |
63 | if not os.path.exists(agg_shp):
64 | sun=sunreader.SunReader(sun_dir)
65 | g=sun.grid()
66 | fields=np.zeros(g.Ncells(),dtype=[('name',object)])
67 | fields['name'] =["%d"%c for c in range(g.Ncells())]
68 | g.write_cells_shp(agg_shp,overwrite=True,fields=fields)
69 |
70 | def cmd_suntans_post(self,sun_dir):
71 | """ sun_dir
72 | sun_dir: path to directory containing suntans.dat
73 | Write flowgeom.nc for each subdomain of dwaq output under the given
74 | directory.
75 | """
76 | sun=sunreader.SunReader(sun_dir)
77 | sundwaq.postprocess(sun=sun,force=False)
78 |
79 |
80 | if __name__ == '__main__':
81 | splicer=SunSplicer()
82 | splicer.main()
83 |
--------------------------------------------------------------------------------
/stompy/model/delft/test_agg.py:
--------------------------------------------------------------------------------
1 | """
2 | Tests related to aggregating WAQ hydro
3 | on hold, as the current aggregation code uses netcdf net files to
4 | figure out the partitions, which aren't available for the FTI
5 | tutorial case.
6 | """
7 | from __future__ import print_function
8 |
9 | import os
10 | import shutil
11 |
12 | import nose
13 | import numpy as np
14 | from . import waq_scenario
15 |
16 |
17 | PC=waq_scenario.ParameterConstant
18 | Sub=waq_scenario.Substance
19 | IC=waq_scenario.Initial
20 |
21 |
22 | class Testbox(waq_scenario.Scenario):
23 | base_path=os.path.join(os.path.dirname(__file__),'testbox')
24 | name="bloombox02-test"
25 |
26 | integration_option="15 NODISP-AT-BOUND LOWER-ORDER-AT-BOUND DISP-AT-NOFLOW"
27 |
28 | def cmd_default(self):
29 | self.cmd_write_runid()
30 | self.cmd_write_hydro()
31 |
32 | def test_agg():
33 | dwaq_path="data/waq_hyd" # /tut_fti_waq.hyd
34 | hydro=waq_scenario.DwaqAggregator("box_defs.shp",
35 | "r17",dwaq_path,nprocs=None)
36 |
37 | scen=TextBox(hydro=hydro)
38 |
39 | if os.path.exists(scen.base_path):
40 | print("base path:",scen.base_path)
41 | shutil.rmtree(scen.base_path)
42 |
43 | scen.cmd_default()
44 |
45 | shutil.rmtree(scen.base_path)
46 |
47 |
48 | if __name__=='__main__':
49 | nose.main()
50 |
--------------------------------------------------------------------------------
/stompy/model/delft/test_dflow_grid.py:
--------------------------------------------------------------------------------
1 | import nose
2 | import nefis
3 | import numpy as np
4 | import dflow_grid as dg
5 |
6 | def load_data():
7 | nef=nefis.Nefis('data/trim-tut_fti_waq.dat',
8 | 'data/trim-tut_fti_waq.def')
9 | g=dg.DflowGrid2D.from_nef_map(nef)
10 |
11 | u1=nef['map-series'].getelt('U1',[10])
12 | rho=nef['map-series'].getelt('RHO',[10])
13 | dp0=nef['map-const'].getelt('DP0',[0])
14 | dps0=nef['map-const'].getelt('DPS0',[0])
15 |
16 | nef.close()
17 | return g,u1,rho,dp0,dps0
18 |
19 | def test_create():
20 | g,u1,rho,dp0,dps0=load_data()
21 | assert(g)
22 |
23 | # Plotting
24 | def test_wireframe():
25 | g,u1,rho,dp0,dps0 = load_data()
26 | g.wireframe()
27 |
28 | def test_pcolor_face():
29 | g,u1,rho,dp0,dps0 = load_data()
30 | g.pcolor_face(rho[1])
31 |
32 | def test_contourf_node():
33 | g,u1,rho,dp0,dps0 = load_data()
34 | g.contourf_node(dp0)
35 |
36 | def test_pcolor_node():
37 | g,u1,rho,dp0,dps0 = load_data()
38 | g.pcolor_node(dp0)
39 |
40 | if __name__ == '__main__':
41 | nose.main()
42 |
--------------------------------------------------------------------------------
/stompy/model/delft/test_waq_process.py:
--------------------------------------------------------------------------------
1 | import nose
2 |
3 | from delft import waq_scenario
4 | from delft import waq_process
5 |
6 | def test_sub_lookup():
7 | scen=waq_scenario.Scenario(None)
8 | pdb=waq_process.ProcessDB(scenario=scen)
9 | sub=pdb.substance_by_id('Green')
10 |
11 | assert(sub.item_nm=='Algae (non-Diatoms)')
12 |
13 |
14 | if __name__ == '__main__':
15 | nose.main()
16 |
--------------------------------------------------------------------------------
/stompy/model/fvcom/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | INCOMPLETE
3 | Minimal start to tools for FVCOM runs
4 | """
5 |
--------------------------------------------------------------------------------
/stompy/model/fvcom/fvcom.py:
--------------------------------------------------------------------------------
1 | import netCDF4
2 | import memoize as memo
3 | import numpy as np
4 | import trigrid
5 | import pytz
6 |
7 | class FvcomNC(object):
8 | tz='US/Eastern'
9 | tzvalue='-0500'
10 |
11 | def __init__(self,nc_file,**kwargs):
12 | self.nc_file = nc_file
13 | self.nc=netCDF4.Dataset(self.nc_file)
14 | self.__dict__.update(kwargs)
15 |
16 | # pickle protocol interface - since Dataset cannot be pickled.
17 | def __getstate__(self):
18 | d = dict(self.__dict__)
19 | del d['nc']
20 | return d
21 | def __setstate__(self,d):
22 | self.__dict__.update(d)
23 | self.nc=netCDF4.Dataset(self.nc_file)
24 |
25 | @property
26 | @memo.memoize()
27 | def time(self):
28 | nc_t_var=self.nc.variables['time']
29 | units,origin = nc_t_var.units.split(" since ")
30 | if origin[-1] in '0123456789':
31 | origin = origin + self.tzvalue
32 | tzero = np.datetime64(origin,'s')
33 |
34 | days=self.nc.variables['Itime'][:] * np.timedelta64(1,'D')
35 | msecs=self.nc.variables['Itime2'][:]*np.timedelta64(1,'ms')
36 | t=tzero+days+msecs
37 | return t
38 |
39 | @property
40 | @memo.memoize()
41 | def points(self):
42 | return np.array( [self.nc.variables['x'][:],
43 | self.nc.variables['y'][:]], dtype='f8' ).T
44 | @property
45 | @memo.memoize()
46 | def centers(self):
47 | return np.array( [self.nc.variables['xc'][:],
48 | self.nc.variables['yc'][:]] ).T
49 | @property
50 | @memo.memoize()
51 | def trigrid(self):
52 | cells=self.nc.variables['nv'][:].T - 1
53 | points=self.points.copy()
54 | g=trigrid.TriGrid(points=points,cells=cells)
55 | areas=g.areas()
56 | sel=np.nonzero(areas<0)[0]
57 | cells[sel,:] = cells[sel,::-1]
58 |
59 | # make a clean one with the new cells
60 | g=trigrid.TriGrid(points=points,cells=cells)
61 | g.make_edges_from_cells()
62 | return g
63 |
64 | # convenience for getting cell centered mean quantities
65 | @property
66 | @memo.memoize()
67 | def hc(self):
68 | h=self.nc.variables['h'][:]
69 | return h[self.trigrid.cells].mean(axis=1)
70 |
71 | @memo.memoize(lru=2)
72 | def zetac(self,tidx):
73 | zeta=self.nc.variables['zeta'][tidx]
74 | return zeta[self.trigrid.cells].mean(axis=1)
75 |
76 | @memo.memoize(lru=2)
77 | def uvw(self,tidx,c=slice(None),sigma_layer=slice(None)):
78 | u=self.nc.variables['u'][tidx,sigma_layer,c]
79 | v=self.nc.variables['v'][tidx,sigma_layer,c]
80 | w=self.nc.variables['ww'][tidx,sigma_layer,c]
81 |
82 | return np.concatenate( (u[...,None],v[...,None],w[...,None]), axis=-1 )
83 |
84 | @memo.memoize(lru=2)
85 | def to_sigma_layer(self,tidx,c,X):
86 | """ 0-based sigma layer index
87 | """
88 | z=X[2]
89 | h=self.hc[c]
90 | zeta=self.zetac(tidx)[c]
91 |
92 | # [-1,0]
93 | sigma=(z-(-h))/(zeta-(-h)) - 1
94 | siglevels=self.nc.variables['siglev'][:,self.trigrid.cells[c]].mean(axis=1)
95 | layer=np.searchsorted(-siglevels,-sigma).clip(0,len(siglevels)-2)
96 | return layer
97 |
--------------------------------------------------------------------------------
/stompy/model/openfoam/cli.py:
--------------------------------------------------------------------------------
1 | from . import depth_average
2 | from ... import utils
3 | import os
4 |
5 | def main(argv=None):
6 | import argparse
7 |
8 | parser = argparse.ArgumentParser(description='Postprocess OpenFOAM results, esp. depth-averaging')
9 |
10 | parser.add_argument("-c", "--case", help="Path to case, default is working directory",
11 | default=".")
12 | parser.add_argument("-U", "--velocity", help="Enable depth-averaged velocity output",
13 | action="store_true")
14 | parser.add_argument("-s","--stage", help="Enable stage (water surface elevation) output",
15 | action="store_true")
16 | parser.add_argument("-t","--time", help="Select output times as comma-separated time names, or 'all'",
17 | default="all")
18 | parser.add_argument("-r","--res", help="Output raster cell size (positive), or count in x (negative)",
19 | default=20.0, type=float)
20 | parser.add_argument("-f","--force", help="Force overwrite existing files",action='store_true')
21 |
22 | args = parser.parse_args(argv)
23 |
24 | pf = depth_average.PostFoam(sim_dir=args.case)
25 |
26 | if args.time=='all':
27 | times = pf.available_times(omit_zero=True)
28 | else:
29 | times = args.time.split(",")
30 | print(f"{len(times)} time step(s) to process")
31 |
32 | raster_info = pf.set_raster_parameters(dx=args.res)
33 |
34 | print(f"Output rasters will be {raster_info['ny']}x{raster_info['nx']}")
35 | output_path=os.path.join(args.case,"postProcessing",'python')
36 | if not os.path.exists(output_path):
37 | os.makedirs(output_path)
38 | print(f"Writing output to {output_path}")
39 |
40 | for t in utils.progress(times,msg="Time steps: %s"):
41 | if args.velocity:
42 | fn=os.path.join(output_path,f"U_{t}.tif")
43 | if args.force or not os.path.exists(fn):
44 | fld_U=pf.to_raster('U',t)
45 | # should put the velocity components into bands.
46 | fld_U.write_gdal(fn,overwrite=True)
47 | if args.stage:
48 | fn=os.path.join(output_path,f"stage_{t}.tif")
49 | if args.force or not os.path.exists(fn):
50 | fld_stage=pf.to_raster('wse',t)
51 | fld_stage.write_gdal(fn,overwrite=True)
52 |
53 | if __name__ == '__main__':
54 | main()
55 |
--------------------------------------------------------------------------------
/stompy/model/otps/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 |
--------------------------------------------------------------------------------
/stompy/model/otps/__init__.py:
--------------------------------------------------------------------------------
1 | from .otps_model import *
2 |
--------------------------------------------------------------------------------
/stompy/model/pypart/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing to do
2 |
--------------------------------------------------------------------------------
/stompy/model/slurm_mixin.py:
--------------------------------------------------------------------------------
1 | """
2 | First cut at refactoring slurm interaction
3 | """
4 |
5 | # For farm -- assumes that for any mpi work we're already in a job.
6 | class SlurmMixin:
7 | @classmethod
8 | def slurm_jobid(cls):
9 | return os.environ.get('SLURM_JOBID',None)
10 |
11 | @classmethod
12 | def assert_slurm(cls):
13 | # Could use srun outside of an existing job to synchronously
14 | # schedule and run. But then we'd have to get the partition and task
15 | # details down to here.
16 | assert cls.slurm_jobid() is not None,"mpi tasks need to be run within a job!"
17 |
18 | @classmethod
19 | def slurm_num_procs(cls):
20 | return int(os.environ['SLURM_NTASKS'])
21 |
22 | @classmethod
23 | def slurm_pack_options(cls,n):
24 | """
25 | Return options to pass to srun to invoke an mpi task
26 | with n cpus.
27 | """
28 | # is there a single component that works?
29 | n_het_tasks=0 # running count of tasks across components
30 | packs=[] # list of components needed to get to n
31 |
32 | # Scan up to 10 components:
33 | for group in range(10):
34 | group=str(group)
35 | group_size=int(os.environ.get( f'SLURM_NTASKS_PACK_GROUP_{group}', 0))
36 | if group_size==0: break
37 | if group_size>=n:
38 | packs=[group]
39 | break
40 | if n_het_tasks0:
51 | print(f"Scanned PACK_GROUPS and found {n_het_tasks} < {n}. No can do.",
52 | flush=True)
53 | raise Exception("Insufficient cpus for MPI request")
54 | else:
55 | # Not a pack job.
56 | n_tasks=int(os.environ.get('SLURM_NTASKS',0))
57 | if n_tasks==n:
58 | print(f"Homogeneous job, and n==NTASKS")
59 | return []
60 | elif n_tasks SLURM ntasks {n_tasks}")
62 | else:
63 | options=['-n',str(n)]
64 | print(f"Homogeneous oversized job. Add {' '.join(options)}",
65 | flush=True)
66 | return options
67 |
68 | def run_mpi(self,sun_args):
69 | # This needs to be better abstracted, not suntans specific.
70 | self.assert_slurm()
71 |
72 | sun="sun"
73 | if self.sun_bin_dir is not None:
74 | sun=os.path.join(self.sun_bin_dir,sun)
75 |
76 | pack_opts=self.slurm_pack_options(self.num_procs)
77 | cmd=["srun"]
78 | cmd+=pack_opts
79 | cmd+=[sun] + sun_args
80 | print("About to invoke MPI cmd:")
81 | print(cmd,flush=True)
82 | subprocess.call(cmd)
83 |
84 |
--------------------------------------------------------------------------------
/stompy/model/suntans/__init__.py:
--------------------------------------------------------------------------------
1 | # make it importable
2 |
--------------------------------------------------------------------------------
/stompy/plot/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing
2 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/Blue_Cyan_Yellow.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/nd/basic/Blue_Cyan_Yellow.cpt
2 | # autogenerated GMT palette "Basic_Blue_Cyan_Yellow"
3 | # cptutils version 1.44, Tue Mar 13 13:16:00 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 0 255 25 0 128 255
6 | 25 0 128 255 50 0 255 255
7 | 50 0 255 255 75 128 255 128
8 | 75 128 255 128 100 255 255 0
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/DEM_screen.cpt:
--------------------------------------------------------------------------------
1 | # cpt file created by: Thomas Dewez for elevations
2 | #
3 | # COLOR_MODEL = RGB
4 | 0 0 132 53 100 51 204 0
5 | 100 51 204 0 200 244 240 113
6 | 200 244 240 113 400 244 189 69
7 | 400 244 189 69 600 153 100 43
8 | 600 153 100 43 800 255 255 255
9 | B 255 255 255
10 | F 0 132 53
11 | N 0 132 53
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/GMT_cyclic.cpt:
--------------------------------------------------------------------------------
1 | # $Id: GMT_cyclic.cpt,v 1.1 2007/10/01 15:36:21 remko Exp $
2 | #
3 | # Cyclic spectrum, spans 360 degrees of hue
4 | # Designed by Remko Scharroo, Altimetrics LLC
5 | # COLOR_MODEL = +HSV
6 | 0 0 1 1 180 180 1 1
7 | 180 180 1 1 360 360 1 1
8 | B 0 0 1
9 | F 0 0 0
10 | N 0 0 0.75
11 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/GMT_drywet.cpt:
--------------------------------------------------------------------------------
1 | # $Id: GMT_drywet.cpt,v 1.1 2002/05/23 22:59:15 pwessel Exp $
2 | #
3 | # Dry to Wet colorbar
4 | # Created by Ed Maurer, U Washington
5 | 0 134 97 42 2 238 199 100
6 | 2 238 199 100 4 180 238 135
7 | 4 180 238 135 6 50 238 235
8 | 6 50 238 235 8 12 120 238
9 | 8 12 120 238 10 38 1 183
10 | 10 38 1 183 12 8 51 113
11 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/Primary_04.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/nd/rich/Primary_04.cpt
2 | # autogenerated GMT palette "Rich Primary 04"
3 | # cptutils version 1.44, Tue Mar 13 13:15:15 2012
4 | # COLOR_MODEL = RGB
5 | 0 217 217 0 25 217 108 0
6 | 25 217 108 0 50 217 0 0
7 | 50 217 0 0 75 108 28 70
8 | 75 108 28 70 100 0 56 140
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/RdYlGn.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: RdYlGn
3 | 8
4 | 0.000000 0.062500 0.125000 0.647059 0.000000 0.149020 1.000000 0.843137 0.188235 0.152941 1.000000 0 0
5 | 0.125000 0.187500 0.250000 0.843137 0.188235 0.152941 1.000000 0.956863 0.427451 0.262745 1.000000 0 0
6 | 0.250000 0.312500 0.375000 0.956863 0.427451 0.262745 1.000000 0.992157 0.682353 0.380392 1.000000 0 0
7 | 0.375000 0.437500 0.500000 0.992157 0.682353 0.380392 1.000000 0.996078 0.878431 0.545098 1.000000 0 0
8 | 0.500000 0.562500 0.625000 0.850980 0.937255 0.545098 1.000000 0.650980 0.850980 0.415686 1.000000 0 0
9 | 0.625000 0.687500 0.750000 0.650980 0.850980 0.415686 1.000000 0.400000 0.741176 0.388235 1.000000 0 0
10 | 0.750000 0.812500 0.875000 0.400000 0.741176 0.388235 1.000000 0.101961 0.596078 0.313725 1.000000 0 0
11 | 0.875000 0.937500 1.000000 0.101961 0.596078 0.313725 1.000000 0.000000 0.407843 0.215686 1.000000 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/Spectral.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: Spectral
3 | 8
4 | 0.000000 0.062500 0.125000 0.619608 0.003922 0.258824 1.000000 0.835294 0.243137 0.309804 1.000000 0 0
5 | 0.125000 0.187500 0.250000 0.835294 0.243137 0.309804 1.000000 0.956863 0.427451 0.262745 1.000000 0 0
6 | 0.250000 0.312500 0.375000 0.956863 0.427451 0.262745 1.000000 0.992157 0.682353 0.380392 1.000000 0 0
7 | 0.375000 0.437500 0.500000 0.992157 0.682353 0.380392 1.000000 0.996078 0.878431 0.545098 1.000000 0 0
8 | 0.500000 0.562500 0.625000 0.901961 0.960784 0.596078 1.000000 0.670588 0.866667 0.643137 1.000000 0 0
9 | 0.625000 0.687500 0.750000 0.670588 0.866667 0.643137 1.000000 0.400000 0.760784 0.647059 1.000000 0 0
10 | 0.750000 0.812500 0.875000 0.400000 0.760784 0.647059 1.000000 0.196078 0.533333 0.741176 1.000000 0 0
11 | 0.875000 0.937500 1.000000 0.196078 0.533333 0.741176 1.000000 0.368627 0.309804 0.635294 1.000000 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/Split_Complementary_01a.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/nd/turanj/Split_Complementary_01a.cpt
2 | # autogenerated GMT palette "Turanj Split Complementary 01a"
3 | # cptutils version 1.44, Tue Mar 13 13:15:19 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 25 255 25 128 63 128
6 | 25 128 63 128 50 255 102 0
7 | 50 255 102 0 75 128 178 76
8 | 75 128 178 76 100 0 255 153
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/Split_Complementary_07.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/nd/vermillion/Split_Complementary_07.cpt
2 | # autogenerated GMT palette "Vermillion Split Complementary 07"
3 | # cptutils version 1.44, Tue Mar 13 13:16:06 2012
4 | # COLOR_MODEL = RGB
5 | 0 217 22 43 25 108 62 149
6 | 25 108 62 149 50 0 102 255
7 | 50 0 102 255 75 0 147 137
8 | 75 0 147 137 100 0 191 19
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/StepSeq25.cpt:
--------------------------------------------------------------------------------
1 | # ../cpt/ncar/StepSeq25.cpt
2 | # autogenerated GMT palette "StepSeq25.txt"
3 | # cptutils version 1.41, Fri Jan 20 21:02:01 2012
4 | # COLOR_MODEL = RGB
5 | 0.000000e+00 153 15 15 1.000000e+00 153 15 15
6 | 1.000000e+00 178 44 44 2.000000e+00 178 44 44
7 | 2.000000e+00 204 81 81 3.000000e+00 204 81 81
8 | 3.000000e+00 229 126 126 4.000000e+00 229 126 126
9 | 4.000000e+00 255 178 178 5.000000e+00 255 178 178
10 | 5.000000e+00 153 84 15 6.000000e+00 153 84 15
11 | 6.000000e+00 178 111 44 7.000000e+00 178 111 44
12 | 7.000000e+00 204 142 81 8.000000e+00 204 142 81
13 | 8.000000e+00 229 177 126 9.000000e+00 229 177 126
14 | 9.000000e+00 255 216 178 1.000000e+01 255 216 178
15 | 1.000000e+01 107 153 15 1.100000e+01 107 153 15
16 | 1.100000e+01 133 178 44 1.200000e+01 133 178 44
17 | 1.200000e+01 163 204 81 1.300000e+01 163 204 81
18 | 1.300000e+01 195 229 126 1.400000e+01 195 229 126
19 | 1.400000e+01 229 255 178 1.500000e+01 229 255 178
20 | 1.500000e+01 15 107 153 1.600000e+01 15 107 153
21 | 1.600000e+01 44 133 178 1.700000e+01 44 133 178
22 | 1.700000e+01 81 163 204 1.800000e+01 81 163 204
23 | 1.800000e+01 126 195 229 1.900000e+01 126 195 229
24 | 1.900000e+01 178 229 255 2.000000e+01 178 229 255
25 | 2.000000e+01 38 15 153 2.100000e+01 38 15 153
26 | 2.100000e+01 66 44 178 2.200000e+01 66 44 178
27 | 2.200000e+01 101 81 204 2.300000e+01 101 81 204
28 | 2.300000e+01 143 126 229 2.400000e+01 143 126 229
29 | 2.400000e+01 191 178 255 2.500000e+01 191 178 255
30 | B 0 0 0
31 | F 255 255 255
32 | N 255 0 0
33 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/Tertiary_01b.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/nd/terra/Tertiary_01b.cpt
2 | # autogenerated GMT palette "Terra Tertiary 01b"
3 | # cptutils version 1.44, Tue Mar 13 13:15:33 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 13 127 25 96 17 82
6 | 25 96 17 82 50 191 21 38
7 | 50 191 21 38 75 222 138 19
8 | 75 222 138 19 100 252 255 0
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/YlOrRd_09.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: YlOrRd_09
3 | 9
4 | 0.000000 0.055550 0.111100 1.000000 1.000000 0.800000 1.000000 1.000000 1.000000 0.800000 1.000000 0 0
5 | 0.111100 0.166650 0.222200 1.000000 0.929412 0.627451 1.000000 1.000000 0.929412 0.627451 1.000000 0 0
6 | 0.222200 0.277750 0.333300 0.996078 0.850980 0.462745 1.000000 0.996078 0.850980 0.462745 1.000000 0 0
7 | 0.333300 0.388850 0.444400 0.996078 0.698039 0.298039 1.000000 0.996078 0.698039 0.298039 1.000000 0 0
8 | 0.444400 0.500000 0.555600 0.992157 0.552941 0.235294 1.000000 0.992157 0.552941 0.235294 1.000000 0 0
9 | 0.555600 0.611150 0.666700 0.988235 0.305882 0.164706 1.000000 0.988235 0.305882 0.164706 1.000000 0 0
10 | 0.666700 0.722250 0.777800 0.890196 0.101961 0.109804 1.000000 0.890196 0.101961 0.109804 1.000000 0 0
11 | 0.777800 0.833350 0.888900 0.741176 0.000000 0.149020 1.000000 0.741176 0.000000 0.149020 1.000000 0 0
12 | 0.888900 0.944450 1.000000 0.501961 0.000000 0.149020 1.000000 0.501961 0.000000 0.149020 1.000000 0 0
13 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/__init__.py:
--------------------------------------------------------------------------------
1 | # really a data directoy, but setup complains if there isn't an init file.
2 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/aspectcolr.cpt:
--------------------------------------------------------------------------------
1 | # GMT colour palette table (cpt)
2 | # grass2cpt ouput
3 | # COLOR_MODEL = RGB
4 | 0.000000e+00 255 255 255 1.000000e+00 255 255 0
5 | 1.000000e+00 255 255 0 9.000000e+01 0 255 0
6 | 9.000000e+01 0 255 0 1.800000e+02 0 255 255
7 | 1.800000e+02 0 255 255 2.700000e+02 255 0 0
8 | 2.700000e+02 255 0 0 3.600000e+02 255 255 0
9 | N 128 128 128
10 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/brightsong2.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/pj/1/brightsong2.cpt
2 | # autogenerated GMT palette "pj-brightsong2"
3 | # cptutils version 1.44, Tue Mar 13 13:17:05 2012
4 | # COLOR_MODEL = RGB
5 | 0 74 228 103 29 255 255 64
6 | 29 255 255 64 100 255 63 153
7 | B 0 0 0
8 | F 255 255 255
9 | N 255 0 0
10 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/butterflyfairy.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/rc/butterflyfairy.cpt
2 | # autogenerated GMT palette "~1butterflyfairy"
3 | # cptutils version 1.44, Tue Mar 13 13:17:36 2012
4 | # COLOR_MODEL = RGB
5 | 0 167 77 38 25 215 167 105
6 | 25 215 167 105 50 133 203 206
7 | 50 133 203 206 75 19 88 138
8 | 75 19 88 138 100 1 6 9
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/caleblack.cpt:
--------------------------------------------------------------------------------
1 | # taken from visit's caleblack
2 | #
3 | #
4 | # COLOR_MODEL = RGB
5 | 0 0 0 0 25 0 0 255
6 | 25 0 0 255 50 0 255 255
7 | 50 0 255 255 75 0 255 0
8 | 75 0 255 0 100 255 255 0
9 | 100 255 255 0 125 255 0 0
10 | 125 255 0 0 150 255 0 255
11 | B 0 0 0
12 | F 255 255 255
13 | N 255 0 0
14 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/cbcSpectral.cpt:
--------------------------------------------------------------------------------
1 | # cbcont/div/cbcSpectral.cpt
2 | # autogenerated GMT palette "Spectral_11"
3 | # cptutils version 1.36, Sun Apr 18 18:51:48 2010
4 | # COLOR_MODEL = RGB
5 | -5.500000e+00 158 1 66 -5.000000e+00 158 1 66
6 | -5.000000e+00 158 1 66 -4.500000e+00 186 32 72
7 | -4.500000e+00 186 32 72 -4.000000e+00 213 62 79
8 | -4.000000e+00 213 62 79 -3.500000e+00 228 86 73
9 | -3.500000e+00 228 86 73 -3.000000e+00 244 109 67
10 | -3.000000e+00 244 109 67 -2.500000e+00 249 142 82
11 | -2.500000e+00 249 142 82 -2.000000e+00 253 174 97
12 | -2.000000e+00 253 174 97 -1.500000e+00 254 199 118
13 | -1.500000e+00 254 199 118 -1.000000e+00 254 224 139
14 | -1.000000e+00 254 224 139 -5.000000e-01 254 240 165
15 | -5.000000e-01 254 240 165 0.000000e+00 255 255 191
16 | 0.000000e+00 255 255 191 5.000000e-01 242 250 172
17 | 5.000000e-01 242 250 172 1.000000e+00 230 245 152
18 | 1.000000e+00 230 245 152 1.500000e+00 200 233 158
19 | 1.500000e+00 200 233 158 2.000000e+00 171 221 164
20 | 2.000000e+00 171 221 164 2.500000e+00 136 208 164
21 | 2.500000e+00 136 208 164 3.000000e+00 102 194 165
22 | 3.000000e+00 102 194 165 3.500000e+00 76 165 177
23 | 3.500000e+00 76 165 177 4.000000e+00 50 136 189
24 | 4.000000e+00 50 136 189 4.500000e+00 72 108 176
25 | 4.500000e+00 72 108 176 5.000000e+00 94 79 162
26 | 5.000000e+00 94 79 162 5.500000e+00 94 79 162
27 | B 0 0 0
28 | F 0 0 0
29 | N 0 0 0
30 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/colormaps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/stompy/plot/cmaps/colormaps.png
--------------------------------------------------------------------------------
/stompy/plot/cmaps/diverging.cpt:
--------------------------------------------------------------------------------
1 | # COLOR_MODEL = RGB
2 | 0 204 255 255 45 146 194 255
3 | 35 146 194 255 50 0 0 0
4 | 50 0 0 0 65 239 207 136
5 | 65 239 207 136 100 255 255 186
6 | B 0 0 0
7 | F 255 255 255
8 | N 255 0 255
9 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/dkbluered.cpt:
--------------------------------------------------------------------------------
1 | # autogenerated GMT palette ""
2 | # cptutils version 1.31, Mon Feb 2 00:31:48 2009
3 | # COLOR_MODEL = RGB
4 | 0.000000e+00 7 0 51 1.000000e+00 17 0 79
5 | 1.000000e+00 17 0 79 2.000000e+00 25 0 107
6 | 2.000000e+00 25 0 107 3.000000e+00 28 0 135
7 | 3.000000e+00 28 0 135 4.000000e+00 25 0 163
8 | 4.000000e+00 25 0 163 5.000000e+00 22 0 191
9 | 5.000000e+00 22 0 191 6.000000e+00 15 0 219
10 | 6.000000e+00 15 0 219 7.000000e+00 2 0 247
11 | 7.000000e+00 2 0 247 8.000000e+00 20 33 255
12 | 8.000000e+00 20 33 255 9.000000e+00 56 76 255
13 | 9.000000e+00 56 76 255 1.000000e+01 89 117 255
14 | 1.000000e+01 89 117 255 1.100000e+01 122 153 255
15 | 1.100000e+01 122 153 255 1.200000e+01 155 186 255
16 | 1.200000e+01 155 186 255 1.300000e+01 191 211 255
17 | 1.300000e+01 191 211 255 1.400000e+01 224 237 255
18 | 1.400000e+01 224 237 255 1.500000e+01 255 255 255
19 | 1.500000e+01 255 255 255 1.600000e+01 255 237 224
20 | 1.600000e+01 255 237 224 1.700000e+01 255 211 191
21 | 1.700000e+01 255 211 191 1.800000e+01 255 186 155
22 | 1.800000e+01 255 186 155 1.900000e+01 255 153 122
23 | 1.900000e+01 255 153 122 2.000000e+01 255 117 89
24 | 2.000000e+01 255 117 89 2.100000e+01 255 76 56
25 | 2.100000e+01 255 76 56 2.200000e+01 255 33 20
26 | 2.200000e+01 255 33 20 2.300000e+01 247 0 2
27 | 2.300000e+01 247 0 2 2.400000e+01 219 0 15
28 | 2.400000e+01 219 0 15 2.500000e+01 191 0 22
29 | 2.500000e+01 191 0 22 2.600000e+01 163 0 25
30 | 2.600000e+01 163 0 25 2.700000e+01 135 0 28
31 | 2.700000e+01 135 0 28 2.800000e+01 107 0 25
32 | 2.800000e+01 107 0 25 2.900000e+01 79 0 17
33 | 2.900000e+01 79 0 17 3.000000e+01 53 0 7
34 | B 0 0 0
35 | F 255 255 255
36 | N 255 0 0
37 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/es_platinum_06.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/es/platinum/es_platinum_06.cpt
2 | # autogenerated GMT palette "ES Platinum 06"
3 | # cptutils version 1.44, Tue Mar 13 13:18:16 2012
4 | # COLOR_MODEL = RGB
5 | 0 30 35 39 100 240 242 244
6 | B 0 0 0
7 | F 255 255 255
8 | N 255 0 0
9 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/f-30-31-32.cpt:
--------------------------------------------------------------------------------
1 | # f-30-31-32.cpt
2 | # autogenerated GMT palette "formula-30-31-32.rgb"
3 | # cptutils version 1.44, Tue Mar 13 13:00:30 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 0 0 1 0 0 16
6 | 1 0 0 16 2 0 0 32
7 | 2 0 0 32 3 0 0 49
8 | 3 0 0 49 4 0 0 65
9 | 4 0 0 65 5 0 0 81
10 | 5 0 0 81 6 0 0 97
11 | 6 0 0 97 7 0 0 113
12 | 7 0 0 113 8 0 0 130
13 | 8 0 0 130 9 0 0 146
14 | 9 0 0 146 10 0 0 162
15 | 10 0 0 162 11 0 0 178
16 | 11 0 0 178 12 0 0 194
17 | 12 0 0 194 13 0 0 210
18 | 13 0 0 210 14 0 0 227
19 | 14 0 0 227 15 0 0 243
20 | 15 0 0 243 16 3 0 255
21 | 16 3 0 255 17 16 0 255
22 | 17 16 0 255 18 28 0 255
23 | 18 28 0 255 19 41 0 255
24 | 19 41 0 255 20 54 0 255
25 | 20 54 0 255 21 66 0 255
26 | 21 66 0 255 22 79 0 255
27 | 22 79 0 255 23 92 0 255
28 | 23 92 0 255 24 104 0 255
29 | 24 104 0 255 25 117 0 255
30 | 25 117 0 255 26 130 0 255
31 | 26 130 0 255 27 142 4 251
32 | 27 142 4 251 28 155 12 243
33 | 28 155 12 243 29 168 21 234
34 | 29 168 21 234 30 180 29 226
35 | 30 180 29 226 31 193 37 218
36 | 31 193 37 218 32 206 45 210
37 | 32 206 45 210 33 218 53 202
38 | 33 218 53 202 34 231 61 194
39 | 34 231 61 194 35 243 69 186
40 | 35 243 69 186 36 255 77 178
41 | 36 255 77 178 37 255 85 170
42 | 37 255 85 170 38 255 93 162
43 | 38 255 93 162 39 255 102 153
44 | 39 255 102 153 40 255 110 145
45 | 40 255 110 145 41 255 118 137
46 | 41 255 118 137 42 255 126 129
47 | 42 255 126 129 43 255 134 121
48 | 43 255 134 121 44 255 142 113
49 | 44 255 142 113 45 255 150 105
50 | 45 255 150 105 46 255 158 97
51 | 46 255 158 97 47 255 166 89
52 | 47 255 166 89 48 255 174 81
53 | 48 255 174 81 49 255 182 73
54 | 49 255 182 73 50 255 191 64
55 | 50 255 191 64 51 255 199 56
56 | 51 255 199 56 52 255 207 48
57 | 52 255 207 48 53 255 215 40
58 | 53 255 215 40 54 255 223 32
59 | 54 255 223 32 55 255 231 24
60 | 55 255 231 24 56 255 239 16
61 | 56 255 239 16 57 255 247 8
62 | 57 255 247 8 58 255 255 2
63 | 58 255 255 2 59 255 255 53
64 | 59 255 255 53 60 255 255 103
65 | 60 255 255 103 61 255 255 154
66 | 61 255 255 154 62 255 255 204
67 | 62 255 255 204 63 255 255 255
68 | B 0 0 0
69 | F 255 255 255
70 | N 255 0 0
71 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/haxby.cpt:
--------------------------------------------------------------------------------
1 | # GMT colour palette table (cpt)
2 | # grass2cpt ouput
3 | # COLOR_MODEL = RGB
4 | 0.000000e+00 37 57 175 1.000000e+01 40 127 251
5 | 1.000000e+01 40 127 251 2.000000e+01 50 190 255
6 | 2.000000e+01 50 190 255 3.000000e+01 106 235 255
7 | 3.000000e+01 106 235 255 4.000000e+01 138 236 174
8 | 4.000000e+01 138 236 174 5.000000e+01 205 255 162
9 | 5.000000e+01 205 255 162 6.000000e+01 240 236 121
10 | 6.000000e+01 240 236 121 7.000000e+01 255 189 87
11 | 7.000000e+01 255 189 87 8.000000e+01 255 161 68
12 | 8.000000e+01 255 161 68 9.000000e+01 255 186 133
13 | 9.000000e+01 255 186 133 1.000000e+02 255 255 255
14 | N 128 128 128
15 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/hot_and_cold.cpt:
--------------------------------------------------------------------------------
1 | # taken from visit's hot_and_cold
2 | #
3 | #
4 | # COLOR_MODEL = RGB
5 | 0 0 255 255 45 0 0 255
6 | 45 0 0 255 50 64 0 64
7 | 50 64 0 64 55 255 0 0
8 | 55 255 0 0 100 255 255 0
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/hot_desaturated.cpt:
--------------------------------------------------------------------------------
1 | # taken from visit's hot_desaturated
2 | #
3 | #
4 | # COLOR_MODEL = RGB
5 | 0 71 71 219 25 0 0 91
6 | 25 0 0 91 50 0 255 255
7 | 50 0 255 255 75 0 127 0
8 | 75 0 127 0 100 255 255 0
9 | 100 255 255 0 125 255 96 0
10 | 125 255 96 0 150 107 0 0
11 | 150 107 0 0 175 224 76 76
12 | B 0 0 0
13 | F 255 255 255
14 | N 255 0 0
15 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/iris1.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/pj/3/iris1.cpt
2 | # autogenerated GMT palette "pj3-iris1"
3 | # cptutils version 1.44, Tue Mar 13 13:17:01 2012
4 | # COLOR_MODEL = RGB
5 | 0.00 255 255 255 16.99 114 24 140
6 | 16.99 114 24 140 30.00 76 57 131
7 | 30.00 76 57 131 52.00 17 162 2
8 | 52.00 17 162 2 77.00 65 195 65
9 | 77.00 65 195 65 95.00 58 116 68
10 | 95.00 58 116 68 100.00 58 116 68
11 | B 0 0 0
12 | F 255 255 255
13 | N 255 0 0
14 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/nonlinear_gray01.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: nonlinear_gray01
3 | 4
4 | 0.000000 0.057487 0.110294 0.000000 0.000000 0.000000 1.000000 0.250000 0.250000 0.250000 1.000000 0 0 0 0
5 | 0.110294 0.308824 0.493984 0.250000 0.250000 0.250000 1.000000 0.500000 0.500000 0.500000 1.000000 0 0 0 0
6 | 0.493984 0.625000 0.864973 0.500000 0.500000 0.500000 1.000000 0.750000 0.750000 0.750000 1.000000 0 0 0 0
7 | 0.864973 0.949198 1.000000 0.750000 0.750000 0.750000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 0 0
8 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/nrl_sirkes.cpt:
--------------------------------------------------------------------------------
1 | # ../cpt/ncar/nrl_sirkes.cpt
2 | # autogenerated GMT palette "nrl_sirkes.txt"
3 | # cptutils version 1.41, Fri Jan 20 21:02:01 2012
4 | # COLOR_MODEL = RGB
5 | 0.000000e+00 0 97 128 1.000000e+00 0 97 128
6 | 1.000000e+00 0 128 161 2.000000e+00 0 128 161
7 | 2.000000e+00 0 161 191 3.000000e+00 0 161 191
8 | 3.000000e+00 0 191 224 4.000000e+00 0 191 224
9 | 4.000000e+00 0 224 255 5.000000e+00 0 224 255
10 | 5.000000e+00 0 255 255 6.000000e+00 0 255 255
11 | 6.000000e+00 51 252 252 7.000000e+00 51 252 252
12 | 7.000000e+00 102 252 252 8.000000e+00 102 252 252
13 | 8.000000e+00 153 252 252 9.000000e+00 153 252 252
14 | 9.000000e+00 204 252 252 1.000000e+01 204 252 252
15 | 1.000000e+01 255 255 255 1.100000e+01 255 255 255
16 | 1.100000e+01 252 252 0 1.200000e+01 252 252 0
17 | 1.200000e+01 252 224 0 1.300000e+01 252 224 0
18 | 1.300000e+01 252 191 0 1.400000e+01 252 191 0
19 | 1.400000e+01 252 161 0 1.500000e+01 252 161 0
20 | 1.500000e+01 252 128 0 1.600000e+01 252 128 0
21 | 1.600000e+01 252 97 0 1.700000e+01 252 97 0
22 | 1.700000e+01 252 64 0 1.800000e+01 252 64 0
23 | 1.800000e+01 252 33 0 1.900000e+01 252 33 0
24 | 1.900000e+01 191 0 0 2.000000e+01 191 0 0
25 | 2.000000e+01 128 0 0 2.100000e+01 128 0 0
26 | B 0 0 0
27 | F 255 255 255
28 | N 255 0 0
29 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/nrl_sirkes_nowhite.cpt:
--------------------------------------------------------------------------------
1 | # ../cpt/ncar/nrl_sirkes_nowhite.cpt
2 | # autogenerated GMT palette "nrl_sirkes_nowhite.txt"
3 | # cptutils version 1.41, Fri Jan 20 21:02:02 2012
4 | # COLOR_MODEL = RGB
5 | 0.000000e+00 0 97 128 1.000000e+00 0 97 128
6 | 1.000000e+00 0 128 161 2.000000e+00 0 128 161
7 | 2.000000e+00 0 161 191 3.000000e+00 0 161 191
8 | 3.000000e+00 0 191 224 4.000000e+00 0 191 224
9 | 4.000000e+00 0 224 255 5.000000e+00 0 224 255
10 | 5.000000e+00 0 255 255 6.000000e+00 0 255 255
11 | 6.000000e+00 51 252 252 7.000000e+00 51 252 252
12 | 7.000000e+00 102 252 252 8.000000e+00 102 252 252
13 | 8.000000e+00 153 252 252 9.000000e+00 153 252 252
14 | 9.000000e+00 252 252 0 1.000000e+01 252 252 0
15 | 1.000000e+01 252 224 0 1.100000e+01 252 224 0
16 | 1.100000e+01 252 191 0 1.200000e+01 252 191 0
17 | 1.200000e+01 252 161 0 1.300000e+01 252 161 0
18 | 1.300000e+01 252 128 0 1.400000e+01 252 128 0
19 | 1.400000e+01 252 97 0 1.500000e+01 252 97 0
20 | 1.500000e+01 252 64 0 1.600000e+01 252 64 0
21 | 1.600000e+01 252 33 0 1.700000e+01 252 33 0
22 | 1.700000e+01 191 0 0 1.800000e+01 191 0 0
23 | 1.800000e+01 128 0 0 1.900000e+01 128 0 0
24 | B 0 0 0
25 | F 255 255 255
26 | N 255 0 0
27 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/parrot.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/rc/parrot.cpt
2 | # autogenerated GMT palette "~1parrot"
3 | # cptutils version 1.44, Tue Mar 13 13:17:36 2012
4 | # COLOR_MODEL = RGB
5 | 0.00 195 0 33 45.00 231 211 85
6 | 45.00 231 211 85 55.00 231 211 85
7 | 55.00 231 211 85 85.01 0 29 112
8 | 85.01 0 29 112 100.00 0 29 112
9 | B 0 0 0
10 | F 255 255 255
11 | N 255 0 0
12 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/pm3d14.cpt:
--------------------------------------------------------------------------------
1 | # pm3d14.cpt
2 | # autogenerated GMT palette "pm3d14.rgb"
3 | # cptutils version 1.44, Tue Mar 13 12:59:53 2012
4 | # COLOR_MODEL = RGB
5 | 0 255 255 255 1 223 255 230
6 | 1 223 255 230 2 210 255 204
7 | 2 210 255 204 3 199 255 180
8 | 3 199 255 180 4 191 255 156
9 | 4 191 255 156 5 183 255 133
10 | 5 183 255 133 6 176 255 111
11 | 6 176 255 111 7 170 255 91
12 | 7 170 255 91 8 164 254 72
13 | 8 164 254 72 9 159 254 56
14 | 9 159 254 56 10 153 254 41
15 | 10 153 254 41 11 148 254 28
16 | 11 148 254 28 12 144 253 18
17 | 12 144 253 18 13 139 253 10
18 | 13 139 253 10 14 135 252 4
19 | 14 135 252 4 15 131 252 1
20 | 15 131 252 1 16 126 251 0
21 | 16 126 251 0 17 123 250 2
22 | 17 123 250 2 18 119 249 6
23 | 18 119 249 6 19 115 248 13
24 | 19 115 248 13 20 111 247 23
25 | 20 111 247 23 21 108 246 34
26 | 21 108 246 34 22 104 244 48
27 | 22 104 244 48 23 101 243 64
28 | 23 101 243 64 24 98 241 82
29 | 24 98 241 82 25 94 239 101
30 | 25 94 239 101 26 91 237 122
31 | 26 91 237 122 27 88 235 144
32 | 27 88 235 144 28 85 233 168
33 | 28 85 233 168 29 82 230 192
34 | 29 82 230 192 30 79 227 217
35 | 30 79 227 217 31 76 225 242
36 | 31 76 225 242 32 73 222 255
37 | 32 73 222 255 33 70 218 255
38 | 33 70 218 255 34 68 215 255
39 | 34 68 215 255 35 65 211 255
40 | 35 65 211 255 36 62 207 255
41 | 36 62 207 255 37 60 203 255
42 | 37 60 203 255 38 57 199 255
43 | 38 57 199 255 39 54 195 255
44 | 39 54 195 255 40 52 190 255
45 | 40 52 190 255 41 49 185 255
46 | 41 49 185 255 42 47 179 255
47 | 42 47 179 255 43 44 174 255
48 | 43 44 174 255 44 42 168 255
49 | 44 42 168 255 45 39 162 255
50 | 45 39 162 255 46 37 156 255
51 | 46 37 156 255 47 35 149 255
52 | 47 35 149 255 48 32 142 255
53 | 48 32 142 255 49 30 135 255
54 | 49 30 135 255 50 28 128 255
55 | 50 28 128 255 51 26 120 255
56 | 51 26 120 255 52 23 112 255
57 | 52 23 112 255 53 21 103 255
58 | 53 21 103 255 54 19 94 255
59 | 54 19 94 255 55 17 85 255
60 | 55 17 85 255 56 15 76 255
61 | 56 15 76 255 57 12 66 255
62 | 57 12 66 255 58 10 56 255
63 | 58 10 56 255 59 8 46 255
64 | 59 8 46 255 60 6 35 255
65 | 60 6 35 255 61 4 24 255
66 | 61 4 24 255 62 2 12 255
67 | 62 2 12 255 63 0 0 255
68 | B 0 0 0
69 | F 255 255 255
70 | N 255 0 0
71 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/poison.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/neota/elem/poison.cpt
2 | # autogenerated GMT palette "ELEM poison"
3 | # cptutils version 1.44, Tue Mar 13 13:16:19 2012
4 | # COLOR_MODEL = RGB
5 | 0.00 0 0 0 6.73 32 11 11
6 | 6.73 32 11 11 13.45 64 21 21
7 | 13.45 64 21 21 21.64 66 44 84
8 | 21.64 66 44 84 29.82 67 67 147
9 | 29.82 67 67 147 41.81 79 111 151
10 | 41.81 79 111 151 53.80 91 155 155
11 | 53.80 91 155 155 59.65 112 172 144
12 | 59.65 112 172 144 65.50 134 189 134
13 | 65.50 134 189 134 72.51 169 197 152
14 | 72.51 169 197 152 79.53 204 204 170
15 | 79.53 204 204 170 89.77 230 230 212
16 | 89.77 230 230 212 100.00 255 255 255
17 | B 0 0 0
18 | F 255 255 255
19 | N 255 0 0
20 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/saga-01.cpt:
--------------------------------------------------------------------------------
1 | # saga-01.cpt
2 | # autogenerated GMT palette "saga-01.txt"
3 | # cptutils version 1.44, Thu Mar 8 23:40:39 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 1 128 1 0 7 167
6 | 1 0 7 167 2 0 25 202
7 | 2 0 25 202 3 0 53 230
8 | 3 0 53 230 4 0 88 248
9 | 4 0 88 248 5 1 127 255
10 | 5 1 127 255 6 7 167 248
11 | 6 7 167 248 7 25 202 230
12 | 7 25 202 230 8 53 230 202
13 | 8 53 230 202 9 88 248 167
14 | 9 88 248 167 10 128 255 128
15 | 10 128 255 128 11 167 248 88
16 | 11 167 248 88 12 202 230 53
17 | 12 202 230 53 13 230 202 25
18 | 13 230 202 25 14 248 167 7
19 | 14 248 167 7 15 255 128 1
20 | 15 255 128 1 16 248 88 0
21 | 16 248 88 0 17 230 53 0
22 | 17 230 53 0 18 202 25 0
23 | 18 202 25 0 19 167 7 0
24 | B 0 0 0
25 | F 255 255 255
26 | N 255 0 0
27 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/saga-02.cpt:
--------------------------------------------------------------------------------
1 | # saga-02.cpt
2 | # autogenerated GMT palette "saga-02.txt"
3 | # cptutils version 1.44, Thu Mar 8 23:40:39 2012
4 | # COLOR_MODEL = RGB
5 | 0 61 63 255 1 55 70 255
6 | 1 55 70 255 2 42 83 255
7 | 2 42 83 255 3 27 98 255
8 | 3 27 98 255 4 13 112 255
9 | 4 13 112 255 5 0 126 253
10 | 5 0 126 253 6 6 150 223
11 | 6 6 150 223 7 20 168 191
12 | 7 20 168 191 8 41 180 158
13 | 8 41 180 158 9 66 187 126
14 | 9 66 187 126 10 95 190 95
15 | 10 95 190 95 11 126 187 66
16 | 11 126 187 66 12 158 180 41
17 | 12 158 180 41 13 191 168 20
18 | 13 191 168 20 14 223 150 6
19 | 14 223 150 6 15 253 127 0
20 | 15 253 127 0 16 255 112 13
21 | 16 255 112 13 17 255 98 27
22 | 17 255 98 27 18 255 83 42
23 | 18 255 83 42 19 255 70 55
24 | B 0 0 0
25 | F 255 255 255
26 | N 255 0 0
27 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/saga-13.cpt:
--------------------------------------------------------------------------------
1 | # saga-13.cpt
2 | # autogenerated GMT palette "saga-13.txt"
3 | # cptutils version 1.44, Thu Mar 8 23:40:39 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 255 0 1 38 242 0
6 | 1 38 242 0 2 76 229 0
7 | 2 76 229 0 3 114 216 0
8 | 3 114 216 0 4 152 203 0
9 | 4 152 203 0 5 191 191 0
10 | 5 191 191 0 6 203 178 0
11 | 6 203 178 0 7 216 165 0
12 | 7 216 165 0 8 229 152 0
13 | 8 229 152 0 9 242 139 0
14 | 9 242 139 0 10 255 127 0
15 | 10 255 127 0 11 248 114 0
16 | 11 248 114 0 12 242 101 0
17 | 12 242 101 0 13 235 88 0
18 | 13 235 88 0 14 229 75 0
19 | 14 229 75 0 15 223 63 0
20 | 15 223 63 0 16 191 50 0
21 | 16 191 50 0 17 159 37 0
22 | 17 159 37 0 18 127 25 0
23 | 18 127 25 0 19 95 12 0
24 | B 0 0 0
25 | F 255 255 255
26 | N 255 0 0
27 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/saga-16.cpt:
--------------------------------------------------------------------------------
1 | # saga-16.cpt
2 | # autogenerated GMT palette "saga-16.txt"
3 | # cptutils version 1.44, Thu Mar 8 23:40:39 2012
4 | # COLOR_MODEL = RGB
5 | 0 0 25 152 1 0 50 178
6 | 1 0 50 178 2 0 76 203
7 | 2 0 76 203 3 0 101 229
8 | 3 0 101 229 4 0 127 255
9 | 4 0 127 255 5 40 141 244
10 | 5 40 141 244 6 80 156 233
11 | 6 80 156 233 7 120 170 222
12 | 7 120 170 222 8 160 185 211
13 | 8 160 185 211 9 200 200 200
14 | 9 200 200 200 10 211 185 160
15 | 10 211 185 160 11 222 170 120
16 | 11 222 170 120 12 233 156 80
17 | 12 233 156 80 13 244 141 40
18 | 13 244 141 40 14 255 127 0
19 | 14 255 127 0 15 229 101 0
20 | 15 229 101 0 16 203 76 0
21 | 16 203 76 0 17 178 50 0
22 | 17 178 50 0 18 152 25 0
23 | 18 152 25 0 19 127 0 0
24 | B 0 0 0
25 | F 255 255 255
26 | N 255 0 0
27 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/salinity_bgy1.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: salinity_bgy1
3 | 5
4 | 0.000000 0.028617 0.052464 0.952941 0.916626 0.900623 1.000000 0.843137 0.827967 0.413303 1.000000 0 0 0 0
5 | 0.052464 0.134340 0.262321 0.843137 0.827967 0.413303 1.000000 0.559091 0.764706 0.200923 1.000000 0 0 0 0
6 | 0.262321 0.441176 0.593800 0.559091 0.764706 0.200923 1.000000 0.521569 0.796078 0.807843 1.000000 0 0 0 0
7 | 0.593800 0.767091 0.945151 0.521569 0.796078 0.807843 1.000000 0.074510 0.345098 0.541176 1.000000 0 0 0 0
8 | 0.945151 0.973768 1.000000 0.074510 0.345098 0.541176 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 0 0
9 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/salinity_bgy2.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: salinity_bgy2
3 | 5
4 | 0.000000 0.030749 0.063503 0.952941 0.916626 0.900623 1.000000 0.876863 0.767744 0.399647 1.000000 0 0 0 0
5 | 0.063503 0.195856 0.322193 0.876863 0.767744 0.399647 1.000000 0.559091 0.764706 0.200923 1.000000 0 0 0 0
6 | 0.322193 0.441176 0.593800 0.559091 0.764706 0.200923 1.000000 0.521569 0.796078 0.807843 1.000000 0 0 0 0
7 | 0.593800 0.767091 0.911096 0.521569 0.796078 0.807843 1.000000 0.074510 0.345098 0.541176 1.000000 0 0 0 0
8 | 0.911096 0.958556 1.000000 0.074510 0.345098 0.541176 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 0 0
9 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/salinity_bgy3.ggr:
--------------------------------------------------------------------------------
1 | GIMP Gradient
2 | Name: salinity_bgy3
3 | 5
4 | 0.000000 0.030749 0.063503 0.952941 0.916626 0.756863 1.000000 0.876863 0.767744 0.399647 1.000000 0 0 0 0
5 | 0.063503 0.195856 0.322193 0.876863 0.767744 0.399647 1.000000 0.559091 0.764706 0.200923 1.000000 0 0 0 0
6 | 0.322193 0.441176 0.593800 0.559091 0.764706 0.200923 1.000000 0.521569 0.796078 0.807843 1.000000 0 0 0 0
7 | 0.593800 0.767091 0.948798 0.521569 0.796078 0.807843 1.000000 0.074510 0.345098 0.541176 1.000000 0 0 0 0
8 | 0.948798 0.973877 1.000000 0.074510 0.345098 0.541176 1.000000 0.024783 0.114783 0.180000 1.000000 0 0 0 0
9 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/scoutie.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/rc/scoutie.cpt
2 | # autogenerated GMT palette "~1scouty"
3 | # cptutils version 1.44, Tue Mar 13 13:17:37 2012
4 | # COLOR_MODEL = RGB
5 | 0.00 255 204 0 50.00 0 226 90
6 | 50.00 0 226 90 85.01 26 0 121
7 | 85.01 26 0 121 100.00 26 0 121
8 | B 0 0 0
9 | F 255 255 255
10 | N 255 0 0
11 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/slyphide.cpt:
--------------------------------------------------------------------------------
1 | # cpt-city/pj/4/slyphide.cpt
2 | # autogenerated GMT palette "pj4-slyphide"
3 | # cptutils version 1.44, Tue Mar 13 13:16:58 2012
4 | # COLOR_MODEL = RGB
5 | 0.00 243 240 193 20.00 190 222 159
6 | 20.00 190 222 159 45.00 123 163 93
7 | 45.00 123 163 93 73.00 116 114 159
8 | 73.00 116 114 159 92.99 76 31 112
9 | 92.99 76 31 112 100.00 76 31 112
10 | B 0 0 0
11 | F 255 255 255
12 | N 255 0 0
13 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/srtGreys05.cpt:
--------------------------------------------------------------------------------
1 | # GMT palette srtGreys05.cpt
2 | #
3 | # This product includes color specifications and designs
4 | # developed by Cynthia Brewer (http://colorbrewer.org/).
5 | #
6 | # Converted to the cpt format by J.J.Green
7 | # Serrated sequential palette with 6 colours
8 | #
9 | # COLOR_MODEL = RGB
10 | 0.00 217 217 217 1.00 247 247 247
11 | 1.00 189 189 189 2.00 217 217 217
12 | 2.00 150 150 150 3.00 189 189 189
13 | 3.00 099 099 099 4.00 150 150 150
14 | 4.00 037 037 037 5.00 099 099 099
15 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/temperature.cpt:
--------------------------------------------------------------------------------
1 | # extracted from GRID-Arendal
2 | # http://www.grida.no/graphicslib/detail/mean-surface-temperature_c7e4
3 | #
4 | # COLOR_MODEL = RGB
5 | 17.00 30 92 179 17.33 30 92 179
6 | 17.33 23 111 193 17.67 23 111 193
7 | 17.67 11 142 216 18.00 11 142 216
8 | 18.00 4 161 230 18.33 4 161 230
9 | 18.33 25 181 241 18.67 25 181 241
10 | 18.67 51 188 207 19.00 51 188 207
11 | 19.00 102 204 206 19.33 102 204 206
12 | 19.33 153 219 184 19.67 153 219 184
13 | 19.67 192 229 136 20.00 192 229 136
14 | 20.00 204 230 75 20.33 204 230 75
15 | 20.33 243 240 29 20.67 243 240 29
16 | 20.67 254 222 39 21.00 254 222 39
17 | 21.00 252 199 7 21.33 252 199 7
18 | 21.33 248 157 14 21.67 248 157 14
19 | 21.67 245 114 21 22.00 245 114 21
20 | 22.00 241 71 28 22.33 241 71 28
21 | 22.33 219 30 38 22.67 219 30 38
22 | 22.67 164 38 44 23.00 164 38 44
23 | B 0 0 0
24 | F 255 255 255
25 | N 255 0 0
26 |
--------------------------------------------------------------------------------
/stompy/plot/cmaps/wave.cpt:
--------------------------------------------------------------------------------
1 | # GMT colour palette table (cpt)
2 | # grass2cpt ouput
3 | # COLOR_MODEL = RGB
4 | 0.000000e+00 255 85 85 1.667000e+01 170 170 0
5 | 1.667000e+01 170 170 0 3.333000e+01 85 255 85
6 | 3.333000e+01 85 255 85 5.000000e+01 0 170 170
7 | 5.000000e+01 0 170 170 6.667000e+01 85 85 255
8 | 6.667000e+01 85 85 255 8.333000e+01 170 0 170
9 | 8.333000e+01 170 0 170 1.000000e+02 255 85 85
10 | N 128 128 128
11 |
--------------------------------------------------------------------------------
/stompy/plot/ggr.py:
--------------------------------------------------------------------------------
1 | """ Read Gimp .ggr gradient files.
2 | Ned Batchelder, http://nedbatchelder.com
3 | This code is in the public domain.
4 | """
5 |
6 | __version__ = '1.0.20070915'
7 |
8 | import colorsys, math
9 |
10 | class GimpGradient:
11 | """ Read and interpret a Gimp .ggr gradient file.
12 | """
13 | def __init__(self, f=None):
14 | if f:
15 | self.read(f)
16 |
17 | class _segment:
18 | pass
19 |
20 | def read(self, f):
21 | """ Read a .ggr file from f (either an open file or a file path).
22 | """
23 | try:
24 | f=open(f)
25 | except TypeError:
26 | pass # probably f is already a file
27 |
28 | if f.readline().strip() != "GIMP Gradient":
29 | raise Exception("Not a GIMP gradient file")
30 | line = f.readline().strip()
31 | if not line.startswith("Name: "):
32 | raise Exception("Not a GIMP gradient file")
33 | self.name = line.split(": ", 1)[1]
34 | nsegs = int(f.readline().strip())
35 | self.segs = []
36 | for i in range(nsegs):
37 | line = f.readline().strip()
38 | seg = self._segment()
39 | (seg.l, seg.m, seg.r,
40 | seg.rl, seg.gl, seg.bl, _,
41 | seg.rr, seg.gr, seg.br, _,
42 | seg.fn, seg.space) = list(map(float, line.split()))[:13]
43 | self.segs.append(seg)
44 |
45 | def color(self, x):
46 | """ Get the color for the point x in the range [0..1).
47 | The color is returned as an rgb triple, with all values in the range
48 | [0..1).
49 | """
50 | # Find the segment.
51 | for seg in self.segs:
52 | if seg.l <= x <= seg.r:
53 | break
54 | else:
55 | # No segment applies! Return black I guess.
56 | return (0,0,0)
57 |
58 | # Normalize the segment geometry.
59 | mid = (seg.m - seg.l)/(seg.r - seg.l)
60 | pos = (x - seg.l)/(seg.r - seg.l)
61 |
62 | # Assume linear (most common, and needed by most others).
63 | if pos <= mid:
64 | f = pos/mid/2
65 | else:
66 | f = (pos - mid)/(1 - mid)/2 + 0.5
67 |
68 | # Find the correct interpolation factor.
69 | if seg.fn == 1: # Curved
70 | f = math.pow(pos, math.log(0.5) / math.log(mid));
71 | elif seg.fn == 2: # Sinusoidal
72 | f = (math.sin((-math.pi/2) + math.pi*f) + 1)/2
73 | elif seg.fn == 3: # Spherical increasing
74 | f -= 1
75 | f = math.sqrt(1 - f*f)
76 | elif seg.fn == 4: # Spherical decreasing
77 | f = 1 - math.sqrt(1 - f*f);
78 |
79 | # Interpolate the colors
80 | if seg.space == 0:
81 | c = (
82 | seg.rl + (seg.rr-seg.rl) * f,
83 | seg.gl + (seg.gr-seg.gl) * f,
84 | seg.bl + (seg.br-seg.bl) * f
85 | )
86 | elif seg.space in (1,2):
87 | hl, sl, vl = colorsys.rgb_to_hsv(seg.rl, seg.gl, seg.bl)
88 | hr, sr, vr = colorsys.rgb_to_hsv(seg.rr, seg.gr, seg.br)
89 |
90 | if seg.space == 1 and hr < hl:
91 | hr += 1
92 | elif seg.space == 2 and hr > hl:
93 | hr -= 1
94 |
95 | c = colorsys.hsv_to_rgb(
96 | (hl + (hr-hl) * f) % 1.0,
97 | sl + (sr-sl) * f,
98 | vl + (vr-vl) * f
99 | )
100 | return c
101 |
--------------------------------------------------------------------------------
/stompy/plot/mkanim.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Thu Oct 6 12:20:10 2022
4 |
5 | @author: rusty
6 | """
7 |
8 | import subprocess, os
9 |
10 | out='cimarron_v1.mp4'
11 |
12 | def mkanim(out,frame_path,fps=16,ffmpeg='ffmpeg',overwrite=True):
13 | """
14 | out: path to output mp4 file
15 | frame_path: pattern for image paths, including %04d or similar for
16 | frame number.
17 | """
18 | if os.path.exists(out):
19 | if overwrite:
20 | os.unlink(out)
21 | else:
22 | raise Exception(f"{out} exists")
23 |
24 | res=subprocess.run(['ffmpeg',
25 | '-framerate',str(fps),
26 | '-i',frame_path,
27 | # this deals with odd dimensions
28 | '-vf',"crop=trunc(iw/2)*2:trunc(ih/2)*2",
29 | '-c:v','libx264',
30 | '-preset','slow',
31 | '-profile:v','high',
32 | '-level:v','4.0',
33 | '-pix_fmt','yuv420p',
34 | '-crf','20','-r',str(fps),
35 | out], capture_output=True)
36 | print(res.stderr.decode())
37 |
--------------------------------------------------------------------------------
/stompy/plot/plot_wkb.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from matplotlib.collections import PatchCollection,LineCollection
3 | from matplotlib.path import Path
4 | from matplotlib.patches import PathPatch
5 | import matplotlib.pyplot as plt
6 | import numpy as np
7 | from .. import utils
8 |
9 | def plot_linestring(linestring,**kwargs):
10 | ax=kwargs.pop('ax',plt.gca())
11 | c = np.array(linestring.coords)
12 | return ax.plot( c[:,0],c[:,1],**kwargs)[0]
13 |
14 | def plot_multilinestring(mls,**kwargs):
15 | ax=kwargs.pop('ax',plt.gca())
16 | if mls.geom_type == 'MultiLineString':
17 | segs = [np.array(ls.coords) for ls in mls.geoms]
18 | coll = LineCollection(segs,**kwargs)
19 | ax.add_collection(coll)
20 | return coll
21 | else:
22 | return plot_linestring(mls,**kwargs)
23 |
24 | ########
25 | # New, non-hacked way to plot polygons with holes
26 | # From: http://sgillies.net/blog/1013/painting-punctured-polygons-with-matplotlib/
27 |
28 | def ring_coding(ob):
29 | # The codes will be all "LINETO" commands, except for "MOVETO"s at the
30 | # beginning of each subpath
31 | n = len(ob.coords)
32 | codes = np.ones(n, dtype=Path.code_type) * Path.LINETO
33 | codes[0] = Path.MOVETO
34 | # unsure of difference between CLOSEPOLY and leaving as is.
35 | # codes[-1] = Path.CLOSEPOLY # doesn't seem to make a difference
36 | return codes
37 |
38 | def pathify(polygon):
39 | # Convert coordinates to path vertices. Objects produced by Shapely's
40 | # analytic methods have the proper coordinate order, no need to sort.
41 |
42 | # 20170707: matplotlib pickier about ordering of internal rings, may have
43 | # reverse interiors.
44 | # 20170719: shapely doesn't guarantee one order or the other
45 | def ensure_orientation(a,ccw=True):
46 | """
47 | take an array-like [N,2] set of points defining a polygon,
48 | return an array which is ordered ccw (or cw is ccw=False)
49 | """
50 | a=np.asarray(a) # pre-shapely 2
51 | area=utils.signed_area(a)
52 | if ccw == (area<0):
53 | a=a[::-1]
54 | return a
55 |
56 | vertices = np.concatenate(
57 | [ ensure_orientation(polygon.exterior.coords,ccw=True)]
58 | + [ ensure_orientation(r.coords,ccw=False) for r in polygon.interiors])
59 | codes = np.concatenate(
60 | [ring_coding(polygon.exterior)]
61 | + [ring_coding(r) for r in polygon.interiors])
62 | return Path(vertices, codes)
63 |
64 | def poly_to_patch(polygon,**kwargs):
65 | return PathPatch(pathify(polygon), **kwargs)
66 |
67 | def multipoly_to_patches(multipoly,*args,**kwargs):
68 | patches = [poly_to_patch(p) for p in multipoly.geoms]
69 | return PatchCollection(patches,*args,**kwargs)
70 |
71 | def plot_polygon(p,*args,**kwargs):
72 | if 'holes' in kwargs:
73 | print("dropping obsolete holes keyword argument")
74 | del kwargs['holes']
75 |
76 | ax = kwargs.pop('ax',plt.gca())
77 |
78 | patch = poly_to_patch(p,*args,**kwargs)
79 | ax.add_patch(patch)
80 | return patch
81 |
82 | def plot_multipolygon(mp,*args,**kwargs):
83 | if 'holes' in kwargs:
84 | print("dropping obsolete holes keyword argument")
85 | del kwargs['holes']
86 | ax = kwargs.pop('ax',plt.gca())
87 | coll = multipoly_to_patches(mp,*args,**kwargs)
88 | ax.add_collection( coll )
89 | return coll
90 |
91 |
92 | def plot_wkb(g,*args,**kwargs):
93 | if g.geom_type == 'MultiPolygon':
94 | return plot_multipolygon(g,*args,**kwargs)
95 | elif g.geom_type=='Polygon':
96 | return plot_polygon(g,*args,**kwargs)
97 | elif g.geom_type == 'MultiLineString':
98 | return plot_multilinestring(g,*args,**kwargs)
99 | elif g.geom_type =='LineString':
100 | return plot_linestring(g,*args,**kwargs)
101 | else:
102 | raise Exception("no match to type")
103 |
104 |
--------------------------------------------------------------------------------
/stompy/priority_queue.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 |
3 | # Priority dictionary using binary heaps
4 | # David Eppstein, UC Irvine, 8 Mar 2002
5 |
6 | class priorityDictionary(dict):
7 | def __init__(self):
8 | '''Initialize priorityDictionary by creating binary heap
9 | of pairs (value,key). Note that changing or removing a dict entry will
10 | not remove the old pair from the heap until it is found by smallest() or
11 | until the heap is rebuilt.'''
12 | self.__heap = []
13 | dict.__init__(self)
14 |
15 | def smallest(self):
16 | '''Find smallest item after removing deleted items from heap.'''
17 | if len(self) == 0:
18 | raise IndexError( "smallest of empty priorityDictionary")
19 | heap = self.__heap
20 | while heap[0][1] not in self or self[heap[0][1]] != heap[0][0]:
21 | lastItem = heap.pop()
22 | insertionPoint = 0
23 | while 1:
24 | smallChild = 2*insertionPoint+1
25 | if smallChild+1 < len(heap) and \
26 | heap[smallChild] > heap[smallChild+1]:
27 | smallChild += 1
28 | if smallChild >= len(heap) or lastItem <= heap[smallChild]:
29 | heap[insertionPoint] = lastItem
30 | break
31 | heap[insertionPoint] = heap[smallChild]
32 | insertionPoint = smallChild
33 | return heap[0][1]
34 |
35 | def __iter__(self):
36 | '''Create destructive sorted iterator of priorityDictionary.'''
37 | def iterfn():
38 | while len(self) > 0:
39 | x = self.smallest()
40 | yield x
41 | del self[x]
42 | return iterfn()
43 |
44 | def __setitem__(self,key,val):
45 | '''Change value stored in dictionary and add corresponding
46 | pair to heap. Rebuilds the heap if the number of deleted items grows
47 | too large, to avoid memory leakage.'''
48 | dict.__setitem__(self,key,val)
49 | heap = self.__heap
50 | if len(heap) > 2 * len(self):
51 | self.__heap = [(v,k) for k,v in self.items()]
52 | self.__heap.sort() # builtin sort likely faster than O(n) heapify
53 | else:
54 | newPair = (val,key)
55 | insertionPoint = len(heap)
56 | heap.append(None)
57 | while insertionPoint > 0 and \
58 | newPair < heap[(insertionPoint-1)//2]:
59 | heap[insertionPoint] = heap[(insertionPoint-1)//2]
60 | insertionPoint = (insertionPoint-1)//2
61 | heap[insertionPoint] = newPair
62 |
63 | def setdefault(self,key,val):
64 | '''Reimplement setdefault to call our customized __setitem__.'''
65 | if key not in self:
66 | self[key] = val
67 | return self[key]
68 |
--------------------------------------------------------------------------------
/stompy/scriptable.py:
--------------------------------------------------------------------------------
1 | """
2 | provide command line access to methods on classes
3 | """
4 | from __future__ import print_function
5 |
6 | import sys
7 | import getopt
8 |
9 | class Unbuffered(object):
10 | def __init__(self, stream):
11 | self.stream = stream
12 | def write(self, data):
13 | self.stream.write(data)
14 | self.stream.flush()
15 | def __getattr__(self, attr):
16 | return getattr(self.stream, attr)
17 |
18 | class Scriptable(object):
19 | def invoke_command(self,cmd,args):
20 | meth_name = "cmd_" + cmd
21 |
22 | try:
23 | f = getattr(self,meth_name)
24 | except AttributeError:
25 | print("Command '%s' is not recognized"%cmd)
26 | self.cmd_help()
27 | sys.exit(1)
28 | f(*args)
29 |
30 | def cmd_help(self):
31 | """
32 | List available commands
33 | """
34 | print("Available commands")
35 | for k in dir(self):
36 | if k.startswith('cmd_'):
37 | v=getattr(self,k)
38 | doc=(v.__doc__ or "undocumented").strip()
39 | # 9 seems to work for the usual indentation (8 spaces)
40 | # plus the 9 to line up with '%15s: ' below
41 | doc=doc.replace("\n","\n"+" "*9)
42 | print("%15s: %s"%(k.replace('cmd_',''),doc))
43 |
44 | cli_options="h" # can be overridden in subclasses
45 | def cli_usage(self):
46 | print("python {} [command]".format(sys.argv[0]) )
47 | print(" Command is one of:" )
48 | for att in dir(self):
49 | if att.startswith('cmd_'):
50 | print(" "+att[4:])
51 | print("Use help for more info")
52 | def cli_handle_option(self,opt,val):
53 | if opt == '-h':
54 | self.cli_usage()
55 | sys.exit(0)
56 | else:
57 | print("Unhandled option '%s'"%opt)
58 | self.cli_usage()
59 | seys.exit(1)
60 |
61 | def main(self,args=None):
62 | """ parse command line and start making things
63 | """
64 | if args is None:
65 | args = sys.argv[1:]
66 |
67 | try:
68 | opts,rest = getopt.getopt(args, self.cli_options)
69 | except getopt.GetoptError:
70 | self.cli_usage()
71 | sys.exit(1)
72 |
73 | for opt,val in opts:
74 | self.cli_handle_option(opt,val)
75 |
76 | if len(rest) > 0:
77 | cmd = rest[0]
78 | rest = rest[1:]
79 | else:
80 | # default action:
81 | cmd = 'default'
82 |
83 | # try making all output unbuffered:
84 | sys.stdout = Unbuffered(sys.stdout)
85 |
86 | # DependencyGraph.check_timestamps = self.check_timestamps
87 | self.invoke_command(cmd,rest)
88 |
--------------------------------------------------------------------------------
/stompy/spatial/__init__.py:
--------------------------------------------------------------------------------
1 | # nothing
2 |
--------------------------------------------------------------------------------
/stompy/spatial/algorithms.py:
--------------------------------------------------------------------------------
1 | import shapely.ops
2 | from shapely import geometry
3 |
4 | def cut_polygon(poly,line):
5 | # slice the exterior separately from interior, then recombine
6 | ext_sliced=poly.exterior.union( line )
7 | ext_poly=geometry.Polygon(poly.exterior)
8 | int_sliced=[ p.union(line)
9 | for p in poly.interiors ]
10 |
11 | ext_parts, _dangles,_cuts,_invalids = shapely.ops.polygonize_full( ext_sliced )
12 | ext_parts=list(ext_parts) # so we can update entries
13 |
14 | # It's possible to introduce some new area here - places where the cut line
15 | # goes outside the exterior but forms a loop with the exterior.
16 |
17 | ext_parts=[p_ext
18 | for p_ext in ext_parts
19 | if p_ext.intersection(ext_poly).area / p_ext.area > 0.99 ]
20 |
21 | for p in int_sliced:
22 | int_parts, _dangles,_cuts,_invalids = shapely.ops.polygonize_full( p )
23 | # remove from an ext_part if there's overlap
24 | for p_int in int_parts:
25 | for i_ext, p_ext in enumerate(ext_parts):
26 | if p_ext.intersects(p_int):
27 | ext_parts[i_ext] = p_ext.difference(p_int)
28 |
29 | return ext_parts
30 |
--------------------------------------------------------------------------------
/stompy/spatial/geom_types.py:
--------------------------------------------------------------------------------
1 | from osgeo import ogr
2 |
3 | # map geometry types to names:
4 | ogr2text = {
5 | ogr.wkbGeometryCollection:'GeometryCollection',
6 | ogr.wkbGeometryCollection25D:'GeometryCollection25D',
7 | ogr.wkbLineString:'LineString',
8 | ogr.wkbLineString25D:'LineString25D',
9 | ogr.wkbLinearRing:'LinearRing',
10 | ogr.wkbMultiLineString:'MultiLineString',
11 | ogr.wkbMultiLineString25D:'MultiLineString25D',
12 | ogr.wkbMultiPoint:'MultiPoint',
13 | ogr.wkbMultiPoint25D:'MultiPoint25D',
14 | ogr.wkbMultiPolygon:'MultiPolygon',
15 | ogr.wkbMultiPolygon25D:'MultiPolygon25D',
16 | ogr.wkbPoint:'Point',
17 | ogr.wkbPoint25D:'Point25D',
18 | ogr.wkbPolygon:'Polygon',
19 | ogr.wkbPolygon25D:'Polygon25D',
20 | ogr.wkbUnknown:'Unknown',
21 | }
22 |
23 | text2ogr = dict( [ [ogr2text[k],k] for k in ogr2text.keys()] )
24 |
--------------------------------------------------------------------------------
/stompy/spatial/interp_nn.py:
--------------------------------------------------------------------------------
1 | """
2 | Nearest neighbor interpolation using scipy voronoi
3 |
4 | Note that this is not fast enough for interpolation of raster, but instead meant
5 | for a relatively small number of target points, where the same weights can
6 | be re-used many times.
7 | """
8 | import numpy as np
9 | from .. import memoize, utils
10 | from scipy.spatial import Voronoi
11 |
12 | def signed_area_py(points):
13 | # typical voronoi regions don't have that many vertices and
14 | # using straight pythong is ~3x faster.
15 | N=points.shape[0]
16 | area=0.0
17 | for i in range(N):
18 | ip1 = (i+1)%N
19 | area += points[i,0]*points[ip1,1] - points[ip1,0]*points[i,1]
20 | return 0.5*area
21 |
22 | def nn_weights(src_xy,
23 | dst_xy,
24 | center=None,
25 | pad=None):
26 | """
27 | src_xy: [N,2] locations of source data points
28 | dst_xy: [2] location of point to extract
29 | center: specify a center for the dummy points, defaults to mean
30 | pd: specify scale for dummy points, default to 100x the larger span.
31 | """
32 | if src_xy.shape[0]==0:
33 | return np.zeros(0)
34 | if src_xy.shape[0]==1:
35 | return np.r_[1.0]
36 |
37 | # anything else it should work, even if goofy.
38 |
39 | if center is None:
40 | center=src_xy.mean(axis=0)
41 | if pad is None:
42 | pad = 100*(src_xy.max(axis=0) - src_xy.min(axis=0)).max()
43 |
44 | assert pad>0,"Degenerate points?"
45 |
46 | dummies = np.array( [[center[0]-pad,center[1]-pad],
47 | [center[0]+pad,center[1]-pad],
48 | [center[0]-pad,center[1]+pad],
49 | [center[0]+pad,center[1]+pad]] )
50 |
51 | if 1:
52 | vor1 = Voronoi(np.concatenate([src_xy,dummies]))
53 | vor2 = Voronoi(np.concatenate([src_xy,dummies,[dst_xy]]))
54 |
55 | # how does one deal with the ridge vertices?
56 | # cheat and put some dummy vertices far away, and ignore
57 | # area stolen from them.
58 |
59 | weights=[]
60 | for i in range(src_xy.shape[0]):
61 | reg1=vor1.regions[ vor1.point_region[i] ]
62 | reg2=vor2.regions[ vor2.point_region[i] ]
63 | verts1=vor1.vertices[reg1]
64 | verts2=vor2.vertices[reg2]
65 | #area1=np.abs(utils.signed_area(verts1))
66 | #area2=np.abs(utils.signed_area(verts2))
67 | area1=np.abs(signed_area_py(verts1))
68 | area2=np.abs(signed_area_py(verts2))
69 | if area1 cp.frame:
45 | self.pop_op()
46 | finally:
47 | self.state='recording'
48 |
49 | def backstep(self):
50 | if self.state!='recording':
51 | raise Exception("backstep: state is not recording")
52 | self.state='reverting'
53 | try:
54 | self.pop_op()
55 | finally:
56 | self.state='recording'
57 |
58 | def commit(self):
59 | assert self.state != 'reverting'
60 | self.op_stack = None
61 | self.op_stack_serial += 1
62 | self.state='inactive'
63 |
64 | def push_op(self,meth,*data,**kwdata):
65 | self.abs_serial=self.abs_serial+1
66 | if self.state!='recording':
67 | return
68 |
69 | if self.op_stack is not None:
70 | self.op_stack.append( (meth,data,kwdata) )
71 |
72 | def pop_op(self):
73 | assert self.state=='reverting'
74 |
75 | self.abs_serial=self.abs_serial+1
76 |
77 | f = self.op_stack.pop()
78 | self.log.debug("popping: %s"%( str(f) ) )
79 | meth = f[0]
80 | args = f[1]
81 | kwargs = f[2]
82 |
83 | meth(*args,**kwargs)
84 |
85 | def __getstate__(self):
86 | try:
87 | d=super(OpHistory,self).__getstate__()
88 | except AttributeError:
89 | d = dict(self.__dict__)
90 |
91 | d['op_stack']=None
92 | d['state']='inactive'
93 |
94 | return d
95 |
--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | *.png
2 | cache
3 | test_cache
4 | ptm_out
5 | run-dfm_to_ptm
6 | cells.dat
7 | edges.dat
8 | final.pav
9 | final.pdf
10 | points.dat
11 | smoothed-shoreline.*
12 | tom.log
13 |
14 | uk_tides
15 | dwaq_aggregation.*
16 | output*
17 | run-dfm*
18 |
--------------------------------------------------------------------------------
/test/data/.gitignore:
--------------------------------------------------------------------------------
1 | *.tar.Z
2 | DATA
3 |
--------------------------------------------------------------------------------
/test/data/Ex1.g01.hdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/Ex1.g01.hdf
--------------------------------------------------------------------------------
/test/data/dem_sources.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/dem_sources.dbf
--------------------------------------------------------------------------------
/test/data/dem_sources.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_UTM_Zone_10N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]
--------------------------------------------------------------------------------
/test/data/dem_sources.qpj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD83 / UTM zone 10N",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","26910"]]
2 |
--------------------------------------------------------------------------------
/test/data/dem_sources.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/dem_sources.shp
--------------------------------------------------------------------------------
/test/data/dem_sources.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/dem_sources.shx
--------------------------------------------------------------------------------
/test/data/dumbarton.dbf:
--------------------------------------------------------------------------------
1 | _ A ! FID N
0.000
--------------------------------------------------------------------------------
/test/data/dumbarton.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_UTM_Zone_10N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]
--------------------------------------------------------------------------------
/test/data/dumbarton.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/dumbarton.shp
--------------------------------------------------------------------------------
/test/data/dumbarton.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/dumbarton.shx
--------------------------------------------------------------------------------
/test/data/lsb_combined_v14_net.nc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/lsb_combined_v14_net.nc
--------------------------------------------------------------------------------
/test/data/scale-lines.dbf:
--------------------------------------------------------------------------------
1 | _ A W scale N
6000. 1000. 200.0 100.0 200.0 100.0 200.0 200.0 35.00 35.00 35.00 35.00 35.00 25.00 35.00 25.00 35.00 18.00 35.00 40.00 40.00 50.00 50.00 90.00 100.0
--------------------------------------------------------------------------------
/test/data/scale-lines.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_UTM_Zone_10N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]
--------------------------------------------------------------------------------
/test/data/scale-lines.qpj:
--------------------------------------------------------------------------------
1 | PROJCS["UTM Zone 10, Northern Hemisphere",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9108"]],AUTHORITY["EPSG","4269"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]
2 |
--------------------------------------------------------------------------------
/test/data/scale-lines.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/scale-lines.shp
--------------------------------------------------------------------------------
/test/data/scale-lines.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/scale-lines.shx
--------------------------------------------------------------------------------
/test/data/scale.dbf:
--------------------------------------------------------------------------------
1 | _$ A W scale N
50.000000000000000 50.000000000000000 50.000000000000000 100.000000000000000 50.000000000000000 1500.000000000000000 500.000000000000000 500.000000000000000 100.000000000000000 200.000000000000000 200.000000000000000 100.000000000000000 500.000000000000000 100.000000000000000 100.000000000000000 100.000000000000000 200.000000000000000 200.000000000000000 100.000000000000000 50.000000000000000 35.000000000000000 35.000000000000000 35.000000000000000 35.000000000000000 35.000000000000000 35.000000000000000 50.000000000000000 100.000000000000000 50.000000000000000 75.000000000000000 50.000000000000000 16.000000000000000 24.000000000000000 24.000000000000000 26.000000000000000 12.000000000000000
--------------------------------------------------------------------------------
/test/data/scale.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_UTM_Zone_10N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]
--------------------------------------------------------------------------------
/test/data/scale.qpj:
--------------------------------------------------------------------------------
1 | PROJCS["UTM Zone 10, Northern Hemisphere",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9108"]],AUTHORITY["EPSG","4269"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",-123],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]
2 |
--------------------------------------------------------------------------------
/test/data/scale.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/scale.shp
--------------------------------------------------------------------------------
/test/data/scale.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/scale.shx
--------------------------------------------------------------------------------
/test/data/temp-transect.nc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rustychris/stompy/5d86c88d0b1dff442d2294e322b651c6fb7e3f1f/test/data/temp-transect.nc
--------------------------------------------------------------------------------
/test/dev_crash.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import logging
4 | import matplotlib.pyplot as plt
5 | import numpy as np
6 | import pdb
7 |
8 | from scipy import optimize as opt
9 |
10 | from stompy.spatial import field
11 | from stompy import utils
12 |
13 | from stompy.grid import (unstructured_grid, exact_delaunay, front)
14 |
15 | import logging
16 | logging.basicConfig(level=logging.INFO)
17 |
18 | from stompy.spatial.linestring_utils import upsample_linearring,resample_linearring
19 | from stompy.spatial import field,constrained_delaunay,wkb2shp
20 |
21 | ## Curve -
22 |
23 | def hex_curve():
24 | hexagon = np.array( [[0,11],
25 | [10,0],
26 | [30,0],
27 | [40,9],
28 | [30,20],
29 | [10,20]] )
30 | return front.Curve(hexagon)
31 |
32 |
33 | def test_basic_setup():
34 | boundary=hex_curve()
35 | af=front.AdvancingTriangles()
36 | scale=field.ConstantField(3)
37 |
38 | af.add_curve(boundary)
39 | af.set_edge_scale(scale)
40 |
41 | # create boundary edges based on scale and curves:
42 | af.initialize_boundaries()
43 |
44 | return af
45 |
46 | # when resample nodes on a sliding boundary, want to calculate the available
47 | # span, and if it's small, start distributing the nodes evenly.
48 | # where small is defined by local_scale * max_span_factor
49 |
50 | def test_resample():
51 | af=test_basic_setup()
52 | a=0
53 | b=af.grid.node_to_nodes(a)[0]
54 | he=af.grid.nodes_to_halfedge(a,b)
55 | anchor=he.node_rev()
56 | n=he.node_fwd()
57 | n2=he.rev().node_rev()
58 | # Fails here, in grid.modify_node
59 | af.resample(n=n,anchor=anchor,scale=25,direction=1)
60 | af.resample(n=n2,anchor=anchor,scale=25,direction=-1)
61 |
62 | test_resample()
63 |
64 |
65 | # during modify_node(n=9)
66 | # 9 comes in as node b in call to line_is_free
67 | # vertex handle gives it as 22.5,0.0, which is the new location
68 | # lw from line_walk is bad.
69 | # after_add_node() just inserts the new point into the DT.
70 | # - could be related to premature garbage collection of points?
71 | # nope.
72 | # - related to init_face? has to be there for proper functioning
73 | # - or failure to remove the original vertex before creating the new one?
74 | # no, that seems to be taken care of.
75 |
76 | # does a line free call work before modifying the node?
77 | # nope. So maybe something else in the early part of before_modify_node
78 | # invalidates the state?
79 | # it's the second time through the loop that fails?
80 | # 10--9 crashes, even when it's the first in the loop
81 | # even if we could drop init_face, it segfaults without it.
82 | # segfaults when performing the line walk on a deep copy of DT.
83 | # the test it is attempting is along an existing finite edge.
84 | # happens whether the edge is constrained or not.
85 |
86 | # Possible next steps:
87 | # 1. could remove the node, insert in the new spot, maybe do a locate first?
88 | # and for any nodes which are now DT neighbors clearly we can skip the
89 | # line_is_free.
90 | # 2. hand-write the line_is_free stuff, ala live_dt.
91 | # 3. Abstract out the line_is_free stuff in live_dt, and both that and this
92 | # can use it.
93 |
--------------------------------------------------------------------------------
/test/dev_front.py:
--------------------------------------------------------------------------------
1 | reload(unstructured_grid)
2 | reload(exact_delaunay)
3 | reload(front)
4 |
5 | import test_front
6 | reload(test_front)
7 | from test_front import *
8 |
9 | ##
10 | rings=sine_sine_rings()
11 | density = field.ConstantField(25.0)
12 |
13 | af=front.AdvancingTriangles()
14 | af.set_edge_scale(density)
15 |
16 | af.add_curve(rings[0],interior=False)
17 | for ring in rings[1:]:
18 | af.add_curve(ring,interior=True)
19 | af.initialize_boundaries()
20 |
21 | # gets pretty far, then corrupts some shoreline
22 | # while getting an intersecting constraint error
23 | af.loop(283)
24 |
25 | #
26 |
27 | ##
28 | af.loop(1)
29 | zoom=(3685.3576744887459, 3766.6617074119663, -106.27412460553033, -45.230532144628569)
30 | zoom=(2391.5283204797729, 2467.0778002411375, -175.48232649105583, -118.75928967022534)
31 | zoom=(617.5288764629438, 851.27615881930399, 122.37679637174006, 241.99027866141051)
32 | af.plot_summary(label_nodes=False)
33 |
34 | site=af.choose_site()
35 | site.plot()
36 |
37 | plt.axis(zoom)
38 |
39 | ##
40 |
41 | # this is what fails.
42 | af.resample_neighbors(site)
43 |
--------------------------------------------------------------------------------
/test/dev_grayscott.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | '''
4 | Reaction Diffusion : Gray-Scott model
5 |
6 | References:
7 | ----------
8 | Complex Patterns in a Simple System
9 | John E. Pearson, Science 261, 5118, 189-192, 1993.
10 |
11 | Encode movie
12 | ------------
13 |
14 | ffmpeg -r 30 -i "tmp-%03d.png" -c:v libx264 -crf 23 -pix_fmt yuv420p bacteria.mp4
15 | '''
16 |
17 | # https://www.youtube.com/watch?v=xL1kjpBqRNQ
18 |
19 | import numpy as np
20 | import matplotlib.pyplot as plt
21 |
22 |
23 | # Parameters from http://www.aliensaint.com/uo/java/rd/
24 | # -----------------------------------------------------
25 | n = 200
26 | Du, Dv, F, k = 0.16, 0.08, 0.035, 0.065 # Bacteria 1
27 | # Du, Dv, F, k = 0.14, 0.06, 0.035, 0.065 # Bacteria 2
28 | Du=np.linspace(0.20,0.12,n)[None,:]
29 | Dv=np.linspace(0.10,0.05,n)[None,:]
30 |
31 | # Du, Dv, F, k = 0.16, 0.08, 0.060, 0.062 # Coral
32 | # Du, Dv, F, k = 0.19, 0.05, 0.060, 0.062 # Fingerprint
33 | # Du, Dv, F, k = 0.10, 0.10, 0.018, 0.050 # Spirals
34 | # Du, Dv, F, k = 0.12, 0.08, 0.020, 0.050 # Spirals Dense
35 | # Du, Dv, F, k = 0.10, 0.16, 0.020, 0.050 # Spirals Fast
36 | # Du, Dv, F, k = 0.16, 0.08, 0.020, 0.055 # Unstable
37 | # Du, Dv, F, k = 0.16, 0.08, 0.050, 0.065 # Worms 1
38 | # Du, Dv, F, k = 0.16, 0.08, 0.054, 0.063 # Worms 2
39 | # Du, Dv, F, k = 0.16, 0.08, 0.035, 0.060 # Zebrafish
40 |
41 |
42 | Z = np.zeros((n+2,n+2), [('U', np.double), ('V', np.double)])
43 | U,V = Z['U'], Z['V']
44 | u,v = U[1:-1,1:-1], V[1:-1,1:-1]
45 |
46 | r = 20
47 | u[...] = 1.0
48 | U[n/2-r:n/2+r,n/2-r:n/2+r] = 0.50
49 | V[n/2-r:n/2+r,n/2-r:n/2+r] = 0.25
50 | u += 0.05*np.random.random((n,n))
51 | v += 0.05*np.random.random((n,n))
52 |
53 |
54 | plt.ion()
55 |
56 | size = np.array(Z.shape)
57 | dpi = 72.0
58 | figsize= size[1]/float(dpi),size[0]/float(dpi)
59 | fig = plt.figure(figsize=figsize, dpi=dpi, facecolor="white",num=3)
60 | fig.add_axes([0.0, 0.0, 1.0, 1.0], frameon=False)
61 | im = plt.imshow(V, interpolation='bicubic', cmap=plt.cm.gray_r)
62 | plt.xticks([]), plt.yticks([])
63 |
64 | ##
65 | for i in xrange(10000):
66 | Lu = ( U[0:-2,1:-1] +
67 | U[1:-1,0:-2] - 4*U[1:-1,1:-1] + U[1:-1,2:] +
68 | U[2: ,1:-1] )
69 | Lv = ( V[0:-2,1:-1] +
70 | V[1:-1,0:-2] - 4*V[1:-1,1:-1] + V[1:-1,2:] +
71 | V[2: ,1:-1] )
72 |
73 | uvv = u*v*v
74 | u += (Du*Lu - uvv + F *(1-u))
75 | v += (Dv*Lv + uvv - (F+k)*v )
76 |
77 | if i % 50 == 0:
78 | im.set_data(V)
79 | im.set_clim(vmin=V.min(), vmax=V.max())
80 | plt.draw()
81 | plt.pause(0.01)
82 |
83 | # plt.ioff()
84 | # plt.savefig("../figures/zebra.png",dpi=dpi)
85 | # plt.savefig("../figures/bacteria.png",dpi=dpi)
86 | # plt.savefig("../figures/fingerprint.png",dpi=dpi)
87 | # plt.show()
88 |
--------------------------------------------------------------------------------
/test/dev_mpi_ugrid.py:
--------------------------------------------------------------------------------
1 | """
2 | Use dask.Array to lazily combine subdomain outputs
3 | """
4 | import os,glob
5 | import copy
6 | import numpy as np
7 | import xarray as xr
8 | from stompy import utils
9 | from stompy.grid import unstructured_grid
10 | import matplotlib.pyplot as plt
11 |
12 |
13 | ##
14 |
15 | out_dir="/home/rusty/src/csc/dflowfm/runs/v03regroup_20190115/DFM_OUTPUT_flowfm"
16 | map_files=glob.glob(os.path.join(out_dir,'*0???_map.nc'))
17 |
18 | ##
19 |
20 | from stompy.grid import multi_ugrid
21 |
22 | # Slow, all the time is in add_grid().
23 | mu=multi_ugrid.MultiUgrid(map_files,cleanup_dfm=True)
24 |
25 | ucmag=mu['mesh2d_ucmag'].isel(time=-1).values
26 |
27 | plt.figure(1).clf()
28 |
29 | ccoll=mu.grid.plot_cells(values=ucmag,cmap='jet')
30 |
31 | plt.axis('tight')
32 | plt.axis('equal')
33 |
34 |
35 |
--------------------------------------------------------------------------------
/test/dev_sms.py:
--------------------------------------------------------------------------------
1 | from stompy.grid import unstructured_grid
2 | import six
3 |
4 | six.moves.reload_module(unstructured_grid)
5 |
6 | # thanks to Jacob Zhao for sample input
7 | g=unstructured_grid.UnstructuredGrid.read_sms("0509.grd")
8 |
9 | ##
10 |
11 | # appears to bring in cells, edges and edge marks okay.
12 | plt.figure(1).clf()
13 | g.plot_edges(values=g.edges['mark'])
14 | g.plot_cells(alpha=0.5)
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/test/test_cgal_line_walk.py:
--------------------------------------------------------------------------------
1 | from CGAL.CGAL_Triangulation_2 import Constrained_Delaunay_triangulation_2
2 | from CGAL.CGAL_Kernel import Point_2
3 |
4 | from stompy.grid import cgal_line_walk
5 |
6 | import numpy as np
7 |
8 | def test_cgal_link_walk():
9 | DT=Constrained_Delaunay_triangulation_2()
10 |
11 | xys=np.array( [ [0,0],
12 | [1,0],
13 | [0,1],
14 | [1,2] ],'f8' )
15 | # in some versions, Point_2 is picky that it gets doubles,
16 | # not ints.
17 | pnts=[Point_2(xy[0],xy[1])
18 | for xy in xys]
19 |
20 | vhs=[DT.insert(p) for p in pnts]
21 |
22 | DT.insert_constraint(vhs[0],vhs[2])
23 |
24 | ##
25 |
26 | res0=cgal_line_walk.line_walk(DT,vhs[0],vhs[1])
27 |
28 | assert not DT.is_constrained(res0[0][1])
29 | res1=cgal_line_walk.line_walk(DT,vhs[0],vhs[2])
30 |
31 | assert DT.is_constrained(res1[0][1])
32 |
33 | assert len(cgal_line_walk.line_conflicts(DT,p1=[5,5],p2=[5,6]))==0
34 |
35 | assert len(cgal_line_walk.line_conflicts(DT,p1=[0.5,-0.5],p2=[0.5,0.5]))==0
36 |
37 | assert len(cgal_line_walk.line_conflicts(DT,p1=[-0.5,0.5],p2=[0.5,0.5]))>0
38 |
39 | res3=cgal_line_walk.line_conflicts(DT,p1=[0,-1],p2=[2,1])
40 | assert len(res3)>0
41 | assert res3[0][0]=='v'
42 |
43 |
44 |
--------------------------------------------------------------------------------
/test/test_cgal_triangulation.py:
--------------------------------------------------------------------------------
1 | from CGAL.CGAL_Triangulation_2 import Constrained_Delaunay_triangulation_2
2 | from CGAL.CGAL_Kernel import Point_2
3 |
4 | def test_basic():
5 | def create():
6 | DT = Constrained_Delaunay_triangulation_2()
7 |
8 | pnts=[Point_2(0.0, 0.0),
9 | Point_2(1.0, 0.0),
10 | Point_2(1.0, 1.0)]
11 |
12 | vhs=[ DT.insert(pnt) for pnt in pnts ]
13 |
14 | DT.insert_constraint(vhs[0],vhs[1])
15 | DT.insert_constraint(vhs[1],vhs[2])
16 |
17 | DT.remove_incident_constraints(vhs[1])
18 |
19 | return DT
20 |
21 | DTs=[create()
22 | for _ in range(100)]
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/test_cimis.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import os
3 | import shutil
4 | import six
5 | import numpy as np
6 | from stompy.io.local import cimis
7 |
8 | # os.environ['CIMIS_KEY']='FILL_THIS_IN'
9 |
10 | def test_cimis():
11 | """
12 | Fetch CIMIS data for station 171. This requires a network connection
13 | and defining CIMIS_KEY (freely available application key) in the environment
14 | or above in this file.
15 | """
16 | # Start anew
17 | print("Get pristine cache dir")
18 | cache_dir='test_cache'
19 | os.path.exists(cache_dir) and shutil.rmtree(cache_dir)
20 | os.mkdir(cache_dir)
21 |
22 | print("Fetch first time")
23 | # 2/5/2001 is start of record for union city
24 | period=[np.datetime64('2016-01-01'),
25 | np.datetime64('2016-03-01')]
26 | df=cimis.cimis_fetch_to_xr(171,period[0],period[1],station_meta=True,
27 | days_per_request='10D',cache_dir=cache_dir)
28 | print("Fetch second time")
29 | df2=cimis.cimis_fetch_to_xr(171,period[0],period[1],station_meta=True,
30 | days_per_request='10D',cache_dir=cache_dir)
31 | print("Done")
32 | return df2
33 |
34 |
--------------------------------------------------------------------------------
/test/test_cmap.py:
--------------------------------------------------------------------------------
1 | from stompy.plot import cmap
2 |
3 | def test_list_gradients():
4 | assert len(cmap.list_gradients())
5 |
6 | def test_load_gradient():
7 | assert cmap.load_gradient('hot_desaturated.cpt') is not None
8 |
--------------------------------------------------------------------------------
/test/test_coamps.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import six
3 | from stompy.io.local import coamps
4 | six.moves.reload_module(coamps)
5 |
6 |
7 | bounds=[340000, 610000, 3980000, 4294000]
8 |
9 | ds=coamps.coamps_dataset( bounds=bounds,
10 | start=np.datetime64("2018-01-01 00:00:00"),
11 | stop= np.datetime64("2018-02-01 00:00:00"),
12 | cache_dir="/home/rusty/src/sfb_ocean/wind/cache",
13 | fields=['wnd_utru','wnd_vtru'],
14 | fetch=False)
15 |
16 | # that call first does
17 | # def fetch_coamps_wind(start,stop, cache_dir, **kw):
18 | # to do the downloading.
19 |
20 | # then iterates over def coamps_files(start,stop,cache_dir,fields=['wnd_utru','wnd_vtru','pres_msl']):
21 | # to figure out what to compile
22 | ##
23 | six.moves.reload_module(coamps)
24 | files=coamps.coamps_files(start=np.datetime64("2018-01-01 00:00:00"),
25 | stop= np.datetime64("2018-02-01 00:00:00"),
26 | cache_dir="/home/rusty/src/sfb_ocean/wind/cache",
27 | fields=['wnd_utru','wnd_vtru'])
28 |
29 | files=list(files)
30 |
--------------------------------------------------------------------------------
/test/test_constrained_delaunay.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from stompy.spatial.constrained_delaunay import ConstrainedXYZField
4 |
5 | data_dir=os.path.join(os.path.dirname(__file__),'data')
6 |
7 | def test_basic():
8 | basedir = data_dir
9 |
10 | s = ConstrainedXYZField.read_shps([os.path.join(basedir,'scale.shp'),
11 | os.path.join(basedir,'scale-lines.shp')],
12 | value_field='scale')
13 |
14 | sg = s.to_grid(nx=500,ny=500)
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/test_dfm.py:
--------------------------------------------------------------------------------
1 | """
2 | Test setup for DFM model run configuration
3 | """
4 |
5 | import subprocess
6 | import six
7 | import os
8 | import xarray as xr
9 | from stompy.grid import unstructured_grid
10 | from stompy import utils
11 | import numpy as np
12 | import stompy.model.delft.dflow_model as dfm
13 | import stompy.model.hydro_model as hm
14 |
15 | ##
16 |
17 | # machine-specific paths --
18 | # for tests, assume that PATH and LD_LIBRARY_PATH are set appropriately.
19 |
20 | def base_model(run_dir='run-dfm-test00'):
21 | g=unstructured_grid.UnstructuredGrid(max_sides=4)
22 |
23 | ret=g.add_rectilinear([0,0],[500,500],50,50)
24 | # sloping N-S from -3 at y=0 to +2 at y=500
25 | g.add_node_field('node_z_bed',-3 + g.nodes['x'][:,1]/100)
26 |
27 | model=dfm.DFlowModel()
28 | model.load_template('dflow-template.mdu')
29 | model.set_grid(g)
30 |
31 | model.num_procs=0
32 |
33 | model.set_run_dir(run_dir, mode='pristine')
34 | model.run_start=np.datetime64("2018-01-01 00:00")
35 | model.run_stop =np.datetime64("2018-01-03 00:00")
36 | dt=np.timedelta64(300,'s')
37 | t=np.arange(model.run_start-20*dt,
38 | model.run_stop +20*dt,
39 | dt)
40 | # 4h period
41 | periodic_Q=5*np.sin((t-t[0])/np.timedelta64(1,'s') * 2*np.pi/(4*3600.))
42 | Q=xr.DataArray(periodic_Q,dims=['time'],coords={'time':t})
43 | inflow=hm.FlowBC(name='inflow',
44 | geom=np.array([ [0,0],[0,500]]),
45 | flow=Q)
46 |
47 | stage=hm.HarmonicStageBC(name='stage',
48 | msl=1.0,S2=(0.5,0),
49 | geom=np.array([ [500,0],[500,500]]))
50 |
51 | source=hm.SourceSinkBC(name='source', flow=20.0,
52 | geom=np.array([100,100]))
53 |
54 | model.add_bcs([inflow,stage,source])
55 |
56 | model.projection='EPSG:26910'
57 | model.mdu['geometry','WaterLevIni']=0.0
58 | model.mdu['output','WaqInterval']=1800
59 | model.mdu['output','MapInterval']=1800
60 | model.write()
61 |
62 | return model
63 |
64 | ##
65 | def test_bcs():
66 | # Get a well-behaved small hydro run:
67 | model=base_model()
68 | model.partition()
69 | model.run_model()
70 |
71 |
--------------------------------------------------------------------------------
/test/test_dfm_grid.py:
--------------------------------------------------------------------------------
1 | from stompy.model.delft import dfm_grid
2 | import matplotlib.pyplot as plt
3 | import xarray as xr
4 |
5 | ##
6 |
7 | # g=dfm_grid.DFMGrid("/home/rusty/models/grids/mick_alviso_v4_net.nc/mick_alviso_v4_net.nc")
8 | nc_fn="/home/rusty/models/delft/dfm/alviso/20151214/Alviso_input/alviso2012_net.nc"
9 | g=dfm_grid.DFMGrid(nc_fn)
10 | ds=xr.open_dataset(nc_fn)
11 |
12 | ##
13 |
14 | fig=plt.figure(1)
15 | fig.clf()
16 | ax=fig.add_subplot(1,1,1)
17 |
18 | g.plot_edges(ax=ax,color='k')
19 |
--------------------------------------------------------------------------------
/test/test_dfm_to_ptm.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Thu Jun 16 05:21:30 2022
4 |
5 | @author: rusty
6 | """
7 | import six
8 | from stompy.model.delft import dfm_to_ptm
9 | six.moves.reload_module(dfm_to_ptm)
10 |
11 | # Testing
12 | #mdu_path="../flowfm.mdu"
13 | # This one is giving some bizarre fluxes.
14 | mdu_path="S:/Data/Hydro/UCD_CSC/DFM/runs/test_run2_dwaq_20160701/flowfm.mdu"
15 | converter=dfm_to_ptm.DFlowToPTMHydro(mdu_path,'test_hydro.nc',time_slice=slice(0,10),
16 | grd_fn='test_sub.grd',overwrite=True)
17 |
18 | #%%
19 |
20 | # 105255 .. 105296 sequential, inclusive
21 | converter.unmapped_faces # =np.nonzero(~valid)[0]
22 | # mostly negative, all are substantial
23 | converter.unmapped_fluxes # =Qs[~valid]
24 |
25 | # These are indexes into the horizontal exchanges of flow.
26 | # should be able to get those to links (probably 1:1, since it's a 1D run)
27 | hyd=converter.hyd
28 | # sgn is +1 for all of these
29 | unmapped_links=hyd.exch_to_2d_link[converter.unmapped_faces]['link']
30 |
31 | unmapped_elts=hyd.links[unmapped_links,1]
32 |
33 | g=hyd.grid()
34 | #%%
35 | import matplotlib.pyplot as plt
36 | fig,ax=plt.subplots(num=1,clear=1)
37 | ax.set_adjustable('datalim')
38 | g.plot_edges(lw=0.5,color='k',alpha=0.5)
39 | def labeler(i,r):
40 | return str(converter.unmapped_fluxes[i==unmapped_elts])
41 | g.plot_cells(mask=unmapped_elts,labeler=labeler)
42 |
43 | # The locations still look like DCD
44 | # but the fluxes at these points are large.
45 | # is it possible that I'm pulling the wrong faces of these cells?
46 | # like it's getting mixed up between the src/sink exchange and a real
47 | # exchange, maybe 1-off?
48 | # also, check the actual DCD inputs. maybe they are off.
49 |
--------------------------------------------------------------------------------
/test/test_exact_delaunay2.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 |
3 | import numpy as np
4 |
5 | from stompy.grid import exact_delaunay, unstructured_grid
6 |
7 | Triangulation=exact_delaunay.Triangulation
8 | from stompy.spatial import robust_predicates
9 |
10 | def test_gen_intersected_elements():
11 | dt = Triangulation()
12 | pnts = [ [0,0],
13 | [5,0],
14 | [10,0],
15 | [5,5] ]
16 |
17 | nA=dt.add_node( x=pnts[0] ) # This tests insert into empty
18 | dt.add_node( x=pnts[1] ) # adjacent_vertex
19 | dt.add_node( x=pnts[2] ) # adjacent_vertex
20 | dt.add_node( x=pnts[3] ) # adjacent_edge
21 |
22 | dt.add_node( x=[3,0] ) # colinear
23 |
24 | dt.add_node( x=[6,2] ) # into cell interior
25 | nB=dt.add_node( x=[12,4] ) # collinear cell interior
26 |
27 | nodes=list(dt.valid_node_iter())
28 |
29 | for iA,nA in enumerate(nodes):
30 | for nB in nodes[iA+1:]:
31 | print("test_gen_intersected_elements: %s to %s"%(dt.nodes['x'][nA],
32 | dt.nodes['x'][nB]))
33 | fwd=list(dt.gen_intersected_elements(nA=nA,nB=nB))
34 | rev=list(dt.gen_intersected_elements(nA=nB,nB=nA))
35 | assert len(fwd) == len(rev)
36 |
37 | def test_gen_int_elts_dim1():
38 | dt = Triangulation()
39 | pnts = [ [0,0],
40 | [5,0],
41 | [10,0] ]
42 | for pnt in pnts:
43 | dt.add_node( x=pnt )
44 |
45 | assert len(list(dt.gen_intersected_elements(0,1)))==3
46 | assert len(list(dt.gen_intersected_elements(0,2)))==5
47 | assert len(list(dt.gen_intersected_elements(1,2)))==3
48 |
49 | # and with some points
50 | assert len(list(dt.gen_intersected_elements(pA=[-1,-1],
51 | pB=[-1,1])))==0
52 | elts=list(dt.gen_intersected_elements(pA=[0,-1],pB=[0,1]))
53 | assert len(elts)==1
54 | assert elts[0][0]=='node'
55 |
56 | elts=list(dt.gen_intersected_elements(pA=[0,-1],pB=[1,1]))
57 | assert len(elts)==1
58 | assert elts[0][0]=='edge'
59 |
60 | def test_gen_int_elts_dim0():
61 | dt = Triangulation()
62 |
63 | assert len(list(dt.gen_intersected_elements(pA=[-1,0],pB=[1,0])))==0
64 |
65 | dt.add_node(x=[0,0])
66 |
67 | assert len(list(dt.gen_intersected_elements(pA=[-1,0],pB=[1,0])))==1
68 | assert len(list(dt.gen_intersected_elements(pA=[-1,0],pB=[1,1])))==0
69 |
--------------------------------------------------------------------------------
/test/test_field.py:
--------------------------------------------------------------------------------
1 | import os
2 | import numpy as np
3 |
4 | from stompy.spatial import field
5 |
6 |
7 | datadir=os.path.join( os.path.dirname(__file__), 'data')
8 |
9 | #depth_bin_file = '/home/rusty/classes/research/spatialdata/us/ca/suntans/bathymetry/compiled2/final.bin'
10 |
11 | def test_xyz():
12 | depth_bin_file = os.path.join(datadir,'depth.xyz')
13 |
14 | f = field.XYZText(fname=depth_bin_file)
15 | f.build_index()
16 |
17 | center = np.array([ 563379.6 , 4196117. ])
18 |
19 | elev = f.inv_dist_interp(center,
20 | min_n_closest=8,
21 | min_radius=3900.0)
22 |
23 |
24 |
25 | ##
26 |
27 | def test_lin_interp():
28 | X=np.array([[0.,0.],[10.,0.],[10.,10.],[0.,10.]])
29 | F=np.array([1.,2.,3.,4.])
30 |
31 | f = field.XYZField(X=X,F=F)
32 |
33 | elev = f.interpolate( [2,3] )
34 |
35 | out=f.interpolate(X)
36 | assert np.allclose(out,F)
37 |
38 |
39 |
--------------------------------------------------------------------------------
/test/test_filters.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from stompy import filters
3 |
4 | def test_modes():
5 | t_h=np.arange(0,24*20)
6 |
7 | x= 2.0+ ( 1.0 *np.cos( t_h/12.4 * 2*np.pi ) +
8 | 0.3 *np.cos( t_h/12. * 2*np.pi ) +
9 | 0.1 *np.cos( t_h/24.8 * 2*np.pi ) +
10 | 0.1 *np.cos( t_h/24. * 2*np.pi ) )
11 | x_lp=filters.lowpass_godin(x,t_h/24.)
12 | x_lp_nan=filters.lowpass_godin(x,t_h/24.,ends='nan')
13 |
14 | if 0:
15 | import matplotlib.pyplot as plt # just for dev
16 | plt.figure(10).clf()
17 | plt.plot(t_h,x)
18 | plt.plot(t_h,x_lp)
19 | plt.plot(t_h,x_lp_nan)
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/test_front_speed.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import logging
4 | import matplotlib.pyplot as plt
5 | import numpy as np
6 | import pdb
7 |
8 | from scipy import optimize as opt
9 |
10 | from stompy.spatial import field
11 | from stompy import utils
12 |
13 | from stompy.grid import (unstructured_grid, exact_delaunay, front)
14 |
15 | import logging
16 | logging.basicConfig(level=logging.INFO)
17 |
18 | from stompy.spatial.linestring_utils import upsample_linearring,resample_linearring
19 | from stompy.spatial import field,constrained_delaunay,wkb2shp
20 |
21 | ## Curve -
22 |
23 | def hex_curve():
24 | hexagon = np.array( [[0,11],
25 | [10,0],
26 | [30,0],
27 | [40,9],
28 | [30,20],
29 | [10,20]] )
30 | return front.Curve(hexagon)
31 |
32 | def test_basic_setup():
33 | boundary=hex_curve()
34 | af=front.AdvancingTriangles()
35 | scale=field.ConstantField(3)
36 |
37 | af.add_curve(boundary)
38 | af.set_edge_scale(scale)
39 |
40 | # create boundary edges based on scale and curves:
41 | af.initialize_boundaries()
42 |
43 | if 0:
44 | plt.clf()
45 | g=af.grid
46 | g.plot_edges()
47 | g.plot_nodes()
48 |
49 | #
50 | coll=g.plot_halfedges(values=g.edges['cells'])
51 | coll.set_lw(0)
52 | coll.set_cmap('winter')
53 |
54 | return af
55 |
56 |
57 | def test_no_lookahead():
58 | af=test_basic_setup()
59 | af.log.setLevel(logging.INFO)
60 | af.cdt.post_check=False
61 |
62 | af.current=af.root=front.DTChooseSite(af)
63 |
64 | def cb():
65 | af.plot_summary(label_nodes=False)
66 | try:
67 | af.current.site.plot()
68 | except: # AttributeError:
69 | pass
70 |
71 | while 1:
72 | if not af.current.children:
73 | break # we're done?
74 |
75 | for child_i in range(len(af.current.children)):
76 | if af.current.try_child(child_i):
77 | # Accept the first child which returns true
78 | break
79 | else:
80 | assert False # none of the children worked out
81 | return af
82 | ##
83 | # 172 cells, with CGAL, takes 8.7s ? so 20 cells/second.
84 |
85 | test_no_lookahead()
86 |
87 | # 10s in prun
88 | # removed some log.debug statements
89 | # 8.3s
90 | # 5.8s in optimize, 1.1s in line_walk
91 |
92 | ##
93 |
--------------------------------------------------------------------------------
/test/test_gen_spatial_index.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import nose
3 |
4 | from stompy.spatial import gen_spatial_index
5 |
6 | reload(gen_spatial_index)
7 |
8 | def helper(implementation):
9 | x=np.linspace(0,1,51)
10 | y=np.linspace(0,1,51)
11 | X,Y=np.meshgrid(x,y)
12 |
13 | pnts=np.c_[ X.ravel(), X.ravel(), Y.ravel(), Y.ravel() ]
14 |
15 | klass=gen_spatial_index.point_index_class_factory(implementation=implementation)
16 | tuples=zip( np.arange(len(pnts)), pnts, [None]*len(pnts) )
17 |
18 | index=klass(tuples,interleaved=False)
19 |
20 | # avoid ambiguous answer - 0.015 better than 0.01
21 | target=np.array([0.015,0.015,0.02,0.02])
22 |
23 | hits=index.nearest( target, 5)
24 | hits=list(hits) # in case it's a generator
25 |
26 | brute=np.argmin(utils.dist(pnts[:,[0,2]]-target[[0,2]]))
27 |
28 | assert hits[0]==brute
29 |
30 | def test_rtree():
31 | helper('rtree')
32 |
33 | def test_best():
34 | helper('best')
35 |
36 | def test_kdtree():
37 | helper('kdtree')
38 |
39 | def test_qgis():
40 | # likely to fail if not run from within qgis.
41 | helper('qgis')
42 |
43 | ##
44 |
45 | if __name__=='__main__':
46 | nose.main()
47 |
48 |
--------------------------------------------------------------------------------
/test/test_harm_decomp.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 |
3 |
4 | from stompy import harm_decomp
5 | import numpy as np
6 |
7 | def test_basic():
8 | # A sample problem:
9 | omegas = np.array([1.0,0.0])
10 |
11 | # the constructed data:
12 | amps = np.array([1,5.0])
13 | phis = np.array([1,0])
14 |
15 | t = np.linspace(0,10*np.pi,125)
16 | h = amps[0]*np.cos(omegas[0]*t - phis[0]) + amps[1]*np.cos(omegas[1]*t - phis[1])
17 |
18 | comps = harm_decomp.decompose(t,h,omegas)
19 | recon=harm_decomp.recompose(t,comps,omegas)
20 |
21 | assert np.allclose( recon, h)
22 |
23 | print("Components: ",comps)
24 |
25 |
--------------------------------------------------------------------------------
/test/test_lag.py:
--------------------------------------------------------------------------------
1 | from stompy.utils import *
2 | import xarray as xr
3 | import matplotlib.pyplot as plt
4 | import numpy as np
5 |
6 |
7 | ##
8 |
9 | def test_basic():
10 | # Test timeseries:
11 | t_h=np.arange(0,24*30,0.1) # 6 minute time steps in units of hours
12 | # And as np datetimes:
13 | t=np.datetime64("2000-01-01 00:00") + (3600*t_h)*np.timedelta64(1,'s')
14 |
15 | mod=xr.Dataset()
16 | mod['time']=('time',),t
17 | mod['x']=( ('time',),
18 | np.cos( 2*np.pi *t_h /12.4) + 0.2*np.cos( 2*np.pi *t_h /12.0) )
19 |
20 | obs=xr.Dataset()
21 | # give it a time shift:
22 | obs['time']=('time',),t+np.timedelta64(45,'m')
23 | obs['x']=( ('time',),
24 | (np.cos( 2*np.pi *t_h /12.4) + 0.2*np.cos( 2*np.pi *t_h /12.0) ) )
25 | # Add some noise to everybody
26 | obs['x'].values += 0.1*(np.random.random(t_h.shape) - 0.5)
27 | mod['x'].values += 0.1*(np.random.random(t_h.shape) - 0.5)
28 |
29 | # Make it shorter and coarser in time
30 | obs = obs.isel(time=slice(20,-100,3))
31 |
32 | lag=utils.find_lag_xr(mod.x,obs.x)
33 |
34 | print lag / np.timedelta64(1,'m')
35 |
36 | assert np.abs( lag - np.timedelta64(-45,'m')) < np.timedelta64(5,'m')
37 |
38 | try:
39 | import matplotlib.pyplot as plt
40 |
41 | plt.figure(1).clf()
42 | fig,ax=plt.subplots(num=1)
43 |
44 | ax.plot(obs.time,obs.x,label='Obs')
45 | ax.plot(mod.time,mod.x,label='Mod')
46 | ax.plot(mod.time-lag,mod.x,label='Mod w/lag')
47 |
48 | ax.legend(fontsize=10)
49 | except ImportError:
50 | pass
51 |
52 |
--------------------------------------------------------------------------------
/test/test_live_dt.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging
3 | logging.basicConfig(level=logging.INFO)
4 |
5 | import numpy as np
6 | import matplotlib.pyplot as plt
7 |
8 | from stompy.grid import live_dt, paver, exact_delaunay, trigrid, orthomaker
9 |
10 | def run_basic(klass):
11 | pnts = np.array([ [0,0],
12 | [3,0],
13 | [5,0],
14 | [10,0],
15 | [5,5],
16 | [6,2],
17 | [12,4]], np.float64 )
18 |
19 | g=klass(points=pnts)
20 |
21 | g.add_edge(0,1)
22 | g.add_edge(1,2)
23 | g.add_edge(2,3)
24 | j24=g.add_edge(2,4)
25 | g.add_edge(0,4)
26 | j25=g.add_edge(2,5)
27 | j56=g.add_edge(5,6)
28 | g.add_edge(3,6)
29 | g.add_edge(4,5)
30 |
31 | # plt.figure(1).clf()
32 | # g.plot()
33 | # g.plot_nodes()
34 |
35 | # point on convex hull away from the triangulation
36 | assert g.shoot_ray(0,[2,1])[0]==j24
37 | assert g.shoot_ray(2,[1,1])[0]==j56
38 | assert g.shoot_ray(3,[-4,2])[0] in (j25,j56)
39 | # py code is failing these:
40 | res=g.shoot_ray(0,[0,1])
41 | assert res == (None,None)
42 |
43 | def test_basic_cgal():
44 | run_basic(live_dt.LiveDtCGAL)
45 |
46 | def test_basic_python():
47 | run_basic(live_dt.LiveDtPython)
48 |
49 |
--------------------------------------------------------------------------------
/test/test_merge_grids.py:
--------------------------------------------------------------------------------
1 | import nose
2 | from stompy.grid import unstructured_grid
3 | reload(unstructured_grid)
4 | from nose.tools import assert_raises
5 |
6 | ##
7 |
8 | def test_merge():
9 | ugA=unstructured_grid.SuntansGrid('/Users/rusty/src/umbra/Umbra/sample_data/sfbay')
10 | ugB=unstructured_grid.SuntansGrid('/Users/rusty/src/umbra/Umbra/sample_data/sfbay')
11 |
12 | x_cut=568000
13 | n_sel=ugA.nodes['x'][:,0]0.99
99 |
100 |
--------------------------------------------------------------------------------
/test/test_py_apollonius.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from stompy.spatial import field
3 |
4 | def test_basic():
5 | pa=field.PyApolloniusField()
6 |
7 | pa.insert([0,0],10)
8 | pa.insert([100,100],5)
9 |
10 | g=pa.to_grid(100,100)
11 |
12 | # good to test a single point, too
13 | pa( [10,10] )
14 |
15 | ##
16 |
17 | def test_larger():
18 | # About 1.5s on basic macbook
19 | pa=field.PyApolloniusField()
20 |
21 | for it in range(1000):
22 | xy=1000*np.random.random(2)
23 | pa.insert(xy,10)
24 |
25 | g=pa.to_grid(200,200)
26 |
27 |
--------------------------------------------------------------------------------
/test/test_rbr.py:
--------------------------------------------------------------------------------
1 | from stompy.io import rbr
2 |
3 | def test_rbr():
4 | """ no tests yet, aside from making sure it can import """
5 | pass
6 |
7 |
--------------------------------------------------------------------------------
/test/test_rdb.py:
--------------------------------------------------------------------------------
1 | import os
2 | import numpy as np
3 | import nose
4 |
5 | from stompy.io import rdb, rdb_codes
6 |
7 | datadir=os.path.join(os.path.dirname(__file__),'data')
8 |
9 | def test_basic():
10 | fn=os.path.join(datadir,'test_rdb.rdb')
11 | r=rdb.Rdb(source_file=fn)
12 |
13 | def test_xarray():
14 | ds1=rdb.rdb_to_dataset(os.path.join(datadir,'test_rdb.rdb'))
15 | ds2=rdb.rdb_to_dataset(os.path.join(datadir,'coyote.rdb'))
16 |
17 | assert ds2.time.dtype==np.datetime64
18 |
19 | def test_codes():
20 | pcodes=rdb_codes.parm_codes()
21 | scodes=rdb_codes.stat_codes()
22 | pcodes.loc[60]
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/test_read_ras.py:
--------------------------------------------------------------------------------
1 | import stompy.grid.unstructured_grid as ugrid
2 |
3 | def test_read_ras2d():
4 | g2=ugrid.UnstructuredGrid.read_ras2d('data/Ex1.g01.hdf')
5 |
--------------------------------------------------------------------------------
/test/test_tom.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Added -f 5.0 to coarsen the scale and complete much faster.
4 | # this should take about 1800 steps to complete, maybe 1 minute on a 2019 laptop.
5 | python ../stompy/grid/tom.py -f 5.0 -s data/scale-lines.shp -b data/dumbarton.shp
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/test/test_transect.py:
--------------------------------------------------------------------------------
1 | from stompy.model.suntans import transect
2 |
3 | def test_transect():
4 | """no tests yet, just import
5 | """
6 | pass
7 |
--------------------------------------------------------------------------------
/test/test_transect_contour.py:
--------------------------------------------------------------------------------
1 | import xarray as xr
2 | from stompy import xr_transect
3 | import matplotlib.pyplot as plt
4 |
5 | def test_transect_contour():
6 | tran=xr.open_dataset('data/temp-transect.nc')
7 |
8 | plt.figure(10).clf()
9 | fig,axs=plt.subplots(2,1,num=10,sharex=True,sharey=True)
10 | xr_transect.plot_scalar(tran,'temp',ax=axs[0])
11 | xr_transect.plot_scalar_pcolormesh(tran,'temp',ax=axs[1])
12 |
13 | xr_transect.contour(tran,'temp',np.linspace(5,27,28),
14 | ax=axs[1],colors='k',linewidths=0.5)
15 |
16 |
--------------------------------------------------------------------------------
/test/test_trigrid.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from stompy.grid import trigrid
4 |
5 | def test_read_sun():
6 | path=os.path.join( os.path.dirname(__file__),'data','sfbay')
7 |
8 | g = trigrid.TriGrid(suntans_path=path)
9 | g.Ncells()
10 |
11 |
12 | if __name__ == '__main__':
13 | g = TriGrid(sms_fname="/home/rusty/data/sfbay/grids/100km-arc/250m/250m-100km_arc.grd")
14 | g.plot()
15 | g.verify_bc(do_plot=1)
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/test/test_uk_tides.py:
--------------------------------------------------------------------------------
1 | from stompy.io.local import uk_tides
2 | import numpy as np
3 |
4 | cache_dir="."
5 |
6 | # stations=get_tide_gauges(cache_dir)
7 | uk_tides.get_tide_gauges(cache_dir='.')
8 |
9 |
10 | station='E72124'
11 | ds=uk_tides.fetch_tides(station=station,
12 | start_date=np.datetime64("2019-07-01"),
13 | end_date=np.datetime64("2019-07-10"),
14 | cache_dir=cache_dir)
15 |
16 |
--------------------------------------------------------------------------------
/test/test_unstructured_grid_plot.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 |
3 | import numpy as np
4 | import os
5 |
6 | import matplotlib.pyplot as plt
7 | from stompy.grid import unstructured_grid
8 | from stompy.model.delft import dfm_grid
9 |
10 |
11 | def test_square_axes():
12 | sample_data=os.path.join(os.path.dirname(__file__),'data')
13 | g=unstructured_grid.UnstructuredGrid.read_dfm(os.path.join(sample_data,"lsb_combined_v14_net.nc"))
14 |
15 | expected=np.r_[490243.0, 609718.4589319953, 4137175.7739677625, 4232151.0]
16 |
17 | fig=plt.figure(1)
18 | fig.clf()
19 | g.plot_cells()
20 | plt.draw()
21 | result=plt.axis()
22 | diff = np.abs(np.array(result) - expected)
23 | assert np.all(diff<10.0)
24 |
25 | fig.clf()
26 | g.plot_nodes()
27 | plt.draw()
28 | result=plt.axis()
29 | diff = np.abs(np.array(result) - expected)
30 | assert np.all(diff<10.0)
31 |
32 | fig.clf()
33 | g.plot_edges()
34 | plt.draw()
35 | result=plt.axis()
36 | diff = np.abs(np.array(result) - expected)
37 | assert np.all(diff<10.0)
38 |
39 | # What about shared axes?
40 | # This works:
41 | fig.clf()
42 | fig,axs=plt.subplots(1,2,sharex=True,sharey=True,num=1)
43 | g.plot_nodes(ax=axs[0])
44 | g.plot_nodes(ax=axs[1])
45 | plt.draw()
46 | result=plt.axis()
47 | diff = np.abs(np.array(result) - expected)
48 | assert np.all(diff<10.0)
49 |
50 | # This is okay
51 | fig.clf()
52 | fig,axs=plt.subplots(1,2,sharex=True,sharey=True,num=1)
53 | g.plot_edges(ax=axs[0])
54 | g.plot_edges(ax=axs[1])
55 | plt.draw()
56 | result=plt.axis()
57 | diff = np.abs(np.array(result) - expected)
58 | assert np.all(diff<10.0)
59 |
60 | fig.clf()
61 | fig,axs=plt.subplots(1,2,sharex=True,sharey=True,num=1)
62 | g.plot_cells(ax=axs[0])
63 | g.plot_cells(ax=axs[1])
64 | plt.draw()
65 | result=plt.axis()
66 | diff = np.abs(np.array(result) - expected)
67 | assert np.all(diff<10.0)
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/test/test_usgs_nwis.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 | import time
4 |
5 | import numpy as np
6 | from stompy.io.local import usgs_nwis
7 |
8 | ##
9 |
10 | def test_basic():
11 | # This requires internet access!
12 | ds=usgs_nwis.nwis_dataset(station="11337190",
13 | start_date=np.datetime64('2012-08-01'),
14 | end_date =np.datetime64('2012-10-01'),
15 | products=[60, # "Discharge, cubic feet per second"
16 | 10], # "Temperature, water, degrees Celsius"
17 | days_per_request=30)
18 |
19 |
20 | def test_provisional():
21 | usgs_a8_site="372512121585801"
22 |
23 | ds=usgs_nwis.nwis_dataset(usgs_a8_site,
24 | np.datetime64("2015-12-10"),
25 | np.datetime64("2015-12-20"),
26 | products=[72178])
27 |
28 | def test_missing():
29 | station="11162765"
30 | t_start=np.datetime64('2016-10-01')
31 | t_stop=np.datetime64('2016-12-01')
32 | # This period has some missing data identified by '***' which
33 | # caused problems in older versions of rdb.py
34 | ds=usgs_nwis.nwis_dataset(station,
35 | t_start,t_stop,
36 | products=[95,90860],
37 | days_per_request=20)
38 |
39 | def test_caching():
40 | station="11162765"
41 | t_start=np.datetime64('2016-10-01')
42 | t_stop=np.datetime64('2016-12-01')
43 |
44 | cache_dir='tmp_cache'
45 | if os.path.exists(cache_dir):
46 | # Start clean
47 | shutil.rmtree(cache_dir)
48 |
49 | os.mkdir(cache_dir)
50 |
51 | timings=[]
52 | for trial in [0,1]:
53 | t0=time.time()
54 | ds=usgs_nwis.nwis_dataset(station,
55 | t_start,t_stop,
56 | products=[95,90860],
57 | days_per_request='10D',cache_dir=cache_dir)
58 | timings.append(time.time() - t0)
59 |
60 | assert timings[0]>5*timings[1]
61 |
--------------------------------------------------------------------------------
/test/test_utils.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from stompy.utils import segment_segment_intersection
3 |
4 | def test_segment_segment_intersection():
5 | x1=segment_segment_intersection( np.array( [ [0,0],[1,0]] ),
6 | np.array( [ [0,0],[0,1]] ) )
7 | assert np.allclose( x1, [0,0])
8 |
9 | x2=segment_segment_intersection( np.array( [ [0,0],[1,0]] ),
10 | np.array( [ [1,0],[0,0]] ) )
11 | assert x2 is None
12 |
13 | x3=segment_segment_intersection( np.array( [ [0,0],[1,0]] ),
14 | np.array( [ [0,1],[1,1]] ) )
15 | assert x3 is None
16 |
17 | x4=segment_segment_intersection( np.array( [ [0,0],[1,1]] ),
18 | np.array( [ [1,0],[0,1]] ) )
19 | assert np.allclose(x4,[0.5,0.5])
20 |
21 |
--------------------------------------------------------------------------------
/test/test_waq_scenario.py:
--------------------------------------------------------------------------------
1 | from stompy.model.delft import waq_scenario
2 | import datetime
3 |
4 | def test_waq_timestep_timedelta():
5 | inputs=[100,"100","0010","5000000",5100]
6 |
7 | for x in inputs:
8 | td=waq_scenario.waq_timestep_to_timedelta(x)
9 | ts=waq_scenario.timedelta_to_waq_timestep(td)
10 | td2=waq_scenario.waq_timestep_to_timedelta(ts)
11 | assert td == td2
12 |
--------------------------------------------------------------------------------
/test/test_wkb2shp.py:
--------------------------------------------------------------------------------
1 | import os
2 | import numpy as np
3 | from stompy.spatial import wkb2shp
4 | from stompy import utils
5 | import six
6 | six.moves.reload_module(wkb2shp)
7 |
8 | def test_load_shp():
9 | feats=wkb2shp.shp2geom("data/dem_sources.shp")
10 | assert np.any(~utils.isnat(feats['start_date']))
11 |
12 | def test_load_shp_query():
13 | feats=wkb2shp.shp2geom("data/dem_sources.shp")
14 | queries=["priority < 100",
15 | "start_date is null"]
16 | # This appears not to be supported yet. unclear.
17 | # 'start_date is null or (cast(start_date as character) < "2014-09-01")']
18 |
19 | for query in queries:
20 | print(query)
21 | feat_sel=wkb2shp.shp2geom("data/dem_sources.shp",
22 | query=query)
23 | assert len(feats)>len(feat_sel)
24 |
25 | if 0:
26 | # Doesn't work.
27 | def test_write_gpkg():
28 | from shapely import geometry
29 |
30 | geoms=[ geometry.Point( -120.0, 37.0 ),
31 | geometry.Point( -121.0, 37.5 ) ]
32 | if os.path.exists('test.gpkg'):
33 | import shutil
34 | shutil.rmtree('test.gpkg')
35 | wkb2shp.wkb2shp("test.gpkg",geoms,driver='GPKG',srs_text='WGS84',
36 | layer_name='points')
37 |
38 |
39 |
--------------------------------------------------------------------------------
/test/test_xr_transect.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from stompy import xr_transect
4 |
5 | def test_transect():
6 | """
7 | Test loading a 'section_hydro' formatted transect, and resample to evenly
8 | spaced z.
9 | """
10 | untrim_sec=xr_transect.section_hydro_to_transect("data/section_hydro.txt",name="7B")
11 |
12 | new_z=np.linspace( untrim_sec.z_bed.values.min(),
13 | untrim_sec.z_surf.values.max(),
14 | 100)
15 |
16 | untrim_sec_eq=xr_transect.resample_z(untrim_sec,new_z)
17 |
18 | plt.figure(22).clf()
19 | fig,axs=plt.subplots(2,1,num=22,sharex=True,sharey=True)
20 |
21 | xr_transect.plot_scalar(untrim_sec,'Ve',ax=axs[0])
22 | xr_transect.plot_scalar(untrim_sec_eq,'Ve',ax=axs[1])
23 |
24 | axs[0].text(0.02,0.9,'Original',transform=axs[0].transAxes)
25 | axs[1].text(0.02,0.9,'Resample',transform=axs[1].transAxes)
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------