Repository: DHI/mikeio
Pull request #243 (2021-09-20 07:26:57)

Dfsu documentation
Restructure documentation and add more material on Dfsu and Mesh


Patch:
diff --git a/docs/api.rst b/docs/api.rst
deleted file mode 100644
index a7bbf7a1..00000000
--- a/docs/api.rst
+++ /dev/null
@@ -1,54 +0,0 @@
-.. _api:
-
-API Documentation
-=================
-
-Dfs0
-----
-.. autoclass:: mikeio.Dfs0
-	:members:
-	:inherited-members:
-
-Dfs1
-----
-.. autoclass:: mikeio.Dfs1
-	:members:
-	:inherited-members:
-
-Dfs2
-----
-.. autoclass:: mikeio.Dfs2
-	:members:
-	:inherited-members:
-
-Dfsu
-----
-.. autoclass:: mikeio.Dfsu
-	:members:
-	:inherited-members:
-
-Mesh
-----
-.. autoclass:: mikeio.Mesh
-	:members:
-	:inherited-members:
-
-Dataset
--------
-.. autoclass:: mikeio.Dataset
-	:members:
-	:inherited-members:
-
-EUM
----
-.. automodule:: mikeio.eum
-	:members:
-
-
-Generic
--------
-.. automodule:: mikeio
-	:members:
-
-.. automodule:: mikeio.generic
-	:members:
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index 26167f45..0ac84d13 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -17,7 +17,7 @@
 
 # -- Project information -----------------------------------------------------
 
-project = "mikeio"
+project = "MIKE IO"
 copyright = "2021, Henrik Andersson, Marc Ridler, Jesper Mariegaard, Rasmus Halvgaard"
 author = "Henrik Andersson, Marc Ridler, Jesper Mariegaard, Rasmus Halvgaard"
 release = ""
@@ -49,3 +49,5 @@ html_theme = "sphinx_book_theme"
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
 # html_static_path = ["_static"]
+
+html_logo = "../images/logo/SVG/MIKE-IO-Logo-Pos-RGB.svg"
diff --git a/docs/understanding_dataset.rst b/docs/dataset.rst
similarity index 63%
rename from docs/understanding_dataset.rst
rename to docs/dataset.rst
index ff41d0ec..8e9db8c6 100644
--- a/docs/understanding_dataset.rst
+++ b/docs/dataset.rst
@@ -1,12 +1,12 @@
-.. _understanding_dataset:
+.. _dataset:
 
-Understanding Dataset
-*********************
-The `Dataset <api.html#mikeio.Dataset>`_ is the common MIKE IO data structure 
+Dataset
+*******
+The `Dataset <#mikeio.Dataset>`_ is the common MIKE IO data structure 
 for data from dfs files. 
 All `read()` methods in MIKE IO return a Dataset with three main properties:
 
-* **items** - a list of `ItemInfo <api.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
+* **items** - a list of `ItemInfo <eum.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
 * **time** - a pandas.DateTimeIndex with the time instances of the data
 * **data** - a list of NumPy arrays---one for each item
 
@@ -52,7 +52,7 @@ Note that this behavior is similar to pandas and xarray.
 
 Selecting timesteps or elements
 -------------------------------
-The `isel() <api.html#mikeio.Dataset.isel>`_ method can be used for selecting specific timesteps or elements across a Dataset. 
+The `isel() <#mikeio.Dataset.isel>`_ method can be used for selecting specific timesteps or elements across a Dataset. 
 
 * ds.isel([0, 1], axis=0) - selects timestep 0 and 1
 * ds.isel([3,78], axis=1) - selects element 3 and 78
@@ -96,21 +96,21 @@ Methods
 Dataset has several useful methods for working with data, 
 including different ways of *selecting* data:
 
-* `head() <api.html#mikeio.Dataset.head>`_ - Return the first n timesteps
-* `tail() <api.html#mikeio.Dataset.tail>`_ - Return the last n timesteps
-* `thin() <api.html#mikeio.Dataset.thin>`_ - Return every n:th timesteps
-* `isel() <api.html#mikeio.Dataset.isel>`_ - Select subset along an axis
+* `head() <#mikeio.Dataset.head>`_ - Return the first n timesteps
+* `tail() <#mikeio.Dataset.tail>`_ - Return the last n timesteps
+* `thin() <#mikeio.Dataset.thin>`_ - Return every n:th timesteps
+* `isel() <#mikeio.Dataset.isel>`_ - Select subset along an axis
 
 *Aggregations* along an axis:
 
-* `mean() <api.html#mikeio.Dataset.mean>`_ - Mean value along an axis
-* `nanmean() <api.html#mikeio.Dataset.nanmean>`_ - Mean value along an axis (NaN removed)
-* `max() <api.html#mikeio.Dataset.max>`_ - Max value along an axis
-* `nanmax() <api.html#mikeio.Dataset.nanmax>`_ - Max value along an axis (NaN removed)
-* `min() <api.html#mikeio.Dataset.min>`_ - Min value along an axis
-* `nanmin() <api.html#mikeio.Dataset.nanmin>`_ - Min value along an axis (NaN removed)
-* `average() <api.html#mikeio.Dataset.average>`_ - Compute the weighted average along the specified axis.
-* `aggregate() <api.html#mikeio.Dataset.aggregate>`_ - Aggregate along an axis
+* `mean() <#mikeio.Dataset.mean>`_ - Mean value along an axis
+* `nanmean() <#mikeio.Dataset.nanmean>`_ - Mean value along an axis (NaN removed)
+* `max() <#mikeio.Dataset.max>`_ - Max value along an axis
+* `nanmax() <#mikeio.Dataset.nanmax>`_ - Max value along an axis (NaN removed)
+* `min() <#mikeio.Dataset.min>`_ - Min value along an axis
+* `nanmin() <#mikeio.Dataset.nanmin>`_ - Min value along an axis (NaN removed)
+* `average() <#mikeio.Dataset.average>`_ - Compute the weighted average along the specified axis.
+* `aggregate() <#mikeio.Dataset.aggregate>`_ - Aggregate along an axis
 
 *Mathematical operations* +, - and * with numerical values:
 
@@ -125,11 +125,19 @@ and + and - between two Datasets (if number of items and shapes conform):
 
 Other methods that also return a Dataset:
 
-* `interp_time() <api.html#mikeio.Dataset.interp_time>`_ - Temporal interpolation (see `Time interpolation notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Time%20interpolation.ipynb>`_)
-* `dropna() <api.html#mikeio.Dataset.dropna>`_ - Remove time steps where all items are NaN
-* `squeeze() <api.html#mikeio.Dataset.squeeze>`_ - Remove axes of length 1
+* `interp_time() <#mikeio.Dataset.interp_time>`_ - Temporal interpolation (see `Time interpolation notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Time%20interpolation.ipynb>`_)
+* `dropna() <#mikeio.Dataset.dropna>`_ - Remove time steps where all items are NaN
+* `squeeze() <#mikeio.Dataset.squeeze>`_ - Remove axes of length 1
 
 *Conversion* methods:
 
