In [ ]:
import glob
import os
import io
import pymap3d

import cartopy.feature as cf
import geopandas as gpd
import holoviews as hv
import hvplot.pandas
import hvplot.xarray
import numpy as np
import pandas as pd
import shapely
import thalassa
import xarray as xr

import searvey

import pyposeidon
import pyposeidon.meteo as pmeteo
import pyposeidon.dem as pdem
import pyposeidon.boundary as pbound
import pyposeidon.mesh as pmesh
import pyposeidon.model as pmodel
from pyposeidon.utils import cast

import pyposeidon.utils.hplot as hplot
import pyposeidon.utils.pplot as pplot

hv.extension("bokeh")

!mkdir -p data/iceland

Geometry¶

In [ ]:
lon_min = -28.0
lon_max = -11.1
lat_min =  62.0
lat_max =  68.0

bbox = shapely.box(lon_min, lat_min, lon_max, lat_max)
geometry = dict(lon_min=lon_min, lon_max=lon_max, lat_min=lat_min, lat_max=lat_max)

Coastlines¶

In [ ]:
OSM_FOLDER = "/home/tomsail/work/python/seareport_org/coastlines/raw/osm/land-polygons-complete-4326"
In [ ]:
coastlines = gpd.read_file(OSM_FOLDER + "/land_polygons.shp", bbox=bbox)
coastlines
Out[ ]:
FID geometry
0 29026 POLYGON ((-22.02066 64.16396, -22.02093 64.163...
1 29034 POLYGON ((-21.76014 64.16271, -21.76026 64.162...
2 29035 POLYGON ((-21.77483 64.18337, -21.77487 64.183...
3 29062 POLYGON ((-21.83118 64.18681, -21.83212 64.187...
4 29065 POLYGON ((-21.9012 64.25611, -21.90095 64.2561...
... ... ...
3637 766100 POLYGON ((-22.40777 65.09126, -22.40769 65.091...
3638 766101 POLYGON ((-22.41448 65.09122, -22.41439 65.091...
3639 769143 POLYGON ((-15.21416 64.27749, -15.21428 64.277...
3640 770114 POLYGON ((-23.64125 64.73958, -23.64099 64.739...
3641 772163 POLYGON ((-19.00579 63.41416, -19.00584 63.414...

3642 rows × 2 columns

Boundaries¶

In [ ]:
boundary = pbound.Boundary(geometry=geometry, coastlines=coastlines)
boundary.contours.head()
len(boundary.contours)
2024-07-15 07:22:41,215 WARNING  pyposeidon.boundary __init__:67 coastlines is not a file, trying with geopandas Dataset
Out[ ]:
geometry tag lindex nps
0 LINESTRING (-28 68, -11.1 68, -11.1 62, -28 62... open 1 4
1 LINESTRING (-13.85278 65.57077, -13.85307 65.5... island -1 5
2 LINESTRING (-13.84513 65.56995, -13.845 65.570... island -2 6
3 LINESTRING (-13.68221 65.5536, -13.68187 65.55... island -3 6
4 LINESTRING (-13.68278 65.55315, -13.68273 65.5... island -4 5
Out[ ]:
3643
In [ ]:
boundary.show()
Out[ ]:
<Axes: >
No description has been provided for this image
In [ ]:
# boundary.contours.hvplot(geo=True, tiles=True, frame_height=500)

DEM¶

In [ ]:
# url = "https://coastwatch.pfeg.noaa.gov/erddap/griddap/srtm30plus"
url = "data/iceland.nc"
dem = pdem.Dem(dem_source=url, **geometry)
dem.Dataset.load()
2024-07-15 07:22:43,862 INFO     pyposeidon.tools open_dataset:350 extracting dem from data/iceland.nc

2024-07-15 07:22:43,863 DEBUG    pyposeidon.tools open_dataset:361 Engine: netcdf4
/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/pyposeidon/dem.py:131: UserWarning: There are multiple data_vars. Assuming 'elevation' is the first one: ['Band1', 'crs']
  warnings.warn(f"There are multiple data_vars. Assuming 'elevation' is the first one: {data_vars}")
2024-07-15 07:22:44,594 INFO     pyposeidon.dem dem_:210 dem done

2024-07-15 07:22:44,595 WARNING  pyposeidon.dem __init__:81 coastlines not present, aborting adjusting dem

Out[ ]:
<xarray.Dataset> Size: 23MB
Dimensions:    (latitude: 1444, longitude: 4059)
Coordinates:
  * latitude   (latitude) float64 12kB 61.99 62.0 62.0 62.01 ... 68.0 68.0 68.01
  * longitude  (longitude) float64 32kB -28.01 -28.0 -28.0 ... -11.1 -11.1
Data variables:
    elevation  (latitude, longitude) float32 23MB -1.389e+03 ... -1.837e+03
Attributes:
    long_name:     GDAL Band Number 1
    grid_mapping:  crs
xarray.Dataset
    • latitude: 1444
    • longitude: 4059
    • latitude
      (latitude)
      float64
      61.99 62.0 62.0 ... 68.0 68.0 68.01
      standard_name :
      latitude
      long_name :
      latitude
      units :
      degrees_north
      array([61.99375 , 61.997917, 62.002083, ..., 67.997917, 68.002083, 68.00625 ])
    • longitude
      (longitude)
      float64
      -28.01 -28.0 -28.0 ... -11.1 -11.1
      standard_name :
      longitude
      long_name :
      longitude
      units :
      degrees_east
      array([-28.00625 , -28.002083, -27.997917, ..., -11.10625 , -11.102083,
             -11.097917])
    • elevation
      (latitude, longitude)
      float32
      -1.389e+03 ... -1.837e+03
      long_name :
      GDAL Band Number 1
      grid_mapping :
      crs
      array([[-1389., -1392., -1429., ..., -1047., -1046., -1044.],
             [-1454., -1456., -1477., ..., -1049., -1047., -1045.],
             [-1487., -1481., -1474., ..., -1049., -1047., -1046.],
             ...,
             [ -344.,  -350.,  -355., ..., -1828., -1831., -1828.],
             [ -340.,  -345.,  -351., ..., -1823., -1828., -1832.],
             [ -340.,  -345.,  -349., ..., -1823., -1829., -1837.]],
            dtype=float32)
    • latitude
      PandasIndex
      PandasIndex(Index([ 61.99374999984879,  61.99791666651539, 62.002083333181986,
              62.00624999984859,  62.01041666651519,  62.01458333318179,
             62.018749999848396, 62.022916666514995, 62.027083333181594,
               62.0312499998482,
             ...
               67.9687499997545,  67.97291666642109,  67.97708333308769,
               67.9812499997543,  67.98541666642089,   67.9895833330875,
               67.9937499997541,  67.99791666642069,   68.0020833330873,
              68.00624999975389],
            dtype='float64', name='latitude', length=1444))
    • longitude
      PandasIndex
      PandasIndex(Index([-28.006250000209224, -28.002083333542473, -27.997916666875724,
             -27.993750000208976, -27.989583333542228,  -27.98541666687548,
              -27.98125000020873,  -27.97708333354198,  -27.97291666687523,
              -27.96875000020848,
             ...
             -11.135416666542103, -11.131249999875354, -11.127083333208606,
             -11.122916666541858, -11.118749999875106, -11.114583333208358,
              -11.11041666654161, -11.106249999874862,  -11.10208333320811,
             -11.097916666541362],
            dtype='float64', name='longitude', length=4059))
  • long_name :
    GDAL Band Number 1
    grid_mapping :
    crs
In [ ]:
dem.Dataset.to_netcdf("./data/iceland/dem.nc")

Mesh¶

In [ ]:
mesh = pmesh.set(
    mesh_generator='oceanmesh',
    bgmesh = "om",
    dem_source="./data/iceland/dem.nc",
    type='tri2d',
    geometry=geometry,
    coastlines=coastlines,
    grad = 0.15,
    bathy_gradient= True,
    resolution_min=0.02,
    resolution_max=1.50,
    alpha_wavelength= 100,  # number of element to resolve WL
    alpha_slope= 10,  # number of element to resolve bathy gradient
)
mesh.Dataset.dims
2024-07-15 07:22:44,770 WARNING  pyposeidon.boundary __init__:67 coastlines is not a file, trying with geopandas Dataset
2024-07-15 07:22:46,870 INFO     pyposeidon.moceanmesh get:157 Creating mesh with Oceanmesh

2024-07-15 07:22:46,871 INFO     pyposeidon.moceanmesh make_oceanmesh:420 Executing oceanmesh
2024-07-15 07:22:50,713 INFO     pyposeidon.moceanmesh make_oceanmesh:464 oceanmesh: distance function
2024-07-15 07:22:50,978 INFO     pyposeidon.moceanmesh make_oceanmesh:466 oceanmesh: feature size function
2024-07-15 07:22:53,083 INFO     pyposeidon.moceanmesh make_oceanmesh:477 ./data/iceland/dem.nc
2024-07-15 07:22:53,191 INFO     pyposeidon.moceanmesh make_oceanmesh:479 oceanmesh: WL size function
2024-07-15 07:22:53,556 INFO     pyposeidon.moceanmesh make_oceanmesh:486 oceanmesh: bathymetric size function
2024-07-15 07:22:54,148 INFO     pyposeidon.moceanmesh make_oceanmesh:539 oceanmesh: generate mesh
2024-07-15 07:23:16,682 INFO     pyposeidon.moceanmesh make_oceanmesh:566 oceanmesh: boundaries
Out[ ]:
FrozenMappingWarningOnValuesAccess({'nSCHISM_hgrid_node': 36683, 'nSCHISM_hgrid_face': 70876, 'nMaxSCHISM_hgrid_face_nodes': 3, 'bnodes': 2510})
In [ ]:
mesh.Dataset.pplot.mesh()
Out[ ]:
<Axes: title={'center': 'Mesh plot'}, xlabel='Longitude (degrees)', ylabel='Latitude (degrees)'>
No description has been provided for this image
In [ ]:
mesh.to_file('./data/iceland/hgrid.gr3')
!head ./data/iceland/hgrid.gr3
2024-07-15 07:23:17,325 INFO     pyposeidon.mesh to_file:376 writing mesh to file ./data/iceland/hgrid.gr3
	 uniform.gr3
	 70876 36683
1	-21.5669000313	67.5843322685	0.0000000000
2	-13.5993326425	64.9130533526	0.0000000000
3	-23.9949065590	65.5776208081	0.0000000000
4	-14.6220620374	64.3555872484	0.0000000000
5	-17.3052891209	63.1876102642	0.0000000000
6	-20.2997668446	63.4227245966	0.0000000000
7	-18.2148689814	66.9584673197	0.0000000000
8	-25.8802156161	63.4917894940	0.0000000000

Fix bathy¶

In [ ]:
#define in a dictionary the properties of the model..
model_parameters = {
    "solver_name": "telemac",
    "rpath": "./data/iceland/",
    "dem_source": "./data/iceland/dem.nc",
    "mesh_file": "./data/iceland/hgrid.gr3",
    "update": ["dem"], #set which component should be updated  (meteo,dem,model)
    "start_date": "2018-10-01T00:00:00",
    "time_frame": "1d",
    "global": False,
}
model_parameters
Out[ ]:
{'solver_name': 'telemac',
 'rpath': './data/iceland/',
 'dem_source': './data/iceland/dem.nc',
 'mesh_file': './data/iceland/hgrid.gr3',
 'update': ['dem'],
 'start_date': '2018-10-01T00:00:00',
 'time_frame': '1d',
 'global': False}
In [ ]:
model = pmodel.set(**model_parameters)
model.create()
model.mesh.to_file('./data/iceland/hgrid.gr3')
!head ./data/iceland/hgrid.gr3
2024-07-15 07:23:18,386 INFO     pyposeidon.tools open_dataset:350 extracting dem from ./data/iceland/dem.nc

2024-07-15 07:23:18,387 DEBUG    pyposeidon.tools open_dataset:361 Engine: netcdf4
2024-07-15 07:23:18,393 WARNING  pyposeidon.dem dem_:163 Lon must be within -28.006250000209224 and -11.097916666541362
2024-07-15 07:23:18,393 WARNING  pyposeidon.dem dem_:164 compensating if global dataset available
2024-07-15 07:23:18,394 WARNING  pyposeidon.dem dem_:167 Lat is within 61.99374999984879 and 68.00624999975389
2024-07-15 07:23:18,397 INFO     pyposeidon.dem dem_:210 dem done

2024-07-15 07:23:18,398 WARNING  pyposeidon.dem __init__:81 coastlines not present, aborting adjusting dem

2024-07-15 07:23:18,399 INFO     pyposeidon.mesh read_file:239 read mesh file ./data/iceland/hgrid.gr3
2024-07-15 07:23:18,734 INFO     pyposeidon.telemac create:1007 bathy is set to 0, interpolating dem on mesh
2024-07-15 07:23:18,735 INFO     pyposeidon.dem dem_on_mesh:224 .. interpolating on mesh ..

2024-07-15 07:23:18,736 INFO     pyposeidon.dem dem_on_mesh:233 .. using elevation values ..

/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/pyposeidon/mesh.py:247: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  ni, nj = df.iloc[0].str.split()[0]
2024-07-15 07:23:19,344 INFO     pyposeidon.dem dem_on_mesh:264 dem on mesh done

2024-07-15 07:23:19,345 WARNING  pyposeidon.telemac bath:871 coastlines not present, aborting adjusting dem

2024-07-15 07:23:19,345 INFO     pyposeidon.telemac get_depth_from_dem:887 Dem already adjusted

2024-07-15 07:23:19,346 INFO     pyposeidon.telemac get_depth_from_dem:898 updating bathymetry ..

2024-07-15 07:23:19,347 INFO     pyposeidon.telemac create:1009 found bathy in mesh file

2024-07-15 07:23:19,348 INFO     pyposeidon.telemac force:763 skipping meteo ..

2024-07-15 07:23:19,349 INFO     pyposeidon.telemac config:659 using default telemac2d json config file ...

2024-07-15 07:23:19,345 WARNING  pyposeidon.telemac bath:871 coastlines not present, aborting adjusting dem

2024-07-15 07:23:19,345 INFO     pyposeidon.telemac get_depth_from_dem:887 Dem already adjusted

2024-07-15 07:23:19,346 INFO     pyposeidon.telemac get_depth_from_dem:898 updating bathymetry ..

2024-07-15 07:23:19,347 INFO     pyposeidon.telemac create:1009 found bathy in mesh file

2024-07-15 07:23:19,348 INFO     pyposeidon.telemac force:763 skipping meteo ..

2024-07-15 07:23:19,349 INFO     pyposeidon.telemac config:659 using default telemac2d json config file ...

2024-07-15 07:23:19,360 INFO     pyposeidon.mesh to_file:376 writing mesh to file ./data/iceland/hgrid.gr3
	 uniform.gr3
	 70876 36683
1	-21.5669000313	67.5843322685	684.0000000000
2	-13.5993326425	64.9130533526	66.0000000000
3	-23.9949065590	65.5776208081	54.0000000000
4	-14.6220620374	64.3555872484	23.0000000000
5	-17.3052891209	63.1876102642	897.0000000000
6	-20.2997668446	63.4227245966	10.0000000000
7	-18.2148689814	66.9584673197	394.0000000000
8	-25.8802156161	63.4917894940	355.0000000000
In [ ]:
def parse_hgrid_nodes(path: os.PathLike[str] | str) -> pd.DataFrame:
    with open(path, "rb") as fd:
        _ = fd.readline()
        _, no_points = map(int, fd.readline().strip().split(b" "))
        content = io.BytesIO(b''.join(next(fd) for _ in range(no_points)))
        nodes = pd.read_csv(
            content,
            engine="pyarrow",
            sep="\t",
            header=None,
            names=["lon", "lat", "depth"],
            index_col=0
        )
    nodes = nodes.reset_index(drop=True)
    return nodes
    
def parse_hgrid_elements3(path: os.PathLike[str] | str) -> pd.DataFrame:
    with open(path, "rb") as fd:
        _ = fd.readline()
        no_elements, no_points = map(int, fd.readline().strip().split(b" "))
        for _ in range(no_points):
            next(fd) 
        content = io.BytesIO(b''.join(next(fd) for _ in range(no_elements)))
        elements = pd.read_csv(
            content,
            engine="pyarrow",
            sep="\t",
            header=None,
            names=["no_nodes", "n1", "n2", "n3"],
            index_col=0
        )
    elements = elements.assign(
        n1=elements.n1 - 1,
        n2=elements.n2 - 1,
        n3=elements.n3 - 1,
    ).reset_index(drop=True)
    return elements

def get_skews_and_base_cfls(lons, lats, depths) -> np.ndarray:
    # The shape of each one of the input arrays needs to be (3, <no_triangles>)
    #ell = pymap3d.Ellipsoid.from_name("wgs84")
    ell = pymap3d.Ellipsoid(6378206.4, 6378206.4, "schism", "schism")
    local_x, local_y, _ = pymap3d.geodetic2enu(lats, lons, depths, lats[0], lons[0], depths[0], ell=ell)
    areas = (local_x[1] * local_y[2] - local_x[2] * local_y[1]) * 0.5
    rhos = np.sqrt(areas / np.pi)
    max_sides = np.maximum(
        np.sqrt(local_x[1] ** 2 + local_y[1] ** 2),
        np.sqrt(local_x[2] ** 2 + local_y[2] ** 2),
        np.sqrt((local_x[2] - local_x[1]) ** 2 + (local_y[2] - local_y[1]) ** 2),
    )
    skews = max_sides / rhos
    base_cfls = np.sqrt(9.81 * np.maximum(0.1, depths.mean(axis=0))) / rhos / 2
    return skews, base_cfls

def get_skews_and_base_cfls_from_path(path: os.PathLike[str] | str) -> np.ndarray:
    nodes = parse_hgrid_nodes(path)
    elements = parse_hgrid_elements3(path)
    tri = elements[["n1", "n2", "n3"]].values
    lons = nodes.lon.values[tri].T
    lats = nodes.lat.values[tri].T
    depths = nodes.depth.values[tri].T
    skews, base_cfls = get_skews_and_base_cfls(lons=lons, lats=lats, depths=depths)
    return skews, base_cfls
    
In [ ]:
skews, base_cfls = get_skews_and_base_cfls_from_path("./data/iceland/hgrid.gr3")
CFL_THRESHOLD = 0.4
print(f"elements violating CFL threshold < {CFL_THRESHOLD}")
print("time            N         %")
for dt in (1, 50, 75, 100, 120, 150, 200, 300, 400, 600, 900, 1200, 1800, 3600):
    violations = (base_cfls * dt < CFL_THRESHOLD).sum()
    print(f"{dt:>4d} {violations:>12d} {violations / len(base_cfls) * 100:>8.2f}%")
    
elements violating CFL threshold < 0.4
time            N         %
   1        70876   100.00%
  50         4028     5.68%
  75         2096     2.96%
 100         1580     2.23%
 120         1377     1.94%
 150         1210     1.71%
 200         1029     1.45%
 300          825     1.16%
 400          777     1.10%
 600           48     0.07%
 900            0     0.00%
1200            0     0.00%
1800            0     0.00%
3600            0     0.00%
In [ ]:
pd.DataFrame({"skew": skews}).describe([0.25, 0.5, 0.75, 0.9, 0.95, 0.99, 0.995, 0.999])
Out[ ]:
skew
count 70876.000000
mean 3.766559
std 0.538883
min 2.508742
25% 3.425276
50% 3.837101
75% 4.131190
90% 4.394984
95% 4.572409
99% 4.908128
99.5% 5.029456
99.9% 5.334526
max 9.411692
In [ ]:
def get_meta() -> gpd.GeoDataFrame:
    meta_web = searvey.get_ioc_stations().drop(columns=["lon", "lat"])
    meta_api = (
        pd.read_json(
            "http://www.ioc-sealevelmonitoring.org/service.php?query=stationlist&showall=all"
        )
        .drop_duplicates()
        .drop(columns=["lon", "lat"])
        .rename(columns={"Code": "ioc_code", "Lon": "longitude", "Lat": "latitude"})
    )
    merged = pd.merge(
        meta_web,
        meta_api[["ioc_code", "longitude", "latitude"]].drop_duplicates(),
        on=["ioc_code"],
    )
    updated = merged.assign(
        geometry=gpd.points_from_xy(merged.longitude, merged.latitude, crs="EPSG:4326")
    )
    return updated

ioc_ = get_meta()
ioc_[bbox.contains(ioc_.geometry)].to_csv('data/iceland/stations.csv')
In [ ]:
#define in a dictionary the properties of the model..
model_parameters = {
    "solver_name": "telemac",
    "tag": "telemac2d",
    "rpath": "./data/iceland/20181001",
    "mesh_file": "./data/iceland/hgrid.gr3",
    "update": ["all"], #set which component should be updated  (meteo,dem,model)
    "meteo_source": glob.glob("data/uvp_*.grib"),
    "meteo_merge": "last",  # combine meteo
    "meteo_combine_by": "nested",
    "meteo_xr_kwargs": {"concat_dim": "step"},
    "start_date": "2018-10-01T00:00:00",
    "time_frame": "2d",
    "obs": "data/iceland/stations.csv",
    "monitor": True,
    "parameters": {
        "dt": 100
    }
}
model_parameters
Out[ ]:
{'solver_name': 'telemac',
 'tag': 'telemac2d',
 'rpath': './data/iceland/20181001',
 'mesh_file': './data/iceland/hgrid.gr3',
 'update': ['all'],
 'meteo_source': ['data/uvp_2018100200.grib',
  'data/uvp_2018100112.grib',
  'data/uvp_2018100100.grib',
  'data/uvp_2018100212.grib'],
 'meteo_merge': 'last',
 'meteo_combine_by': 'nested',
 'meteo_xr_kwargs': {'concat_dim': 'step'},
 'start_date': '2018-10-01T00:00:00',
 'time_frame': '2d',
 'obs': 'data/iceland/stations.csv',
 'monitor': True,
 'parameters': {'dt': 100}}

run days 1&2¶

In [ ]:
a = pmodel.set(**model_parameters)
a.create()
# IMPORTANT! Here, for a simple surge application, 
# we will need close all boundaries, otherwise the 
# model will run out of water
a.mesh.Dataset.type[:] = 'closed' # it will create a cli file with all boundaries closed (this can be done only once)
# we also need to drop some meteo variables, it is necesarry for zarr export
a.output(**{"global": False})
a.set_obs()
a.save() # saves the json model file
a.run() # runs the model
2024-07-15 07:23:26,793 INFO     pyposeidon.telemac create:987 no dem available

2024-07-15 07:23:26,794 INFO     pyposeidon.mesh read_file:239 read mesh file ./data/iceland/hgrid.gr3
/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/pyposeidon/mesh.py:247: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  ni, nj = df.iloc[0].str.split()[0]
2024-07-15 07:23:27,266 INFO     pyposeidon.telemac create:1009 found bathy in mesh file

2024-07-15 07:23:27,267 INFO     pyposeidon.meteo cfgrib:147 extracting meteo
2024-07-15 07:23:27,267 INFO     pyposeidon.meteo cfgrib:147 extracting meteo
2024-07-15 07:23:32,795 INFO     pyposeidon.meteo cfgrib:170 combining meteo by keeping the newest value
2024-07-15 07:23:32,818 INFO     pyposeidon.meteo cfgrib:292 meteo done

2024-07-15 07:23:32,820 INFO     pyposeidon.telemac config:659 using default telemac2d json config file ...

2024-07-15 07:23:32,822 INFO     pyposeidon.telemac get_depth_from_dem:887 Dem already adjusted

2024-07-15 07:23:32,822 INFO     pyposeidon.telemac output:1039 Keeping bathymetry from hgrid.gr3 ..

2024-07-15 07:23:32,824 INFO     pyposeidon.telemac output:1041 saving geometry file.. 
2024-07-15 07:23:32,831 DEBUG    pyposeidon.telemac flip_triangles:170 reversed 0 triangles
2024-07-15 07:23:32,832 DEBUG    pyposeidon.telemac flip_triangles:171 [TEMPORARY FIX]: REMOVE THE POLE TRIANGLES
2024-07-15 07:23:32,835 INFO     pyposeidon.telemac mesh_to_slf:928 Manning file created..

2024-07-15 07:23:33,040 INFO     pyposeidon.mesh to_file:376 writing mesh to file ./data/iceland/20181001/hgrid.gr3
2024-07-15 07:23:34,071 INFO     pyposeidon.telemac output:1048 saving meteo file.. 
2024-07-15 07:23:43,555 INFO     pyposeidon.telemac output:1071 saving boundary file.. 
Islands
2024-07-15 07:23:44,499 INFO     pyposeidon.telemac output:1076 saving CAS file.. 
2024-07-15 07:23:44,515 INFO     pyposeidon.telemac output:1080 output done

2024-07-15 07:23:44,516 INFO     pyposeidon.telemac set_obs:1384 get stations from data/iceland/stations.csv

2024-07-15 07:23:44,522 INFO     pyposeidon.telemac set_obs:1407 set in-situ measurements locations 

2024-07-15 07:23:44,547 INFO     pyposeidon.telemac set_obs:1449 write out stations.csv file 

2024-07-15 07:23:44,549 INFO     pyposeidon.telemac set_obs:1452 write out stations.in file 

2024-07-15 07:23:44,554 INFO     pyposeidon.telemac run:1088 executing model

  ~> Checking keyword/rubrique coherence

run days 3&4 from hotstart¶

In [ ]:
# restart model
prev_ = pd.Timestamp('2018-10-01')
next_ = pd.Timestamp('2018-10-03')
end_ = pd.Timestamp('2018-10-05')
ppath = os.path.join('data/iceland', prev_.strftime("%Y%m%d"))
npath = os.path.join('data/iceland', next_.strftime("%Y%m%d"))
m = pyposeidon.model.read(os.path.join(ppath, "telemac2d_model.json"))
meteo = pmeteo.Meteo(glob.glob("data/uvp_*.grib"),meteo_merge= "last", meteo_combine_by= "nested", meteo_xr_kwargs= {"concat_dim": "step"},)
rs = cast.set(
    solver_name="telemac",
    model=m,
    ppath=ppath,  # old path
    cpath=npath,  # new path
    meteo=meteo.Dataset.sel(time=slice(next_, end_)).compute(),
    sdate=next_,  # new start date
    end_date=end_,  # new end date
    start=next_,  # start
    copy=True,
)
b = rs.run(execute=False)
2024-07-15 07:24:50,247 INFO     pyposeidon.meteo cfgrib:147 extracting meteo
2024-07-15 07:24:54,405 INFO     pyposeidon.meteo cfgrib:170 combining meteo by keeping the newest value
2024-07-15 07:24:54,415 INFO     pyposeidon.meteo cfgrib:292 meteo done

2024-07-15 07:24:54,562 DEBUG    pyposeidon.utils.cast run:560 Copy model files
2024-07-15 07:24:54,564 DEBUG    pyposeidon.utils.cast copy_files:51 copied src -> dst: /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181001/geo.slf -> /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181003/geo.slf
2024-07-15 07:24:54,565 DEBUG    pyposeidon.utils.cast copy_files:51 copied src -> dst: /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181001/geo.cli -> /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181003/geo.cli
2024-07-15 07:24:54,566 DEBUG    pyposeidon.utils.cast copy_files:51 copied src -> dst: /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181001/station.in -> /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181003/station.in
2024-07-15 07:24:54,566 DEBUG    pyposeidon.utils.cast run:566 .. done
2024-07-15 07:24:54,567 DEBUG    pyposeidon.utils.cast run:569 copy restart file
2024-07-15 07:24:54,567 INFO     pyposeidon.utils.cast copy_or_symlink:68 Copying: /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181001/restart_2D.slf -> /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181003/prev_2D.slf
2024-07-15 07:24:54,573 INFO     pyposeidon.utils.cast run:577 process meteo

2024-07-15 07:24:54,574 INFO     pyposeidon.telemac to_force:770 saving meteo file.. 
INFO:xarray_selafin.Serafin:Writing the output file: "/home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181003/input_wind.slf"
2024-07-15 07:24:56,038 INFO     pyposeidon.telemac config:655 reading parameter file /home/tomsail/work/python/pyPoseidon/Tutorial/data/iceland/20181001/telemac2d_model.json

2024-07-15 07:24:56,039 INFO     pyposeidon.telemac config:742 output telemac2d CAS file ...

2024-07-15 07:24:56,050 INFO     pyposeidon.telemac set_obs:1384 get stations from data/iceland/stations.csv

2024-07-15 07:24:56,055 INFO     pyposeidon.telemac set_obs:1407 set in-situ measurements locations 

2024-07-15 07:24:56,055 INFO     pyposeidon.mesh read_file:239 read mesh file ./data/iceland/hgrid.gr3
/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/pyposeidon/mesh.py:247: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  ni, nj = df.iloc[0].str.split()[0]
2024-07-15 07:24:56,406 INFO     pyposeidon.telemac set_obs:1449 write out stations.csv file 

2024-07-15 07:24:56,417 INFO     pyposeidon.telemac set_obs:1452 write out stations.in file 

2024-07-15 07:24:56,417 INFO     pyposeidon.telemac set_obs:1452 write out stations.in file 

2024-07-15 07:24:56,419 INFO     pyposeidon.utils.cast run:601 done for date : 20181003.00
In [ ]:
b.run()
2024-07-15 07:24:56,427 INFO     pyposeidon.telemac run:1088 executing model

run 4 days model - check¶

In [ ]:
#define in a dictionary the properties of the model..
model_parameters = {
    "solver_name": "telemac",
    "tag": "telemac2d",
    "rpath": "./data/iceland/20181001-04",
    "mesh_file": "./data/iceland/hgrid.gr3",
    "update": ["all"], #set which component should be updated  (meteo,dem,model)
    "meteo_source": glob.glob("data/uvp_*.grib"),
    "meteo_merge": "last",  # combine meteo
    "meteo_combine_by": "nested",
    "meteo_xr_kwargs": {"concat_dim": "step"},
    "start_date": "2018-10-01T00:00:00",
    "time_frame": "4d",
    "global": False,
    "obs": "data/iceland/stations.csv",
    "monitor": True,
    "parameters": {
        "dt": 100
    }
}
model_parameters
Out[ ]:
{'solver_name': 'telemac',
 'tag': 'telemac2d',
 'rpath': './data/iceland/20181001-04',
 'mesh_file': './data/iceland/hgrid.gr3',
 'update': ['all'],
 'meteo_source': ['data/uvp_2018100200.grib',
  'data/uvp_2018100112.grib',
  'data/uvp_2018100100.grib',
  'data/uvp_2018100212.grib'],
 'meteo_merge': 'last',
 'meteo_combine_by': 'nested',
 'meteo_xr_kwargs': {'concat_dim': 'step'},
 'start_date': '2018-10-01T00:00:00',
 'time_frame': '4d',
 'global': False,
 'obs': 'data/iceland/stations.csv',
 'monitor': True,
 'parameters': {'dt': 100}}
In [ ]:
c = pmodel.set(**model_parameters)
c.create()
# IMPORTANT! Here, for a simple surge application, 
# we will need close all boundaries, otherwise the 
# model will run out of water
c.mesh.Dataset.type[:] = 'closed' # it will create a cli file with all boundaries closed (this can be done only once)
# we also need to drop some meteo variables, it is necesarry for zarr export
c.meteo.Dataset = c.meteo.Dataset.compute()
c.output()
c.set_obs()
c.save() # saves the json model file
c.run() # runs the model
2024-07-15 07:25:58,336 INFO     pyposeidon.telemac create:987 no dem available

2024-07-15 07:25:58,337 INFO     pyposeidon.mesh read_file:239 read mesh file ./data/iceland/hgrid.gr3
/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/pyposeidon/mesh.py:247: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  ni, nj = df.iloc[0].str.split()[0]
2024-07-15 07:25:58,688 INFO     pyposeidon.telemac create:1009 found bathy in mesh file

2024-07-15 07:25:58,689 INFO     pyposeidon.meteo cfgrib:147 extracting meteo
2024-07-15 07:26:03,008 INFO     pyposeidon.meteo cfgrib:170 combining meteo by keeping the newest value
2024-07-15 07:26:03,019 INFO     pyposeidon.meteo cfgrib:292 meteo done

2024-07-15 07:26:03,020 INFO     pyposeidon.telemac config:659 using default telemac2d json config file ...

2024-07-15 07:26:03,333 INFO     pyposeidon.telemac get_depth_from_dem:887 Dem already adjusted

2024-07-15 07:26:03,333 INFO     pyposeidon.telemac output:1039 Keeping bathymetry from hgrid.gr3 ..

2024-07-15 07:26:03,335 INFO     pyposeidon.telemac output:1041 saving geometry file.. 
2024-07-15 07:26:03,339 DEBUG    pyposeidon.telemac flip_triangles:170 reversed 0 triangles
2024-07-15 07:26:03,340 DEBUG    pyposeidon.telemac flip_triangles:171 [TEMPORARY FIX]: REMOVE THE POLE TRIANGLES
2024-07-15 07:26:03,342 INFO     pyposeidon.telemac mesh_to_slf:928 Manning file created..

INFO:xarray_selafin.Serafin:Writing the output file: "./data/iceland/20181001-04/geo.slf"
2024-07-15 07:26:03,502 INFO     pyposeidon.mesh to_file:376 writing mesh to file ./data/iceland/20181001-04/hgrid.gr3
2024-07-15 07:26:04,362 INFO     pyposeidon.telemac output:1048 saving meteo file.. 
INFO:xarray_selafin.Serafin:Writing the output file: "./data/iceland/20181001-04/input_wind.slf"
2024-07-15 07:26:06,961 INFO     pyposeidon.telemac output:1071 saving boundary file.. 
Islands
2024-07-15 07:26:07,951 INFO     pyposeidon.telemac output:1076 saving CAS file.. 
2024-07-15 07:26:07,959 INFO     pyposeidon.telemac output:1080 output done

2024-07-15 07:26:07,960 INFO     pyposeidon.telemac set_obs:1384 get stations from data/iceland/stations.csv

2024-07-15 07:26:07,964 INFO     pyposeidon.telemac set_obs:1407 set in-situ measurements locations 

2024-07-15 07:26:08,000 INFO     pyposeidon.telemac set_obs:1449 write out stations.csv file 

2024-07-15 07:26:08,003 INFO     pyposeidon.telemac set_obs:1452 write out stations.in file 

2024-07-15 07:26:08,008 INFO     pyposeidon.telemac run:1088 executing model

compare results¶

In [ ]:
res_2days = xr.open_dataset("data/iceland/20181001-04/results_2D.slf")
res_day1 = xr.open_dataset("data/iceland/20181001/results_2D.slf")
res_day2 = xr.open_dataset("data/iceland/20181003/results_2D.slf")
In [ ]:
node = 15000
p1 = res_day1.S.isel(node = node).hvplot(label = "Day 1&2")
p2 = res_day2.S.isel(node = node).hvplot(label = "Day 3&4")
p3 = res_2days.S.isel(node = node).hvplot(label = "4 Days", line_dash='dashed')
p1 * p2 * p3
Out[ ]:

compare with observations¶

In [ ]:
res_2days = xr.open_dataset("data/iceland/20181001-04/results_1D.slf")
res_day1 = xr.open_dataset("data/iceland/20181001/results_1D.slf")
res_day2 = xr.open_dataset("data/iceland/20181003/results_1D.slf")
res_day2
Out[ ]:
<xarray.Dataset> Size: 35kB
Dimensions:  (time: 1729, node: 1)
Coordinates:
    x        (node) float32 4B ...
    y        (node) float32 4B ...
  * time     (time) datetime64[ns] 14kB 2018-10-03 ... 2018-10-05
Dimensions without coordinates: node
Data variables:
    U        (time, node) float32 7kB ...
    V        (time, node) float32 7kB ...
    S        (time, node) float32 7kB ...
Attributes:
    title:       HISTORY FILE
    language:    en
    float_size:  4
    endian:      >
    params:      (1, 0, 0, 0, 0, 0, 0, 1, 0, 1)
    ipobo:       [1]
    ikle2:       [[1]]
    variables:   {'U': ('VELOCITY U', 'M/S'), 'V': ('VELOCITY V', 'M/S'), 'S'...
    date_start:  (2018, 10, 1, 0, 0, 0)
xarray.Dataset
    • time: 1729
    • node: 1
    • x
      (node)
      float32
      ...
      [1 values with dtype=float32]
    • y
      (node)
      float32
      ...
      [1 values with dtype=float32]
    • time
      (time)
      datetime64[ns]
      2018-10-03 ... 2018-10-05
      array(['2018-10-03T00:00:00.000000000', '2018-10-03T00:01:40.000000000',
             '2018-10-03T00:03:20.000000000', ..., '2018-10-04T23:56:40.000000000',
             '2018-10-04T23:58:20.000000000', '2018-10-05T00:00:00.000000000'],
            dtype='datetime64[ns]')
    • U
      (time, node)
      float32
      ...
      [1729 values with dtype=float32]
    • V
      (time, node)
      float32
      ...
      [1729 values with dtype=float32]
    • S
      (time, node)
      float32
      ...
      [1729 values with dtype=float32]
    • time
      PandasIndex
      PandasIndex(DatetimeIndex(['2018-10-03 00:00:00', '2018-10-03 00:01:40',
                     '2018-10-03 00:03:20', '2018-10-03 00:05:00',
                     '2018-10-03 00:06:40', '2018-10-03 00:08:20',
                     '2018-10-03 00:10:00', '2018-10-03 00:11:40',
                     '2018-10-03 00:13:20', '2018-10-03 00:15:00',
                     ...
                     '2018-10-04 23:45:00', '2018-10-04 23:46:40',
                     '2018-10-04 23:48:20', '2018-10-04 23:50:00',
                     '2018-10-04 23:51:40', '2018-10-04 23:53:20',
                     '2018-10-04 23:55:00', '2018-10-04 23:56:40',
                     '2018-10-04 23:58:20', '2018-10-05 00:00:00'],
                    dtype='datetime64[ns]', name='time', length=1729, freq=None))
  • title :
    HISTORY FILE
    language :
    en
    float_size :
    4
    endian :
    >
    params :
    (1, 0, 0, 0, 0, 0, 0, 1, 0, 1)
    ipobo :
    [1]
    ikle2 :
    [[1]]
    variables :
    {'U': ('VELOCITY U', 'M/S'), 'V': ('VELOCITY V', 'M/S'), 'S': ('FREE SURFACE', 'M')}
    date_start :
    (2018, 10, 1, 0, 0, 0)
In [ ]:
stations = pd.read_csv("data/iceland/stations.csv")
stations
Out[ ]:
Unnamed: 0 ioc_code gloss_id country location connection contacts dcp_id last_observation_level last_observation_time ... observations_arrived_per_month observations_expected_per_month observations_ratio_per_month observations_ratio_per_day sample_interval average_delay_per_day transmit_interval geometry longitude latitude
0 1241 reyk 229 Iceland Reykjavik ftp Icelandic Coast Guard, Hydrographic Department... NaN 1.46 2020-03-20 12:28 ... NaN NaN 0 0 1' NaN 1h POINT (-21.93333 64.15) -21.93333 64.15

1 rows × 26 columns

In [ ]:
from searvey import ioc
data = ioc.get_ioc_station_data('reyk', endtime="2018-10-05", period=30)
data.index = data['time']
data = data.drop(columns=['time'])
data
INFO:searvey.ioc:reyk: Retrieving data from: http://www.ioc-sealevelmonitoring.org/bgraph.php?code=reyk&output=tab&period=30&endtime=2018-10-05T00:00:00
Out[ ]:
prs ioc_code
time
2018-09-05 00:00:00 2.727 reyk
2018-09-05 00:01:00 2.738 reyk
2018-09-05 00:02:00 2.744 reyk
2018-09-05 00:03:00 2.749 reyk
2018-09-05 00:04:00 2.752 reyk
... ... ...
2018-10-04 23:56:00 2.166 reyk
2018-10-04 23:57:00 2.178 reyk
2018-10-04 23:58:00 2.196 reyk
2018-10-04 23:59:00 2.214 reyk
2018-10-05 00:00:00 2.229 reyk

43120 rows × 2 columns

In [ ]:
# detide 
from analysea.tide import detide
surge = detide(data["prs"],lat = 64.15)
surge
/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/utide/harmonics.py:16: RuntimeWarning: invalid value encountered in cast
  nshallow = np.ma.masked_invalid(const.nshallow).astype(int)
/home/tomsail/miniconda3/envs/pos_test/lib/python3.11/site-packages/utide/harmonics.py:17: RuntimeWarning: invalid value encountered in cast
  ishallow = np.ma.masked_invalid(const.ishallow).astype(int) - 1
solve: matrix prep ... solution ... done.
Out[ ]:
time
2018-09-05 00:00:00   -0.011617
2018-09-05 00:01:00   -0.007003
2018-09-05 00:02:00   -0.007361
2018-09-05 00:03:00   -0.008691
2018-09-05 00:04:00   -0.011993
                         ...   
2018-10-04 23:56:00   -0.050843
2018-10-04 23:57:00   -0.047389
2018-10-04 23:58:00   -0.037939
2018-10-04 23:59:00   -0.028494
2018-10-05 00:00:00   -0.022052
Name: prs, Length: 43120, dtype: float64
In [ ]:
p1 = res_day1.S.isel(node = 0).hvplot(label = "Day 1")
p2 = res_day2.S.isel(node = 0).hvplot(label = "Day 2")
p3 = res_2days.S.isel(node = 0).hvplot(label = "2 Days", line_dash='dashed')
obs_ = surge.loc["2018-10-01":"2018-10-05"].hvplot(label = "Observations", color = 'k', line_dash='dotted')
p1 * p2  * p3 * obs_
Out[ ]: