.. _tuto_grid:

Build the grid
--------------

The first step in creating a configuration is to build the grid for the region 
of interest.
Subsequent steps, such as defining initial and boundary conditions, 
depend on the grid and use the CROCO grid file.

To create your grid, you can use:

* ``make_grid.py``: script for batch execution without any user interaction
* ``nb_make_grid.ipynb``: notebook version that allows user interaction: 
  visualizing the grid, eventually manually editing the bathymetry and mask

Both perform the same following steps:

* Define the grid position, and compute longitude and latitude
* Interpolate the bathymetry onto CROCO grid
* Build the land-sea mask
* Smooth the bathymetry based on chosen criteria

The notebook version allows additional features:

* Visualizing the grid position, bathymetry, and mask
* Manually edit the land-sea mask and the bathymetry to modify artifacts, 
  sharp transitions, etc.

.. tip::

    Using the notebook, you can also manually edit the land-sea mask and 
    the bathymetry from an existing CROCO grid file and update the smoothing.



In the following you will be guided to use these scripts to create your grid. 

Environment
^^^^^^^^^^^

.. warning::  
  
    First be sure that you have installed the required Python environment 
    and activate it (e.g. ``micromamba activate croco_pyenv``).


User-defined parameters
^^^^^^^^^^^^^^^^^^^^^^^

All the requested user-defined parameters to build the grid are gathered in a 
configuration file, here named ``grid.ini``. 

This file contains: 

.. literalinclude:: ../../prepro/Examples/benguela_multifiles/grid.ini
   :language: ini

The **[Croco_Files]** section defines the path and prefix for CROCO files:

.. list-table::
  
   * - ``croco_files_dir``
     - Path of the CROCO files directory
   * - ``croco_grd_prefix``
     - Prefix for the CROCO grid file that will be created.
       For a usual grid, the output file will be ``croco_grd_prefix.nc``,
       for a zoom offline grid it will be ``croco_grd_prefix_zoom_offline.nc``
       and for a nested agrif grid it will be ``croco_grd_prefix.nc.agrif_level``

The **[Zoom_Options]** section defines if the grid is the main grid 
(parent grid) or a nested grid (zoom or child grid):

.. list-table::
  
   * - ``is_zoom``
     - True/False flag to define if the grid is a zoom or the main grid
   * - ``is_agrif``
     - True/False flag to define if the grid is an agrif nested grid
   * - ``agrif_level``
     - integer
       level of the agrif grid to consider (0 is parent, 1 is first child)

For starting building the main/parent grid, put ``False`` to both these fields,
and 0 to ``agrif_level``. 

The **[Grid_Position]** section defines parameters to position the grid.
It is used for the parent grid or for offline zooms (not for Agrif zooms,
for which the grid is placed relatively to the parent). 
The user can select either a curvilinear grid or a rectangular grid. This choice is controlled by the ``grid_type`` parameter.
Depending on the selected grid type, different grid parameters must be specified:

- For a **curvilinear grid**, the required parameters are: ``central_lon``, ``central_lat``, ``size_x_km``, ``size_y_km``, ``npoints_x``, ``npoints_y``, and ``grid_angle``.

- For a **rectangular grid**, the required parameters are: ``lon_min``, ``lon_max``, ``lat_min``, ``lat_max``, ``dlon``, and ``dlat``.

.. list-table::
  
   * - ``grid_type``
     - Must be either ``curvilinear`` or ``rectangular``. Otherwise, an error is raised. If this parameter is not specified, a curvilinear grid is used by default.
   * - ``central_lon``
     - Central longitude of the curvilinear grid 
   * - ``central_lat``
     - Central latitude of the curvilinear grid 
   * - ``size_x_km``
     - Size of the domain along x in km for the curvilinear grid
   * - ``size_y_km``
     - Size of the domain along y in km for the curvilinear grid
   * - ``npoints_x``
     - Number of points along x for the curvilinear grid
   * - ``npoints_y``
     - Number of points along y for the curvilinear grid
   * - ``grid_angle``
     - Rotation angle of the curvilinear grid (trigonometric convention)
   * - ``lon_min``
     - Minimum longitude of the rectangular grid
   * - ``lon_max``
     - Maximum longitude of the rectangular grid
   * - ``lat_min``
     - Minimum latitude of the rectangular grid
   * - ``lat_max``
     - Maximum latitude of the rectangular grid
   * - ``dlon``
     - Longitudinal grid spacing of the rectangular grid
   * - ``dlat``
     - Latitudinal grid spacing of the rectangular grid