-* `to_dataframe() <api.html#mikeio.Dataset.to_dataframe>`_ - Convert Dataset to a Pandas DataFrame
-* `to_dfs0() <api.html#mikeio.Dataset.to_dfs0>`_ - Write Dataset to a Dfs0 file
+* `to_dataframe() <#mikeio.Dataset.to_dataframe>`_ - Convert Dataset to a Pandas DataFrame
+* `to_dfs0() <#mikeio.Dataset.to_dfs0>`_ - Write Dataset to a Dfs0 file
+
+
+
+Dataset API
+-----------
+.. autoclass:: mikeio.Dataset
+	:members:
+	:inherited-members:
\ No newline at end of file
diff --git a/docs/dfs0.rst b/docs/dfs0.rst
new file mode 100644
index 00000000..56e54b0a
--- /dev/null
+++ b/docs/dfs0.rst
@@ -0,0 +1,48 @@
+.. _dfs0:
+
+Dfs0
+****
+
+A dfs0 file is also called a time series file. The MIKE IO `Dfs0 class <dfs0.html#mikeio.Dfs0>`_ provide functionality for working with dfs0 files.  
+
+Working with data from dfs0 files are conveniently done in one of two ways:
+
+* mikeio.Dataset - keeps EUM information (convenient if you save data to new dfs0 file)
+* pandas.DataFrame - utilize all the powerful methods of pandas
+
+
+Read Dfs0 to Dataset
+--------------------
+
+.. code-block:: python
+
+    >>> from mikeio import Dfs0
+    >>> dfs = Dfs0("testdata/da_diagnostic.dfs0")
+    >>> ds = dfs.read()   
+   
+
+From Dfs0 to pandas DataFrame
+-----------------------------
+
+.. code-block:: python
+
+    >>> dfs = Dfs0("testdata/da_diagnostic.dfs0")
+    >>> df = dfs.to_dataframe()
+
+From pandas DataFrame to Dfs0
+-----------------------------
+
+.. code-block:: python
+
+    >>> df = pd.read_csv("co2-mm-mlo.csv", parse_dates=True, index_col='Date', na_values=-99.99)
+    >>> df.to_dfs0("mauna_loa_co2.dfs0")
+
+
+
+
+Dfs0 API
+--------
+.. autoclass:: mikeio.Dfs0
+	:members:
+	:inherited-members:
+
diff --git a/docs/dfs123.rst b/docs/dfs123.rst
new file mode 100644
index 00000000..cd5ae03e
--- /dev/null
+++ b/docs/dfs123.rst
@@ -0,0 +1,62 @@
+.. _dfs123:
+
+Dfs1, Dfs2 and Dfs3
+*******************
+
+MIKE IO has a similar API for the three gridded dfs file types: Dfs1, Dfs2 and Dfs2. 
+
+All Dfs classes (and the Dataset) class are representations of timeseries and 
+share these properties: 
+
+* items - a list of `ItemInfo <eum.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
+* n_items - Number of items
+* n_timesteps - Number of timesteps
+* start_time - First time instance (as datetime)
+* end_time - Last time instance (as datetime)
+* deletevalue - File delete value (NaN value)
+
+All Dfs classes have these methods:
+
+* read(items, time_steps, ...)
+* write(filename, data, ...)
+
+
+Dfs2
+----
+
+A dfs2 file is also called a grid series file. Values in a dfs2 file are ‘element based’, i.e. values are defined in the centre of each grid cell. 
+The MIKE IO `Dfs2 class <#mikeio.Dfs2>`_ provide functionality for working with dfs2 files.  
+
+.. code-block:: python
+
+    >>> from mikeio import Dfs2
+    >>> dfs = Dfs2("testdata/gebco_sound.dfs2")
+    <mikeio.Dfs2>
+    dx: 0.00417
+    dy: 0.00417
+    Items:
+    0:  Elevation <Total Water Depth> (meter)
+    Time: time-invariant file (1 step)   
+
+
+Dfs2 Example notebooks
+----------------------
+* `Dfs2-Bathymetry <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Dfs2%20-%20Bathymetry.ipynb>`_ - GEBCO NetCDF/xarray to dfs2 
+* `Dfs2-Boundary <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Dfs2%20-%20Boundary.ipynb>`_ - Vertical transect dfs2, interpolation in time 
+* `Dfs2-Export-to-netCDF <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Dfs2%20-%20Export%20to%20netcdf.ipynb>`_ Export dfs2 to NetCDF
+* `Dfs2-GFS <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Dfs2%20-%20Global%20Forecasting%20System.ipynb>`_ - GFS NetCDF/xarray to dfs2
+* `Dfs2-SST <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Dfs2%20-%20Sea%20surface%20temperature.ipynb>`_ - DMI NetCDF/xarray to dfs2 
+* `Dfs2 | getting-started-with-mikeio <https://dhi.github.io/getting-started-with-mikeio/dfs2.html>`_
+
+
+Dfs1 API
+--------
+.. autoclass:: mikeio.Dfs1
+	:members:
+	:inherited-members:
+
+Dfs2 API
+--------
+.. autoclass:: mikeio.Dfs2
+	:members:
+	:inherited-members:
\ No newline at end of file
diff --git a/docs/dfsu.rst b/docs/dfsu.rst
new file mode 100644
index 00000000..1f9cdd80
--- /dev/null
+++ b/docs/dfsu.rst
@@ -0,0 +1,211 @@
+.. _dfsu:
+
+Dfsu and Mesh
+*************
+
+Dfsu and mesh files are both flexible mesh file formats used by MIKE 21/3 engines. 
+The .mesh file is an ASCII format for storing the flexible mesh geometry. 
+The .dfsu file is a binary dfs file with data on this mesh. The mesh geometry is 
+available in a .dfsu file as static items.  
+
+For a detailed description of the .mesh and .dfsu file specification see the `flexible file format documentation <https://manuals.mikepoweredbydhi.help/2021/General/FM_FileSpecification.pdf>`_.
+
+
+The flexible mesh
+---------------------
+
+The mesh geometry in a .mesh or a .dfsu file consists of a number of nodes and a number of elements.
+
+Each node has:
+
+* Node id
+* X,Y,Z coordinate
+* Code for the boundary
+
+Each element has:
+
+* Element id
+* Element type; triangular, quadrilateral, prism etc.
+* Element table; specifies for each element the nodes that defines the element. 
+
+.. warning::
+    In MIKE Zero, node ids and element ids are 1-based. 
+    In MIKE IO, all ids are **0-based** following standard Python indexing. 
+    That means, as an example, that when finding the element closest to a 
+    point its id will be 1 lower in MIKE IO compared to examining the file in MIKE Zero.
+
+
+
+Common Dfsu and Mesh properties
+-------------------------------
+
+MIKE IO has a `Dfsu class <#mikeio.Dfsu>`_ for handling .dfsu files 
+and a `Mesh class <#mikeio.Mesh>`_ for handling .mesh files both they inherit from the 
+same base class and have the same core functionality. 
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Mesh.n_nodes
+    mikeio.Mesh.node_coordinates
+    mikeio.Mesh.codes
+    mikeio.Mesh.boundary_polylines
+    mikeio.Mesh.n_elements
+    mikeio.Mesh.element_coordinates
+    mikeio.Mesh.element_table
+    mikeio.Mesh.max_nodes_per_element
+    mikeio.Mesh.is_tri_only
+    mikeio.Mesh.projection_string
+    mikeio.Mesh.is_geo
+    mikeio.Mesh.is_local_coordinates
+    mikeio.Mesh.type_name    
+
+
+Common Dfsu and Mesh methods
+----------------------------
+
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Mesh.contains
+    mikeio.Mesh.find_nearest_elements
+    mikeio.Mesh.plot
+    mikeio.Mesh.to_shapely
+    mikeio.Mesh.get_overset_grid
+    mikeio.Mesh.get_2d_interpolant
+    mikeio.Mesh.interp2d
+    mikeio.Mesh.get_element_area
+    mikeio.Mesh.elements_to_geometry
+
+
+Mesh functionality
+------------------
+
+The Mesh class is initialized with a mesh or a dfsu file. 
+
+
+.. code-block:: python
+
+    >>> msh = Mesh("../tests/testdata/odense_rough.mesh")
+    >>> msh
+    Number of elements: 654
+    Number of nodes: 399
+    Projection: UTM-33
+
+
+Apart from the common flexible file functionality, 
+the Mesh object has the following methods and properties:
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Mesh.write
+    mikeio.Mesh.plot_boundary_nodes
+    mikeio.zn
+
+See the `Mesh API specification <#mikeio.Mesh>`_ below for a detailed description. 
+See the `Mesh Example notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Mesh.ipynb>`_ for more Mesh operations (including shapely examples).
+
+
+Dfsu functionality
+------------------
+
+The Dfsu class is initialized with a mesh or a dfsu file. 
+
+Apart from the common flexible file functionality, the Dfsu has the following *properties*:
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Dfsu.deletevalue
+    mikeio.Dfsu.n_items
+    mikeio.Dfsu.items
+    mikeio.Dfsu.n_timesteps
+    mikeio.Dfsu.start_time
+    mikeio.Dfsu.end_time
+    mikeio.Dfsu.timestep
+    mikeio.Dfsu.is_2d
+
+
+Apart from the common flexible file functionality, the Dfsu has the following *methods*:
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Dfsu.read
+    mikeio.Dfsu.write
+    mikeio.Dfsu.write_header
+    mikeio.Dfsu.close
+    mikeio.Dfsu.extract_track
+
+See the `Dfsu API specification <#mikeio.Dfsu>`_ below for a detailed description. 
+See the `Dfsu Read Example notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Dfsu%20-%20Read.ipynb>`_ for basic dfsu functionality.
+
+
+
+Dfsu types
+----------
+
+The following dfsu file types are supported by MIKE IO.
+
+* 2D horizontal. 
+* 3D layered. 
+* 2D vertical profile - a vertical slice through a 3D layered file. 
+* 1D vertical column - a vertical dfs1 file and is produced by taking out one column of a 3D layered file.
+* 3D/4D SW, two horizontal dimensions and 1-2 spectral dimensions. Output from MIKE 21 SW.
+
+The layered files (3d, 2d/1d vertical) can have both sigma- and z-layers or only sigma-layers. 
+
+In most cases values are stored in cell centers and vertical (z) information in nodes, 
+but the following values types exists: 
+
+* Standard value type, storing values on elements and/or nodes. This is the default type.
+* Face value type, storing values on element faces. This is used e.g. for HD decoupling files, to store the discharge between elements.
+* Spectral value type, for each node or element, storing vales for a number of frequencies and/or directions. This is the file type for spectral output from the MIKE 21 SW. 
+
+
+
+
+Layered dfsu files
+------------------ 
+
+There are three type of layered dfsu files: 3D dfsu, 2d vertical slices and 1d vertical profiles.
+
+Apart from the basic dfsu functionality, layered dfsu have the below additional *properties*: 
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Dfsu.n_layers
+    mikeio.Dfsu.n_sigma_layers
+    mikeio.Dfsu.n_z_layers
+    mikeio.Dfsu.layer_ids
+    mikeio.Dfsu.top_elements
+    mikeio.Dfsu.bottom_elements
+    mikeio.Dfsu.n_layers_per_column
+    mikeio.Dfsu.geometry2d
+    mikeio.Dfsu.e2_e3_table
+    mikeio.Dfsu.elem2d_ids
+
+Apart from the basic dfsu functionality, layered dfsu have the below additional *methods*: 
+
+.. autosummary::
+    :nosignatures:
+
+    mikeio.Dfsu.get_layer_elements
+    mikeio.Dfsu.find_nearest_profile_elements
+    mikeio.Dfsu.plot_vertical_profile
+
+
+Dfsu API
+--------
+.. autoclass:: mikeio.Dfsu
+	:members:
+	:inherited-members:
+
+Mesh API
+--------
+.. autoclass:: mikeio.Mesh
+	:members:
+	:inherited-members:
\ No newline at end of file
diff --git a/docs/eum.rst b/docs/eum.rst
new file mode 100644
index 00000000..3986d98d
--- /dev/null
+++ b/docs/eum.rst
@@ -0,0 +1,30 @@
+.. _eum:
+
+EUM and items
+*************
+
+The dfs items in MIKE IO are represented by the `ItemInfo class <eum.html#mikeio.eum.ItemInfo>`_. 
+An ItemInfo consists of:
+
+* name - a user-defined string 
+* type - an `EUMType <eum.html#mikeio.eum.EUMType>`_ 
+* unit - an `EUMUnit <eum.html#mikeio.eum.EUMUnit>`_
+
+.. code-block:: python
+
+    >>> from mikeio.eum import ItemInfo, EUMType
+    >>> item = ItemInfo("Viken", EUMType.Water_Level)
+    >>> item
+    Viken <Water Level> (meter)
+    >>> ItemInfo(EUMType.Wind_speed)
+    Wind speed <Wind speed> (meter per sec)
+
+See the `Units notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Units.ipynb>`_ for more examples.
+
+
+
+
+EUM API
+-------
+.. automodule:: mikeio.eum
+	:members:
diff --git a/docs/generic.rst b/docs/generic.rst
new file mode 100644
index 00000000..c87aa8ab
--- /dev/null
+++ b/docs/generic.rst
@@ -0,0 +1,39 @@
+.. _generic:
+
+Generic
+*******
+
+MIKE IO has `generic dfs <#module-mikeio.generic>`_ functionality that works for all dfs files: 
+
+* `read() <#mikeio.read>`_ - Read all data to a Dataset
+* `concat() <#mikeio.generic.extract>`_ - Concatenates files along the time axis
+* `extract() <#mikeio.generic.extract>`_ - Extract timesteps and/or items to a new dfs file
+* `diff() <#mikeio.generic.diff>`_ - Calculate difference between two dfs files
+* `sum() <#mikeio.generic.extract>`_ - Calculate the sum of two dfs files
+* `scale() <#mikeio.generic.extract>`_ - Apply scaling to any dfs file
+
+All methods except read() create a new dfs file.
+
+.. code-block:: python
+
+   from mikeio import generic
+   generic.concat(["fileA.dfs2", "fileB.dfs2"], "new_file.dfs2")
+
+.. code-block:: python
+
+   import mikeio 
+   ds = mikeio.read("new_file.dfs2")
+
+See the `Generic notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/main/notebooks/Generic.ipynb>`_ for more examples.
+
+
+
+
+
+Generic API
+-----------
+.. automodule:: mikeio
+	:members:
+
+.. automodule:: mikeio.generic
+	:members:
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
index 4041fb34..d69ac35a 100644
--- a/docs/getting_started.rst
+++ b/docs/getting_started.rst
@@ -14,10 +14,10 @@ Resources
 
 Dataset
 *******
-The `Dataset <api.html#mikeio.Dataset>`_ is the common MIKE IO data structure for data read from dfs files. 
+The `Dataset <dataset.html#mikeio.Dataset>`_ is the common MIKE IO data structure for data read from dfs files. 
 All `read()` methods in MIKE IO returns a Dataset with the three main properties:
 
-* items - a list of `ItemInfo <api.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
+* items - a list of `ItemInfo <eum.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
 * time - a pandas.DateTimeIndex with the time instances of the data
 * data - a list of NumPy arrays---one for each item
 
@@ -29,7 +29,7 @@ Common dfs functionality
 All Dfs classes and the Dataset class are representations of timeseries and 
 share these properties: 
 
-* items - a list of `ItemInfo <api.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
+* items - a list of `ItemInfo <eum.html#mikeio.eum.ItemInfo>`_ with name, type and unit of each item
 * n_items - Number of items
 * n_timesteps - Number of timesteps
 * start_time - First time instance (as datetime)
@@ -44,12 +44,12 @@ All Dfs classes have these methods:
 
 Items, ItemInfo and EUM
 ***********************
-The dfs items in MIKE IO are represented by the `ItemInfo class <api.html#mikeio.eum.ItemInfo>`_. 
+The dfs items in MIKE IO are represented by the `ItemInfo class <eum.html#mikeio.eum.ItemInfo>`_. 
 An ItemInfo consists of:
 
 * name - a user-defined string 