The curvilinear grid will be created as an orthogonal grid with minimal gridsize 
variation. 
It uses a Mercator projection around the equator and then rotates the sphere 
around its three axes to position the grid wherever it is located.
The grid resolution is given by dividing the domain size by the number of point 
in each direction (``size_x_km/npoints_x``, in km). 

The **[Grid_Smoothing_Params]** section defines the bathymetry smoothing 
parameters:

.. list-table::
  
   * - ``hmin``
     - Minimum depth [m] allowed for each cell. It should be adapted 
       depending on the chosen resolution
       (e.g., ``dx=100km → hmin=300``, ``dx=25km → hmin=150``)
       Note that it will affects smoothing, which works on ``grad(h)/h``.
   * - ``hmax``
     - Maximum depth [m]. Limits bathymetry to prevent extrapolation below
       available input levels.
   * - ``interp_rad``
     - Interpolation radius (in grid points) for the CROCO grid. Typically between 2 and 8.
   * - ``rfact``
     - Maximum slope parameter, ``r-fact = grad(h)/h``, used during smoothing.
       Lower values yield smoother results.
   * - ``smooth_meth``
     - Smoothing method to use. Options: ``smooth``, ``lsmooth``,
       ``lsmooth_legacy``, ``lsmooth2``, ``lsmooth1``, ``cond_rx0_topo``
       See details on these method below. 

The bathymetry is first interpolated onto the CROCO grid using weighted averaging. 
The weights are computed using a Hann window, more precisely from its polynomial fit 
(which is less computationally expensive), whose size is defined by the 
interpolation radius (``interp_rad``).

Since CROCO is a sigma-coordinate model, it is sensitive to pressure gradient errors. 
Although these are accounted for and reduced by the numerical methods used in the model, 
it is however necessary to smooth the bathymetry so that the slope is everywhere 
less than a defined r-factor.
The default value for the r-factor is set to 0.2, but it can be changed by the user.
The lower the value, the smoother the topography.
Before smoothing, the routine uses hmin and hmax to bound the topography.
Topography values lower than hmin, or higher than hmax, are set to hmin and hmax, 
respectively. Smoothing is then performed. Several smoothing methods exist in CROCO, 
which can be divided into two categories:

* rx-condition: smooths the raw topography until the slope criterion is met
* log-smooth: transforms the topography into its logarithm and smooths it

Here is a brief description of the various available smoothing method:

.. list-table::
  
   * - ``smooth``
     - mask-dependent r-factor based on rx-condition, using Neumann boundary 
       condition at the coastline
   * - ``lsmooth``
     - mask-dependent r-factor based on log_smooth condition
   * - ``lsmooth2``
     - same as lsmooth, but instead of explicitly computing diagonal fluxes,  
       apply cross-averaging to 90-degree fluxes
   * - ``lsmooth1``
     - same as lsmooth, but without diagonal fluxes
   * - ``lsmooth_legacy``
     - same as lsmooth but mask independant
   * - ``cond_rx0_topo``
     - it compares pair-wise adjacent points in either X or Y direction and if 
       r-factor exceeds the prescribed maximum, the shallower depth between 
       the two points is increased so that r-factor remains within the limit. 
       Because of inter-dependency among the points the process is repeated 
       iteratively.

.. note:: 
  
  To avoid errors close to the coastline, it is better to choose data with 
  continuity on land.

Mask creation is handled by the python library regionmask and can handle any 
shapefile to define it. 
CROCO can manage wetting and drying process in coastal areas, in this case the 
land/sea boundary in CROCO should be extended further than the usual coastline. 
In that case, the coastline data will be ignored, 
and the topography data will be used instead. 
The minimum depth, hmin, thus needs to be set to a value lower than zero. 
The mask will be drawn at hmin altitude.

The **[Grid_Isolated_Waterbodies]** section defines parameters used for eventually 
masking isolated water bodies:

.. list-table::
  
   * - ``mask_isolated_waterbodies``
     - True/False flag to activate/deactivate functionality 
   * - ``main_water_body_x_idx``
     - Index of the starting point (in the main water body) in x-direction 
   * - ``main_water_body_y_idx``
     - Index of the starting point (in the main water body) in y-direction


In some cases, mask generation can leave water bodies inside the land 
(lakes for example) which are not connected to the main water body. 
If not wanted, the isolated water bodies can be masked using the 
`mask_isolated_waterbodies` functionnality. 
It takes a user-specified initial point, which is assumed to be in the main 
water body and, starting from this point, considers the adjacent non-masked 
points as “water”. Extending further, non-masked point are also marked as “water” 
if at least one its neighbouring points is already marked as “water”. 
At the end, remaining non-connected water bodies, 
not marked as “water”, because not connected to the main water body, are masked.

The **[Grid_Input_Files]** section defines paths of input files:

.. list-table::
  
   * - ``topo_file_reader``
     - Keyword for the data reader to use in ``readers.jsonc``
       file for dimension name correspondance 
   * - ``topo_file``
     - Path/name of the source bathymetry file
   * - ``shp_file``
     - Path/name of the source coastline file

To build a CROCO grid two input data are necessary:

* bathymetry data (netcdf), examples available in DATASETS_CROCOTOOLS/Topo, but
  any other data can be used by adding a keyword and associated dictionnary in ``reader.jsonc``.
  Some datasets can be downloaded easily :

  * `ETOPO <https://www.ncei.noaa.gov/products/etopo-global-relief-model>`_  
  * STRM30 : `STRM30_pae-paha.pacioos.hawaii.edu <https://pae-paha.pacioos.hawaii.edu/thredds/dem.html?dataset=srtm30plus_v11_land>`_  
    or `STRM30_topex.ucsd.edu <http://topex.ucsd.edu/WWW_html/srtm30_plus.html>`_ 
  * `GEBCO <https://www.gebco.net/>`_ 
  * `HOMONIM <https://diffusion.shom.fr/donnees/bathymerie/mnt-facade-atl-homonim.html>`_ : (100m, French coast) 

* coastline data (shapefile), example available in DATASETS_CROCOTOOLS/gshhs, used
  to build the mask if hmin is positive (if hmin is negative, hmin value will be used instead).

Build the grid with ``make_grid.py``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* Edit the ``grid.ini`` configuration file. 
* Launch the script:

  ::

    ./make_grid.py grid.ini


.. note:: 
  
    Created your ``croco_files_dir`` directory before executing the script. 


Build the grid with ``nb_make_grid.ipynb``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* Run the cell for importing dependencies: 

  ::

    %matplotlib widget  
    %load_ext autoreload
    %autoreload 2

    # Import custom modules
    from Modules.croco_class import CROCO

* Run the cell to read and edit the **[Croco_Files]** section defines 
  directory and path of CROCO files

  ::

      # Read the config file and create a CROCO instance
      croco = CROCO("grid.ini")

      # Edit the appropriate section in the config file
      croco.edit_section_widget("Croco_Files")

Edit the path for CROCO directory and filname for CROCO grid. 

Click the ``Save changes`` button to save your new settings in the 
configuration local dictionnary. 

* Run the cell to read and edit the **[Grid_Input_Files]** section defines 
  directories and path of inputs and outputs files

  ::

      # Edit the appropriate section in the config file
      croco.edit_section_widget("Grid_Input_Files")

Edit the paths to your topographic/bathymetric data, coastline shapefile, 
and output path for CROCO grid. 

Click the ``Save changes`` button to save your new settings in the 
configuration local dictionnary. 

* Run the cell to edit the **[Grid_Position]** section defining parameters 
  to postion the grid:

  ::

      # Edit the appropriate section in the config file
      croco.edit_section_widget("Grid_Position")

Edit the grid settings. 

Click the ``Save changes`` button to save your new settings in the 
configuration local dictionnary. 

* Run the cell to create the grid:

  ::

      # Create lon/lat grid
      croco.create_grid()

.. note:: 
  
  Domain is defined using an Oblique Mercator projection.  

* Run the cell to display the grid position on a map:

  ::

      # Display the grid
      croco.plot_grid_outline()

If you are happy with the grid position, continue, otherwise change 
the grid parameters and run the last 2 cells again. 