-* type - an `EUMType <api.html#mikeio.eum.EUMType>`_ 
-* unit - an `EUMUnit <api.html#mikeio.eum.EUMUnit>`_
+* type - an `EUMType <eum.html#mikeio.eum.EUMType>`_ 
+* unit - an `EUMUnit <eum.html#mikeio.eum.EUMUnit>`_
 
 .. code-block:: python
 
@@ -65,7 +65,7 @@ See the `Units notebook <https://nbviewer.jupyter.org/github/DHI/mikeio/blob/mai
 
 Dfs0
 ****
-A dfs0 file is also called a time series file. The MIKE IO `Dfs0 class <api.html#mikeio.Dfs0>`_ provide functionality for working with dfs0 files.  
+A dfs0 file is also called a time series file. The MIKE IO `Dfs0 class <dfs0.html#mikeio.Dfs0>`_ provide functionality for working with dfs0 files.  
 
 Working with data from dfs0 files are conveniently done in one of two ways:
 
@@ -109,7 +109,7 @@ Example notebooks
 Dfs2
 ****
 A dfs2 file is also called a grid series file. Values in a dfs2 file are ‘element based’, i.e. values are defined in the centre of each grid cell. 
-The MIKE IO `Dfs2 class <api.html#mikeio.Dfs2>`_ provide functionality for working with dfs2 files.  
+The MIKE IO `Dfs2 class <dfs123.html#mikeio.Dfs2>`_ provide functionality for working with dfs2 files.  
 
 .. code-block:: python
 
@@ -134,18 +134,17 @@ Example notebooks
 
 Generic dfs
 ***********
-MIKE IO has `generic dfs <api.html#module-mikeio.generic>`_ functionality that works for all dfs files: 
+MIKE IO has `generic dfs <generic.html#module-mikeio.generic>`_ functionality that works for all dfs files: 
 
-* `read() <api.html#mikeio.read>`_ - Read all data to a Dataset
-* `concat() <api.html#mikeio.generic.extract>`_ - Concatenates files along the time axis
-* `extract() <api.html#mikeio.generic.extract>`_ - Extract timesteps and/or items to a new dfs file
-* `diff() <api.html#mikeio.generic.diff>`_ - Calculate difference between two dfs files
-* `sum() <api.html#mikeio.generic.extract>`_ - Calculate the sum of two dfs files
-* `scale() <api.html#mikeio.generic.extract>`_ - Apply scaling to any dfs file
+* `read() <generic.html#mikeio.read>`_ - Read all data to a Dataset
+* `concat() <generic.html#mikeio.generic.extract>`_ - Concatenates files along the time axis
+* `extract() <generic.html#mikeio.generic.extract>`_ - Extract timesteps and/or items to a new dfs file
+* `diff() <generic.html#mikeio.generic.diff>`_ - Calculate difference between two dfs files
+* `sum() <generic.html#mikeio.generic.extract>`_ - Calculate the sum of two dfs files
+* `scale() <generic.html#mikeio.generic.extract>`_ - Apply scaling to any dfs file
 
 All methods except read() create a new dfs file.
 