* Run the cell to edit the **[Grid_Smoothing_params]** section defining the 
  bathymetry smoothing parameters:

  ::

      # Edit the appropriate section in the config file
      croco.edit_section_widget("Grid_Smoothing_params")

Edit the smoothing parameters settings.

Click the ``Save changes`` button to save your new settings in the 
configuration local dictionnary. 

* Run the cell to edit the **[Grid_Isolated_Waterbodies]** section defining 
  parameters used for eventually masking isolated water bodies:

  ::

      # Edit the appropriate section in the config file
      croco.edit_section_widget("Grid_Isolated_Waterbodies")


Edit the parameters for masking isolated water bodies settings.

Click the ``Save changes`` button to save your new settings in the 
configuration local dictionnary. 

* Run the cell to interpolate the bathymetry, create the mask, and smooth 
  the bathymetry:

  ::
            
      # Interpolate bathymetry, create mask and smooth bathymetry
      croco.create_mask_and_topo()

The smoothing coefficients are printed as output so you can check if the criteria.

* Run the cell to display the bathymetry and mask on a map:

  ::

      # Display the bathymetry and mask
      croco.plot_h()


If you are happy with the bathymetry and mask, continue to save cell, otherwise 
change the smoothing parameters or `Grid_Isolated_Waterbodies` parameters and run the 
last cell again. 

If you further want to manually edit some bathymetry or mask points, go to 
the next section of the notebook "Edit mask and bathymetry". 

* Run the cell to save your grid in a netcdf file, and save your settings for 
  building the grid in a new configuration file:

.. warning:: 
   
   You need to have clicked the ``Save changes`` buttons on each section to 
   actually update the dictionnary and save it properly!

   ::

       # Save CROCO grid in a netcdf file define as croco_grd
       croco.save_grid_nc()

       # Save your CROCO grid settings for later use
       croco.save_config("grid_new.ini")


.. note:: 
  
    Created your ``croco_files_dir`` directory before executing the script. 


Mask and bathymetry manual edition
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may want to manually edit the mask or bathymetry of your CROCO grid 
(e.g. to remove unwanted artifacts, or too sharp transitions). 

Interactive tools are provided in ``nb_make_grid.ipynb`` to do so: a point 
by point editor, and a rectangle selector editor to change a larger area at once. 

* Run the cell to edit the bathymetry:

  ::

      # Edit the bathymetry
      croco.map_editor("h")

You can then choose the ``Mode`` to ``point`` (point by point change) or 
``rectangle`` (rectangle area change at once). 

Clike on a point or select a rectangle on the map to edit. 

Choose the new value in ``New value``, and click ``Update`` to update 
it on the map. 

You can ``Undo`` your change, or ``Save`` it into a dedicated file which 
path/name has to be given in ``Save path``. 

.. tip::
  
  Note that you can zoom-in/zoom-out on the map with the usual left plot tools 
  to more precisely edit a given area. 
  When using the side-plot tools, dot not forget to click once again on it 
  (e.g. zoom tool) before being able to use point or rectangle selector. 

* You can similarly edit the mask with the cell:

  ::

      # Edit the mask
      croco.map_editor("maskr")

* After editing the mask and/or bathymetry, apply the final bathymetry 
  smoothing (note: smoothing is mask-dependent) by running:

  ::

      # Smooth the bathymetry after bathy/mask edition
      croco.smooth_after_mask_edit()

* Display the final smoothed bathymetry and mask with the cell:

  ::

      # Display the new bathymetry and mask
      croco.plot_h()

* Eventually edit the CROCO grid file name:

  ::

      # Edit the appropriate section in the config file
      croco.edit_section_widget("Files")

Click the ``Save changes`` button to save your new settings in the 
configuration local dictionnary. 

* Finally save your new CROCO grid file:

  ::

      # Save CROCO grid in a netcdf file define as croco_grd
      croco.save_grid_nc()

      # Save your CROCO grid settings for later use
      croco.save_config("grid_new.ini")


Build a nested grid
^^^^^^^^^^^^^^^^^^^

To build a nested grid you will have to define in **[Zoom_Options]** section the
variable zoom to True, as well as fill additionnal sections: 
**[Grid_Zoom_Params]**, **[Grid_Zoom_Agrif]**.

To do so, follow the "Build a nest" tutorial. 