-
 .. code-block:: python
 
    from mikeio import generic
diff --git a/docs/index.rst b/docs/index.rst
index 8f70cc0e..4c952a4d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -21,7 +21,11 @@ See our sister library `MIKE IO 1D <https://github.com/DHI/mikeio1d>`_ for .res1
    :hidden:
 
    getting_started
-   understanding_dataset
    design
-   api
-   
+   dataset
+   dfs0
+   dfs123
+   dfsu   
+   eum
+   generic
+   
\ No newline at end of file
diff --git a/mikeio/dfsu.py b/mikeio/dfsu.py
index 2826799f..2d41fe70 100644
--- a/mikeio/dfsu.py
+++ b/mikeio/dfsu.py
@@ -78,7 +78,8 @@ class _UnstructuredGeometry:
 
     @property
     def type_name(self):
-        return self._type.name
+        """Type name, e.g. Mesh, Dfsu2D"""
+        return self._type.name if self._type else "Mesh"
 
     @property
     def n_nodes(self):
@@ -105,9 +106,16 @@ class _UnstructuredGeometry:
 
     @property
     def codes(self):
-        """Node codes of all nodes"""
+        """Node codes of all nodes (0=water, 1=land, 2...=open boundaries)"""
         return self._codes
 
+    @codes.setter
+    def codes(self, v):
+        if len(v) != self.n_nodes:
+            raise ValueError(f"codes must have length of nodes ({self.n_nodes})")
+        self._codes = np.array(v, dtype=np.int32)
+        self._valid_codes = None
+
     @property
     def valid_codes(self):
         """Unique list of node codes"""
@@ -117,11 +125,12 @@ class _UnstructuredGeometry:
 
     @property
     def boundary_codes(self):
-        """provides a unique list of boundary codes"""
+        """Unique list of boundary codes"""
         return [code for code in self.valid_codes if code > 0]
 
     @property
     def projection_string(self):
+        """The projection string"""
         return self._projstr
 
     @property
@@ -131,6 +140,7 @@ class _UnstructuredGeometry:
 
     @property
     def is_local_coordinates(self):
+        """Are coordinates relative (NON-UTM)?"""
         return self._projstr == "NON-UTM"
 
     @property
@@ -259,7 +269,7 @@ class _UnstructuredGeometry:
         return [self.element_table[j] for j in elements]
 
     def elements_to_geometry(self, elements, node_layers="all"):
-        """export elements to new geometry
+        """export elements to new flexible file geometry
 
         Parameters
         ----------
@@ -628,6 +638,11 @@ class _UnstructuredGeometry:
         self._tree2d = cKDTree(xy)
 
     def _find_n_nearest_2d_elements(self, x, y=None, n=1):
+        if n > self.geometry2d.n_elements:
+            raise ValueError(
+                f"Cannot find {n} nearest! Number of 2D elements: {self.geometry2d.n_elements}"
+            )
+
         if self._tree2d is None:
             self._create_tree2d()
 
@@ -2241,7 +2256,7 @@ class Dfsu(_UnstructuredFile, EquidistantTimeSeries):
         elements=None,
         title=None,
     ):
-        """Write the header of a new dfsu file
+        """Write the header of a new dfsu file (for writing huge files)
 
         Parameters
         -----------
@@ -2648,6 +2663,25 @@ class Dfsu(_UnstructuredFile, EquidistantTimeSeries):
 
 
 class Mesh(_UnstructuredFile):
+    """
+    The Mesh class is initialized with a mesh or a dfsu file.
+
+    Parameters
+    ---------
+    filename: str
+        dfsu or mesh filename
+
+    Examples
+    --------
+
+    >>> msh = Mesh("../tests/testdata/odense_rough.mesh")
+    >>> msh
+    Number of elements: 654
+    Number of nodes: 399
+    Projection: UTM-33
+
+    """
+
     def __init__(self, filename):
         super().__init__()
         self._filename = filename
@@ -2658,31 +2692,49 @@ class Mesh(_UnstructuredFile):
         self._n_sigma = None
         self._type = None  # DfsuFileType.Mesh
 
+    @property
+    def zn(self):
+        """Static bathymetry values (depth) at nodes"""
+        return self.node_coordinates[:, 2]
+
+    @zn.setter
+    def zn(self, v):
+        if len(v) != self.n_nodes:
+            raise ValueError(f"zn must have length of nodes ({self.n_nodes})")
+        self._nc[:, 2] = v
+        self._ec = None
+
     def set_z(self, z):
-        """Change the depth by setting the z value of each node
+        """Deprecated: use msh.zn = values instead
+
+        Change the depth by setting the z value of each node
 
         Parameters
         ----------
         z : np.array(float)
             new z value at each node
         """
-        if len(z) != self.n_nodes:
-            raise ValueError(f"z must have length of nodes ({self.n_nodes})")
-        self._nc[:, 2] = z
-        self._ec = None
+        warnings.warn(
+            "Mesh.set_z is deprecated, please use msh.zn = values instead.",
+            FutureWarning,
+        )
+        self.zn = z
 
     def set_codes(self, codes):
-        """Change the code values of the nodes
+        """Deprecated: use msh.codes = values instead
+
+        Change the code values of the nodes
 
         Parameters
         ----------
         codes : list(int)
             code of each node
         """
-        if len(codes) != self.n_nodes:
-            raise ValueError(f"codes must have length of nodes ({self.n_nodes})")
-        self._codes = codes
-        self._valid_codes = None
+        warnings.warn(
+            "Mesh.set_codes is deprecated, please use msh.codes = values instead.",
+            FutureWarning,
+        )
+        self.codes = codes
 
     def write(self, outfilename, elements=None):
         """write mesh to file (will overwrite if file exists)


Test patch:
diff --git a/tests/test_mesh.py b/tests/test_mesh.py
index 343c09f9..13d9b9a5 100644
--- a/tests/test_mesh.py
+++ b/tests/test_mesh.py
@@ -52,27 +52,31 @@ def test_set_z():
     msh = Mesh(filename)
     zn = msh.node_coordinates[:, 2]
     zn[zn < -3] = -3
-    msh.set_z(zn)
+
+    msh.node_coordinates[:, 2] = zn
     zn = msh.node_coordinates[:, 2]
     assert zn.min() == -3
 
-    with pytest.raises(ValueError):
-        # not same length
-        msh.set_z(zn[0:4])
-
 
 def test_set_codes():
     filename = os.path.join("tests", "testdata", "odense_rough.mesh")
     msh = Mesh(filename)
     codes = msh.codes
     assert msh.codes[2] == 2
-    codes[codes == 2] = 7
-    msh.set_codes(codes)
+    codes[codes == 2] = 7  # work directly on reference
+
     assert msh.codes[2] == 7
 
+    new_codes = msh.codes.copy()
+    new_codes[new_codes == 7] = 9
+    msh.codes = new_codes  # assign from copy
+
+    assert msh.codes[2] == 9
+
     with pytest.raises(ValueError):
         # not same length
-        msh.set_codes(codes[0:4])
+        msh.codes = codes[0:4]
+
 
 def test_write(tmpdir):
     outfilename = os.path.join(tmpdir.dirname, "simple.mesh")