diff --git a/.gitignore b/.gitignore index ea7e6e0..959513f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,9 @@ dataout execs .venv scripts/GF_ConvPar_nml -sources +sources/MONAN-Model_release +sources/convert_mpas_release +sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/data/* +!sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/data/.gitkeep run.* +*.pyc diff --git a/docs/figs/grid3.png b/docs/figs/grid3.png new file mode 100644 index 0000000..9bf7750 Binary files /dev/null and b/docs/figs/grid3.png differ diff --git a/docs/figs/grid4.png b/docs/figs/grid4.png new file mode 100644 index 0000000..172c1a5 Binary files /dev/null and b/docs/figs/grid4.png differ diff --git a/docs/figs/grid5.png b/docs/figs/grid5.png new file mode 100644 index 0000000..0e896f7 Binary files /dev/null and b/docs/figs/grid5.png differ diff --git a/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_240.region.grid_corrected.png b/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_240.region.grid_corrected.png new file mode 100644 index 0000000..98a6def Binary files /dev/null and b/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_240.region.grid_corrected.png differ diff --git a/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png b/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png new file mode 100644 index 0000000..af76396 Binary files /dev/null and b/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png differ diff --git a/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid_cut.png b/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid_cut.png new file mode 100644 index 0000000..f507b7e Binary files /dev/null and b/docs/figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid_cut.png differ diff --git a/docs/figs/mesh_params.png b/docs/figs/mesh_params.png new file mode 100644 index 0000000..0e5724a Binary files /dev/null and b/docs/figs/mesh_params.png differ diff --git a/docs/figs/pressure_group1_ncar.png b/docs/figs/pressure_group1_ncar.png new file mode 100644 index 0000000..61b5047 Binary files /dev/null and b/docs/figs/pressure_group1_ncar.png differ diff --git a/docs/figs/pressure_group1_tut1.png b/docs/figs/pressure_group1_tut1.png new file mode 100644 index 0000000..3fdf519 Binary files /dev/null and b/docs/figs/pressure_group1_tut1.png differ diff --git a/docs/figs/pressure_group2.png b/docs/figs/pressure_group2.png new file mode 100644 index 0000000..b5a42ad Binary files /dev/null and b/docs/figs/pressure_group2.png differ diff --git a/docs/figs/surface_pressure_tut3_2007062300.png b/docs/figs/surface_pressure_tut3_2007062300.png new file mode 100644 index 0000000..f7aa957 Binary files /dev/null and b/docs/figs/surface_pressure_tut3_2007062300.png differ diff --git a/docs/figs/surface_pressure_tut3_2007062400.png b/docs/figs/surface_pressure_tut3_2007062400.png new file mode 100644 index 0000000..c643039 Binary files /dev/null and b/docs/figs/surface_pressure_tut3_2007062400.png differ diff --git a/docs/figs/surface_pressure_tut3_2007062500.png b/docs/figs/surface_pressure_tut3_2007062500.png new file mode 100644 index 0000000..86ecee3 Binary files /dev/null and b/docs/figs/surface_pressure_tut3_2007062500.png differ diff --git a/docs/figs/vorticity_group1_ncar.png b/docs/figs/vorticity_group1_ncar.png new file mode 100644 index 0000000..2dde483 Binary files /dev/null and b/docs/figs/vorticity_group1_ncar.png differ diff --git a/docs/figs/vorticity_group1_tut1.png b/docs/figs/vorticity_group1_tut1.png new file mode 100644 index 0000000..8d405db Binary files /dev/null and b/docs/figs/vorticity_group1_tut1.png differ diff --git a/docs/figs/vorticity_group2.png b/docs/figs/vorticity_group2.png new file mode 100644 index 0000000..3223784 Binary files /dev/null and b/docs/figs/vorticity_group2.png differ diff --git a/docs/tutorial1-meshes.md b/docs/tutorial1-meshes.md new file mode 100644 index 0000000..2492601 --- /dev/null +++ b/docs/tutorial1-meshes.md @@ -0,0 +1,359 @@ +# Tutorial for generating personalized meshes for MONAN + +## 1) First steps in EGEON +To start our exercise, we first need to log in into EGEON and set up a conda environment, which will be needed to execute some of the steps in running a MONAN simulation. + +### 1.1) Log in + +In your terminal, write +``` +ssh -Y $USER@egeon-login.cptec.inpe.br +``` +entering in `$USER` the username you received from the organization team. You will then be prompted to give your password, which you should have received as well. + +### 1.2) Load the anaconda module + +Once you are in, load the anaconda module by +``` +module load anaconda3-2022.05-gcc-11.2.0-q74p53i +``` + +### 1.3) Configure shell to use conda +Start with the command +``` +conda init +``` +Then, do +``` +source ~/.bashrc +``` + +### 1.4) Make sure you have access to our conda environment + +Write the command +``` +conda config --add envs_dirs /pesq/share/monan/curso_OMM_INPE_2025/.conda/envs +``` + +### 1.5) Test if you can activate our conda environment + +Write the command +``` +conda activate vtx_env +``` + +If you see "(vtx_env)" in front of your username in the terminal, you're all set to start! + +## 2) Cloning scripts repository +Our second step is to clone the repository `scripts_CD-CT`, which contains all the code needed to run a MONAN simulation. + +### 2.1) Go to your work directory: +``` +cd /mnt/beegfs/$USER +``` +### 2.2) Clone the scripts repository: + +``` +git clone -b feature/scripts-849-NF-idealized https://github.com/CGFD-USP/scripts_CD-CT +``` + +## 3) Generating MONAN meshes +Now that you have the scripts repository, we can start generating meshes. In this tutorial you will generate three types of mesh: + +1) A **uniform global mesh**, i.e. a mesh with cells approximately the same size all over the globe. This type of mesh will be used in our first exercise with MONAN, where we will perform an idealized global simulation taking artificial initial conditions; + +2) A **refined global mesh**, i.e. a mesh where the size of cells decreases over a particular region of interest where one wants detailed information of simulated phenomena. This type of mesh will be used both in our first exercise with MONAN, for comparison with uniform global meshes, and in our second exercise, where we will simulate an actual cyclone that happened in the La Plata region in 2007; + +3) A **refined regional mesh**, i.e. a mesh where as above the size of cells decreases over a region of interest, but where the rest of the globe is cut off so that one can perform the simulation only over that particular region, thereby saving a lot of computational time. This type of mesh will be used for the cases we will study over the next days of the course. + +To start generating our meshes, we need to tell the code our username so that it knows where to look for the mesh generation algorithm and where to save our meshes. To do this, follow steps 3.1)-3.2) below. + +### 3.1) Go to the scripts directory +``` +cd scripts_CD-CT/scripts +``` + +### 3.2) Substitute in mesh_input_file.txt the placeholder $USER by your actual username +``` +sed -i "s|\\\$USER|$USER|g" mesh_input_file.txt +``` + +Now, check in mesh_input_file.txt if your username is actually there. For this, open the file with the text editor +``` +vi mesh_input_file.txt +``` +After opening the file, make sure that the variables ending in "`_dir`" contain a directory using your actual username. For example, if the username is `guilherme.mendonca`, you should see: +``` +exp_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/scripts +vtx_mpas_meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes +meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/datain/fixed +``` +Check if these three lines contain your username. If so, we are ready to generate our meshes! + +### 3.3) Uniform global mesh +We start with the uniform global mesh. Still in `mesh_input_file.txt`, you can edit the characteristics of your mesh. These characteristics are generally set by the variables +``` +## Coordinates of mesh center +lon=-30 +lat=50 +## Inner and outer radius (km) +inner_radius=2000 +outer_radius=2800 +## Number of external layers for r > outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=240 +## Low resolution for r > outer_radius +low_res=600 +## Whether to cut regional mesh (y/n) +do_regional=n +## Grid type (doughnut/constant) +grid_type=constant +``` + +Most of these parameters only make sense when thinking about a refined mesh. For this first exercise with a uniform mesh, the only parameters we have to worry about are `high_res`, which will define the resolution of our mesh (in km), `do_regional`, which defines whether we want a global or a regional mesh, and `grid_type`, which defines whether our mesh will have constant resolution or will be refined. + +For our uniform global mesh, make sure the following values are set: +``` +high_res=240 +do_regional=n +grid_type=constant +``` + +Please leave the remaining parameters as they are. Now save and exit the file (command :wq). + +#### 3.3.1) Generate the mesh + +Now, you can generate the mesh by executing +``` +bash 2.create_mesh.bash +``` + +#### 3.3.2) Plot the mesh + +After `2.create_mesh.bash` finishes running, we can plot the generated mesh. To do that, first get the geographical files needed for the plot: + +``` +mkdir -p "/home/$USER/.local/share" && cp -r /pesq/share/monan/curso_OMM_INPE_2025/.local/share/cartopy "/home/$USER/.local/share/" +``` + +Now, edit the file plot_mpas_grid.bash: +``` +vi plot_mpas_grid.bash +``` + +In GFILEPATH, add the name of the mesh you just generated after ${DATAIN}/fixed/, for example: +``` +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.region.grid.nc +``` + +In POSTFILEPATH, add the directory you want to save the plot, for example: +``` +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.region.grid.png +``` + +Save and exit (:wq) plot_mpas_grid.bash, then run the script: +``` +bash plot_mpas_grid.bash +``` + +After the plot is done, you may or may not be able to open the plot in EGEON. You can try by + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display /mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/$MESH.grid.png +``` +where in `$MESH` you use the name of your generated mesh (see `POSTFILEPATH` above). + +If this does not work, you need to copy the plot to your local machine to then open it locally. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:/mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/$MESH.grid.png . +``` +where `$USER` is your username and `$MESH` the name of your mesh. + +The result should look like the following: +![Alt text](figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_240.region.grid_corrected.png) + + +### 3.3) Refined global mesh +We now proceed to the refined global mesh. Open again `mesh_input_file.txt` with vi: +``` +vi mesh_input_file.txt +``` +Now, the remaining parameters we ignored in the last section become important. A refined mesh looks something like this: + +![Alt text](figs/mesh_params.png) + + + +As shown in the figure, `high_res`and `low_res` indicate the resolution inside and outside our region of interest. Parameters `inner_radius` and `outer_radius` indicate the radius of the internal part of this region, where the resolution is equal to `high_res`, and the radius of the external region, where the resolution is equal to `low_res`; the difference between these parameters give the size of the transition region where the resolution changes. Important are now also `lat` and `lon`, which give the center of this region of interest. + +For our refined global mesh, copy and paste the mesh parameters as follows: +``` +## Coordinates of mesh center +lon=-30 +lat=50 +## Inner and outer radius (km) +inner_radius=2000 +outer_radius=2800 +## Number of external layers for r > outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=48 +## Low resolution for r > outer_radius +low_res=240 +## Whether to cut regional mesh (y/n) +do_regional=n +## Grid type (doughnut/constant) +grid_type=doughnut +# Automatic additions +``` +where now `grid_type=doughnut` indicates that we want the refinement. The parameter `n_layers`is still not relevant for us: it indicates, if you have a regional mesh, how many "layers" of cells around outer_radius one wants to have before cutting the regional mesh from the global mesh. + +**Important: Make sure the last line file_name=lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.region is deleted**, because it refers to the mesh we generated in the previous section. + +Save and exit the file (command :wq). + +#### 3.3.1) Generate the mesh + +Now, you can generate the mesh by executing +``` +bash 2.create_mesh.bash +``` + +#### 3.3.2) Plot the mesh + +To plot the mesh, edit the file plot_mpas_grid.bash: +``` +vi plot_mpas_grid.bash +``` + +In GFILEPATH, add the name of the mesh you just generated after ${DATAIN}/fixed/, for example: +``` +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.nc +``` + +In POSTFILEPATH, add the directory you want to save the plot, for example: +``` +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png +``` + +Save and exit (:wq) plot_mpas_grid.bash, then run the script: +``` +bash plot_mpas_grid.bash +``` + +After the plot is done, you may or may not be able to open the plot in EGEON. You can try by + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display /mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/$MESH.grid.png +``` +where in `$MESH` you use the name of your generated mesh (see `POSTFILEPATH` above). + +If this does not work, you need to copy the plot to your local machine to then open it locally. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:/mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/$MESH.grid.png . +``` +where `$USER` is your username and `$MESH` the name of your mesh. + +The result should look like this: + +![Alt text](figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png) + +### 3.4) Refined regional mesh +We now proceed to the refined regional mesh. Open again `mesh_input_file.txt` with vi: +``` +vi mesh_input_file.txt +``` +Now, the only difference to the refined global mesh is that we want our mesh to be regional. For this, we just have to set `do_regional=y`. In addition, now `n_layers`becomes important: it tells the code how many "layers" of cells around outer_radius one wants to have before cutting the regional mesh from the global mesh. Hence it defines the limiting region where the regional mesh will be cut. We will use the default value `n_layers=8`. + +Hence, you can copy the parameters as follows: +``` +## Coordinates of mesh center +lon=-30 +lat=50 +## Inner and outer radius (km) +inner_radius=2000 +outer_radius=2800 +## Number of external layers for r > outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=48 +## Low resolution for r > outer_radius +low_res=240 +## Whether to cut regional mesh (y/n) +do_regional=y +## Grid type (doughnut/constant) +grid_type=doughnut +# Automatic additions +``` + +**Important: Make sure the last line file_name=lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region is deleted**, because it refers to the mesh we generated in the previous section. + +Save and exit the file (command :wq). + +#### 3.3.1) Generate the mesh + +Before you generate this mesh, make sure the previous mesh is not overwritten by doing + +``` +mv ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.nc ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global.grid.nc + +mv ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.graph.info ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global.graph.info + +mv ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global + +mv ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png ../datain/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global.grid.png +``` + +Now, you can generate the mesh by executing +``` +bash 2.create_mesh.bash +``` + +#### 3.3.2) Plot the mesh + +To plot the mesh, edit the file plot_mpas_grid.bash: +``` +vi plot_mpas_grid.bash +``` + +In GFILEPATH, add the name of the mesh you just generated after ${DATAIN}/fixed/, for example: +``` +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.nc +``` + +In POSTFILEPATH, add the directory you want to save the plot, for example: +``` +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png +``` + +Save and exit (:wq) plot_mpas_grid.bash, then run the script: +``` +bash plot_mpas_grid.bash +``` + +After the plot is done, you may or may not be able to open the plot in EGEON. You can try by + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display /mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/$MESH.grid.png +``` +where in `$MESH` you use the name of your generated mesh (see `POSTFILEPATH` above). + +If this does not work, you need to copy the plot to your local machine to then open it locally. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:/mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/$MESH.grid.png . +``` +where `$USER` is your username and `$MESH` the name of your mesh. + +The result should look like this: + +![Alt text](figs/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid_cut.png) diff --git a/docs/tutorial2-ideal-case.md b/docs/tutorial2-ideal-case.md new file mode 100644 index 0000000..62bbd9f --- /dev/null +++ b/docs/tutorial2-ideal-case.md @@ -0,0 +1,524 @@ +# Tutorial for running an idealized global MONAN simulation + +## 1) First steps in EGEON +To start our exercise, we first need to log in into EGEON and set up a conda environment, which will be needed to execute some of the steps in running a MONAN simulation. + +### 1.1) Log in + +In your terminal, write +``` +ssh -Y $USER@egeon-login.cptec.inpe.br +``` +entering in `$USER` the username you received from the organization team. You will then be prompted to give your password, which you should have received as well. + +### 1.2) Load the anaconda module + +Once you are in, load the anaconda module by +``` +module load anaconda3-2022.05-gcc-11.2.0-q74p53i +``` + +### 1.3) Configure shell to use conda +Start with the command +``` +conda init +``` +Then, do +``` +source ~/.bashrc +``` + +### 1.4) Make sure you have access to our conda environment + +Write the command +``` +conda config --add envs_dirs /pesq/share/monan/curso_OMM_INPE_2025/.conda/envs +``` + +### 1.5) Test if you can activate our conda environment + +Write the command +``` +conda activate vtx_env +``` + +If you see "(vtx_env)" in front of your username in the terminal, you're all set to start! + +## 2) Cloning scripts repository +Our second step is to clone the repository `scripts_CD-CT`, which contains all the code needed to run a MONAN simulation. + +### 2.1) Go to your work directory: +``` +cd /mnt/beegfs/$USER +``` + +**If you already have cloned the repository in tutorial 1, skip step 2.2)!** + +### 2.2) Clone the scripts repository: + +``` +git clone -b feature/scripts-849-NF-idealized https://github.com/CGFD-USP/scripts_CD-CT +``` + +## 3) Installing and compiling MONAN +Once you have cloned the repository, we can install and compile the model. + +### 3.1) In your work directory, go to scripts_CD-CT/scripts: + +``` +cd scripts_CD-CT/scripts +``` + +### 3.2) Edit 0.run_all.bash: +The general script `0.run_all.bash` orchestrates all steps needed to run a simulation with MONAN. The first of these steps is the installation and compilation of the model. To execute it, open `0.run_all.bash` with the text editor vi: +``` +vi 0.run_all.bash +``` +### 3.3) Then, make sure the first code line in STEP 1 is not commented out: +``` +time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +### 3.4) Now, make sure all the following code lines in STEP 1, 2, 3, 4, 5 are commented out: +``` +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing fase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` +### 3.5) Now, save and exit the file in vi (command :wq), then run 0.run_all.bash to install and compile MONAN: +``` +bash 0.run_all.bash +``` + +**Important**: When asked "Are you sure you are installing the right versions scripts x MONAN-Model ? [Y/n]", type Y! + +## 4) Meshes + +After script `0.run_all.bash` finishes running, you have MONAN installed and compiled. The next step would be to generate the global mesh with which you will run your simulation. Since in tutorial 1 we have already generated two global meshes, one without refinement and one with refinement, we will use those generated meshes for our simulation. + +To do this, we split the class into two groups: + +##### Group 1: mesh without refinement + +##### Group 2: mesh with refinement + +Depending on the group you're, in you will follow when indicated below the steps specific for the mesh without refinement (group 1) or for the mesh with refinement (group 2). + +**If you could not generate the mesh you needed in the previous tutorial, do not worry: we will leave an option for you to download a pre-prepared mesh from NCAR so that you can follow the exercise as well. That mesh doesn't have refinement and has very similar characteristics to the mesh group 1 will use, so you will belong as well to group 1.** + +## 5) Preprocessing + +Now it's time for preparing your simulation. In this idealized test case, this is done by taking the mesh and generating from it an "init" file that contains the idealized initial conditions needed for our test case and also the vertical grid. This is accomplished by script `3.pre_processing.bash`, so our goal in this section is to run that script. This will be done again via the general script `0.run_all.bash`. + +### 5.1) Edit 0.run_all.bash +We start by editing `0.run_all.bash`: +``` +vi 0.run_all.bash +``` + +Here we will set the input variables for our simulation. In the section "Input variables" of the script, make sure the following is set, depending on your group: + +#### Group 1: mesh without refinement + +##### Using mesh generated in tutorial 1 +If you're from group 1 and could finish the mesh without refinement in the previous tutorial, set the "Input variables" as follows: + +``` +github_link="https://github.com/monanadmin/MONAN-Model.git" +monan_branch=release/1.4.1-rc +convertmpas_branch=release/1.2.0 +EXP=IDEALIZED2 +YYYYMMDDHHi=2025111800 +FCST=360 +MESH=lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.region +RES=240 #3 # Minimum grid spacing (km) +REGIONAL=N # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) +``` +##### Using mesh to be downloaded from NCAR +If you're from group 1 and could not finish the mesh without refinement in the previous tutorial, set the "Input variables" as follows: +``` +github_link="https://github.com/monanadmin/MONAN-Model.git" +monan_branch=release/1.4.1-rc +convertmpas_branch=release/1.2.0 +EXP=IDEALIZED2 +YYYYMMDDHHi=2025111800 +FCST=360 +MESH=x1.10242 +RES=240 #3 # Minimum grid spacing (km) +REGIONAL=N # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) +``` + +#### Group 2: mesh with refinement + +##### Using mesh generated in tutorial 1 +If you're from group 2 and could finish the mesh with refinement in the previous tutorial, set the "Input variables" as follows: +``` +github_link="https://github.com/monanadmin/MONAN-Model.git" +monan_branch=release/1.4.1-rc +convertmpas_branch=release/1.2.0 +EXP=IDEALIZED2 +YYYYMMDDHHi=2025111800 +FCST=360 +MESH=lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global +RES=48 #3 # Minimum grid spacing (km) +REGIONAL=N # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) +``` + +Otherwise, follow the instructions above for **Group 1 - Using mesh to be downloaded from NCAR**! + +#### Everyone + +For us the relevant variables are the following: +- EXP=IDEALIZED2, which is telling the code which kind of experiment will be performed (IDEALIZED2 indicates that we take the idealized test case number 2, following the MPAS' User Guide https://www2.mmm.ucar.edu/projects/mpas/mpas_atmosphere_users_guide_8.2.0.pdf, section 7.1). Also possible here are options EXP=ERA5 and EXP=GFS, if one wants to perform real-data simulations (see our tutorial 3). +- YYYYMMDDHHi=2025111800, which is telling the date and hour the simulation will start (in this present idealized exercise, the date and hour don't really matter, so we can in principle leave any date and hour here) +- FCST=360, which is telling for how many hours we will run the simulation (15 days) +- MESH=`$MESH`, which is the name of the mesh that will be used for the simulation (here `$MESH`varies depending on which group you're in) +- RES=`$RES`, which is telling the minimum grid spacing in km used in this mesh (this also depends on your group) +- REGIONAL=N, which is telling that we do not want a regional simulation (we want a global simulation) + +After setting these variables, just comment out the code line from STEP 1 in the code: +``` +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +Uncomment the code line from STEP 3: +``` +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +``` + +Now, make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save the file and exit it (:wq). + +### 5.2) Run 0.run_all.bash +We can now finally execute the preprocessing by doing +``` +bash 0.run_all.bash +``` + +The execution of this script may take a while -- this is the time you may want to grab a coffee and have some pão de queijo (I hope it's available). + +After the execution is completed, the "init" file, named `$MESH`.init.nc, should have been generated under /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2025111800/Pre. Please check if it's there. If so, we are ready for running our global simulation! + +## 6) Running the global simulation +After all the configurations set in the previous step, running the global simulation is a matter of executing script 4.run_model.bash, which is done once more by editing and running `0.run_all.bash`. + +### 6.1) Edit 0.run_all.bash + +``` +vi 0.run_all.bash +``` + +Comment out code line in STEP 3: +``` +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +``` + +Uncomment code line in STEP 4: +``` +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +``` + +Make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save and exit (:wq). + +### 6.2) Run 0.run_all.bash +``` +bash 0.run_all.bash +``` + +Running the simulation will probably take another while -- so maybe more coffee and pão de queijo? + +While you enjoy your coffee break, you may check the status of your simulation by + +``` +squeue -u $USER +``` + +Once the simulation is done, you should see many files starting with MONAN_* under /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2025111800/Model. + +If the files are there, congratulations, you're ready to check the results! + +## 7) Checking the results +To check the results we can plot fields on the native MPAS mesh using 5.run_post_on_mpas_grid.bash. + +For that, make sure you have the geographical files needed for the plot: + +``` +mkdir -p "/home/$USER/.local/share" && cp -r /pesq/share/monan/curso_OMM_INPE_2025/.local/share/cartopy "/home/$USER/.local/share/" +``` + +Now we can proceed to the plotting. + +### 7.1) Pressure field + +#### 7.1.1) Edit 5.run_post_on_mpas_grid.bash +``` +vi 5.run_post_on_mpas_grid.bash +``` + +Here you will choose the parameters you'd like for your plot. You set them by editing the "Local variables", according to your group. We will start by plotting the pressure field, and then the vorticity field, both of them on day 13 of the simulation. + +#### Group 1: mesh without refinement + +##### Using mesh generated in tutorial 1: +You can just copy and paste the code below into the appropriate "Local variables" section in `5.run_post_on_mpas_grid.bash`: +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=pressure +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.regionL55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.region.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +##### Using mesh downloaded from NCAR: +You can just copy and paste the code below into the appropriate "Local variables" section in `5.run_post_on_mpas_grid.bash`: +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=pressure +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.x1.10242L55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/x1.10242.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +#### Group 2: mesh with refinement + +##### Using mesh generated in tutorial 1: +You can just copy and paste the code below into the appropriate "Local variables" section in `5.run_post_on_mpas_grid.bash`: +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=pressure +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.globalL55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +#### Everyone + +After selecting the parameters you want, just exit and save the script (:wq). + +### 7.1.2) Run 5.run_post_on_mpas_grid.bash +``` +bash 5.run_post_on_mpas_grid.bash +``` + +After the plotting is done, you can find it in the `$POSTFILEDIR`directory you have set above. + +As with the mesh, you may not be able to open your plot in EGEON. If you cannot open it using + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display $POSTFILEPATH +``` +where `$POSTFILEPATH` was defined above, you need to copy the plot to your local machine. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:$POSTFILEPATH . +``` +After that, you can finally check your plot by opening it in your local machine. + +The resulting pressure field should look like the following: + +##### Group 1 - mesh generated in tutorial 1 + +![Alt text](figs/pressure_group1_tut1.png) + +##### Group 1 - mesh downloaded from NCAR + +![Alt text](figs/pressure_group1_ncar.png) + +##### Group 2 - mesh generated in tutorial 1 (note the detailed structure in the region of refinement) + +![Alt text](figs/pressure_group2.png) + +### 7.2) Vorticity field + +#### 7.2.1) Edit 5.run_post_on_mpas_grid.bash +``` +vi 5.run_post_on_mpas_grid.bash +``` + +#### Group 1: mesh without refinement + +##### Using mesh generated in tutorial 1: +You can just copy and paste the code below into the appropriate "Local variables" section in `5.run_post_on_mpas_grid.bash`: +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=vorticity +# Minimum and maximum values of variable for colorbar +V_MIN=-0.000125 +V_MAX=0.000125 +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.regionL55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_240_lres_600.region.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +##### Using mesh downloaded from NCAR: +You can just copy and paste the code below into the appropriate "Local variables" section in `5.run_post_on_mpas_grid.bash`: +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=vorticity +# Minimum and maximum values of variable for colorbar +V_MIN=-0.000125 +V_MAX=0.000125 +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.x1.10242L55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/x1.10242.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +#### Group 2: mesh with refinement + +##### Using mesh generated in tutorial 1: +You can just copy and paste the code below into the appropriate "Local variables" section in `5.run_post_on_mpas_grid.bash`: +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=vorticity +# Minimum and maximum values of variable for colorbar +V_MIN=-0.000125 +V_MAX=0.000125 +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.globalL55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +#### Everyone + +After selecting the parameters you want, just exit and save the script (:wq). + +### 7.2.2) Run 5.run_post_on_mpas_grid.bash +``` +bash 5.run_post_on_mpas_grid.bash +``` + +After the plotting is done, you can find it in the `$POSTFILEDIR`directory you have set above. + +As with the mesh, you may not be able to open your plot in EGEON. If you cannot open it using + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display $POSTFILEPATH +``` +where `$POSTFILEPATH` was defined above, you need to copy the plot to your local machine. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:$POSTFILEPATH . +``` +After that, you can finally check your plot by opening it in your local machine. + +The resulting pressure field should look like the following: + +##### Group 1 - mesh generated in tutorial 1 + +![Alt text](figs/vorticity_group1_tut1.png) + +##### Group 1 - mesh downloaded from NCAR + +![Alt text](figs/vorticity_group1_ncar.png) + +##### Group 2 - mesh generated in tutorial 1 (note the detailed structure in the region of refinement) + +![Alt text](figs/vorticity_group2.png) diff --git a/docs/tutorial3-real-case-global.md b/docs/tutorial3-real-case-global.md new file mode 100644 index 0000000..3ad74f3 --- /dev/null +++ b/docs/tutorial3-real-case-global.md @@ -0,0 +1,460 @@ +# Tutorial for running a real-case global MONAN simulation + +## 1) First steps in EGEON +To start our exercise, we first need to log in into EGEON and set up a conda environment, which will be needed to execute some of the steps in running a MONAN simulation. + +### 1.1) Log in + +In your terminal, write +``` +ssh -Y $USER@egeon-login.cptec.inpe.br +``` +entering in `$USER` the username you received from the organization team. You will then be prompted to give your password, which you should have received as well. + +### 1.2) Load the anaconda module + +Once you are in, load the anaconda module by +``` +module load anaconda3-2022.05-gcc-11.2.0-q74p53i +``` + +### 1.3) Configure shell to use conda +Start with the command +``` +conda init +``` +Then, do +``` +source ~/.bashrc +``` + +### 1.4) Make sure you have access to our conda environment + +Write the command +``` +conda config --add envs_dirs /pesq/share/monan/curso_OMM_INPE_2025/.conda/envs +``` + +### 1.5) Test if you can activate our conda environment + +Write the command +``` +conda activate vtx_env +``` + +If you see "(vtx_env)" in front of your username in the terminal, you're all set to start! + +## 2) Cloning scripts repository +Our second step is to clone the repository `scripts_CD-CT`, which contains all the code needed to run a MONAN simulation. + +### 2.1) Go to your work directory: +``` +cd /mnt/beegfs/$USER +``` + +**If you already have cloned the repository in tutorial 1, skip step 2.2)!** + +### 2.2) Clone the scripts repository: + +``` +git clone -b feature/scripts-849-NF-idealized https://github.com/CGFD-USP/scripts_CD-CT +``` + +## 3) Installing and compiling MONAN +Once you have cloned the repository, we can install and compile the model. **If you have already installed and compiled the model in the previous tutorial, skip to section 4!** + +### 3.1) In your work directory, go to scripts_CD-CT/scripts: + +``` +cd scripts_CD-CT/scripts +``` + +### 3.2) Edit 0.run_all.bash: +The general script `0.run_all.bash` orchestrates all steps needed to run a simulation with MONAN. The first of these steps is the installation and compilation of the model. To execute it, open `0.run_all.bash` with the text editor vi: +``` +vi 0.run_all.bash +``` +### 3.3) Then, make sure the first code line in STEP 1 is not commented out: +``` +time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +### 3.4) Now, make sure all the following code lines in STEP 1, 2, 3, 4, 5 are commented out: +``` +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing fase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` +### 3.5) Now, save and exit the file in vi (command :wq), then run 0.run_all.bash to install and compile MONAN: +``` +bash 0.run_all.bash +``` + +**Important**: When asked "Are you sure you are installing the right versions scripts x MONAN-Model ? [Y/n]", type Y! + +## 4) Preparing your mesh + +Now that you have installed and compiled the model, it's time to generate your mesh. This can be done by executing script `2.create_mesh.bash`. But before doing that, we need to set up the characteristics we want our mesh to have. This is done in `mesh_input_file.txt`, so we will start from there. + +### 4.1) Substitute in mesh_input_file.txt the placeholder $USER by your actual username +``` +sed -i "s|\\\$USER|$USER|g" mesh_input_file.txt +``` + +### 4.2) Check in mesh_input_file.txt if your username is actually there +To check this, open the file with the text editor +``` +vi mesh_input_file.txt +``` +After opening the file, make sure that the variables ending in "`_dir`" contain a directory using your actual username. For example, if the username is `guilherme.mendonca`, you should see: +``` +exp_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/scripts +vtx_mpas_meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes +meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/datain/fixed +``` +Check if these three lines contain your username. If so, continue to the next section. + +### 4.3) Set the mesh characteristics you'd like to have +Still in `mesh_input_file.txt`, you can now edit the characteristics of your mesh. For our exercise, we want a mesh with a refinement from 50 km resolution within the region of the cyclone (center ~ lat=-55, lon=-35 within a radius of ~ 2000 km) to 250 km resolution outside this region. As you have seen in tutorial 1, this can be done by setting the mesh parameters to +``` +## Coordinates of mesh center +lon=-55 +lat=-35 +## Inner and outer radius (km) +inner_radius=2000 +outer_radius=2800 +## Number of external layers for r > outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=50 +## Low resolution for r > outer_radius +low_res=250 +## Whether to cut regional mesh (y/n) +do_regional=n +## Grid type (doughnut/constant) +grid_type=doughnut +# Automatic additions +``` + +If you'd like, you can change the mesh characteristics. **But: Since we are interested in simulating a particular cyclone, do not change the coordinates of the mesh center (`lat`,`lon`), and also please keep the size of the high-resolution cells `high_res` unchanged (this influences the time step that will be taken for the simulation, and also the computation time). Please leave also `do_regional` and `grid_type` as they are (as you have seen in tutorial 1, they control whether we want a global or regional mesh (we want global), and also whether we want a refinement (we do)).** + +You can change though the values for `inner_radius` and `outer_radius`, which will influence the size of the transition region where the cell size is changing from high to low resolution. Interesting could also be to change a bit `low_res`, which gives the size of the cells outside our region of interest. + +### 4.4) Generate the mesh +``` +bash 2.create_mesh.bash +``` +Note that in this section 4.4) we did not use the general script `0.run_all.bash`, which executes each of the MONAN simulation steps with their respective input arguments. We could have used it, but since `2.create_mesh.sh` has no input arguments (every input information is entered via `mesh_input_file.txt`), we can simply execute it directly via `bash 2.create_mesh.bash` as we do here. + +### 4.5) Plot the generated mesh +We will now plot the generated mesh. To do that, first get the geographical files needed for the plot: + +``` +mkdir -p "/home/$USER/.local/share" && cp -r /pesq/share/monan/curso_OMM_INPE_2025/.local/share/cartopy "/home/$USER/.local/share/" +``` + +Now, edit the file plot_mpas_grid.bash: +``` +vi plot_mpas_grid.bash +``` + +Now, in GFILEPATH, add the name of the mesh you just generated after ${DATAIN}/fixed/: +``` +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.nc +``` + +In POSTFILEPATH, add the directory you want to save the plot, for example: +``` +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png +``` + +Save and exit (:wq) plot_mpas_grid.bash, then run the script: +``` +bash plot_mpas_grid.bash +``` + +After the plot is done, you may or may not be able to open the plot in EGEON. You can try by + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display /mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png +``` + +If this does not work, you need to copy the plot to your local machine to then open it locally. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:/mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png . +``` +where `$USER` is your username. + +You should see something like this: + +![Alt text](figs/grid3.png) + +## 5) Preprocessing + +Now it's time for preparing your simulation. This is done by 1) generating a "static file", which contains static fields to be used in the simulation (e.g. terrain height, vegetation characteristics, albedo); 2) processing real datasets to be used as initial conditions; 3) interpolating the initial conditions on the mesh and generating also a vertical grid. All of this is accomplished by script `3.pre_processing.bash`, so our goal in this section is to run that script, which is done again via the general script `0.run_all.bash`. + +### 5.1) Edit 0.run_all.bash +We start by editing `0.run_all.bash`: +``` +vi 0.run_all.bash +``` + +Here we will set the input variables for our simulation. In the section "Input variables" of the script, make sure the following is set: + +``` +github_link="https://github.com/monanadmin/MONAN-Model.git" +monan_branch=release/1.4.1-rc +convertmpas_branch=release/1.2.0 +EXP=ERA5 +YYYYMMDDHHi=2007062200 +FCST=72 +MESH=lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region +RES=50 #3 # Minimum grid spacing (km) +REGIONAL=N # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) +``` + +For us the relevant variables are the following, for which we enter already the values as examples: +- EXP=ERA5, which is telling which dataset we will use for the simulation +- YYYYMMDDHHi=2007062200, which is telling the date and hour the simulation will start +- FCST=72, which is telling for how many hours we will run the simulation +- MESH=lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region, which is the name of the mesh that will be used for the simulation (that we've just generated in step 4) +- RES=50, which is telling the minimum grid spacing used in this mesh (km) +- REGIONAL=N, which is telling that we do not want a regional simulation (we want a global simulation) + +After setting these variables, just comment out the code line from STEP 1 in the code: +``` +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +Uncomment the code line from STEP 3: +``` +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +``` + +Now, make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save the file and exit it (:wq). + +### 5.2) Run 0.run_all.bash +We can now finally execute the preprocessing by doing +``` +bash 0.run_all.bash +``` + +The execution of this script may take a while -- time for a coffee break! + +After the execution is completed, there are three files you should have generated (please check): + +1) The static file referred to above, named lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.static.nc, within /mnt/beegfs/`$USER`/scripts_CD-CT/datain/fixed + +2) An "intermediate file" containing preprocessed data from your real dataset, named `ERA5:2007-06-22_00`, within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Pre + +3) An "init file" containing the interpolated initial conditions from that intermediate file, named lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.init.nc, within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Pre + +If all these files have been correctly generated, we are ready for running our global simulation! + +## 6) Running the global simulation +After all the configurations set in the previous step, running the global simulation is a matter of executing script 4.run_model.bash, which is done once more by editing and running `0.run_all.bash`. + +Here we will use the physical parametrizations standard for MONAN. If you'd like to change it to a parametrization you prefer, you just need to: + +1) Open the namelist for the atmosphere core of the model: +``` +vi namelists/namelist.atmosphere.TEMPLATE +``` +2) Find the physics section: +``` +&physics + config_sst_update = false + config_sstdiurn_update = false + config_deepsoiltemp_update = false + config_radtlw_interval = '00:30:00' + config_radtsw_interval = '00:30:00' + config_conv_interval = '#CONFIG_CONV_INTERVAL#' + config_bucket_update = 'none' + config_physics_suite = 'convection_permitting_monan' + config_mynn_edmf = 0 +``` +3) Change the parametrization you'd like, for instance by changing the surface layer scheme: +``` +&physics + config_sst_update = false + config_sstdiurn_update = false + config_deepsoiltemp_update = false + config_radtlw_interval = '00:30:00' + config_radtsw_interval = '00:30:00' + config_conv_interval = '#CONFIG_CONV_INTERVAL#' + config_bucket_update = 'none' + config_physics_suite = 'convection_permitting_monan' + config_mynn_edmf = 0 + config_sfclayer_scheme = sf_monin_obukhov +``` + +To proceed with the standard MONAN configurations, go ahead to step 6.1. + +### 6.1) Edit 0.run_all.bash + +``` +vi 0.run_all.bash +``` + +Comment out code line in STEP 3: +``` +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +``` + +Uncomment code line in STEP 4: +``` +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +``` + +Make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save and exit (:wq). + +### 6.2) Run 0.run_all.bash +``` +bash 0.run_all.bash +``` + +Running the simulation will probably take another while -- so maybe more coffee and pão de queijo? + +While you enjoy your coffee break, you may check the status of your simulation by + +``` +squeue -u $USER +``` + +Once the simulation is done, you should see many files starting with MONAN_* under /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Model. + +If the files are there, congratulations, you're ready to check the results! + +## 7) Checking the results +To check the results we can plot fields on the native MPAS grid using 5.run_post_on_mpas_grid.bash. + +### 7.1) Edit 5.run_post_on_mpas_grid.bash +``` +vi 5.run_post_on_mpas_grid.bash +``` + +Here you will choose the parameters you'd like for your plot. You set them by editing the "Local variables". You can copy and paste the code below to that section: + +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=surface_pressure +## Latitude and longitude min/max values to plot +LAT_MIN=-60 +LAT_MAX=-15 +LON_MIN=-65 +LON_MAX=-20 +# Minimum and maximum values of variable for colorbar +V_MIN=90000 +V_MAX=103000 +# Input file from which variable should be extracted +FILENAME=MONAN_DIAG_G_MOD_ERA5_2007062200_2007062300.00.00.lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.regionL55 +FILEPATH=${DATAOUT}/2007062200/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2007062200/Pre/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2007062200/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +After selecting the parameters you want, just exit and save the script (:wq). + +### 7.2) Run 5.run_post_on_mpas_grid.bash +``` +bash 5.run_post_on_mpas_grid.bash +``` + +After the plotting is done, you can find it in the `$POSTFILEDIR`directory you have set above. + +As with the mesh, you may not be able to open your plot in EGEON. If you cannot open it using + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display $POSTFILEPATH +``` +where `$POSTFILEPATH` was defined above, you need to copy the plot to your local machine. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:$POSTFILEPATH . +``` +After that, you can finally check your plot by opening it in your local machine. + +The plot should look like this: + +![Alt text](figs/surface_pressure_tut3_2007062300.png) + +If you now repeat the procedure above, but choosing not date 2007062300 but date 2007062400 (FILENAME=MONAN_DIAG_G_MOD_ERA5_2007062200_2007062400.00.00.lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.regionL55): + +![Alt text](figs/surface_pressure_tut3_2007062400.png) + +And similarly for 2007062500: + +![Alt text](figs/surface_pressure_tut3_2007062500.png) diff --git a/docs/tutorial4-real-case-regional-ERA5.md b/docs/tutorial4-real-case-regional-ERA5.md new file mode 100644 index 0000000..d66d4d6 --- /dev/null +++ b/docs/tutorial4-real-case-regional-ERA5.md @@ -0,0 +1,415 @@ +# Tutorial for running a real-case regional MONAN simulation with ERA5 data + +## 1) First steps in EGEON +To start our exercise, we first need to log in into EGEON and set up a conda environment, which will be needed to execute some of the steps in running a MONAN simulation. + +### 1.1) Log in + +In your terminal, write +``` +ssh -Y $USER@egeon-login.cptec.inpe.br +``` +entering in `$USER` the username you received from the organization team. You will then be prompted to give your password, which you should have received as well. + +### 1.2) Load the anaconda module + +Once you are in, load the anaconda module by +``` +module load anaconda3-2022.05-gcc-11.2.0-q74p53i +``` + +### 1.3) Configure shell to use conda +Start with the command +``` +conda init +``` +Then, do +``` +source ~/.bashrc +``` + +### 1.4) Make sure you have access to our conda environment + +Write the command +``` +conda config --add envs_dirs /pesq/share/monan/curso_OMM_INPE_2025/.conda/envs +``` + +### 1.5) Test if you can activate our conda environment + +Write the command +``` +conda activate vtx_env +``` + +If you see "(vtx_env)" in front of your username in the terminal, you're all set to start! + +## 2) Cloning scripts repository +Our second step is to clone the repository `scripts_CD-CT`, which contains all the code needed to run a MONAN simulation. + +### 2.1) Go to your work directory: +``` +cd /mnt/beegfs/$USER +``` + +**If you already have cloned the repository in tutorial 1, skip step 2.2)!** + +### 2.2) Clone the scripts repository: + +``` +git clone -b feature/scripts-849-NF-idealized https://github.com/CGFD-USP/scripts_CD-CT +``` + +## 3) Installing and compiling MONAN +Once you have cloned the repository, we can install and compile the model. **If you have already installed and compiled the model in the previous tutorial, skip to section 4!** + +### 3.1) In your work directory, go to scripts_CD-CT/scripts: + +``` +cd scripts_CD-CT/scripts +``` + +### 3.2) Edit 0.run_all.bash: +The general script `0.run_all.bash` orchestrates all steps needed to run a simulation with MONAN. The first of these steps is the installation and compilation of the model. To execute it, open `0.run_all.bash` with the text editor vi: +``` +vi 0.run_all.bash +``` +### 3.3) Then, make sure the first code line in STEP 1 is not commented out: +``` +time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +### 3.4) Now, make sure all the following code lines in STEP 1, 2, 3, 4, 5 are commented out: +``` +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing fase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` +### 3.5) Now, save and exit the file in vi (command :wq), then run 0.run_all.bash to install and compile MONAN: +``` +bash 0.run_all.bash +``` + +**Important**: When asked "Are you sure you are installing the right versions scripts x MONAN-Model ? [Y/n]", type Y! + +## 4) Preparing your mesh + +Now that you have installed and compiled the model, it's time to generate your mesh. This can be done by executing script `2.create_mesh.bash`. But before doing that, we need to set up the characteristics we want our mesh to have. This is done in `mesh_input_file.txt`, so we will start from there. + +### 4.1) Substitute in mesh_input_file.txt the placeholder $USER by your actual username +``` +sed -i "s|\\\$USER|$USER|g" mesh_input_file.txt +``` + +### 4.2) Check in mesh_input_file.txt if your username is actually there +To check this, open the file with the text editor +``` +vi mesh_input_file.txt +``` +After opening the file, make sure that the variables ending in "`_dir`" contain a directory using your actual username. For example, if the username is `guilherme.mendonca`, you should see: +``` +exp_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/scripts +vtx_mpas_meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes +meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/datain/fixed +``` +Check if these three lines contain your username. If so, continue to the next section. + +### 4.3) Set the mesh characteristics you'd like to have +Still in `mesh_input_file.txt`, you can now edit the characteristics of your mesh. For our exercise, we want a mesh with a refinement from 50 km resolution within the region of the cyclone (center ~ lat=-55, lon=-35 within a radius of ~ 2000 km) to 250 km resolution outside this region. As you have seen in tutorial 1, this can be done by setting the mesh parameters to +``` +## Coordinates of mesh center +lon=-55 +lat=-35 +## Inner and outer radius (km) +inner_radius=2000 +outer_radius=2800 +## Number of external layers for r > outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=50 +## Low resolution for r > outer_radius +low_res=250 +## Whether to cut regional mesh (y/n) +do_regional=y +## Grid type (doughnut/constant) +grid_type=doughnut +# Automatic additions +``` + +If you'd like, you can change the mesh characteristics. **But: Since we are interested in simulating a particular cyclone, do not change the coordinates of the mesh center (`lat`,`lon`), and also please keep the size of the high-resolution cells `high_res` unchanged (this influences the time step that will be taken for the simulation, and also the computation time). Please leave also `do_regional` and `grid_type` as they are (as you have seen in tutorial 1, they control whether we want a global or regional mesh (we want regional), and also whether we want a refinement (we do)).** + +You can change though the values for `inner_radius` and `outer_radius`, which will influence the size of the transition region where the cell size is changing from high to low resolution. Interesting could also be to change a bit `low_res`, which gives the size of the cells outside our region of interest. + +### 4.4) Generate the mesh +``` +bash 2.create_mesh.bash +``` +Note that in this section 4.4) we did not use the general script `0.run_all.bash`, which executes each of the MONAN simulation steps with their respective input arguments. We could have used it, but since `2.create_mesh.sh` has no input arguments (every input information is entered via `mesh_input_file.txt`), we can simply execute it directly via `bash 2.create_mesh.bash` as we do here. + +### 4.5) Plot the generated mesh +We will now plot the generated mesh. To do that, first get the geographical files needed for the plot: + +``` +mkdir -p "/home/$USER/.local/share" && cp -r /pesq/share/monan/curso_OMM_INPE_2025/.local/share/cartopy "/home/$USER/.local/share/" +``` + +Now, edit the file plot_mpas_grid.bash: +``` +vi plot_mpas_grid.bash +``` + +Now, in GFILEPATH, add the name of the mesh you just generated after ${DATAIN}/fixed/: +``` +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.nc +``` + +In POSTFILEPATH, add the directory you want to save the plot, for example: +``` +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png +``` + +Save and exit (:wq) plot_mpas_grid.bash, then run the script: +``` +bash plot_mpas_grid.bash +``` + +After the plot is done, you may or may not be able to open the plot in EGEON. You can try by + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display /mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png +``` + +If this does not work, you need to copy the plot to your local machine to then open it locally. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:/mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png . +``` +where `$USER` is your username. + +You should see something like this: + +![Alt text](figs/grid4.png) + +## 5) Preprocessing + +Now it's time for preparing your simulation. This is done by 1) generating a "static file", which contains static fields to be used in the simulation (e.g. terrain height, vegetation characteristics, albedo); 2) processing real datasets to be used as initial conditions; 3) interpolating the initial conditions on the mesh and generating also a vertical grid.; and, for this regional example, 4) generating lateral boundary conditions from the real data. All of this is accomplished by script `3.pre_processing.bash`, so our goal in this section is to run that script, which is done again via the general script `0.run_all.bash`. + +### 5.1) Edit 0.run_all.bash +We start by editing `0.run_all.bash`: +``` +vi 0.run_all.bash +``` + +Here we will set the input variables for our simulation. In the section "Input variables" of the script, make sure the following is set: + +``` +github_link="https://github.com/monanadmin/MONAN-Model.git" +monan_branch=release/1.4.1-rc +convertmpas_branch=release/1.2.0 +EXP=ERA5 +YYYYMMDDHHi=2007062200 +FCST=72 +MESH=lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region +RES=50 #3 # Minimum grid spacing (km) +REGIONAL=Y # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) +``` + +For us the relevant variables are the following, for which we enter already the values as examples: +- EXP=ERA5, which is telling which dataset we will use for the simulation +- YYYYMMDDHHi=2007062200, which is telling the date and hour the simulation will start +- FCST=72, which is telling for how many hours we will run the simulation +- MESH=lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region, which is the name of the mesh that will be used for the simulation (that we've just generated in step 4) +- RES=50, which is telling the minimum grid spacing used in this mesh (km) +- REGIONAL=Y, which is telling that we do want a regional simulation +- LBCINT=21600, which is telling the interval in seconds for updating the lateral boundary conditions for the regional simulation + +After setting these variables, just comment out the code line from STEP 1 in the code: +``` +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +Uncomment the code line from STEP 3: +``` +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +``` + +Now, make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save the file and exit it (:wq). + +### 5.2) Run 0.run_all.bash +We can now finally execute the preprocessing by doing +``` +bash 0.run_all.bash +``` + +The execution of this script may take a while -- time for a coffee break! + +After the execution is completed, there are four types of file you should have generated (please check): + +1) The static file referred to above, named lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.static.nc, within /mnt/beegfs/`$USER`/scripts_CD-CT/datain/fixed + +2) Many "intermediate files" containing preprocessed data from your real dataset, named `ERA5:2007-06-*`, within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Pre + +3) An "init file" containing the interpolated initial conditions from that intermediate file, named lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.init.nc, within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Pre + +4) Many "lbc files" containing the interpolated lateral boundary conditions from that intermediate file, named lbc*.nc within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Pre + +If all these files have been correctly generated, we are ready for running our regional simulation! + +## 6) Running the regional simulation +After all the configurations set in the previous step, running the regional simulation is a matter of executing script 4.run_model.bash, which is done once more by editing and running `0.run_all.bash`. + +### 6.1) Edit 0.run_all.bash + +``` +vi 0.run_all.bash +``` + +Comment out code line in STEP 3: +``` +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Uncomment code line in STEP 4: +``` +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +``` + +Make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing fase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +#exit + +# STEP 4: Executing the Model run: +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save and exit (:wq). + +### 6.2) Run 0.run_all.bash +``` +bash 0.run_all.bash +``` + +Running the simulation will probably take another while -- so maybe more coffee and pão de queijo? + +While you enjoy your coffee break, you may check the status of your simulation by + +``` +squeue -u $USER +``` + +Once the simulation is done, you should see many files starting with MONAN_* under /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Model. + +If the files are there, congratulations, you're ready to check the results! + +## 7) Checking the results +To check the results we can plot fields on the native MPAS grid using 5.run_post_on_mpas_grid.bash. + +### 7.1) Edit 5.run_post_on_mpas_grid.bash +``` +vi 5.run_post_on_mpas_grid.bash +``` + +Here you will choose the parameters you'd like for your plot. You set them by editing the "Local variables". You can copy and paste the code below to that section: + +``` +# Local variables------------------------------------------------------ +## Variable to plot +VAR=surface_pressure +## Latitude and longitude min/max values to plot +LAT_MIN=-60 +LAT_MAX=-15 +LON_MIN=-65 +LON_MAX=-20 +# Minimum and maximum values of variable for colorbar +V_MIN=90000 +V_MAX=103000 +# Input file from which variable should be extracted +FILENAME=MONAN_DIAG_G_MOD_ERA5_2007062200_2007062300.00.00.lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.regionL55 +FILEPATH=${DATAOUT}/2007062200/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2007062200/Pre/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2007062200/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- +``` + +After selecting the parameters you want, just exit and save the script (:wq). + +### 7.2) Run 5.run_post_on_mpas_grid.bash +``` +bash 5.run_post_on_mpas_grid.bash +``` + +After the plotting is done, you can find it in the `$POSTFILEDIR`directory you have set above. + +As with the mesh, you may not be able to open your plot in EGEON. If you cannot open it using + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display $POSTFILEPATH +``` +where `$POSTFILEPATH` was defined above, you need to copy the plot to your local machine. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:$POSTFILEPATH . +``` +After that, you can finally check your plot by opening it in your local machine. diff --git a/docs/tutorial5-real-case-regional-GFS.md b/docs/tutorial5-real-case-regional-GFS.md new file mode 100644 index 0000000..c3778b4 --- /dev/null +++ b/docs/tutorial5-real-case-regional-GFS.md @@ -0,0 +1,361 @@ +# Tutorial for running a real-case regional MONAN simulation with GFS data + +## 1) First steps in EGEON +To start our exercise, we first need to log in into EGEON and set up a conda environment, which will be needed to execute some of the steps in running a MONAN simulation. + +### 1.1) Log in + +In your terminal, write +``` +ssh -Y $USER@egeon-login.cptec.inpe.br +``` +entering in `$USER` the username you received from the organization team. You will then be prompted to give your password, which you should have received as well. + +### 1.2) Load the anaconda module + +Once you are in, load the anaconda module by +``` +module load anaconda3-2022.05-gcc-11.2.0-q74p53i +``` + +### 1.3) Configure shell to use conda +Start with the command +``` +conda init +``` +Then, do +``` +source ~/.bashrc +``` + +### 1.4) Make sure you have access to our conda environment + +Write the command +``` +conda config --add envs_dirs /pesq/share/monan/curso_OMM_INPE_2025/.conda/envs +``` + +### 1.5) Test if you can activate our conda environment + +Write the command +``` +conda activate vtx_env +``` + +If you see "(vtx_env)" in front of your username in the terminal, you're all set to start! + +## 2) Cloning scripts repository +Our second step is to clone the repository `scripts_CD-CT`, which contains all the code needed to run a MONAN simulation. + +### 2.1) Go to your work directory: +``` +cd /mnt/beegfs/$USER +``` + +**If you already have cloned the repository in tutorial 1, skip step 2.2)!** + +### 2.2) Clone the scripts repository: + +``` +git clone -b feature/scripts-849-NF-idealized https://github.com/CGFD-USP/scripts_CD-CT +``` + +## 3) Installing and compiling MONAN +Once you have cloned the repository, we can install and compile the model. **If you have already installed and compiled the model in the previous tutorial, skip to section 4!** + +### 3.1) In your work directory, go to scripts_CD-CT/scripts: + +``` +cd scripts_CD-CT/scripts +``` + +### 3.2) Edit 0.run_all.bash: +The general script `0.run_all.bash` orchestrates all steps needed to run a simulation with MONAN. The first of these steps is the installation and compilation of the model. To execute it, open `0.run_all.bash` with the text editor vi: +``` +vi 0.run_all.bash +``` +### 3.3) Then, make sure the first code line in STEP 1 is not commented out: +``` +time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +### 3.4) Now, make sure all the following code lines in STEP 1, 2, 3, 4, 5 are commented out: +``` +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing fase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` +### 3.5) Now, save and exit the file in vi (command :wq), then run 0.run_all.bash to install and compile MONAN: +``` +bash 0.run_all.bash +``` + +**Important**: When asked "Are you sure you are installing the right versions scripts x MONAN-Model ? [Y/n]", type Y! + +## 4) Preparing your mesh + +Now that you have installed and compiled the model, it's time to generate your mesh. This can be done by executing script `2.create_mesh.bash`. But before doing that, we need to set up the characteristics we want our mesh to have. This is done in `mesh_input_file.txt`, so we will start from there. + +### 4.1) Substitute in mesh_input_file.txt the placeholder $USER by your actual username +``` +sed -i "s|\\\$USER|$USER|g" mesh_input_file.txt +``` + +### 4.2) Check in mesh_input_file.txt if your username is actually there +To check this, open the file with the text editor +``` +vi mesh_input_file.txt +``` +After opening the file, make sure that the variables ending in "`_dir`" contain a directory using your actual username. For example, if the username is `guilherme.mendonca`, you should see: +``` +exp_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/scripts +vtx_mpas_meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes +meshes_dir=/mnt/beegfs/guilherme.mendonca/scripts_CD-CT/datain/fixed +``` +Check if these three lines contain your username. If so, continue to the next section. + +### 4.3) Set the mesh characteristics you'd like to have +Still in `mesh_input_file.txt`, you can now edit the characteristics of your mesh. For our exercise, we want a mesh with a refinement from 50 km resolution within the region of the cyclone (center ~ lat=-55, lon=-35 within a radius of ~ 2000 km) to 250 km resolution outside this region. As you have seen in tutorial 1, this can be done by setting the mesh parameters to +``` +## Coordinates of mesh center +lon=-55 +lat=-35 +## Inner and outer radius (km) +inner_radius=500 +outer_radius=1300 +## Number of external layers for r > outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=50 +## Low resolution for r > outer_radius +low_res=250 +## Whether to cut regional mesh (y/n) +do_regional=y +## Grid type (doughnut/constant) +grid_type=doughnut +# Automatic additions +``` + +If you'd like, you can change the mesh characteristics. **But: Since we are interested in simulating a particular cyclone, do not change the coordinates of the mesh center (`lat`,`lon`), and also please keep the size of the high-resolution cells `high_res` unchanged (this influences the time step that will be taken for the simulation, and also the computation time). Please leave also `do_regional` and `grid_type` as they are (as you have seen in tutorial 1, they control whether we want a global or regional mesh (we want regional), and also whether we want a refinement (we do)).** + +You can change though the values for `inner_radius` and `outer_radius`, which will influence the size of the transition region where the cell size is changing from high to low resolution. Interesting could also be to change a bit `low_res`, which gives the size of the cells outside our region of interest. + +### 4.4) Generate the mesh +``` +bash 2.create_mesh.bash +``` +Note that in this section 4.4) we did not use the general script `0.run_all.bash`, which executes each of the MONAN simulation steps with their respective input arguments. We could have used it, but since `2.create_mesh.sh` has no input arguments (every input information is entered via `mesh_input_file.txt`), we can simply execute it directly via `bash 2.create_mesh.bash` as we do here. + +### 4.5) Plot the generated mesh +We will now plot the generated mesh. To do that, first get the geographical files needed for the plot: + +``` +mkdir -p "/home/$USER/.local/share" && cp -r /pesq/share/monan/curso_OMM_INPE_2025/.local/share/cartopy "/home/$USER/.local/share/" +``` + +Now, edit the file plot_mpas_grid.bash: +``` +vi plot_mpas_grid.bash +``` + +Now, in GFILEPATH, add the name of the mesh you just generated after ${DATAIN}/fixed/: +``` +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_-35_lon_-55_oradius_1300_iradius_500_margin_800_hres_50_lres_250.region.grid.nc +``` + +In POSTFILEPATH, add the directory you want to save the plot, for example: +``` +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_-35_lon_-55_oradius_1300_iradius_500_margin_800_hres_50_lres_250.region.grid.png +``` + +Save and exit (:wq) plot_mpas_grid.bash, then run the script: +``` +bash plot_mpas_grid.bash +``` + +After the plot is done, you may or may not be able to open the plot in EGEON. You can try by + +``` +module load imagemagick-7.0.8-7-gcc-11.2.0-46pk2go +display /mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png +``` + +If this does not work, you need to copy the plot to your local machine to then open it locally. This can be done by opening another terminal, then doing +``` +scp $USER@egeon.cptec.inpe.br:/mnt/beegfs/$USER/scripts_CD-CT/datain/fixed/lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.grid.png . +``` +where `$USER` is your username. + +You should see something like this: + +![Alt text](figs/grid5.png) + +## 5) Preprocessing + +Now it's time for preparing your simulation. This is done by 1) generating a "static file", which contains static fields to be used in the simulation (e.g. terrain height, vegetation characteristics, albedo); 2) processing real datasets to be used as initial conditions; 3) interpolating the initial conditions on the mesh and generating also a vertical grid.; and, for this regional example, 4) generating lateral boundary conditions from the real data. All of this is accomplished by script `3.pre_processing.bash`, so our goal in this section is to run that script, which is done again via the general script `0.run_all.bash`. + +### 5.1) Edit 0.run_all.bash +We start by editing `0.run_all.bash`: +``` +vi 0.run_all.bash +``` + +Here we will set the input variables for our simulation. In the section "Input variables" of the script, make sure the following is set: + +``` +github_link="https://github.com/monanadmin/MONAN-Model.git" +monan_branch=release/1.4.1-rc +convertmpas_branch=release/1.2.0 +EXP=GFS +YYYYMMDDHHi=2024042200 +FCST=24 +MESH=lat_-35_lon_-55_oradius_1300_iradius_500_margin_800_hres_50_lres_250.region +RES=50 #3 # Minimum grid spacing (km) +REGIONAL=Y # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) +``` + +For us the relevant variables are the following, for which we enter already the values as examples: +- EXP=GFS, which is telling which dataset we will use for the simulation +- YYYYMMDDHHi=2024042200, which is telling the date and hour the simulation will start +- FCST=24, which is telling for how many hours we will run the simulation +- MESH=lat_-35_lon_-55_oradius_1300_iradius_500_margin_800_hres_50_lres_250.region, which is the name of the mesh that will be used for the simulation (that we've just generated in step 4) +- RES=50, which is telling the minimum grid spacing used in this mesh (km) +- REGIONAL=Y, which is telling that we do want a regional simulation +- LBCINT=21600, which is telling the interval in seconds for updating the lateral boundary conditions for the regional simulation + +After setting these variables, just comment out the code line from STEP 1 in the code: +``` +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +``` +Uncomment the code line from STEP 3: +``` +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +``` + +Now, make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +#time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} ${LBCINT} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save the file and exit it (:wq). + +### 5.2) Run 0.run_all.bash +We can now finally execute the preprocessing by doing +``` +bash 0.run_all.bash +``` + +The execution of this script may take a while -- time for a coffee break! + +After the execution is completed, there are four types of file you should have generated (please check): + +1) The static file referred to above, named lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region.static.nc, within /mnt/beegfs/`$USER`/scripts_CD-CT/datain/fixed + +2) Many "intermediate files" containing preprocessed data from your real dataset, named `GFS:2024-04-*`, within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2024042200/Pre + +3) An "init file" containing the interpolated initial conditions from that intermediate file, named lat_-35_lon_-55_oradius_1300_iradius_500_margin_800_hres_50_lres_250.region.init.nc, within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2024042200/Pre + +4) Many "lbc files" containing the interpolated lateral boundary conditions from that intermediate file, named lbc*.nc within /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2024042200/Pre + +If all these files have been correctly generated, we are ready for running our regional simulation! + +## 6) Running the regional simulation +After all the configurations set in the previous step, running the regional simulation is a matter of executing script 4.run_model.bash, which is done once more by editing and running `0.run_all.bash`. + +### 6.1) Edit 0.run_all.bash + +``` +vi 0.run_all.bash +``` + +Comment out code line in STEP 3: +``` +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Uncomment code line in STEP 4: +``` +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +``` + +Make sure all other code lines in STEP 1,2,3,4,5 are commented out: +``` +# STEP 1: Installing and compiling the A-MONAN model and utility programs: +#time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} +#exit + +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash +#exit + +# STEP 3: Executing the pre-processing fase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +#exit + +# STEP 4: Executing the Model run: +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#exit + +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit + +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +``` + +Save and exit (:wq). + +### 6.2) Run 0.run_all.bash +``` +bash 0.run_all.bash +``` + +Running the simulation will probably take another while -- so maybe more coffee and pão de queijo? + +While you enjoy your coffee break, you may check the status of your simulation by + +``` +squeue -u $USER +``` + +Once the simulation is done, you should see many files starting with MONAN_* under /mnt/beegfs/`$USER`/scripts_CD-CT/dataout/2007062200/Model. + +If the files are there, congratulations, you're ready to check the results! For that, please follow the same procedures described in the the previous tutorials. diff --git a/scripts/0.run_all.bash b/scripts/0.run_all.bash index c020acc..73e087b 100755 --- a/scripts/0.run_all.bash +++ b/scripts/0.run_all.bash @@ -42,10 +42,13 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} github_link="https://github.com/monanadmin/MONAN-Model.git" monan_branch=release/1.4.1-rc convertmpas_branch=release/1.2.0 -EXP=GFS -RES=1024002 -YYYYMMDDHHi=2024010100 -FCST=24 +EXP=ERA5 +YYYYMMDDHHi=2007062200 +FCST=72 +MESH=lat_-35_lon_-55_oradius_2800_iradius_2000_margin_800_hres_50_lres_250.region +RES=50 #3 # Minimum grid spacing (km) +REGIONAL=Y # Whether to run reigonal simulation +LBCINT=21600 # Interval (seconds) for updating lateral boundary conditions (when regional) #---------------------------------------------------------------------- @@ -53,16 +56,20 @@ FCST=24 #time ${SCRIPTS}/1.install_monan.bash ${github_link} ${monan_branch} ${convertmpas_branch} #exit -# STEP 2: Executing the pre-processing fase. Preparing all CI/CC files needed: -#time ${SCRIPTS}/2.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} +# STEP 2: Generating mesh. Preparing all CI/CC files needed: +#time ${SCRIPTS}/2.create_mesh.bash #exit -# STEP 3: Executing the Model run: -time ${SCRIPTS}/3.run_model.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} -exit +# STEP 3: Executing the pre-processing phase. Preparing all CI/CC files needed:time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} ${MESH} +#time ${SCRIPTS}/3.pre_processing.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +#exit + +# STEP 4: Executing the Model run: +time ${SCRIPTS}/4.run_model.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} ${REGIONAL} +#exit -# STEP 4: Executing the Post of Model run: -time ${SCRIPTS}/4.run_post.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} -exit +# STEP 5: Executing the Post of Model run: +#time ${SCRIPTS}/5.run_post.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} +#$exit -time ${SCRIPTS}/make_template.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} +#time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} diff --git a/scripts/2.create_mesh.bash b/scripts/2.create_mesh.bash new file mode 100755 index 0000000..f4b973c --- /dev/null +++ b/scripts/2.create_mesh.bash @@ -0,0 +1,55 @@ +#!/bin/bash + +# !!!!! Requires vtx-mpas-meshes: https://github.com/marta-gil/vtx-mpas-meshes !!!!! + +# Set environment variables exports: +echo "" +echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" +. setenv.bash + +# Standard directories variables:--------------------------------------- +DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} +DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} +SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} +DATAIN=${DIRHOMED}/datain; mkdir -p ${DATAIN} +DATAOUT=${DIRHOMED}/dataout; mkdir -p ${DATAOUT} +SOURCES=${DIRHOMES}/sources; mkdir -p ${SOURCES} +EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} +#---------------------------------------------------------------------- + +echo -e "${GREEN}==>${NC} creating fixed directory to save mesh... \n" +mkdir -p ${DATAIN}/fixed + + +# Activate conda vtx_env environment +CONDA_PATH="$(conda info --root)" +source "$CONDA_PATH/etc/profile.d/conda.sh" +conda activate vtx_env + +# Select parameters from input_file.txt +echo "Reading input parameters:" +while IFS="=" read -r name value; do + if [[ ! "$name" =~ ^\# ]]; then + declare -r $name=$value + echo $name":" $value + fi +done < mesh_input_file.txt + +# Run script +cd $vtx_mpas_meshes_dir +python3 create_regional_mesh.py --vtx_mpas_meshes_dir $vtx_mpas_meshes_dir --exp_dir $exp_dir --meshes_dir $meshes_dir --N $N --lon $lon --lat $lat --inner_radius $inner_radius --outer_radius $outer_radius --n_layers $n_layers --high_res $high_res --low_res $low_res --do_regional $do_regional --grid_type $grid_type + +cd - + +# Select parameters from input_file.txt +echo "Reading input parameters:" +while IFS="=" read -r name value; do + if [[ ! "$name" =~ ^\# ]]; then + declare -r $name=$value + echo $name":" $value + fi +done < mesh_input_file.txt + +# copy relevant files to fixed/ +cd ${meshes_dir}/${file_name} +cp *.grid.nc *.graph.info ../ diff --git a/scripts/2.pre_processing.bash b/scripts/3.pre_processing.bash similarity index 54% rename from scripts/2.pre_processing.bash rename to scripts/3.pre_processing.bash index 34458f3..976af09 100755 --- a/scripts/2.pre_processing.bash +++ b/scripts/3.pre_processing.bash @@ -17,14 +17,14 @@ # #-----------------------------------------------------------------------------# -if [ $# -ne 4 -a $# -ne 1 ] +if [ $# -ne 6 -a $# -ne 1 ] then echo "" echo "Instructions: execute the command below" echo "" echo "${0} EXP_NAME/OP RESOLUTION LABELI FCST" echo "" - echo "EXP_NAME :: Forcing: GFS" + echo "EXP_NAME :: Forcing: GFS, ERA5, or IDEALIZED*, where * corresponds to the idealized test case number following MPAS user guide, section 7.1. Example: IDEALIZED2 ==> test case 2: Jablonowski and Williamson baroclinic wave, with initial perturbation" echo " :: Others options to be added later..." echo "RESOLUTION :: number of points in resolution model grid, e.g: 1024002 (24 km)" echo " 40962 (120 km)" @@ -47,7 +47,7 @@ echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" -# Standart directories variables:--------------------------------------- +# Standard directories variables:--------------------------------------- DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} @@ -60,9 +60,11 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #MESH=lat_40_lon_-8_oradius_300_iradius_100_margin_200_hres_3_lres_30.region YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 FCST=${4}; #FCST=24 +REGIONAL=${5} #REGIONAL=Y +LBCINT=${6} #LBCINT=3600 #------------------------------------------------------- @@ -92,29 +94,71 @@ rsync -rv --chmod=ugo=rw ${DIRDADOS}/MONAN_datain/datain/fixed ${DATAIN} rsync -rv --chmod=ugo=rwx ${DIRDADOS}/MONAN_datain/execs ${DIRHOMED} ln -sf ${DIRDADOS}/MONAN_datain/datain/WPS_GEOG ${DATAIN} - +if [[ $EXP == "GFS" || $EXP == "ERA5" ]]; then # Creating the x1.${RES}.static.nc file once, if does not exist yet:--------------- -if [ ! -s ${DATAIN}/fixed/x1.${RES}.static.nc ] -then - echo -e "${GREEN}==>${NC} Creating static.bash for submiting init_atmosphere to create x1.${RES}.static.nc...\n" - time ./make_static.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} + if [ ! -s ${DATAIN}/fixed/${MESH}.static.nc ] + then + echo -e "${GREEN}==>${NC} Creating static.bash for submiting init_atmosphere to create ${MESH}.static.nc...\n" + time ./make_static.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} + else + echo -e "${GREEN}==>${NC} File ${MESH}.static.nc already exist in ${DATAIN}/fixed.\n" + fi +#---------------------------------------------------------------------------------- +elif [[ $EXP == IDEALIZED* ]]; then + echo -e "${GREEN}==>${NC} Idealized case selected. No need for creating a static file.\n" else - echo -e "${GREEN}==>${NC} File x1.${RES}.static.nc already exist in ${DATAIN}/fixed.\n" + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} Static phase fails! Please select EXP=GFS, EXP=ERA5 or EXP=IDEALIZED*.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 fi -#---------------------------------------------------------------------------------- - # Degrib phase:--------------------------------------------------------------------- -echo -e "${GREEN}==>${NC} Submiting Degrib...\n" -time ./make_degrib.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} +if [[ ${EXP} == "GFS" ]] +then + echo -e "${GREEN}==>${NC} Submitting Degrib for GFS data...\n" + time ./make_degrib_GFS.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +elif [[ ${EXP} == "ERA5" ]] +then + echo -e "${GREEN}==>${NC} Submitting Degrib for ERA5 data...\n" + time ./make_degrib_ERA5.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} ${LBCINT} +elif [[ ${EXP} == IDEALIZED* ]] +then + echo -e "${GREEN}==>${NC} Idealized case selected. No need for degrib.\n" +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} Degrib phase fails! Please select EXP=GFS, EXP=ERA5 or EXP=IDEALIZED*.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi #---------------------------------------------------------------------------------- # Init Atmosphere phase:------------------------------------------------------------ -echo -e "${GREEN}==>${NC} Submiting Init Atmosphere...\n" -time ./make_initatmos.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} +if [[ $EXP == "GFS" || $EXP == "ERA5" ]]; then + echo -e "${GREEN}==>${NC} Submitting Init Atmosphere for real case...\n" + time ./make_initatmos.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${REGIONAL} +elif [[ $EXP == IDEALIZED* ]]; then + echo -e "${GREEN}==>${NC} Submitting Init Atmosphere for idealized case...\n" + time ./make_initatmos_idealized.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} Init Atmosphere phase fails! Please select EXP=GFS, EXP=ERA5 or EXP=IDEALIZED*.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi #---------------------------------------------------------------------------------- - - - +# LBCs phase:------------------------------------------------------------ +if [[ $REGIONAL == "Y" ]]; then + echo -e "${GREEN}==>${NC} Regional simulation: submitting Init Atmosphere to generate lateral boundary conditions...\n" + time ./make_lbcs.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${LBCINT} +elif [[ $REGIONAL == "N" ]]; then + echo -e "${GREEN}==>${NC} Global simulation: no need for lateral boundary conditions.\n" +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} LBCs phase fails! Please select REGIONAL=Y or REGIONAL=N.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi +#---------------------------------------------------------------------------------- diff --git a/scripts/3.run_model.bash b/scripts/4.run_model.bash similarity index 66% rename from scripts/3.run_model.bash rename to scripts/4.run_model.bash index 8aa323f..3a1553a 100755 --- a/scripts/3.run_model.bash +++ b/scripts/4.run_model.bash @@ -7,22 +7,22 @@ # # Performs the following tasks: # -# o VCheck all input files before -# o Creates the submition script +# o Check all input files before +# o Create the submission script # o Submit the model -# o Veriffy all files generated +# o Verify all files generated # # #-----------------------------------------------------------------------------# -if [ $# -ne 4 -a $# -ne 1 ] +if [ $# -ne 7 -a $# -ne 1 ] then echo "" echo "Instructions: execute the command below" echo "" echo "${0} [EXP_NAME/OP] RESOLUTION LABELI FCST" echo "" - echo "EXP_NAME :: Forcing: GFS" + echo "EXP_NAME :: Forcing: GFS, ERA5, or IDEALIZED*, where * corresponds to the idealized test case number following MPAS user guide, section 7.1. Example: IDEALIZED2 ==> test case 2: Jablonowski and Williamson baroclinic wave, with initial perturbation" echo "RESOLUTION :: number of points in resolution model grid, e.g: 1024002 (24 km)" echo "LABELI :: Initial date YYYYMMDDHH, e.g.: 2024010100" echo "FCST :: Forecast hours, e.g.: 24 or 36, etc." @@ -56,9 +56,12 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #MESH YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 FCST=${4}; #FCST=6 +RES=${5}; #RES(km) +REGIONAL=${6}; #REGIONAL=Y +LBCINT=${7} #LBCINT=3600 #------------------------------------------------------- mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Model/logs @@ -85,18 +88,52 @@ printf -v t_strout "%02d:%02d:%02d" "$h" "$m" "$s" # From now on, CONFI_LEN_DISP becames cte = 0.0, pickin up this value from static file. # Calculating default parameters for different resolutions -if [ $RES -eq 1024002 ]; then #24Km +if [ $RES -eq 24 ]; then #24Km CONFIG_DT=150.0 + CONFIG_LEN_DISP=24000.0 CONFIG_CONV_INTERVAL="00:15:00" -elif [ $RES -eq 2621442 ]; then #15Km +elif [ $RES -eq 15 ]; then CONFIG_DT=90.0 + CONFIG_LEN_DISP=15000.0 CONFIG_CONV_INTERVAL="00:15:00" -elif [ $RES -eq 40962 ]; then #120Km +elif [ $RES -eq 120 ]; then CONFIG_DT=600.0 -elif [ $RES -eq 5898242 ]; then #10Km + CONFIG_LEN_DISP=120000.0 +elif [ $RES -eq 240 ]; then + CONFIG_DT=1200.0 + CONFIG_LEN_DISP=240000.0 +elif [ $RES -eq 10 ]; then CONFIG_DT=60.0 CONFIG_LEN_DISP=10000.0 CONFIG_CONV_INTERVAL="00:15:00" +elif [ $RES -eq 3 ]; then + echo "RES 3" + CONFIG_DT=10.0 + CONFIG_LEN_DISP=3000.0 +elif [ $RES -eq 50 ]; then + echo "RES 50" + CONFIG_DT=300.0 + CONFIG_LEN_DISP=50000.0 +elif [ $RES -eq 48 ]; then + echo "RES 48" + CONFIG_DT=288.0 + CONFIG_LEN_DISP=48000.0 +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} [${0}] Simulation parameters for resolution $RES have not been set! \n" + exit -1 +fi + +# Setting configuration to apply or not lateral boundary conditions +if [[ $REGIONAL == "Y" ]]; then + APPLY_LBCS=true +elif [[ $REGIONAL == "N" ]]; then + APPLY_LBCS=false +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} Atmosphere phase fails! Please select REGIONAL=Y or REGIONAL=N so that MONAN knows whether to read or not lateral boundary conditions.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 fi #------------------------------------------------------- @@ -108,25 +145,31 @@ inh=$(printf "%02.0f\n" $(echo "((${FCST}/24)-${ind})*24" | bc -l)) DD_HHMMSS_forecast=$(echo "${ind}_${inh}:00:00") -if [ ! -s ${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores} ] +if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ] then - if [ ! -s ${DATAIN}/fixed/x1.${RES}.graph.info ] + if [[ ${MESH} == x1.* ]] then + if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info ] + then + cd ${DATAIN}/fixed + echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}.tar.gz + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}_static.tar.gz + tar -xzvf ${MESH}.tar.gz + tar -xzvf ${MESH}_static.tar.gz + fi + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" cd ${DATAIN}/fixed - echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" - wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/x1.${RES}.tar.gz - wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/x1.${RES}_static.tar.gz - tar -xzvf x1.${RES}.tar.gz - tar -xzvf x1.${RES}_static.tar.gz + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + rm -fr ${MESH}.tar.gz ${MESH}_static.tar.gz + else + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" + cd ${DATAIN}/fixed + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} fi - echo -e "${GREEN}==>${NC} Creating x1.${RES}.graph.info.part.${cores} ... \n" - cd ${DATAIN}/fixed - gpmetis -minconn -contig -niter=200 x1.${RES}.graph.info ${cores} - rm -fr x1.${RES}.tar.gz x1.${RES}_static.tar.gz fi - -files_needed=("${SCRIPTS}/namelists/stream_list.atmosphere.output" ""${SCRIPTS}/namelists/stream_list.atmosphere.diagnostics${VARTABLE} "${SCRIPTS}/namelists/stream_list.atmosphere.surface" "${EXECS}/atmosphere_model" "${DATAIN}/fixed/x1.${RES}.static.nc" "${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores}" "${DATAOUT}/${YYYYMMDDHHi}/Pre/x1.${RES}.init.nc" "${DATAIN}/fixed/Vtable.GFS") +files_needed=("${SCRIPTS}/namelists/stream_list.atmosphere.output" ""${SCRIPTS}/namelists/stream_list.atmosphere.diagnostics${VARTABLE} "${SCRIPTS}/namelists/stream_list.atmosphere.surface" "${EXECS}/atmosphere_model" "${DATAIN}/fixed/${MESH}.graph.info.part.${cores}" "${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc") for file in "${files_needed[@]}" do if [ ! -s "${file}" ] @@ -141,19 +184,28 @@ cp -f ${EXECS}/atmosphere_model ${DIRRUN} cp -f ${DATAIN}/fixed/*TBL ${DIRRUN} cp -f ${DATAIN}/fixed/*DBL ${DIRRUN} cp -f ${DATAIN}/fixed/*DATA ${DIRRUN} -cp -f ${DATAIN}/fixed/x1.${RES}.static.nc ${DIRRUN} -cp -f ${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores} ${DIRRUN} -cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/x1.${RES}.init.nc ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ${DIRRUN} +cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc ${DIRRUN} cp -f ${DATAIN}/fixed/Vtable.GFS ${DIRRUN} +if [[ $REGIONAL == "Y" ]]; then + cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/lbc*.nc ${DIRRUN} +fi - -if [ ${EXP} = "GFS" ] +if [[ ${EXP} == "GFS" || ${EXP} == "ERA5" ]] then - sed -e "s,#LABELI#,${start_date},g;s,#FCSTS#,${DD_HHMMSS_forecast},g;s,#RES#,${RES},g; -s,#CONFIG_DT#,${CONFIG_DT},g;s,#CONFIG_LEN_DISP#,${CONFIG_LEN_DISP},g;s,#CONFIG_CONV_INTERVAL#,${CONFIG_CONV_INTERVAL},g" \ + sed -e "s,#LABELI#,${start_date},g;s,#FCSTS#,${DD_HHMMSS_forecast},g;s,#MESH#,${MESH},g; +s,#CONFIG_DT#,${CONFIG_DT},g;s,#CONFIG_LEN_DISP#,${CONFIG_LEN_DISP},g;s,#CONFIG_CONV_INTERVAL#,${CONFIG_CONV_INTERVAL},g;s,#APPLY_LBCS#,${APPLY_LBCS},g" \ ${SCRIPTS}/namelists/namelist.atmosphere.TEMPLATE > ${DIRRUN}/namelist.atmosphere - sed -e "s,#RES#,${RES},g;s,#CIORIG#,${EXP},g;s,#LABELI#,${YYYYMMDDHHi},g;s,#NLEV#,${NLEV},g" \ + sed -e "s,#MESH#,${MESH},g;s,#LBCINT#,${LBCINT},g;s,#CIORIG#,${EXP},g;s,#LABELI#,${YYYYMMDDHHi},g;s,#NLEV#,${NLEV},g" \ + ${SCRIPTS}/namelists/streams.atmosphere.TEMPLATE > ${DIRRUN}/streams.atmosphere +elif [[ ${EXP} == IDEALIZED* ]] +then + sed -e "s,#LABELI#,${start_date},g;s,#FCSTS#,${DD_HHMMSS_forecast},g;s,#MESH#,${MESH},g; +s,#CONFIG_DT#,${CONFIG_DT},g;s,#CONFIG_LEN_DISP#,${CONFIG_LEN_DISP},g;s,#CONFIG_CONV_INTERVAL#,${CONFIG_CONV_INTERVAL},g" \ + ${SCRIPTS}/namelists/namelist.atmosphere.TEMPLATE_IDEALIZED > ${DIRRUN}/namelist.atmosphere + + sed -e "s,#MESH#,${MESH},g;s,#LBCINT#,${LBCINT},g;s,#CIORIG#,${EXP},g;s,#LABELI#,${YYYYMMDDHHi},g;s,#NLEV#,${NLEV},g" \ ${SCRIPTS}/namelists/streams.atmosphere.TEMPLATE > ${DIRRUN}/streams.atmosphere fi cp -f ${SCRIPTS}/namelists/stream_list.atmosphere.output ${DIRRUN} @@ -229,7 +281,7 @@ do i=$(printf "%04d" ${ii}) hh=${YYYYMMDDHHi:8:2} currentdate=$(date -d "${YYYYMMDDHHi:0:8} ${hh}:00:00 $(echo "(${i}-1)*${t_strout:0:2}" | bc) hours $(echo "(${i}-1)*${t_strout:3:2}" | bc) minutes $(echo "(${i}-1)*${t_strout:6:2}" | bc) seconds" +"%Y%m%d%H.%M.%S") - file=MONAN_DIAG_G_MOD_${EXP}_${YYYYMMDDHHi}_${currentdate}.x${RES}L55.nc + file=MONAN_DIAG_G_MOD_${EXP}_${YYYYMMDDHHi}_${currentdate}.${MESH}L55.nc if [ ! -s ${DATAOUT}/${YYYYMMDDHHi}/Model/${file} ] then diff --git a/scripts/4.run_post.bash b/scripts/5.run_post.bash similarity index 93% rename from scripts/4.run_post.bash rename to scripts/5.run_post.bash index bd4f5a8..6628c11 100755 --- a/scripts/4.run_post.bash +++ b/scripts/5.run_post.bash @@ -15,7 +15,7 @@ # #-----------------------------------------------------------------------------# -if [ $# -ne 4 -a $# -ne 1 ] +if [ $# -ne 5 -a $# -ne 1 ] then echo "" echo "Instructions: execute the command below" @@ -55,9 +55,10 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #RES=1024002 YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024042000 FCST=${4}; #FCST=40 +RES=${5} #------------------------------------------------------- mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Post/logs @@ -82,28 +83,28 @@ IFS=":" read -r h m s <<< "${t_strout}" printf -v t_strout "%02d:%02d:%02d" "$h" "$m" "$s" # Calculating default parameters for different resolutions -if [ $RES -eq 1024002 ]; then #24Km +if [ $RES -eq 24 ]; then #24Km NLAT=721 #180/0.25 NLON=1441 #360/0.25 STARTLAT=-90.0 STARTLON=0.0 ENDLAT=90.0 ENDLON=360.0 -elif [ $RES -eq 2621442 ]; then #15Km +elif [ $RES -eq 15 ]; then #15Km NLAT=1201 #180/0.15 NLON=2401 #360/0.15 STARTLAT=-90.0 STARTLON=0.0 ENDLAT=90.0 ENDLON=360.0 -elif [ $RES -eq 40962 ]; then #120Km +elif [ $RES -eq 120 ]; then #120Km NLAT=150 #180/1.2 NLON=300 #360/1.2 STARTLAT=-90.0 STARTLON=0.0 ENDLAT=90.0 ENDLON=360.0 -elif [ $RES -eq 5898242 ]; then #10Km +elif [ $RES -eq 10 ]; then #10Km NLAT=1801 #180/0.10 (+1) NLON=3601 #360/0.10 (+1) STARTLAT=-90.0 @@ -122,7 +123,7 @@ else fi -files_needed=("${SCRIPTS}/namelists/include_fields.diag${VARTABLE}" "${SCRIPTS}/namelists/convert_mpas.nml" "${SCRIPTS}/namelists/target_domain.TEMPLATE" "${EXECS}/convert_mpas" "${DATAOUT}/${YYYYMMDDHHi}/Pre/x1.${RES}.init.nc") +files_needed=("${SCRIPTS}/namelists/include_fields.diag${VARTABLE}" "${SCRIPTS}/namelists/convert_mpas.nml" "${SCRIPTS}/namelists/target_domain.TEMPLATE" "${EXECS}/convert_mpas" "${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc") for file in "${files_needed[@]}" do if [ ! -s "${file}" ] @@ -188,7 +189,7 @@ for ii in \$(seq ${inicio} ${fim}) do i=\$(printf "%04d" \${ii}) echo "Preparing post files \${i}" - cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/x1.${RES}.init.nc ${DIRRUN}/dir.\${i} & + cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc ${DIRRUN}/dir.\${i} & cp -f ${EXECS}/convert_mpas ${DIRRUN}/dir.\${i} & done @@ -202,10 +203,10 @@ do hh=${YYYYMMDDHHi:8:2} currentdate=\$(date -d "${YYYYMMDDHHi:0:8} \${hh}:00:00 \$(echo "(\${i}-1)*${t_strout:0:2}" | bc) hours \$(echo "(\${i}-1)*${t_strout:3:2}" | bc) minutes \$(echo "(\${i}-1)*${t_strout:6:2}" | bc) seconds" +"%Y%m%d%H.%M.%S") - diag_name=MONAN_DIAG_G_MOD_${EXP}_${YYYYMMDDHHi}_\${currentdate}.x${RES}L${N_MODEL_LEV}.nc + diag_name=MONAN_DIAG_G_MOD_${EXP}_${YYYYMMDDHHi}_\${currentdate}.${MESH}L${N_MODEL_LEV}.nc - time ./convert_mpas x1.${RES}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Model/\${diag_name} > convert_mpas.output & - echo "./convert_mpas x1.${RES}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Model/\${diag_name} > convert_mpas.output" + time ./convert_mpas ${MESH}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Model/\${diag_name} > convert_mpas.output & + echo "./convert_mpas ${MESH}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Model/\${diag_name} > convert_mpas.output" done # necessario aguardar as rodadas em background @@ -216,7 +217,7 @@ do i=\$(printf "%04d" \${ii}) hh=${YYYYMMDDHHi:8:2} currentdate=\$(date -d "${YYYYMMDDHHi:0:8} \${hh}:00 \$(echo "(\${i}-1)*3" | bc) hours" +"%Y%m%d%H") - diag_name_post=MONAN_DIAG_G_POS_${EXP}_${YYYYMMDDHHi}_\${currentdate}.00.00.x${RES}L${NLEV}.nc + diag_name_post=MONAN_DIAG_G_POS_${EXP}_${YYYYMMDDHHi}_\${currentdate}.00.00.${MESH}L${NLEV}.nc cd ${DIRRUN}/dir.\${i} cp latlon.nc ${DATAOUT}/${YYYYMMDDHHi}/Post/\${diag_name_post} >> convert_mpas.output & @@ -288,4 +289,4 @@ sbatch --wait --dependency=${dependency} ${DIRRUN}/PostAtmos_node.${node}.sh #CR: passar este scriptpara dentro do script PostAtmos_node.0.sh, submetido. cd ${SCRIPTS} -time ${SCRIPTS}/make_template.bash ${EXP} ${RES} ${YYYYMMDDHHi} ${FCST} +time ${SCRIPTS}/make_template.bash ${EXP} ${MESH} ${YYYYMMDDHHi} ${FCST} ${RES} diff --git a/scripts/5.run_post_on_mpas_grid.bash b/scripts/5.run_post_on_mpas_grid.bash new file mode 100755 index 0000000..c7abb2a --- /dev/null +++ b/scripts/5.run_post_on_mpas_grid.bash @@ -0,0 +1,59 @@ +#!/bin/bash +#-----------------------------------------------------------------------------# +# !SCRIPT: run_post_on_mpas_grid +# +# !DESCRIPTION: +# Script to run the postprocessing of MONAN model using the original MPAS grid. +# +#-----------------------------------------------------------------------------# + + +# Set environment variables exports: +echo "" +echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" +. setenv.bash + + + +# Standart directories variables:--------------------------------------- +DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} +DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} +export SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} +DATAIN=${DIRHOMED}/datain; mkdir -p ${DATAIN} +DATAOUT=${DIRHOMED}/dataout; mkdir -p ${DATAOUT} +SOURCES=${DIRHOMES}/sources; mkdir -p ${SOURCES} +EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} +#---------------------------------------------------------------------- + +# Local variables------------------------------------------------------ +## Variable to plot +VAR=vorticity +# Minimum and maximum values of variable for colorbar +V_MIN=-0.000125 +V_MAX=0.000125 +# Input file from which variable should be extracted +FILENAME=MONAN_HIST_G_MOD_IDEALIZED2_2025111800_2025120100.00.00.lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.globalL55 +FILEPATH=${DATAOUT}/2025111800/Model/${FILENAME}.nc +# File from which grid characteristics should be extracted +GFILEPATH=${DATAOUT}/2025111800/Pre/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.global.init.nc +# Output directory and filename to save plot +POSTFILEDIR=${DATAOUT}/2025111800/Post +POSTFILEPATH=${POSTFILEDIR}/${VAR}_${FILENAME}.png +#--------------------------------------------------------------------- + +if [ ! -d "${POSTFILEDIR}" ]; then + mkdir "${POSTFILEDIR}" +fi + +source ~/.bashrc +conda activate vtx_env + +if [[ $LAT_MIN == "" ]]; then + if [[ $V_MIN == "" ]]; then + python3 ${SOURCES}/CGFD-USP-Post-Proc/mpas_plot.py -f $FILEPATH -gf $GFILEPATH -v $VAR -o $POSTFILEPATH + else + python3 ${SOURCES}/CGFD-USP-Post-Proc/mpas_plot.py -f $FILEPATH -gf $GFILEPATH -vmin $V_MIN -vmax $V_MAX -v $VAR -o $POSTFILEPATH + fi +else + python3 ${SOURCES}/CGFD-USP-Post-Proc/mpas_plot.py -f $FILEPATH -gf $GFILEPATH -vmin $V_MIN -vmax $V_MAX -v $VAR -lat_min $LAT_MIN -lat_max $LAT_MAX -lon_min $LON_MIN -lon_max $LON_MAX -o $POSTFILEPATH +fi diff --git a/scripts/download_era5_data.py b/scripts/download_era5_data.py new file mode 100755 index 0000000..19ac201 --- /dev/null +++ b/scripts/download_era5_data.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Unified script for downloading ERA5 pressure-level and surface data for initializing +the MPAS-A model. Supports global and regional simulations. + +The script automatically handles downloading data for specified date ranges and timesteps. +For global simulations, only the initial time step is downloaded. For regional simulations, +data is downloaded for all timesteps. + +SST (sea surface temperature), land-sea mask, and sea-ice data can be optionally included +for all time steps. + +Created by: + Danilo Couto de Souza + Universidade de São Paulo (USP) + São Paulo, Brazil + +Contact: + danilo.oceano@gmail.com +""" + +import os +import cdsapi +import numpy as np +import pandas as pd +from datetime import datetime, timedelta + +# Create the CDSAPI client +client = cdsapi.Client() + +def download_era5_surface_data(date, time, area, target_filename): + """ + Download surface data (sea-level) from ERA5 for a specific date and time. + """ + date = pd.to_datetime(date).strftime('%Y-%m-%d %H:%M') + request = { + 'product_type': ['reanalysis'], + 'variable': [ + '10m_u_component_of_wind','10m_v_component_of_wind','2m_dewpoint_temperature', + '2m_temperature','land_sea_mask','mean_sea_level_pressure', + 'sea_ice_cover','sea_surface_temperature','skin_temperature', + 'snow_depth','soil_temperature_level_1','soil_temperature_level_2', + 'soil_temperature_level_3','soil_temperature_level_4','surface_pressure', + 'volumetric_soil_water_layer_1','volumetric_soil_water_layer_2','volumetric_soil_water_layer_3', + 'volumetric_soil_water_layer_4', 'geopotential' + ], + 'year': [date[:4]], + 'month': [date[5:7]], + 'day': [date[8:10]], + 'time': [time], + 'area': area, + 'format': 'grib', + "download_format": "unarchived" + } + + client.retrieve('reanalysis-era5-single-levels', request).download(target_filename) + print(f"Downloaded surface data: {target_filename}") + +def download_era5_pressure_data(date, time, area, target_filename): + """ + Download pressure-level data from ERA5 for a specific date and time. + """ + # Convert date to string format + date = pd.to_datetime(date).strftime('%Y-%m-%d %H:%M') + request = { + 'product_type': ['reanalysis'], + 'variable': [ + 'geopotential', 'relative_humidity', 'specific_humidity', 'temperature', + 'u_component_of_wind', 'v_component_of_wind', + ], + 'year': [date[:4]], + 'month': [date[5:7]], + 'day': [date[8:10]], + 'time': [time], + 'pressure_level': [ + '10', '20', '30', '50', '70', '100', '125', '150', '200', '225', '250', '300', + '350', '400', '450', '500', '550', '600', '650', '700', '750', '800', '850', + '900', '950', '1000', + ], + 'area': area, + 'format': 'grib', + "download_format": "unarchived" + } + + print(f"Request details: {request}") + client.retrieve('reanalysis-era5-pressure-levels', request).download(target_filename) + print(f"Downloaded pressure data: {target_filename}") + +def download_era5_sst_data(start_date, end_date, time_steps, area, target_filename): + """ + Download SST, sea-ice cover, and land-sea mask data for a range of dates and all time steps. + """ + request = { + 'product_type': 'reanalysis', + 'variable': ['land_sea_mask', 'sea_ice_cover', 'sea_surface_temperature'], + 'year': [start_date[:4], end_date[:4]], + 'month': [start_date[5:7], end_date[5:7]], + 'day': [start_date[8:10], end_date[8:10]], + 'time': time_steps, + 'area': area, + 'format': 'grib', + } + + print(f"Request details: {request}") + client.retrieve('reanalysis-era5-single-levels', request, target_filename) + print(f"Downloaded SST data: {target_filename}") + +def generate_time_steps(start_date, end_date, interval): + """ + Generate a list of time steps for the given date range, based on the specified interval. + """ + time_steps = [] + current_time = start_date.replace(hour=0, minute=0) + while current_time <= end_date.replace(hour=23, minute=0): + time_steps.append(current_time.strftime('%H:%M')) + current_time += timedelta(hours=interval) + return time_steps + +def download_for_time_range(start_date, end_date, time_interval, area, output_dir, download_sst=False): + """ + Downloads data for all time steps within a given date range for regional simulations. + """ + time_steps = np.unique(generate_time_steps(start_date, end_date, time_interval)) + for single_date in (start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)): + date_str = single_date.strftime('%Y-%m-%d') + for time in time_steps: + target_filename_pl = f'{output_dir}/era5_pl_{date_str}_{time.replace(":", "")}.grib' + target_filename_sl = f'{output_dir}/era5_sl_{date_str}_{time.replace(":", "")}.grib' + # Check if the files already exist before downloading + if os.path.exists(target_filename_pl): + print(f"Files already exist: {target_filename_pl}. Skipping download.") + else: + download_era5_pressure_data(date_str, time, area, target_filename_pl) + + if os.path.exists(target_filename_sl): + print(f"Files already exist: {target_filename_sl}. Skipping download.") + else: + download_era5_surface_data(date_str, time, area, target_filename_sl) + + if download_sst: + sst_filename = f'{output_dir}/era5_sst_{start_date.strftime("%Y%m%d")}-{end_date.strftime("%Y%m%d")}.grib' + download_era5_sst_data(start_date, end_date, time_steps, area, sst_filename) + +def download_for_single_timestep(start_date, end_date, time_interval, area, output_dir, download_sst=False): + """ + Downloads data for a single timestep (for global simulations). + """ + time = pd.to_datetime(start_date).strftime('%H:%M') # Get the time in HH:MM format + target_filename_pl = f'{output_dir}/era5_pl_{start_date}_{time.replace(":", "")}.grib' + target_filename_sl = f'{output_dir}/era5_sl_{start_date}_{time.replace(":", "")}.grib' + download_era5_pressure_data(start_date, time, area, target_filename_pl) + download_era5_surface_data(start_date, time, area, target_filename_sl) + + if download_sst: + time_steps = generate_time_steps(datetime.strptime(start_date, '%Y-%m-%d'), datetime.strptime(end_date, '%Y-%m-%d') + timedelta(hours=23), time_interval) + sst_filename = f'{output_dir}/era5_sst_{start_date}.grib' + download_era5_sst_data(start_date, end_date, time_steps, area, sst_filename) + +if __name__ == "__main__": + # Simulation setup: + start_date = datetime.strptime('2009-06-22 00:00', '%Y-%m-%d %H:%M') # Simulation start date + end_date = datetime.strptime('2009-06-23 00:00', '%Y-%m-%d %H:%M') # Simulation end date + + # Simulation type setup ('global' or 'regional') + simulation_type = 'regional' # Choose 'global' or 'regional' + + # Time interval in hours (e.g., 1, 2, 3) for downloading data + # (Even for global simulations, this is used for SST data, if requested) + time_interval = 6 + + # Download area + area = [-90, -180, 90, 180] # Example area [South, West, North, East] + +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +## !!!!!!!!!!! ATENCAO: DIRETORIO PARA SALVER OS DADOS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!! +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + output_dir = '/pesq/share/monan/curso_OMM_INPE_2025/CGFD-USP_Cases/MPAS-BR/met_data/ERA5/DATA' # Output directory +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + # Ensure output directory exists + os.makedirs(output_dir, exist_ok=True) + + # Choose whether to download SST data + download_sst = False # Set to True if SST data is needed, False otherwise + + if simulation_type == 'global': + download_for_single_timestep(start_date, end_date, time_interval, area, output_dir, download_sst) + elif simulation_type == 'regional': + download_for_time_range(start_date, end_date, time_interval, area, output_dir, download_sst) diff --git a/scripts/make_degrib_ERA5.bash b/scripts/make_degrib_ERA5.bash new file mode 100755 index 0000000..37c8849 --- /dev/null +++ b/scripts/make_degrib_ERA5.bash @@ -0,0 +1,275 @@ +#!/bin/bash + +if [ $# -ne 6 ] +then + echo "" + echo "Instructions: execute the command below" + echo "" + echo "${0} EXP_NAME RESOLUTION LABELI FCST" + echo "" + echo "EXP_NAME :: Forcing: GFS" + echo " :: Others options to be added later..." + echo "RESOLUTION :: number of points in resolution model grid, e.g: 1024002 (24 km)" + echo "LABELI :: Initial date YYYYMMDDHH, e.g.: 2024010100" + echo "FCST :: Forecast hours, e.g.: 24 or 36, etc." + echo "" + echo "24 hour forecast example:" + echo "${0} GFS 1024002 2024010100 24" + echo "${0} GFS 40962 2024010100 48" + echo "" + + exit +fi + +# Set environment variables exports: +echo "" +echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" +. setenv.bash + + +# Standart directories variables:--------------------------------------- +DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} +DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} +SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} +DATAIN=${DIRHOMED}/datain; mkdir -p ${DATAIN} +DATAOUT=${DIRHOMED}/dataout; mkdir -p ${DATAOUT} +SOURCES=${DIRHOMES}/sources; mkdir -p ${SOURCES} +EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} +#---------------------------------------------------------------------- + + +# Input variables:-------------------------------------- +EXP=${1}; #EXP=GFS +MESH=${2}; #MESH +YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 +FCST=${4}; #FCST=24 +REGIONAL=${5}; #REGIONAL=Y +LBCINT=${6}; #LBCINT=21600 +#------------------------------------------------------- + +source utils.bash + +# Local variables-------------------------------------- +start_date=${YYYYMMDDHHi:0:4}-${YYYYMMDDHHi:4:2}-${YYYYMMDDHHi:6:2}_${YYYYMMDDHHi:8:2}:00:00 +YYYYMMDDHHf=$(add_hours "$YYYYMMDDHHi" "$FCST") +final_date=${YYYYMMDDHHf:0:4}-${YYYYMMDDHHf:4:2}-${YYYYMMDDHHf:6:2}_${YYYYMMDDHHf:8:2}:00:00 +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +## !!!!!!!!!!! ATENCAO: AQUI ESTA SENDO ASSUMIDO QUE TODOS OS DADOS DO ERA5 NECESSARIOS PARA O !!!!!!!!!!! +## !!!!!!!!!!! EXPERIMENTO ESTAO NO SEGUINTE DIRETORIO: !!!!!!!!!!! +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +ERA5_DATA=/pesq/share/monan/curso_OMM_INPE_2025/CGFD-USP_Cases/MPAS-BR/met_data/ERA5/DATA +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +BNDDIR=${ERA5_DATA} +export DIRRUN=${DIRHOMED}/run.${YYYYMMDDHHi}; rm -fr ${DIRRUN}; mkdir -p ${DIRRUN} +#------------------------------------------------------- +mkdir -p ${DATAIN}/${YYYYMMDDHHi} +mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs + +mkdir -p ${HOME}/local/lib64 +cp -f /usr/lib64/libjasper.so* ${HOME}/local/lib64 +cp -f /usr/lib64/libjpeg.so* ${HOME}/local/lib64 + + +# Se nao existir CI no diretorio ERA5_data, aborta! +if [ ! -s ${BNDDIR}/era5.pl.${YYYYMMDDHHi}.grib ] || [ ! -s ${BNDDIR}/era5.sl.${YYYYMMDDHHi}.grib ] +then + echo -e "${RED}==>${NC}Condicao de contorno inexistente !" + echo -e "${RED}==>${NC}Check ${BNDDIR} or." + echo -e "${RED}==>${NC}Check ${GCCCIS}" + exit 1 +fi + +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +## !!!!!!!!!!! ATENCAO: AQUI ESTA SENDO ASSUMIDO QUE A TABELA Vtable.ECMWF EXISTE NESSE DIRETORIO !!!!!!!! +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# Copiar Vtable do ERA5 +cp /pesq/share/monan/curso_OMM_INPE_2025/CGFD-USP_Cases/WPS/ungrib/Variable_Tables/Vtable.ECMWF ${DATAIN}/fixed +## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +files_needed=("${DATAIN}/fixed/${MESH}.static.nc" "${DATAIN}/fixed/Vtable.ECMWF" "${EXECS}/ungrib.exe" "${BNDDIR}/era5.pl.${YYYYMMDDHHi}.grib" "${BNDDIR}/era5.sl.${YYYYMMDDHHi}.grib") +for file in "${files_needed[@]}" +do + if [ ! -s "${file}" ] + then + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} [${0}] At least the file ${file} was not generated. \n" + exit -1 + fi +done + +# Copia arquivos necessarios para diretorio DIRRUN +cp -f ${DATAIN}/fixed/${MESH}.static.nc ${DIRRUN} +cp -f ${DATAIN}/fixed/Vtable.ECMWF ${DIRRUN}/Vtable +cp -f ${EXECS}/ungrib.exe ${DIRRUN} +cp -f ${SCRIPTS}/namelists/namelist.wps.TEMPLATE ${DIRRUN}/namelist.wps.TEMPLATE + +cp -f ${SCRIPTS}/setenv.bash ${DIRRUN} +cp -f ${SCRIPTS}/link_grib.csh ${DIRRUN} +rm -f ${DIRRUN}/degrib.bash + +if [[ $REGIONAL == "Y" ]]; then + echo "REGIONAL=Y. Degribbing ERA5 data for both initial and lateral boundary conditions..." + cp -f ${BNDDIR}/era5.pl.*.grib ${DATAIN}/${YYYYMMDDHHi} + cp -f ${BNDDIR}/era5.sl.*.grib ${DATAIN}/${YYYYMMDDHHi} + cat << EOF0 > ${DIRRUN}/degrib.bash +#!/bin/bash -x +#SBATCH --job-name=${DEGRIB_jobname} +#SBATCH --nodes=${DEGRIB_nnodes} +#SBATCH --partition=${DEGRIB_QUEUE} +#SBATCH --ntasks=${DEGRIB_ncores} +#SBATCH --tasks-per-node=${DEGRIB_ncpn} # ic for benchmark +#SBATCH --time=${STATIC_walltime} +#SBATCH --output=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/degrib.o%j # File name for standard output +#SBATCH --error=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/degrib.e%j # File name for standard error output +# + +ulimit -s unlimited +ulimit -c unlimited +ulimit -v unlimited + +export PMIX_MCA_gds=hash + + +export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:${HOME}/local/lib64 + +cd ${DIRRUN} +. setenv.bash + +ldd ungrib.exe + +rm -f GRIBFILE.* namelist.wps + + +sed -e "s,#LABELI#,${start_date},g;s,#LABELF#,${final_date},g;s,#LBCINT#,${LBCINT},g;s,#PREFIX#,ERA5,g" \ + ${DIRRUN}/namelist.wps.TEMPLATE > ${DIRRUN}/namelist.wps + +./link_grib.csh ${DATAIN}/${YYYYMMDDHHi}/era5.*.grib + +date +time mpirun -np 1 ./ungrib.exe +date + + +grep "Successful completion of program ungrib.exe" ${DIRRUN}/ungrib.log >& /dev/null + +if [ \$? -ne 0 ]; then + echo " BUMMER: Ungrib generation failed for some yet unknown reason." + echo " " + tail -10 ${DIRRUN}/ungrib.log + echo " " + exit 21 +fi + +# +# clean up and remove links +# + mv ungrib.log ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/ungrib.${start_date}.log + mv namelist.wps ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/namelist.${start_date}.wps + mv ERA5* ${DATAOUT}/${YYYYMMDDHHi}/Pre + + rm -fr ${DATAIN}/${YYYYMMDDHHi} + +echo "End of degrib Job" + + +EOF0 + + +elif [[ $REGIONAL == "N" ]]; then + echo "REGIONAL=N. Degribbing ERA5 data only for initial conditions..." + cp -f ${BNDDIR}/era5.pl.${YYYYMMDDHHi}.grib ${DATAIN}/${YYYYMMDDHHi} + cp -f ${BNDDIR}/era5.sl.${YYYYMMDDHHi}.grib ${DATAIN}/${YYYYMMDDHHi} + cat << EOF0 > ${DIRRUN}/degrib.bash +#!/bin/bash -x +#SBATCH --job-name=${DEGRIB_jobname} +#SBATCH --nodes=${DEGRIB_nnodes} +#SBATCH --partition=${DEGRIB_QUEUE} +#SBATCH --ntasks=${DEGRIB_ncores} +#SBATCH --tasks-per-node=${DEGRIB_ncpn} # ic for benchmark +#SBATCH --time=${STATIC_walltime} +#SBATCH --output=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/degrib.o%j # File name for standard output +#SBATCH --error=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/degrib.e%j # File name for standard error output +# + +ulimit -s unlimited +ulimit -c unlimited +ulimit -v unlimited + +export PMIX_MCA_gds=hash + + +export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:${HOME}/local/lib64 + +cd ${DIRRUN} +. setenv.bash + +ldd ungrib.exe + +rm -f GRIBFILE.* namelist.wps + + +sed -e "s,#LABELI#,${start_date},g;s,#LABELF#,${start_date},g;s,#LBCINT#,${LBCINT},g;s,#PREFIX#,ERA5,g" \ + ${DIRRUN}/namelist.wps.TEMPLATE > ${DIRRUN}/namelist.wps + +./link_grib.csh ${DATAIN}/${YYYYMMDDHHi}/era5.*.${YYYYMMDDHHi}.grib + +date +time mpirun -np 1 ./ungrib.exe +date + + +grep "Successful completion of program ungrib.exe" ${DIRRUN}/ungrib.log >& /dev/null + +if [ \$? -ne 0 ]; then + echo " BUMMER: Ungrib generation failed for some yet unknown reason." + echo " " + tail -10 ${DIRRUN}/ungrib.log + echo " " + exit 21 +fi + +# +# clean up and remove links +# + mv ungrib.log ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/ungrib.${start_date}.log + mv namelist.wps ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/namelist.${start_date}.wps + mv ERA5\:${start_date:0:13} ${DATAOUT}/${YYYYMMDDHHi}/Pre + + rm -fr ${DATAIN}/${YYYYMMDDHHi} + +echo "End of degrib Job" + + +EOF0 + +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} LBCs phase fails during degrib! Please select REGIONAL=Y or REGIONAL=N so that degrib can be done appropriately.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi + + +chmod a+x ${DIRRUN}/degrib.bash + +echo -e "${GREEN}==>${NC} Executing sbatch degrib.bash...\n" +cd ${DIRRUN} +sbatch --wait ${DIRRUN}/degrib.bash + + + +files_ungrib=("${EXP}:${YYYYMMDDHHi:0:4}-${YYYYMMDDHHi:4:2}-${YYYYMMDDHHi:6:2}_${YYYYMMDDHHi:8:2}") +for file in "${files_ungrib[@]}" +do + if [ ! -s ${DATAOUT}/${YYYYMMDDHHi}/Pre/${file} ] + then + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} Degrib fails! At least the file ${file} was not generated at ${DATAIN}/${YYYYMMDDHHi}. \n" + echo -e "${RED}==>${NC} Check logs at ${DATAOUT}/logs/degrib.* .\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 + fi +done + +mv ${DIRRUN}/degrib.bash ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs +rm -fr ${DIRRUN} diff --git a/scripts/make_degrib.bash b/scripts/make_degrib_GFS.bash similarity index 62% rename from scripts/make_degrib.bash rename to scripts/make_degrib_GFS.bash index 6701f30..932dacd 100755 --- a/scripts/make_degrib.bash +++ b/scripts/make_degrib_GFS.bash @@ -1,7 +1,6 @@ #!/bin/bash - -if [ $# -ne 4 ] +if [ $# -ne 6 ] then echo "" echo "Instructions: execute the command below" @@ -14,7 +13,7 @@ then echo "LABELI :: Initial date YYYYMMDDHH, e.g.: 2024010100" echo "FCST :: Forecast hours, e.g.: 24 or 36, etc." echo "" - echo "24 hour forcast example:" + echo "24 hour forecast example:" echo "${0} GFS 1024002 2024010100 24" echo "${0} GFS 40962 2024010100 48" echo "" @@ -41,14 +40,19 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #MESH YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 FCST=${4}; #FCST=24 +REGIONAL=${5}; #REGIONAL=Y +LBCINT=${6}; #LBCINT=21600 #------------------------------------------------------- +source utils.bash # Local variables-------------------------------------- start_date=${YYYYMMDDHHi:0:4}-${YYYYMMDDHHi:4:2}-${YYYYMMDDHHi:6:2}_${YYYYMMDDHHi:8:2}:00:00 +YYYYMMDDHHf=$(add_hours "$YYYYMMDDHHi" "$FCST") +final_date=${YYYYMMDDHHf:0:4}-${YYYYMMDDHHf:4:2}-${YYYYMMDDHHf:6:2}_${YYYYMMDDHHf:8:2}:00:00 OPERDIREXP=${OPERDIR}/${EXP} BNDDIR=${OPERDIREXP}/0p25/brutos/${YYYYMMDDHHi:0:4}/${YYYYMMDDHHi:4:2}/${YYYYMMDDHHi:6:2}/${YYYYMMDDHHi:8:2} GCCCIS=/mnt/beegfs/monan/CIs/${EXP} @@ -69,15 +73,15 @@ then if [ ! -s ${GCCCIS}/${YYYYMMDDHHi:0:4}/${YYYYMMDDHHi}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2 ] then echo -e "${RED}==>${NC}Condicao de contorno inexistente !" - echo -e "${RED}==>${NC}Check ${BNDDIR} or." + echo -e "${RED}==>${NC}Check ${BNDDIR} or." echo -e "${RED}==>${NC}Check ${GCCCIS}" - exit 1 + exit 1 else BNDDIR=${GCCCIS}/${YYYYMMDDHHi:0:4}/${YYYYMMDDHHi} - fi + fi fi -files_needed=("${DATAIN}/fixed/x1.${RES}.static.nc" "${DATAIN}/fixed/Vtable.${EXP}" "${EXECS}/ungrib.exe" "${BNDDIR}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2") +files_needed=("${DATAIN}/fixed/${MESH}.static.nc" "${DATAIN}/fixed/Vtable.${EXP}" "${EXECS}/ungrib.exe" "${BNDDIR}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2") for file in "${files_needed[@]}" do if [ ! -s "${file}" ] @@ -88,16 +92,25 @@ do fi done -cp -f ${DATAIN}/fixed/x1.${RES}.static.nc ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.static.nc ${DIRRUN} cp -f ${DATAIN}/fixed/Vtable.${EXP} ${DIRRUN}/Vtable cp -f ${EXECS}/ungrib.exe ${DIRRUN} -cp -f ${BNDDIR}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2 ${DATAIN}/${YYYYMMDDHHi} cp -f ${SCRIPTS}/namelists/namelist.wps.TEMPLATE ${DIRRUN}/namelist.wps.TEMPLATE cp -f ${SCRIPTS}/setenv.bash ${DIRRUN} cp -f ${SCRIPTS}/link_grib.csh ${DIRRUN} rm -f ${DIRRUN}/degrib.bash -cat << EOF0 > ${DIRRUN}/degrib.bash + +if [[ $REGIONAL == "Y" ]]; then + echo "REGIONAL=Y. Degribbing GFS data for both initial and lateral boundary conditions..." + dt=$((LBCINT / 3600)) + hours=($(generate_hours_list "00" "$dt" "$FCST")) + for hour in "${hours[@]}"; do + echo "Temporarily copying GFS data: gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f0${hour}.${YYYYMMDDHHi}.grib2" + cp -f ${BNDDIR}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f0${hour}.${YYYYMMDDHHi}.grib2 ${DATAIN}/${YYYYMMDDHHi} + done + + cat << EOF0 > ${DIRRUN}/degrib.bash #!/bin/bash -x #SBATCH --job-name=${DEGRIB_jobname} #SBATCH --nodes=${DEGRIB_nnodes} @@ -126,16 +139,81 @@ ldd ungrib.exe rm -f GRIBFILE.* namelist.wps -sed -e "s,#LABELI#,${start_date},g;s,#PREFIX#,GFS,g" \ +sed -e "s,#LABELI#,${start_date},g;s,#LABELF#,${final_date},g;s,#LBCINT#,${LBCINT},g;s,#PREFIX#,GFS,g" \ ${DIRRUN}/namelist.wps.TEMPLATE > ${DIRRUN}/namelist.wps -./link_grib.csh ${DATAIN}/${YYYYMMDDHHi}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2 +./link_grib.csh ${DATAIN}/${YYYYMMDDHHi}/gfs.*.grib2 date time mpirun -np 1 ./ungrib.exe date +grep "Successful completion of program ungrib.exe" ${DIRRUN}/ungrib.log >& /dev/null + +if [ \$? -ne 0 ]; then + echo " BUMMER: Ungrib generation failed for some yet unknown reason." + echo " " + tail -10 ${DIRRUN}/ungrib.log + echo " " + exit 21 +fi + +# +# clean up and remove links +# + mv ungrib.log ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/ungrib.${start_date}.log + mv namelist.wps ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/namelist.${start_date}.wps + mv GFS* ${DATAOUT}/${YYYYMMDDHHi}/Pre + + rm -fr ${DATAIN}/${YYYYMMDDHHi} + +echo "End of degrib Job" + + +EOF0 + +elif [[ $REGIONAL == "N" ]]; then + echo "REGIONAL=N. Degribbing GFS data only for initial conditions..." + cp -f ${BNDDIR}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2 ${DATAIN}/${YYYYMMDDHHi} + cat << EOF0 > ${DIRRUN}/degrib.bash +#!/bin/bash -x +#SBATCH --job-name=${DEGRIB_jobname} +#SBATCH --nodes=${DEGRIB_nnodes} +#SBATCH --partition=${DEGRIB_QUEUE} +#SBATCH --ntasks=${DEGRIB_ncores} +#SBATCH --tasks-per-node=${DEGRIB_ncpn} # ic for benchmark +#SBATCH --time=${STATIC_walltime} +#SBATCH --output=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/degrib.o%j # File name for standard output +#SBATCH --error=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/degrib.e%j # File name for standard error output +# + +ulimit -s unlimited +ulimit -c unlimited +ulimit -v unlimited + +export PMIX_MCA_gds=hash + + +export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:${HOME}/local/lib64 + +cd ${DIRRUN} +. setenv.bash + +ldd ungrib.exe + +rm -f GRIBFILE.* namelist.wps + + +sed -e "s,#LABELI#,${start_date},g;s,#LABELF#,${start_date},g;s,#LBCINT#,${LBCINT},g;s,#PREFIX#,GFS,g" \ + ${DIRRUN}/namelist.wps.TEMPLATE > ${DIRRUN}/namelist.wps + +./link_grib.csh ${DATAIN}/${YYYYMMDDHHi}/gfs.t${YYYYMMDDHHi:8:2}z.pgrb2.0p25.f000.${YYYYMMDDHHi}.grib2 + +date +time mpirun -np 1 ./ungrib.exe +date + grep "Successful completion of program ungrib.exe" ${DIRRUN}/ungrib.log >& /dev/null if [ \$? -ne 0 ]; then @@ -159,6 +237,15 @@ echo "End of degrib Job" EOF0 + +else + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} LBCs phase fails during degrib! Please select REGIONAL=Y or REGIONAL=N so that degrib can be done appropriately.\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi + + chmod a+x ${DIRRUN}/degrib.bash echo -e "${GREEN}==>${NC} Executing sbatch degrib.bash...\n" diff --git a/scripts/make_initatmos.bash b/scripts/make_initatmos.bash index 0c28dde..2e1905e 100755 --- a/scripts/make_initatmos.bash +++ b/scripts/make_initatmos.bash @@ -1,7 +1,7 @@ #!/bin/bash -if [ $# -ne 4 ] +if [ $# -ne 5 ] then echo "" echo "Instructions: execute the command below" @@ -40,9 +40,10 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #RES=1024002 YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 FCST=${4}; #FCST=24 +REGIONAL=${5} #REGIONAL=Y #------------------------------------------------------- @@ -54,27 +55,31 @@ export DIRRUN=${DIRHOMED}/run.${YYYYMMDDHHi}; rm -fr ${DIRRUN}; mkdir -p ${DIRRU #------------------------------------------------------- mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs - -if [ ! -s ${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores} ] +if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ] then - if [ ! -s ${DATAIN}/fixed/x1.${RES}.graph.info ] + if [[ ${MESH} == x1.* ]] then + if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info ] + then + cd ${DATAIN}/fixed + echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}.tar.gz + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}_static.tar.gz + tar -xzvf ${MESH}.tar.gz + tar -xzvf ${MESH}_static.tar.gz + fi + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" cd ${DATAIN}/fixed - echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + rm -fr ${MESH}.tar.gz ${MESH}_static.tar.gz + else + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" cd ${DATAIN}/fixed - wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/x1.${RES}.tar.gz - wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/x1.${RES}_static.tar.gz - tar -xzvf x1.${RES}.tar.gz - tar -xzvf x1.${RES}_static.tar.gz + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} fi - echo -e "${GREEN}==>${NC} Creating x1.${RES}.graph.info.part.${cores} ... \n" - cd ${DATAIN}/fixed - gpmetis -minconn -contig -niter=200 x1.${RES}.graph.info ${cores} - rm -fr x1.${RES}.tar.gz x1.${RES}_static.tar.gz fi - -files_needed=("${SCRIPTS}/namelists/namelist.init_atmosphere.TEMPLATE" "${SCRIPTS}/namelists/streams.init_atmosphere.TEMPLATE" "${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores}" "${DATAIN}/fixed/x1.${RES}.static.nc" "${DATAOUT}/${YYYYMMDDHHi}/Pre/${EXP}:${start_date:0:13}" "${EXECS}/init_atmosphere_model") +files_needed=("${SCRIPTS}/namelists/namelist.init_atmosphere.TEMPLATE" "${SCRIPTS}/namelists/streams.init_atmosphere.TEMPLATE" "${DATAIN}/fixed/${MESH}.graph.info.part.${cores}" "${DATAIN}/fixed/${MESH}.static.nc" "${DATAOUT}/${YYYYMMDDHHi}/Pre/${EXP}:${start_date:0:13}" "${EXECS}/init_atmosphere_model") for file in "${files_needed[@]}" do if [ ! -s "${file}" ] @@ -85,16 +90,21 @@ do fi done +if [[ $REGIONAL == "Y" ]]; then + BLEND_BDY_TERRAIN=true +else + BLEND_BDY_TERRAIN=false +fi -sed -e "s,#LABELI#,${start_date},g;s,#GEODAT#,${GEODATA},g;s,#RES#,${RES},g" \ +sed -e "s,#LABELI#,${start_date},g;s,#GEODAT#,${GEODATA},g;s,#MESH#,${MESH},g;s,#EXP#,${EXP},g;s,#BLEND_BDY_TERRAIN#,${BLEND_BDY_TERRAIN},g" \ ${SCRIPTS}/namelists/namelist.init_atmosphere.TEMPLATE > ${DIRRUN}/namelist.init_atmosphere -sed -e "s,#RES#,${RES},g" \ +sed -e "s,#MESH#,${MESH},g" \ ${SCRIPTS}/namelists/streams.init_atmosphere.TEMPLATE > ${DIRRUN}/streams.init_atmosphere -cp -f ${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores} ${DIRRUN} -cp -f ${DATAIN}/fixed/x1.${RES}.static.nc ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.static.nc ${DIRRUN} cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/${EXP}\:${start_date:0:13} ${DIRRUN} cp -f ${EXECS}/init_atmosphere_model ${DIRRUN} @@ -131,10 +141,10 @@ time mpirun -np \${SLURM_NTASKS} ./\${executable} date -mv ${DIRRUN}/log.init_atmosphere.0000.out ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/log.init_atmosphere.0000.x1.${RES}.init.nc.${YYYYMMDDHHi}.out +mv ${DIRRUN}/log.init_atmosphere.0000.out ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/log.init_atmosphere.0000.${MESH}.init.nc.${YYYYMMDDHHi}.out mv ${DIRRUN}/namelist.init_atmosphere ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs mv ${DIRRUN}/streams.init_atmosphere ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs -mv ${DIRRUN}/x1.${RES}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Pre +mv ${DIRRUN}/${MESH}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Pre EOF0 chmod a+x ${DIRRUN}/initatmos.bash @@ -144,7 +154,7 @@ cd ${DIRRUN} sbatch --wait ${DIRRUN}/initatmos.bash mv ${DIRRUN}/initatmos.bash ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs -if [ ! -s ${DATAOUT}/${YYYYMMDDHHi}/Pre/x1.${RES}.init.nc ] +if [ ! -s ${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc ] then echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" echo -e "${RED}==>${NC} Init Atmosphere phase fails! Check logs at ${DATAOUT}/logs/initatmos.* .\n" diff --git a/scripts/make_initatmos_idealized.bash b/scripts/make_initatmos_idealized.bash new file mode 100755 index 0000000..4d62014 --- /dev/null +++ b/scripts/make_initatmos_idealized.bash @@ -0,0 +1,158 @@ +#!/bin/bash + + +if [ $# -ne 4 ] +then + echo "" + echo "Instructions: execute the command below" + echo "" + echo "${0} EXP_NAME RESOLUTION LABELI FCST" + echo "" + echo "EXP_NAME :: Forcing: GFS, ERA5, or IDEALIZED*, where * corresponds to the idealized test case number following MPAS user guide, section 7.1. Example: IDEALIZED2 ==> test case 2: Jablonowski and Williamson baroclinic wave, with initial perturbation" + echo " :: Others options to be added later..." + echo "RESOLUTION :: number of points in resolution model grid, e.g: 1024002 (24 km)" + echo "LABELI :: Initial date YYYYMMDDHH, e.g.: 2024010100" + echo "FCST :: Forecast hours, e.g.: 24 or 36, etc." + echo "" + echo "24 hour forcast example:" + echo "${0} GFS 1024002 2024010100 24" + echo "" + + exit +fi + +# Set environment variables exports: +echo "" +echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" +. setenv.bash + + +# Standart directories variables:--------------------------------------- +DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} +DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} +SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} +DATAIN=${DIRHOMED}/datain; mkdir -p ${DATAIN} +DATAOUT=${DIRHOMED}/dataout; mkdir -p ${DATAOUT} +SOURCES=${DIRHOMES}/sources; mkdir -p ${SOURCES} +EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} +#---------------------------------------------------------------------- + + +# Input variables:-------------------------------------- +EXP=${1}; #EXP=GFS +MESH=${2}; #RES=1024002 +YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 +FCST=${4}; #FCST=24 +#------------------------------------------------------- + + +# Local variables-------------------------------------- +start_date=${YYYYMMDDHHi:0:4}-${YYYYMMDDHHi:4:2}-${YYYYMMDDHHi:6:2}_${YYYYMMDDHHi:8:2}:00:00 +GEODATA=${DATAIN}/WPS_GEOG +cores=${INITATMOS_ncores} +export DIRRUN=${DIRHOMED}/run.${YYYYMMDDHHi}; rm -fr ${DIRRUN}; mkdir -p ${DIRRUN} +#------------------------------------------------------- +mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs + +if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ] +then + if [[ ${MESH} == x1.* ]] + then + if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info ] + then + cd ${DATAIN}/fixed + echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}.tar.gz + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}_static.tar.gz + tar -xzvf ${MESH}.tar.gz + tar -xzvf ${MESH}_static.tar.gz + fi + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" + cd ${DATAIN}/fixed + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + rm -fr ${MESH}.tar.gz ${MESH}_static.tar.gz + else + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" + cd ${DATAIN}/fixed + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + fi +fi + +files_needed=("${SCRIPTS}/namelists/namelist.init_atmosphere.TEMPLATE_IDEALIZED" "${SCRIPTS}/namelists/streams.init_atmosphere.TEMPLATE_IDEALIZED" "${DATAIN}/fixed/${MESH}.graph.info.part.${cores}" "${DATAIN}/fixed/${MESH}.grid.nc" "${EXECS}/init_atmosphere_model") +for file in "${files_needed[@]}" +do + if [ ! -s "${file}" ] + then + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} [${0}] At least the file ${file} was not generated. \n" + exit -1 + fi +done + + +sed -e "s,#LABELI#,${start_date},g;s,#TESTCASENUMBER#,"${EXP: -1}",g;s,#MESH#,${MESH},g" \ + ${SCRIPTS}/namelists/namelist.init_atmosphere.TEMPLATE_IDEALIZED > ${DIRRUN}/namelist.init_atmosphere + +sed -e "s,#MESH#,${MESH},g" \ + ${SCRIPTS}/namelists/streams.init_atmosphere.TEMPLATE_IDEALIZED > ${DIRRUN}/streams.init_atmosphere + + +cp -f ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.grid.nc ${DIRRUN} +cp -f ${EXECS}/init_atmosphere_model ${DIRRUN} + + +cp -f ${SCRIPTS}/setenv.bash ${DIRRUN} +rm -f ${DIRRUN}/initatmos.bash +cat << EOF0 > ${DIRRUN}/initatmos.bash +#!/bin/bash -x +#SBATCH --job-name=${INITATMOS_jobname} +#SBATCH --nodes=${INITATMOS_nnodes} # depends on how many boundary files are available +#SBATCH --partition=${INITATMOS_QUEUE} +#SBATCH --tasks-per-node=${INITATMOS_ncores} # only for benchmark +#SBATCH --time=${STATIC_walltime} +#SBATCH --output=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/initatmos.bash.o%j # File name for standard output +#SBATCH --error=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/initatmos.bash.e%j # File name for standard error output +#SBATCH --exclusive +##SBATCH --mem=500000 + +export executable=init_atmosphere_model + +ulimit -c unlimited +ulimit -v unlimited +ulimit -s unlimited + + +. $(pwd)/setenv.bash + +cd ${DIRRUN} + + + +date +time mpirun -np \${SLURM_NTASKS} ./\${executable} +date + + +mv ${DIRRUN}/log.init_atmosphere.0000.out ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/log.init_atmosphere.0000.${MESH}.init.nc.${YYYYMMDDHHi}.out +mv ${DIRRUN}/namelist.init_atmosphere ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs +mv ${DIRRUN}/streams.init_atmosphere ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs +mv ${DIRRUN}/${MESH}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Pre + +EOF0 +chmod a+x ${DIRRUN}/initatmos.bash + +echo -e "${GREEN}==>${NC} Executing sbatch initatmos.bash...\n" +cd ${DIRRUN} +sbatch --wait ${DIRRUN}/initatmos.bash +mv ${DIRRUN}/initatmos.bash ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs + +if [ ! -s ${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc ] +then + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} Init Atmosphere phase fails! Check logs at ${DATAOUT}/logs/initatmos.* .\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi + +rm -fr ${DIRRUN} diff --git a/scripts/make_lbcs.bash b/scripts/make_lbcs.bash new file mode 100755 index 0000000..078de5d --- /dev/null +++ b/scripts/make_lbcs.bash @@ -0,0 +1,164 @@ +#!/bin/bash + + +if [ $# -ne 5 ] +then + echo "" + echo "Instructions: execute the command below" + echo "" + echo "${0} EXP_NAME RESOLUTION LABELI FCST" + echo "" + echo "EXP_NAME :: Forcing: GFS" + echo " :: Others options to be added later..." + echo "RESOLUTION :: number of points in resolution model grid, e.g: 1024002 (24 km)" + echo "LABELI :: Initial date YYYYMMDDHH, e.g.: 2024010100" + echo "FCST :: Forecast hours, e.g.: 24 or 36, etc." + echo "" + echo "24 hour forcast example:" + echo "${0} GFS 1024002 2024010100 24" + echo "" + + exit +fi + +# Set environment variables exports: +echo "" +echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" +. setenv.bash + + +# Standart directories variables:--------------------------------------- +DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} +DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} +SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} +DATAIN=${DIRHOMED}/datain; mkdir -p ${DATAIN} +DATAOUT=${DIRHOMED}/dataout; mkdir -p ${DATAOUT} +SOURCES=${DIRHOMES}/sources; mkdir -p ${SOURCES} +EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} +#---------------------------------------------------------------------- + + +# Input variables:-------------------------------------- +EXP=${1}; #EXP=GFS +MESH=${2}; #RES=1024002 +YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 +FCST=${4}; #FCST=24 +LBCINT=${5} #LBCINT=3600 +#------------------------------------------------------- + +source utils.bash + +# Local variables-------------------------------------- +start_date=${YYYYMMDDHHi:0:4}-${YYYYMMDDHHi:4:2}-${YYYYMMDDHHi:6:2}_${YYYYMMDDHHi:8:2}:00:00 +YYYYMMDDHHf=$(add_hours "$YYYYMMDDHHi" "$FCST") +final_date=${YYYYMMDDHHf:0:4}-${YYYYMMDDHHf:4:2}-${YYYYMMDDHHf:6:2}_${YYYYMMDDHHf:8:2}:00:00 +GEODATA=${DATAIN}/WPS_GEOG +cores=${INITATMOS_ncores} +export DIRRUN=${DIRHOMED}/run.${YYYYMMDDHHi}; rm -fr ${DIRRUN}; mkdir -p ${DIRRUN} +#------------------------------------------------------- +mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs + +if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ] +then + if [[ ${MESH} == x1.* ]] + then + if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info ] + then + cd ${DATAIN}/fixed + echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}.tar.gz + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}_static.tar.gz + tar -xzvf ${MESH}.tar.gz + tar -xzvf ${MESH}_static.tar.gz + fi + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" + cd ${DATAIN}/fixed + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + rm -fr ${MESH}.tar.gz ${MESH}_static.tar.gz + else + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" + cd ${DATAIN}/fixed + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + fi +fi + +files_needed=("${SCRIPTS}/namelists/namelist.init_atmosphere.LBCS" "${SCRIPTS}/namelists/streams.init_atmosphere.LBCS" "${DATAIN}/fixed/${MESH}.graph.info.part.${cores}" "${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc" "${EXECS}/init_atmosphere_model") +for file in "${files_needed[@]}" +do + if [ ! -s "${file}" ] + then + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} [${0}] At least the file ${file} was not generated. \n" + exit -1 + fi +done + + +sed -e "s,#LABELI#,${start_date},g;s,#LABELF#,${final_date},g;s,#GEODAT#,${GEODATA},g;s,#LBCINT#,${LBCINT},g;s,#MESH#,${MESH},g;s,#EXP#,${EXP},g" \ + ${SCRIPTS}/namelists/namelist.init_atmosphere.LBCS > ${DIRRUN}/namelist.init_atmosphere + +sed -e "s,#MESH#,${MESH},g;s,#LBCINT#,${LBCINT},g" \ + ${SCRIPTS}/namelists/streams.init_atmosphere.LBCS > ${DIRRUN}/streams.init_atmosphere + + +cp -f ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ${DIRRUN} +cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/${MESH}.init.nc ${DIRRUN} +cp -f ${DATAOUT}/${YYYYMMDDHHi}/Pre/${EXP}\:* ${DIRRUN} +cp -f ${EXECS}/init_atmosphere_model ${DIRRUN} + + +cp -f ${SCRIPTS}/setenv.bash ${DIRRUN} +rm -f ${DIRRUN}/lbcs.bash +cat << EOF0 > ${DIRRUN}/lbcs.bash +#!/bin/bash -x +#SBATCH --job-name=${LBCS_jobname} +#SBATCH --nodes=${LBCS_nnodes} # depends on how many boundary files are available +#SBATCH --partition=${LBCS_QUEUE} +#SBATCH --tasks-per-node=${LBCS_ncores} # only for benchmark +#SBATCH --time=${STATIC_walltime} +#SBATCH --output=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/lbcs.bash.o%j # File name for standard output +#SBATCH --error=${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/lbcs.bash.e%j # File name for standard error output +#SBATCH --exclusive +##SBATCH --mem=500000 + +export executable=init_atmosphere_model + +ulimit -c unlimited +ulimit -v unlimited +ulimit -s unlimited + + +. $(pwd)/setenv.bash + +cd ${DIRRUN} + + + +date +time mpirun -np \${SLURM_NTASKS} ./\${executable} +date + + +mv ${DIRRUN}/log.init_atmosphere.0000.out ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/log.init_atmosphere.0000.${MESH}.lbcs.nc.${YYYYMMDDHHi}.out +mv ${DIRRUN}/namelist.init_atmosphere ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/namelist.init_atmosphere.lbcs +mv ${DIRRUN}/streams.init_atmosphere ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs/streams.init_atmosphere.lbcs +mv ${DIRRUN}/${MESH}.init.nc ${DATAOUT}/${YYYYMMDDHHi}/Pre +mv ${DIRRUN}/lbc*.nc ${DATAOUT}/${YYYYMMDDHHi}/Pre + +EOF0 +chmod a+x ${DIRRUN}/lbcs.bash + +echo -e "${GREEN}==>${NC} Executing sbatch lbcs.bash...\n" +cd ${DIRRUN} +sbatch --wait ${DIRRUN}/lbcs.bash +mv ${DIRRUN}/lbcs.bash ${DATAOUT}/${YYYYMMDDHHi}/Pre/logs + +if [ -z "$(ls ${DATAOUT}/${YYYYMMDDHHi}/Pre/lbc* 2>/dev/null)" ] +then + echo -e "\n${RED}==>${NC} ***** ATTENTION *****\n" + echo -e "${RED}==>${NC} LBC phase fails! Check logs at ${DATAOUT}/logs/lbcs.* .\n" + echo -e "${RED}==>${NC} Exiting script. \n" + exit -1 +fi + +rm -fr ${DIRRUN} diff --git a/scripts/make_static.bash b/scripts/make_static.bash index f5e0ee0..a6c1793 100755 --- a/scripts/make_static.bash +++ b/scripts/make_static.bash @@ -40,7 +40,7 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #RES=1024002 YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024012000 FCST=${4}; #FCST=24 #------------------------------------------------------- @@ -53,26 +53,32 @@ export DIRRUN=${DIRHOMED}/run.${YYYYMMDDHHi}; rm -fr ${DIRRUN}; mkdir -p ${DIRRU #------------------------------------------------------- -if [ ! -s ${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores} ] +if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ] then - if [ ! -s ${DATAIN}/fixed/x1.${RES}.graph.info ] + if [[ ${MESH} == x1.* ]] then + if [ ! -s ${DATAIN}/fixed/${MESH}.graph.info ] + then + cd ${DATAIN}/fixed + echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}.tar.gz + wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/${MESH}_static.tar.gz + tar -xzvf ${MESH}.tar.gz + tar -xzvf ${MESH}_static.tar.gz + fi + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" cd ${DATAIN}/fixed - echo -e "${GREEN}==>${NC} downloading meshes tgz files ... \n" - wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/x1.${RES}.tar.gz - wget https://www2.mmm.ucar.edu/projects/mpas/atmosphere_meshes/x1.${RES}_static.tar.gz - tar -xzvf x1.${RES}.tar.gz - tar -xzvf x1.${RES}_static.tar.gz + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} + rm -fr ${MESH}.tar.gz ${MESH}_static.tar.gz + else + echo -e "${GREEN}==>${NC} Creating ${MESH}.graph.info.part.${cores} ... \n" + cd ${DATAIN}/fixed + gpmetis -minconn -contig -niter=200 ${MESH}.graph.info ${cores} fi - echo -e "${GREEN}==>${NC} Creating x1.${RES}.graph.info.part.${cores} ... \n" - cd ${DATAIN}/fixed - gpmetis -minconn -contig -niter=200 x1.${RES}.graph.info ${cores} - rm -fr x1.${RES}.tar.gz x1.${RES}_static.tar.gz fi +files_needed=("${EXECS}/init_atmosphere_model" "${DATAIN}/fixed/${MESH}.graph.info.part.${cores}" "${DATAIN}/fixed/${MESH}.grid.nc" "${SCRIPTS}/namelists/namelist.init_atmosphere.STATIC" "${SCRIPTS}/namelists/streams.init_atmosphere.STATIC") - -files_needed=("${EXECS}/init_atmosphere_model" "${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores}" "${DATAIN}/fixed/x1.${RES}.grid.nc" "${SCRIPTS}/namelists/namelist.init_atmosphere.STATIC" "${SCRIPTS}/namelists/streams.init_atmosphere.STATIC") for file in "${files_needed[@]}" do if [ ! -s "${file}" ] @@ -86,14 +92,14 @@ done cp -f ${DATAIN}/fixed/*.TBL ${DIRRUN} cp -f ${DATAIN}/fixed/*.GFS ${DIRRUN} cp -f ${EXECS}/init_atmosphere_model ${DIRRUN} -cp -f ${DATAIN}/fixed/x1.${RES}.graph.info.part.${cores} ${DIRRUN} -cp -f ${DATAIN}/fixed/x1.${RES}.grid.nc ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.graph.info.part.${cores} ${DIRRUN} +cp -f ${DATAIN}/fixed/${MESH}.grid.nc ${DIRRUN} -sed -e "s,#GEODAT#,${GEODATA},g;s,#RES#,${RES},g" \ +sed -e "s,#GEODAT#,${GEODATA},g;s,#MESH#,${MESH},g" \ ${SCRIPTS}/namelists/namelist.init_atmosphere.STATIC \ > ${DIRRUN}/namelist.init_atmosphere -sed -e "s,#RES#,${RES},g" \ +sed -e "s,#MESH#,${MESH},g" \ ${SCRIPTS}/namelists/streams.init_atmosphere.STATIC \ > ${DIRRUN}/streams.init_atmosphere @@ -144,7 +150,7 @@ echo " ####################################" echo " " -mv log.init_atmosphere.0000.out ${DATAOUT}/logs/log.init_atmosphere.0000.x1.${RES}.static.nc.out +mv log.init_atmosphere.0000.out ${DATAOUT}/logs/log.init_atmosphere.0000.${MESH}.static.nc.out EOF0 @@ -157,11 +163,11 @@ sbatch --wait ${DIRRUN}/static.bash mv ${DIRRUN}/static.bash ${DATAOUT}/logs/ -if [ -s ${DIRRUN}/x1.${RES}.static.nc ] +if [ -s ${DIRRUN}/${MESH}.static.nc ] then - mv ${DIRRUN}/x1.${RES}.static.nc ${DATAIN}/fixed + mv ${DIRRUN}/${MESH}.static.nc ${DATAIN}/fixed else - echo -e "${RED}==>${NC} File ${DIRRUN}/x1.${RES}.static.nc was not created. \n" + echo -e "${RED}==>${NC} File ${DIRRUN}/${MESH}.static.nc was not created. \n" exit -1 fi diff --git a/scripts/make_template.bash b/scripts/make_template.bash index c71eb6a..d27a8b6 100755 --- a/scripts/make_template.bash +++ b/scripts/make_template.bash @@ -15,7 +15,7 @@ # #-----------------------------------------------------------------------------# -if [ $# -ne 4 -a $# -ne 1 ] +if [ $# -ne 5 -a $# -ne 1 ] then echo "" echo "Instructions: execute the command below" @@ -55,9 +55,10 @@ EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} # Input variables:-------------------------------------- EXP=${1}; #EXP=GFS -RES=${2}; #RES=1024002 +MESH=${2}; #RES=1024002 YYYYMMDDHHi=${3}; #YYYYMMDDHHi=2024042000 FCST=${4}; #FCST=40 +RES=${5} #------------------------------------------------------- mkdir -p ${DATAOUT}/${YYYYMMDDHHi}/Post/logs @@ -86,21 +87,21 @@ IFS=":" read -r h m s <<< "${t_strout}" printf -v t_strout "%02d:%02d:%02d" "$h" "$m" "$s" # Calculating default parameters for different resolutions -if [ $RES -eq 1024002 ]; then #24Km +if [ $RES -eq 24 ]; then #24Km NLAT=721 #180/0.25 NLON=1441 #360/0.25 STARTLAT=-90.0 STARTLON=0.0 ENDLAT=90.0 ENDLON=360.0 -elif [ $RES -eq 2621442 ]; then #15Km +elif [ $RES -eq 15 ]; then #15Km NLAT=1201 #180/0.15 NLON=2401 #360/0.15 STARTLAT=-90.0 STARTLON=0.0 ENDLAT=90.0 ENDLON=360.0 -elif [ $RES -eq 40962 ]; then #120Km +elif [ $RES -eq 120 ]; then #120Km NLAT=150 #180/1.2 NLON=300 #360/1.2 STARTLAT=-90.0 @@ -121,8 +122,8 @@ fi output_interval=${t_strouthor} nfiles=$(echo "$FCST/$output_interval + 1" | bc) -diag_name_post=MONAN_DIAG_G_POS_${EXP}_${YYYYMMDDHHi}_${YYYYMMDDHHi}.00.00.x${RES}L${NLEV}.nc -diag_name_templ=MONAN_DIAG_G_POS_${EXP}_${YYYYMMDDHHi}_%y4%m2%d2%h2.%n2.00.x${RES}L${NLEV}.nc +diag_name_post=MONAN_DIAG_G_POS_${EXP}_${YYYYMMDDHHi}_${YYYYMMDDHHi}.00.00.${MESH}L${NLEV}.nc +diag_name_templ=MONAN_DIAG_G_POS_${EXP}_${YYYYMMDDHHi}_%y4%m2%d2%h2.%n2.00.${MESH}L${NLEV}.nc rm -fr ${DIRRUN}/qctlinfo.gs cat > ${DIRRUN}/qctlinfo.gs < outer_radius +n_layers=8 +## High resolution for r < inner_radius +high_res=240 +## Low resolution for r > outer_radius +low_res=600 +## Whether to cut regional mesh (y/n) +do_regional=n +## Grid type (doughnut/constant) +grid_type=constant +# Automatic additions diff --git a/scripts/namelists/namelist.atmosphere.TEMPLATE b/scripts/namelists/namelist.atmosphere.TEMPLATE index bab5a89..9474190 100755 --- a/scripts/namelists/namelist.atmosphere.TEMPLATE +++ b/scripts/namelists/namelist.atmosphere.TEMPLATE @@ -13,7 +13,7 @@ config_h_theta_eddy_visc4 = 0.0 config_v_theta_eddy_visc2 = 0.0 config_horiz_mixing = '2d_smagorinsky' - config_len_disp = 0.0 + config_len_disp = #CONFIG_LEN_DISP# config_visc4_2dsmag = 0.05 config_w_adv_order = 3 config_theta_adv_order = 3 @@ -34,14 +34,14 @@ config_xnutr = 0.2 / &limited_area - config_apply_lbcs = false + config_apply_lbcs = #APPLY_LBCS# / &io config_pio_num_iotasks = 0 config_pio_stride = 1 / &decomposition - config_block_decomp_file_prefix = 'x1.#RES#.graph.info.part.' + config_block_decomp_file_prefix = '#MESH#.graph.info.part.' / &restart config_do_restart = false diff --git a/scripts/namelists/namelist.atmosphere.TEMPLATE_IDEALIZED b/scripts/namelists/namelist.atmosphere.TEMPLATE_IDEALIZED new file mode 100755 index 0000000..680ec34 --- /dev/null +++ b/scripts/namelists/namelist.atmosphere.TEMPLATE_IDEALIZED @@ -0,0 +1,45 @@ +&nhyd_model + config_dt = #CONFIG_DT# + config_start_time = '#LABELI#' + config_run_duration = '#FCSTS#' + config_split_dynamics_transport = false + config_number_of_sub_steps = 6 + config_dynamics_split_steps = 1 + config_h_mom_eddy_visc2 = 0.0 + config_h_mom_eddy_visc4 = 0.0 + config_v_mom_eddy_visc2 = 0.0 + config_h_theta_eddy_visc2 = 0.0 + config_h_theta_eddy_visc4 = 0.0 + config_v_theta_eddy_visc2 = 0.0 + config_horiz_mixing = '2d_smagorinsky' + config_len_disp = #CONFIG_LEN_DISP# + config_theta_adv_order = 3 + config_scalar_adv_order = 3 + config_u_vadv_order = 3 + config_w_vadv_order = 3 + config_theta_vadv_order = 3 + config_scalar_vadv_order = 3 + config_scalar_advection = false + config_positive_definite = false + config_monotonic = false + config_coef_3rd_order = 1. + config_epssm = 0.1 + config_smdiv = 0.1 +/ +&damping + config_zd = 22000.0 + config_xnutr = 0.0 +/ +&decomposition + config_block_decomp_file_prefix = '#MESH#.graph.info.part.' +/ +&restart + config_do_restart = false +/ +&printout + config_print_global_minmax_vel = true + config_print_detailed_minmax_vel = false +/ +&physics + config_physics_suite = 'none' +/ diff --git a/scripts/namelists/namelist.init_atmosphere.LBCS b/scripts/namelists/namelist.init_atmosphere.LBCS new file mode 100755 index 0000000..0405380 --- /dev/null +++ b/scripts/namelists/namelist.init_atmosphere.LBCS @@ -0,0 +1,48 @@ +&nhyd_model + config_init_case = 9 + config_start_time = '#LABELI#' + config_stop_time = '#LABELF#' + config_theta_adv_order = 3 + config_coef_3rd_order = 0.25 +/ +&dimensions + config_nvertlevels = 55 + config_nsoillevels = 4 + config_nfglevels = 35 + config_nfgsoillevels = 4 +/ +&data_sources + config_geog_data_path = '#GEODAT#' + config_met_prefix = '#EXP#' + config_sfc_prefix = 'SST' + config_fg_interval = #LBCINT# + config_landuse_data = 'MODIFIED_IGBP_MODIS_NOAH' + config_topo_data = 'GMTED2010' + config_use_spechumd = true +/ +&vertical_grid + config_ztop = 30000.0 + config_nsmterrain = 1 + config_smooth_surfaces = true + config_dzmin = 0.3 + config_nsm = 30 + config_tc_vertical_grid = true +/ +&interpolation_control + config_extrap_airtemp = 'linear' +/ +&preproc_stages + config_static_interp = false + config_native_gwd_static = false + config_vertical_grid = true + config_met_interp = true + config_input_sst = false + config_frac_seaice = true +/ +&io + config_pio_num_iotasks = 0 + config_pio_stride = 1 +/ +&decomposition + config_block_decomp_file_prefix = '#MESH#.graph.info.part.' +/ diff --git a/scripts/namelists/namelist.init_atmosphere.STATIC b/scripts/namelists/namelist.init_atmosphere.STATIC index 707fb7d..24e60b2 100755 --- a/scripts/namelists/namelist.init_atmosphere.STATIC +++ b/scripts/namelists/namelist.init_atmosphere.STATIC @@ -44,5 +44,5 @@ config_pio_stride = 1 / &decomposition - config_block_decomp_file_prefix = 'x1.#RES#.graph.info.part.' + config_block_decomp_file_prefix = '#MESH#.graph.info.part.' / diff --git a/scripts/namelists/namelist.init_atmosphere.TEMPLATE b/scripts/namelists/namelist.init_atmosphere.TEMPLATE index 2b560a1..9f22f88 100755 --- a/scripts/namelists/namelist.init_atmosphere.TEMPLATE +++ b/scripts/namelists/namelist.init_atmosphere.TEMPLATE @@ -13,7 +13,7 @@ / &data_sources config_geog_data_path = '#GEODAT#' - config_met_prefix = 'GFS' + config_met_prefix = '#EXP#' config_sfc_prefix = 'SST' config_fg_interval = 86400 config_landuse_data = 'MODIFIED_IGBP_MODIS_NOAH' @@ -27,6 +27,7 @@ config_dzmin = 0.3 config_nsm = 30 config_tc_vertical_grid = true + config_blend_bdy_terrain = #BLEND_BDY_TERRAIN# / &interpolation_control config_extrap_airtemp = 'linear' @@ -44,5 +45,5 @@ config_pio_stride = 1 / &decomposition - config_block_decomp_file_prefix = 'x1.#RES#.graph.info.part.' + config_block_decomp_file_prefix = '#MESH#.graph.info.part.' / diff --git a/scripts/namelists/namelist.init_atmosphere.TEMPLATE_IDEALIZED b/scripts/namelists/namelist.init_atmosphere.TEMPLATE_IDEALIZED new file mode 100755 index 0000000..f0b2522 --- /dev/null +++ b/scripts/namelists/namelist.init_atmosphere.TEMPLATE_IDEALIZED @@ -0,0 +1,10 @@ +&nhyd_model + config_init_case = #TESTCASENUMBER# + config_start_time = '#LABELI#' +/ +&dimensions + config_nvertlevels = 55 +/ +&decomposition + config_block_decomp_file_prefix = '#MESH#.graph.info.part.' +/ diff --git a/scripts/namelists/namelist.wps.TEMPLATE b/scripts/namelists/namelist.wps.TEMPLATE index 2aaff90..9694f11 100755 --- a/scripts/namelists/namelist.wps.TEMPLATE +++ b/scripts/namelists/namelist.wps.TEMPLATE @@ -2,8 +2,8 @@ wrf_core = 'ARW', max_dom = 1, start_date = '#LABELI#', - end_date = '#LABELI#', - interval_seconds = 10800, + end_date = '#LABELF#', + interval_seconds = #LBCINT#, io_form_geogrid = 2, debug_level = 0, / diff --git a/scripts/namelists/streams.atmosphere.TEMPLATE b/scripts/namelists/streams.atmosphere.TEMPLATE index c732433..bb62228 100755 --- a/scripts/namelists/streams.atmosphere.TEMPLATE +++ b/scripts/namelists/streams.atmosphere.TEMPLATE @@ -1,7 +1,7 @@ + filename_template="MONAN_HIST_G_MOD_#CIORIG#_#LABELI#_$Y$M$D$h.$m.$s.#MESH#L#NLEV#.nc" + output_interval="3:00:00" > @@ -28,7 +28,7 @@ @@ -37,9 +37,16 @@ + + diff --git a/scripts/namelists/streams.init_atmosphere.LBCS b/scripts/namelists/streams.init_atmosphere.LBCS new file mode 100755 index 0000000..8ead5cb --- /dev/null +++ b/scripts/namelists/streams.init_atmosphere.LBCS @@ -0,0 +1,20 @@ + + + + + + + diff --git a/scripts/namelists/streams.init_atmosphere.STATIC b/scripts/namelists/streams.init_atmosphere.STATIC index 29e4199..e63851a 100755 --- a/scripts/namelists/streams.init_atmosphere.STATIC +++ b/scripts/namelists/streams.init_atmosphere.STATIC @@ -1,18 +1,18 @@ diff --git a/scripts/namelists/streams.init_atmosphere.TEMPLATE b/scripts/namelists/streams.init_atmosphere.TEMPLATE index 10c9e91..4ff5455 100755 --- a/scripts/namelists/streams.init_atmosphere.TEMPLATE +++ b/scripts/namelists/streams.init_atmosphere.TEMPLATE @@ -1,18 +1,18 @@ diff --git a/scripts/namelists/streams.init_atmosphere.TEMPLATE_IDEALIZED b/scripts/namelists/streams.init_atmosphere.TEMPLATE_IDEALIZED new file mode 100755 index 0000000..b927116 --- /dev/null +++ b/scripts/namelists/streams.init_atmosphere.TEMPLATE_IDEALIZED @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/scripts/plot_mpas_grid.bash b/scripts/plot_mpas_grid.bash new file mode 100755 index 0000000..7dc5f2b --- /dev/null +++ b/scripts/plot_mpas_grid.bash @@ -0,0 +1,38 @@ +#!/bin/bash +#-----------------------------------------------------------------------------# +# !SCRIPT: run_post_on_mpas_grid +# +# !DESCRIPTION: +# Script to run the postprocessing of MONAN model using the original MPAS grid. +# +#-----------------------------------------------------------------------------# + + +# Set environment variables exports: +echo "" +echo -e "\033[1;32m==>\033[0m Moduling environment for MONAN model...\n" +. setenv.bash + + + +# Standart directories variables:--------------------------------------- +DIRHOMES=${DIR_SCRIPTS}/scripts_CD-CT; mkdir -p ${DIRHOMES} +DIRHOMED=${DIR_DADOS}/scripts_CD-CT; mkdir -p ${DIRHOMED} +export SCRIPTS=${DIRHOMES}/scripts; mkdir -p ${SCRIPTS} +DATAIN=${DIRHOMED}/datain; mkdir -p ${DATAIN} +DATAOUT=${DIRHOMED}/dataout; mkdir -p ${DATAOUT} +SOURCES=${DIRHOMES}/sources; mkdir -p ${SOURCES} +EXECS=${DIRHOMED}/execs; mkdir -p ${EXECS} +#---------------------------------------------------------------------- + + +# Local variables------------------------------------------------------ +## Grid file +GFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.nc +## Output directory and filename to save plot +POSTFILEPATH=${DATAIN}/fixed/lat_50_lon_-30_oradius_2800_iradius_2000_margin_800_hres_48_lres_240.region.grid.png +#--------------------------------------------------------------------- + +source ~/.bashrc +conda activate vtx_env +python3 ${SOURCES}/CGFD-USP-Post-Proc/mpas_plot_grid.py -g $GFILEPATH -o $POSTFILEPATH diff --git a/scripts/setenv.bash b/scripts/setenv.bash index 793df23..ffb9813 100755 --- a/scripts/setenv.bash +++ b/scripts/setenv.bash @@ -26,7 +26,7 @@ module list # Put your directories: export DIR_SCRIPTS=$(dirname $(dirname $(pwd))) export DIR_DADOS=$(dirname $(dirname $(pwd))) -export MONANDIR=/mnt/beegfs/carlos.souza/issues/735-tag-convert-teste/scripts_CD-CT/sources/MONAN-Model_release/1.4.1-rc +export MONANDIR=/mnt/beegfs/$USER/scripts_CD-CT/sources/MONAN-Model_release/1.4.1-rc # Submiting variables: @@ -54,11 +54,16 @@ export INITATMOS_nnodes=1 export INITATMOS_jobname="Pre.InitAtmos" ### export INITATMOS_walltime="01:00:00" not used yet - using STATIC_walltime +# PRE-LBCs phase: +export LBCS_QUEUE="batch" +export LBCS_ncores=64 +export LBCS_nnodes=1 +export LBCS_jobname="Pre.LBCS" # Model phase: export MODEL_QUEUE="batch" -export MODEL_ncores=512 -export MODEL_nnodes=8 +export MODEL_ncores=256 +export MODEL_nnodes=4 export MODEL_ncpn=64 export MODEL_jobname="Model.MONAN" export MODEL_walltime="8:00:00" diff --git a/scripts/utils.bash b/scripts/utils.bash new file mode 100755 index 0000000..289a74b --- /dev/null +++ b/scripts/utils.bash @@ -0,0 +1,54 @@ +#!/bin/bash + +# Function to add or subtract hours to a given date in YYYYMMDDHH format +add_hours() { + # Built using duck.ai + # Check if the correct number of arguments is provided + if [ "$#" -ne 2 ]; then + echo "Usage: add_hours YYYYMMDDHH HOURS" + return 1 + fi + + # Extract arguments + input_date=$1 + hours_to_add=$2 + + # Create a date string from the input + date_string="${input_date:0:8} ${input_date:8:2}:00" + + # Convert input date to a UTC format that date command can understand + formatted_date=$(date -u -d "$date_string" +"%Y-%m-%d %H:%M:%S") + + # Check if the date command recognized the date + if [ $? -ne 0 ]; then + echo "Invalid date format. Please use YYYYMMDDHH format." + return 1 + fi + + # Add or subtract hours + new_date=$(date -u -d "${formatted_date} ${hours_to_add} hours" +"%Y%m%d%H") + + # Output the new date and hour + echo "$new_date" +} + +# Subroutine to generate a list of forecast hour strings +generate_hours_list() { + # Built using duck.ai + local start_hour="$1" + local dt="$2" + local max_hour="$3" # Set a maximum limit for forecast hours + local hour_list=() # Initialize an empty array for the forecast list + + # Convert start_hour to an integer + local current_hour=$(printf '%d' "$start_hour") + + # Loop to generate forecast hours + while [ "$current_hour" -le "$max_hour" ]; do + hour_list+=($(printf '%02d' "$current_hour")) # Format hour as two digits + current_hour=$((current_hour + dt)) # Increment by dt + done + + # Return the array + echo "${hour_list[@]}" +} diff --git a/sources/CGFD-USP-Create-Mesh/envs/vtx_env.yaml b/sources/CGFD-USP-Create-Mesh/envs/vtx_env.yaml new file mode 100644 index 0000000..3fed832 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/envs/vtx_env.yaml @@ -0,0 +1,329 @@ +name: vtx_env +channels: + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=conda_forge + - _openmp_mutex=4.5=2_kmp_llvm + - abseil-cpp=20211102.0=hd4dd3e8_0 + - alabaster=0.7.12=pyhd3eb1b0_0 + - anyio=3.5.0=py310h06a4308_0 + - aom=3.6.0=h6a678d5_0 + - argon2-cffi=21.3.0=pyhd3eb1b0_0 + - argon2-cffi-bindings=21.2.0=py310h7f8727e_0 + - arpack=3.8.0=nompi_h0baa96a_101 + - arrow-cpp=11.0.0=h374c478_2 + - asciitree=0.3.3=py_2 + - asttokens=2.0.5=pyhd3eb1b0_0 + - attrs=23.1.0=py310h06a4308_0 + - aws-c-common=0.6.8=h5eee18b_1 + - aws-c-event-stream=0.1.6=h6a678d5_6 + - aws-checksums=0.1.11=h5eee18b_2 + - aws-sdk-cpp=1.8.185=h721c034_1 + - babel=2.11.0=py310h06a4308_0 + - backcall=0.2.0=pyhd3eb1b0_0 + - beautifulsoup4=4.12.2=py310h06a4308_0 + - blas=2.116=openblas + - blas-devel=3.9.0=16_linux64_openblas + - bleach=4.1.0=pyhd3eb1b0_0 + - blosc=1.21.5=h0f2a231_0 + - bokeh=3.2.1=py310h2f386ee_0 + - boost-cpp=1.82.0=hdb19cb5_2 + - bottleneck=1.3.5=py310ha9d4c09_0 + - brotli=1.0.9=h5eee18b_7 + - brotli-bin=1.0.9=h5eee18b_7 + - brotlipy=0.7.0=py310h7f8727e_1002 + - brunsli=0.1=h2531618_0 + - bzip2=1.0.8=h7b6447c_0 + - c-ares=1.19.1=h5eee18b_0 + - ca-certificates=2023.7.22=hbcca054_0 + - cairo=1.18.0=h3faef2a_0 + - cartopy=0.21.1=py310h1176785_0 + - cdo=2.3.0=h24bcfa3_0 + - certifi=2023.7.22=pyhd8ed1ab_0 + - cffi=1.15.1=py310h5eee18b_3 + - cfitsio=3.470=h5893167_7 + - cftime=1.6.2=py310ha9d4c09_0 + - charls=2.2.0=h2531618_0 + - charset-normalizer=2.0.4=pyhd3eb1b0_0 + - click=8.0.4=py310h06a4308_0 + - cloudpickle=2.2.1=py310h06a4308_0 + - cmocean=3.0.3=pyhd8ed1ab_0 + - colorama=0.4.6=py310h06a4308_0 + - colorspacious=1.1.2=pyh24bf2e0_0 + - comm=0.1.2=py310h06a4308_0 + - contourpy=1.0.5=py310hdb19cb5_0 + - cryptography=41.0.3=py310hdda0065_0 + - cycler=0.11.0=pyhd3eb1b0_0 + - cytoolz=0.12.0=py310h5eee18b_0 + - dask=2023.6.0=py310h06a4308_0 + - dask-core=2023.6.0=py310h06a4308_0 + - dav1d=1.2.1=h5eee18b_0 + - debugpy=1.6.7=py310h6a678d5_0 + - decorator=5.1.1=pyhd3eb1b0_0 + - defusedxml=0.7.1=pyhd3eb1b0_0 + - distributed=2023.6.0=py310h06a4308_0 + - docutils=0.18.1=py310h06a4308_3 + - eccodes=2.32.1=h35c6de3_0 + - entrypoints=0.4=py310h06a4308_0 + - exceptiongroup=1.0.4=py310h06a4308_0 + - executing=0.8.3=pyhd3eb1b0_0 + - expat=2.5.0=hcb278e6_1 + - fasteners=0.16.3=pyhd3eb1b0_0 + - fftw=3.3.10=nompi_hc118613_108 + - findlibs=0.0.5=pyhd8ed1ab_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=hab24e00_0 + - fontconfig=2.14.2=h14ed4e7_0 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - freeglut=3.2.2=hac7e632_2 + - freetype=2.12.1=h4a9f257_0 + - fribidi=1.0.10=h36c2ea0_0 + - fsspec=2023.9.2=py310h06a4308_0 + - geographiclib=1.52=pyhd8ed1ab_0 + - geometric_features=1.3.0=pyhd8ed1ab_0 + - geopy=2.4.0=pyhd8ed1ab_0 + - geos=3.8.0=he6710b0_0 + - gettext=0.21.1=h27087fc_0 + - gflags=2.2.2=he6710b0_0 + - giflib=5.2.1=h5eee18b_3 + - glog=0.5.0=h2531618_0 + - glpk=5.0=h445213a_0 + - gmp=6.2.1=h295c915_3 + - graphite2=1.3.13=h58526e2_1001 + - grpc-cpp=1.48.2=he1ff14a_1 + - harfbuzz=8.2.1=h3d44ed6_0 + - hdf4=4.2.15=h9772cbc_5 + - hdf5=1.14.2=nompi_h4f84152_100 + - heapdict=1.0.1=pyhd3eb1b0_0 + - icu=73.2=h59595ed_0 + - idna=3.4=py310h06a4308_0 + - imagecodecs=2023.1.23=py310hc4b7b5f_0 + - imageio=2.31.4=py310h06a4308_0 + - imagesize=1.4.1=py310h06a4308_0 + - importlib-metadata=6.0.0=py310h06a4308_0 + - importlib_resources=5.2.0=pyhd3eb1b0_1 + - inpoly=0.2.0=py310h0a54255_5 + - ipykernel=6.25.0=py310h2f386ee_0 + - ipython=8.15.0=py310h06a4308_0 + - ipython_genutils=0.2.0=pyhd3eb1b0_1 + - jasper=4.0.0=h0ff4b12_0 + - jedi=0.18.1=py310h06a4308_1 + - jigsawpy=0.3.3=pyhd8ed1ab_2 + - jinja2=3.1.2=py310h06a4308_0 + - joblib=1.2.0=py310h06a4308_0 + - jpeg=9e=h5eee18b_1 + - jsonschema=4.17.3=py310h06a4308_0 + - jupyter_client=7.4.9=py310h06a4308_0 + - jupyter_core=5.3.0=py310h06a4308_0 + - jupyter_server=1.23.4=py310h06a4308_0 + - jupyterlab_pygments=0.1.2=py_0 + - jxrlib=1.1=h7b6447c_2 + - kiwisolver=1.4.4=py310h6a678d5_0 + - krb5=1.20.1=h143b758_1 + - lazy_loader=0.3=py310h06a4308_0 + - lcms2=2.12=h3be6417_0 + - ld_impl_linux-64=2.38=h1181459_1 + - lerc=3.0=h295c915_0 + - libaec=1.1.2=h59595ed_1 + - libavif=0.11.1=h5eee18b_0 + - libblas=3.9.0=16_linux64_openblas + - libboost=1.82.0=h109eef0_2 + - libbrotlicommon=1.0.9=h5eee18b_7 + - libbrotlidec=1.0.9=h5eee18b_7 + - libbrotlienc=1.0.9=h5eee18b_7 + - libcblas=3.9.0=16_linux64_openblas + - libcurl=8.4.0=h251f7ec_0 + - libdeflate=1.17=h5eee18b_1 + - libedit=3.1.20221030=h5eee18b_0 + - libev=4.33=h7f8727e_1 + - libevent=2.1.12=hdbd6064_1 + - libexpat=2.5.0=hcb278e6_1 + - libffi=3.4.4=h6a678d5_0 + - libgcc-ng=13.2.0=h807b86a_2 + - libgfortran-ng=13.2.0=h69a702a_2 + - libgfortran5=13.2.0=ha4646dd_2 + - libglib=2.78.1=hebfc3b9_0 + - libglu=9.0.0=hac7e632_1003 + - libiconv=1.17=h166bdaf_0 + - liblapack=3.9.0=16_linux64_openblas + - liblapacke=3.9.0=16_linux64_openblas + - libnetcdf=4.9.2=nompi_h80fb2b6_112 + - libnghttp2=1.57.0=h2d74bed_0 + - libnsl=2.0.1=hd590300_0 + - libopenblas=0.3.21=pthreads_h78a6416_3 + - libpng=1.6.39=h5eee18b_0 + - libprotobuf=3.20.3=he621ea3_0 + - libsodium=1.0.18=h7b6447c_0 + - libsqlite=3.44.0=h2797004_0 + - libssh2=1.10.0=hdbd6064_2 + - libstdcxx-ng=13.2.0=h7e041cc_2 + - libthrift=0.15.0=h1795dd8_2 + - libtiff=4.5.1=h6a678d5_0 + - libudunits2=2.2.28=h40f5838_3 + - libuuid=2.38.1=h0b41bf4_0 + - libwebp=1.3.2=h11a3e52_0 + - libwebp-base=1.3.2=h5eee18b_0 + - libxcb=1.15=h0b41bf4_0 + - libxml2=2.11.5=h232c23b_1 + - libzip=1.10.1=h2629f0a_3 + - libzlib=1.2.13=hd590300_5 + - libzopfli=1.0.3=he6710b0_0 + - llvm-openmp=14.0.6=h9e868ea_0 + - locket=1.0.0=py310h06a4308_0 + - lz4=4.3.2=py310h5eee18b_0 + - lz4-c=1.9.4=h6a678d5_0 + - magics=4.14.2=haee2765_1 + - magics-python=1.5.8=pyhd8ed1ab_1 + - markupsafe=2.1.1=py310h7f8727e_0 + - matplotlib-base=3.7.2=py310h1128e8f_0 + - matplotlib-inline=0.1.6=py310h06a4308_0 + - mistune=0.8.4=py310h7f8727e_1000 + - mock=4.0.3=pyhd3eb1b0_0 + - mpas_tools=0.27.0=py310hff011f2_0 + - msgpack-python=1.0.3=py310hd09550d_0 + - munkres=1.1.4=py_0 + - nbclassic=0.5.5=py310h06a4308_0 + - nbclient=0.5.13=py310h06a4308_0 + - nbconvert=6.4.4=py310h06a4308_0 + - nbformat=5.9.2=py310h06a4308_0 + - ncurses=6.4=h6a678d5_0 + - nest-asyncio=1.5.6=py310h06a4308_0 + - netcdf-fortran=4.6.1=nompi_hacb5139_102 + - netcdf4=1.6.5=nompi_py310hba70d50_100 + - networkx=3.1=py310h06a4308_0 + - notebook=6.5.4=py310h06a4308_1 + - notebook-shim=0.2.2=py310h06a4308_0 + - numcodecs=0.11.0=py310h6a678d5_0 + - numexpr=2.8.7=py310h286c3b5_0 + - numpy=1.26.0=py310heeff2f4_0 + - numpy-base=1.26.0=py310h8a23956_0 + - openblas=0.3.21=pthreads_h320a7e8_3 + - openjpeg=2.4.0=h3ad879b_0 + - openssl=3.1.4=hd590300_0 + - orc=1.7.4=hb3bc3d3_1 + - packaging=23.1=py310h06a4308_0 + - pandas=2.0.3=py310h1128e8f_0 + - pandocfilters=1.5.0=pyhd3eb1b0_0 + - pango=1.50.14=ha41ecd1_2 + - parso=0.8.3=pyhd3eb1b0_0 + - partd=1.4.0=py310h06a4308_0 + - pcre2=10.40=hc3806b6_0 + - pexpect=4.8.0=pyhd3eb1b0_3 + - pickleshare=0.7.5=pyhd3eb1b0_1003 + - pillow=10.0.1=py310ha6cbd5a_0 + - pip=23.2.1=py310h06a4308_0 + - pixman=0.42.2=h59595ed_0 + - platformdirs=3.10.0=py310h06a4308_0 + - progressbar2=4.2.0=py310h06a4308_0 + - proj=9.3.0=ha643af7_0 + - prometheus_client=0.14.1=py310h06a4308_0 + - prompt-toolkit=3.0.36=py310h06a4308_0 + - psutil=5.9.0=py310h5eee18b_0 + - pthread-stubs=0.4=h36c2ea0_1001 + - ptyprocess=0.7.0=pyhd3eb1b0_2 + - pure_eval=0.2.2=pyhd3eb1b0_0 + - pyamg=4.2.3=py310h3c18c91_0 + - pyarrow=11.0.0=py310h468efa6_1 + - pycparser=2.21=pyhd3eb1b0_0 + - pyevtk=1.6.0=pyha21a80b_0 + - pygments=2.15.1=py310h06a4308_1 + - pyopenssl=23.2.0=py310h06a4308_0 + - pyparsing=3.0.9=py310h06a4308_0 + - pyproj=3.6.1=py310h32c33b7_4 + - pyrsistent=0.18.0=py310h7f8727e_0 + - pyshp=2.1.3=pyhd3eb1b0_0 + - pysocks=1.7.1=py310h06a4308_0 + - python=3.10.12=hd12c33a_0_cpython + - python-dateutil=2.8.2=pyhd3eb1b0_0 + - python-fastjsonschema=2.16.2=py310h06a4308_0 + - python-igraph=0.10.8=py310h1e3ba49_1 + - python-lmdb=1.4.1=py310h6a678d5_0 + - python-tzdata=2023.3=pyhd3eb1b0_0 + - python-utils=3.3.3=py310h06a4308_0 + - python_abi=3.10=2_cp310 + - pytz=2023.3.post1=py310h06a4308_0 + - pywavelets=1.4.1=py310h5eee18b_0 + - pyyaml=6.0=py310h5eee18b_1 + - pyzmq=23.2.0=py310h6a678d5_0 + - re2=2022.04.01=h295c915_0 + - readline=8.2=h5eee18b_0 + - requests=2.31.0=py310h06a4308_0 + - scikit-image=0.20.0=py310h6a678d5_0 + - scikit-learn=1.3.0=py310h1128e8f_0 + - scipy=1.11.3=py310heeff2f4_0 + - seaborn=0.12.2=py310h06a4308_0 + - send2trash=1.8.0=pyhd3eb1b0_1 + - setuptools=68.0.0=py310h06a4308_0 + - shapely=2.0.1=py310h006c72b_0 + - simplejson=3.19.2=py310h2372a71_0 + - six=1.16.0=pyhd3eb1b0_1 + - snappy=1.1.10=h9fff704_0 + - sniffio=1.2.0=py310h06a4308_1 + - snowballstemmer=2.2.0=pyhd3eb1b0_0 + - sortedcontainers=2.4.0=pyhd3eb1b0_0 + - soupsieve=2.5=py310h06a4308_0 + - sphinx=5.0.2=py310h06a4308_0 + - sphinx_rtd_theme=1.1.1=py310h06a4308_0 + - sphinxcontrib-applehelp=1.0.2=pyhd3eb1b0_0 + - sphinxcontrib-devhelp=1.0.2=pyhd3eb1b0_0 + - sphinxcontrib-htmlhelp=2.0.0=pyhd3eb1b0_0 + - sphinxcontrib-jsmath=1.0.1=pyhd3eb1b0_0 + - sphinxcontrib-qthelp=1.0.3=pyhd3eb1b0_0 + - sphinxcontrib-serializinghtml=1.1.5=pyhd3eb1b0_0 + - sqlite=3.41.2=h5eee18b_0 + - stack_data=0.2.0=pyhd3eb1b0_0 + - tblib=1.7.0=pyhd3eb1b0_0 + - terminado=0.17.1=py310h06a4308_0 + - testpath=0.6.0=py310h06a4308_0 + - texttable=1.6.4=pyhd3eb1b0_0 + - threadpoolctl=2.2.0=pyh0d69192_0 + - tifffile=2023.4.12=py310h06a4308_0 + - tk=8.6.12=h1ccaba5_0 + - toolz=0.12.0=py310h06a4308_0 + - tornado=6.3.2=py310h5eee18b_0 + - traitlets=5.7.1=py310h06a4308_0 + - typing-extensions=4.7.1=py310h06a4308_0 + - typing_extensions=4.7.1=py310h06a4308_0 + - tzdata=2023c=h04d1e81_0 + - udunits2=2.2.28=h40f5838_3 + - urllib3=1.26.16=py310h06a4308_0 + - utf8proc=2.6.1=h27cfd23_0 + - wcwidth=0.2.5=pyhd3eb1b0_0 + - webencodings=0.5.1=py310h06a4308_1 + - websocket-client=0.58.0=py310h06a4308_4 + - wheel=0.41.2=py310h06a4308_0 + - xarray=2023.6.0=py310h06a4308_0 + - xorg-fixesproto=5.0=h7f98852_1002 + - xorg-inputproto=2.3.2=h7f98852_1002 + - xorg-kbproto=1.0.7=h7f98852_1002 + - xorg-libice=1.1.1=hd590300_0 + - xorg-libsm=1.2.4=h7391055_0 + - xorg-libx11=1.8.7=h8ee46fc_0 + - xorg-libxau=1.0.11=hd590300_0 + - xorg-libxdmcp=1.1.3=h7f98852_0 + - xorg-libxext=1.3.4=h0b41bf4_2 + - xorg-libxfixes=5.0.3=h7f98852_1004 + - xorg-libxi=1.7.10=h7f98852_0 + - xorg-libxrender=0.9.11=hd590300_0 + - xorg-renderproto=0.11.1=h7f98852_1002 + - xorg-xextproto=7.3.0=h0b41bf4_1003 + - xorg-xproto=7.0.31=h7f98852_1007 + - xyzservices=2022.9.0=py310h06a4308_1 + - xz=5.4.2=h5eee18b_0 + - yaml=0.2.5=h7b6447c_0 + - zarr=2.13.3=py310h06a4308_0 + - zeromq=4.3.4=h2531618_0 + - zfp=1.0.0=h6a678d5_0 + - zict=3.0.0=py310h06a4308_0 + - zipp=3.11.0=py310h06a4308_0 + - zlib=1.2.13=hd590300_5 + - zstd=1.5.5=hc292b87_0 + - pip: + - cdsapi==0.6.1 + - fonttools==4.43.1 + - jigsaw==3.2.1 + - tqdm==4.66.1 diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/README.md b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/README.md new file mode 100644 index 0000000..f70e2ff --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/README.md @@ -0,0 +1,63 @@ +# vtx-mpas-meshes +Creation and analysis of MPAS-WRF meshes by Vortex + + +Work under progress. +Example of regional mesh: +![example_mesh.png](example_mesh.png) + +Created by Marta Gil Bardají. +Contact email: marta.gil@vortexfdc.com + +## Installation Guide + +To obtain a local copy of the code, clone this github repository [meshes]. Note that you need permission to do so. + + $ git clone git@github.com:marta-gil/vtx-mpas-meshes.git + +The necessary conda environment can be created using the ``environment.yml`` file present in the **vtx-mpas-meshes** repository cloned from github: + + $ conda env create -n -f + +The conda environment contains: +* mpas-tools & jigsaw for mesh creation +* xarray, geopy, cartopy for mesh visualization +* packages for documentation +* jupyter notebook + +The environment should be activated to run the scripts in this repository. + + $ conda activate + +Then you can install the scripts of this repository by installing the `vtxmpasmeshes` source files using the `setup.py` file. + + () $ pyhton setup.py install + +To be able to run the Jupyter Notebooks, add the environment to ipykernel: + + () $ python -m ipykernel install --user --name= + +and a successful message similar to this should appear: + + Installed kernelspec in /home//.local/share/jupyter/kernels/ + +[meshes]: https://github.com/marta-gil/vtx-mpas-meshes.git + +## Mesh generation + +Creates global and regional MPAS meshes based on global latlon resolution maps. The focus is on symmetric resolutions that are highest at a certain area of the planet and decrease radially. + +![example_resolution.png](example_resolution.png) + +Based on https://github.com/pedrospeixoto/MPAS-PXT/blob/master/grids/utilities/jigsaw/spherical_grid.py by Pedro S. Peixoto ppeixoto@usp.br. + +It uses: +* MPAS-Tools http://mpas-dev.github.io/MPAS-Tools/stable/mesh_creation.html#spherical-meshes +* jigsaw: https://github.com/dengwirda/jigsaw-python/tree/master/tests + + + + + + + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/__init__.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/dataset_utilities.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/dataset_utilities.py new file mode 100644 index 0000000..5c99e37 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/dataset_utilities.py @@ -0,0 +1,534 @@ +import numpy as np +import xarray as xr +import math +from geopy.distance import distance + + +derived_variables = { + 'latCell': ['latitude'], + 'lonCell': ['longitude'], + 'latVertex': ['latitudeVertex'], + 'lonVertex': ['longitudeVertex'], + 'areaCell': ['area', 'resolution'], +} + + +def distance_latlon_matrix(lat, lon, lat_ref=0., lon_ref=0., do_tile=False): + if do_tile: + lat = np.tile(lat, (len(lon), 1)).transpose() + lon = np.tile(lon, (len(lat), 1)) + + lon, lat, lon_ref, lat_ref = map(np.radians, [lon, lat, lon_ref, lat_ref]) + + newlon = lon_ref - lon + newlat = lat_ref - lat + + haver_formula = np.sin(newlat / 2.0) ** 2 + np.cos(lat) * \ + np.cos(lat_ref) * np.sin(newlon / 2.0) ** 2 + + dist = 2 * np.arcsin(np.sqrt(haver_formula)) + km = 6367 * dist # 6367 for distance in KM for miles use 3958 + return km + + +def add_mpas_mesh_variables(ds, full=True, **kwargs): + for v in ds.data_vars: + if v not in derived_variables: + continue + + newvs = derived_variables[v] + + for newv in newvs: + if newv in ds: + #print(newv + ' already here') + continue + + if 'lat' in v or 'lon' in v: + ds[newv] = xr.apply_ufunc(np.rad2deg, ds[v]) + ds[newv] = ds[newv].where(ds[newv] <= 180.0, ds[newv] - 360.0) + ds[newv].attrs['units'] = 'degrees' + + elif newv == 'area': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1: + #print('need to correct to earth radius!!') + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + ds[newv] = (ds[v] / 10 ** 6) * correction_rad_earth**2 + ds[newv].attrs['units'] = 'km^2 (assuming areaCell in m^2)' + ds[newv].attrs['long_name'] = 'Area of the cell in km^2' + + elif newv == 'resolution': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1.0: + #print('need to correct to earth radius!!') + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + # km^2 (assuming areaCell in m^2) + area = (ds[v] / 10 ** 6) * correction_rad_earth**2 + + ds[newv] = 2 * (xr.apply_ufunc(np.sqrt, area / math.pi)) + ds[newv].attrs['units'] = 'km' + ds[newv].attrs['long_name'] = 'Resolution of the cell (approx)' + + if full: + ref_point = {} + for v in ['lat_ref', 'lon_ref']: + if v in kwargs: + ref_point[v] = kwargs[v] + ds = add_distance_to_reference(ds, **ref_point) + + ds = compute_metrics_edge_lengths(ds) + ds = compute_metrics_triangle_quality(ds) + + return ds + + +def get_center(lats, lons): + """ + Given 2 DataArrays of lats, lons, it returns the grid center lat, + lon. + :param lats: DataArray of latitudes + :param lons: DataArray of longitudes + :return: lat, lon: floats + """ + + lat = float(lats[abs(lats - lats.mean()).argmin()]) + lon = float(lons[abs(lons - lons.mean()).argmin()]) + + return lat, lon + + +def get_distance_to_center(lats, lons, + center_lat=None, center_lon=None): + """ + Using the haversine formula (spherical distance), it returns the + distance in km of each lat, lon point to the + central point. + """ + if center_lat is None or center_lon is None: + center_lat, center_lon = get_center(lats, lons) + + radius = 6371. # km + d_lat = np.radians(lats - center_lat) # lat distance in radians + d_lon = np.radians(lons - center_lon) # lon distance in radians + + a = (np.sin(d_lat / 2.) * np.sin(d_lat / 2.) + + np.cos(np.radians(center_lat)) * np.cos(np.radians(lats)) * + np.sin(d_lon / 2.) * np.sin(d_lon / 2.)) + c = 2. * np.arctan2(np.sqrt(a), np.sqrt(1. - a)) + d = radius * c + + return d + + +def compute_metrics_edge_lengths(ds): + distances = [] + + for i, cell in enumerate(ds['nCells'].values): + vals = ds['verticesOnCell'].sel(nCells=cell).values + + num_sides = int(ds['nEdgesOnCell'].sel(nCells=cell)) + vals = vals[:num_sides] - 1 + lats = ds['latitudeVertex'].values[vals] + lons = ds['longitudeVertex'].values[vals] + lat_ref = lats[-1] + lon_ref = lons[-1] + + my_cell_dists = [] + for i in range(ds.dims['maxEdges']): + if i >= num_sides: + my_cell_dists.append(np.nan) + continue + d = distance_latlon_matrix(lats[i], lons[i], + lat_ref=lat_ref, + lon_ref=lon_ref, do_tile=False) + + my_cell_dists.append(d) + lat_ref, lon_ref = lats[i], lons[i] + distances.append(my_cell_dists) + + ds['edgesLength'] = xr.DataArray(data=distances, + dims=('nCells', 'maxEdges')) + ds['edgesLength'].attrs = { + 'name': 'Length of edges', + 'units': 'km', + 'long_name': 'Haversine distance between adjacent vertices of a cell.' + } + + ds['mean_edgesLength'] = ds['edgesLength'].mean(dim='maxEdges') + ds['mean_edgesLength'].attrs = { + 'name': 'Mean edge length', + 'units': 'km', + 'long_name': 'Mean edge length of a cell.' + } + + ds['min_edgesLength'] = ds['edgesLength'].min(dim='maxEdges') + ds['min_edgesLength'].attrs = { + 'name': 'Minimum edge length', + 'units': 'km', + 'long_name': 'Minimum edge length of a cell.' + } + + ds['max_edgesLength'] = ds['edgesLength'].max(dim='maxEdges') + ds['max_edgesLength'].attrs = { + 'name': 'Maximum edge', + 'units': 'km', + 'long_name': 'Maximum edge length of a cell.' + } + + ds['rmse_edgesLength'] = xr.apply_ufunc(np.sqrt, + (ds['edgesLength'] ** 2).mean( + dim='maxEdges')) + ds['rmse_edgesLength'].attrs = { + 'name': 'Rmse edge length', + 'units': 'km', + 'long_name': 'Root mean squared edge length.' + } + + ds['ration_edgesLength'] = ds['min_edgesLength'] / ds['max_edgesLength'] + ds['ration_edgesLength'].attrs = { + 'name': 'Ratio of edge lengths', + 'units': '', + 'long_name': 'Ratio between minimum and maximum edge lengths ' + 'of a cell.' + } + + ds['cellDistortion'] = xr.apply_ufunc(np.sqrt, ( + (ds['edgesLength'] - ds['rmse_edgesLength']) ** 2).mean( + dim='maxEdges')) / ds['rmse_edgesLength'] + ds['cellDistortion'].attrs = { + 'name': 'Cell Distortion', + 'units': '', + 'long_name': 'Cell Distortion: Haversine distance between adjacent ' + 'vertices of a cell. ' + 'https://pedrosp.ime.usp.br/papers/PeixotoBarros2013.pdf' + } + return ds + + +def add_distance_to_reference(ds, **kwargs): + lat_ref = kwargs.get('lat_ref', ds.attrs.get('vtx-param-lat_ref', None)) + lon_ref = kwargs.get('lon_ref', ds.attrs.get('vtx-param-lon_ref', None)) + + if lat_ref is None or lon_ref is None: + print('WARNING Not enough info to add distance to center') + return ds + + d = get_distance_to_center(ds['latitude'].values, ds['longitude'].values, + center_lat=lat_ref, center_lon=lon_ref) + + ds['cellDistance'] = xr.DataArray(data=d, dims=('nCells')) + ds['cellDistance'].attrs = { + 'name': 'Distance to ref. point', + 'units': 'km', + 'long_name': 'Distance from cell center to reference point' + } + return ds + + +def open_mpas_regional_file(file, **kwargs): + ds = xr.open_dataset(file) + ds = add_mpas_mesh_variables(ds, **kwargs) + return ds + + +def compute_metrics_triangle_quality(ds): + distances = [] + circ_radius = [] + area_triangles = [] + for vertex in ds['nVertices']: + vals = ds['cellsOnVertex'].sel(nVertices=vertex).values + + if 0 in vals: + distances.append([np.nan, np.nan, np.nan]) + circ_radius.append(np.nan) + area_triangles.append(np.nan) + continue + + vals = vals - 1 + lats = ds['latitude'].sel(nCells=vals).values + lons = ds['longitude'].sel(nCells=vals).values + + lat_ref = lats[-1] + lon_ref = lons[-1] + + dis = [] + for i in range(3): + d = distance_latlon_matrix(lats[i], lons[i], + lat_ref=lat_ref, + lon_ref=lon_ref, do_tile=False) + dis.append(d) + lat_ref, lon_ref = lats[i], lons[i] + + # abc / np.sqrt( ( a + b + c ) ( b + c − a ) ( c + a − b ) ( a + b − c ) ) + radius_ball = dis[0] * dis[1] * dis[2] / np.sqrt( + (dis[0] + dis[1] + dis[2]) * (-dis[0] + dis[1] + dis[2]) * ( + dis[0] - dis[1] + dis[2]) * (dis[0] + dis[1] - dis[2])) + circ_radius.append(radius_ball) + + # sqrt(p ( p − a ) ( p − b ) ( p − c )) where p is half-perimeter + p = (dis[0] + dis[1] + dis[2]) / 2 + area = np.sqrt(p * (p - dis[0]) * (p - dis[1]) * (p - dis[2])) + area_triangles.append(area) + + distances.append(dis) + + ds['tsideLength'] = xr.DataArray(data=distances, + dims=('nVertices', 'vertexDegree')) + ds['tsideLength'].attrs = { + 'name': 'Length of sides for a triangle', + 'units': 'km', + 'long_name': 'Haversine distance between adjacent vertices of triangles (center ' + 'cells that surround a vertex).' + } + + ds['mean_tsideLength'] = ds['tsideLength'].mean(dim='vertexDegree') + ds['edgesLength'].attrs = { + 'name': 'Mean side length', + 'units': 'km', + 'long_name': 'Mean side length of a triangle.' + } + + ds['min_tsideLength'] = ds['tsideLength'].min(dim='vertexDegree') + ds['min_tsideLength'].attrs = { + 'name': 'Minimum side length', + 'units': 'km', + 'long_name': 'Minimum side length of a triangle.' + } + + ds['max_tsideLength'] = ds['tsideLength'].max(dim='vertexDegree') + ds['max_tsideLength'].attrs = { + 'name': 'Maximum side length', + 'units': 'km', + 'long_name': 'Maximum side length of a triangle.' + } + + ds['rmse_tsideLength'] = xr.apply_ufunc(np.sqrt, + (ds['tsideLength'] ** 2).mean( + dim='vertexDegree')) + ds['rmse_tsideLength'].attrs = { + 'name': 'Rmse side length', + 'units': 'km', + 'long_name': 'Root mean squared side length.' + } + + ds['ratio_tsideLength'] = ds['min_tsideLength'] / ds['max_tsideLength'] + ds['ratio_tsideLength'].attrs = { + 'name': 'Ratio of side lengths', + 'units': 'km', + 'long_name': 'Ratio between minimum and maximum side lengths of a triangle.' + } + + ds['triangleDistortion'] = xr.apply_ufunc(np.sqrt, ( + (ds['tsideLength'] - ds['rmse_tsideLength']) ** 2).mean( + dim='vertexDegree')) / ds['rmse_tsideLength'] + ds['triangleDistortion'].attrs = { + 'name': 'Triangle Distortion', + 'units': 'km', + 'long_name': 'Triangle Distortion: computed from the distance between cell centers surrounding a vertex.' + } + + # Circumscribing circle radius : + ds['circums_radius'] = xr.DataArray(data=circ_radius, dims=('nVertices')) + ds['circums_radius'].attrs = { + 'name': 'Radius of the circumscribing circle', + 'units': 'km', + 'long_name': 'Radius of the circumscribing circle of a triangle.' + } + + # https://gmd.copernicus.org/articles/10/2117/2017/gmd-10-2117-2017.pdf + # definition 2 (radius-edge ratio) + ds['radius_edge_ratio'] = ds['circums_radius'] / ds['min_tsideLength'] + ds['circums_radius'].attrs = { + 'name': 'Radius-edge ratio', + 'units': '', + 'long_name': 'The radius-edge ratio is a measure of element shape quality: circums_radius/min_tsideLength' + } + + # Area triangle: + # Definition 3 (area–length ratio) + ds['area_triangle'] = xr.DataArray(data=area_triangles, dims=('nVertices')) + ds['area_triangle'].attrs = { + 'name': 'Area of a triangle', + 'units': 'km', + 'long_name': 'Area of a triangle (from latlon distances).' + } + + ds['area_length_ratio'] = 4 * np.sqrt(3) / 3 * ds['area_triangle'] / ( + ds['rmse_tsideLength'] ** 2) + ds['area_length_ratio'].attrs = { + 'name': 'Area-length ratio', + 'units': 'km', + 'long_name': 'Area-length ratio: 4sqrt(3)/3 area/(rmse_tsideLength)**2' + } + + return ds + + +def get_borders_at_distance(distance_km, centerlat=0., centerlon=0.): + len_grid = distance(kilometers=distance_km) + + maxlat = len_grid.destination(point=(centerlat, centerlon), + bearing=0).latitude + minlat = len_grid.destination(point=(centerlat, centerlon), + bearing=180).latitude + maxlon = len_grid.destination(point=(centerlat, centerlon), + bearing=90).longitude + minlon = len_grid.destination(point=(centerlat, centerlon), + bearing=270).longitude + + return minlon, maxlon, minlat, maxlat + + +def find_min_number_wrf_cells(distance_km=None, resolution_km=None, + previous_domain_cells=0, + margin_cells_each_side=9, + force_buffer=False): + + if distance_km is not None and resolution_km is not None: + min_num_cells = int(distance_km / resolution_km) + # print(' - distance: %f' % distance_km) + # print(' - resolution_km: %f' % resolution_km) + # print(' - minimum number: %f' % min_num_cells) + else: + min_num_cells = 1 + + # num wrf cells has to be odd and multiple of 3. + # it also has to be >= 27 and > previous domain num cells / 3 + 18 + + if previous_domain_cells > 0: + # print(' - previous_domain_cells: %f' % previous_domain_cells) + at_least = int(previous_domain_cells / 3 + 2*margin_cells_each_side) + min_num_cells = max(min_num_cells, at_least) + + if force_buffer: + smallest_grid = int(2 * margin_cells_each_side) + min_num_cells = max(min_num_cells, smallest_grid) + + while not min_num_cells % 2 != 0 or not min_num_cells % 3 == 0: + min_num_cells += 1 + + return min_num_cells + + +def equivalent_wrf_domains(resolutions, diameters, + max_domains=2, silent=False): + + if len(resolutions) != len(diameters): + raise AttributeError('Resolutions and diameters list should ' + 'be same length') + + highresolution = int(resolutions[0]) + if resolutions[-1] is None: + num_domains = len(resolutions) + resol_nests = [int(highresolution * 3 ** i) for i in + range(max_domains)] + else: + lowresolution = int(resolutions[-1]) + + # Find resolution outer domain + options = [int(highresolution * 3 ** i) for i in range(max_domains)] + # find the option closest to lowresolution + dists = [abs(lowresolution - option) for option in options] + mindist = np.argmin(dists) + resol_nests = options[:(mindist + 1)] + num_domains = len(resol_nests) + + domains_def = { + 'max_domains': str(num_domains), + } + + num_cells = {} + for nest in range(num_domains): + # nest = 0 is the highest resolution / smaller domain + # but nest = 0 means highest domain = num_domains + # The outer nest is domain = 1 and nest = num_domains - 1 + domain = num_domains - nest + + # Resolution + domains_def['d' + str(domain) + 'res'] = str(resol_nests[nest]) + + # Number of cells + if nest == 0: + prev_num_cells = 0 + else: + prev_num_cells = num_cells[nest - 1] + + diameter = diameters[nest] + if diameter is None: + wrf_cells = find_min_number_wrf_cells( + previous_domain_cells=prev_num_cells, + margin_cells_each_side=9) + else: + wrf_cells = find_min_number_wrf_cells( + distance_km=diameter, resolution_km=resol_nests[nest], + previous_domain_cells=prev_num_cells) + num_cells[nest] = wrf_cells + + domains_def['d' + str(domain) + 'e_wesn'] = \ + str(wrf_cells + 1) + + if not silent: + print('\nNested n', nest, ' / Domain d', domain) + print('\tResolution:', resol_nests[nest], 'km') + print('\t' + str(wrf_cells) + 'x' + str(wrf_cells), + 'WRF cells of', resol_nests[nest], 'km resolution.') + + for domain in range(1, num_domains + 1): + nest = num_domains - domain + + if domain == 1: + if not silent: + print('Lowest Resolution domain') + dij = 1 + else: + if not silent: + print('Inner domain') + # quantes celes del domini superior (domain-1) ocupa? + upper_cells_total = num_cells[nest + 1] - 1 + upper_cells_covered = (num_cells[nest] - 1) / 3 + dij = int(((upper_cells_total - upper_cells_covered) / 2) + 1) + + # Starting ij + domains_def['d' + str(domain) + 'dij'] = str(dij) + + return domains_def + + +def mpas_mesh_equivalent_wrf(ds, **kwargs): + highresolution = kwargs.get('highresolution', + ds.attrs.get('vtx-param-highresolution', + None)) + size = kwargs.get('size', ds.attrs.get('vtx-param-size', None)) + lowresolution = kwargs.get('lowresolution', + ds.attrs.get('vtx-param-lowresolution', + None)) + regborder = kwargs.get('region_border', ds.attrs.get('vtx-region_border', + None)) + + if size is not None: + innerdiam = 2.*size + else: + innerdiam = None + + if regborder is not None: + outerdiam = 2.*regborder + else: + outerdiam = None + + if highresolution >= 3.: + ewrf = equivalent_wrf_domains([highresolution, lowresolution], + [innerdiam, outerdiam], silent=True) + else: + ewrf = equivalent_wrf_domains([highresolution, None, None], + [innerdiam, None, outerdiam], + max_domains=3, + silent=True) + + return ewrf + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/jigsaw_generator.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/jigsaw_generator.py new file mode 100644 index 0000000..afb7f2e --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/jigsaw_generator.py @@ -0,0 +1,104 @@ +# Marta Gil Bardaji, Vortex, marta.gil@vortexfdc.com +# May 2022 + +# Simplification of the script +# https://github.com/pedrospeixoto/MPAS-PXT/blob/master/grids/utilities/jigsaw/jigsaw_util.py +# by Pedro S. Peixoto Dec 2021 +# +# which is itself based on +# http://mpas-dev.github.io/MPAS-Tools/stable/mesh_creation.html#spherical-meshes +# and Jigsaw scripts: +# https://github.com/dengwirda/jigsaw-python/tree/master/tests + + +import numpy as np +import jigsawpy as jig +import subprocess + + +def jigsaw_gen_sph_grid(cellWidth, x, y, earth_radius=6371.0e3, + basename="mesh"): + """ + A function for building a jigsaw spherical mesh + + Parameters + ---------- + cellWidth : ndarray + The size of each cell in the resulting mesh as a function of space + x, y : ndarray + The x and y coordinates of each point in the cellWidth array + (lon and lat for spherical mesh) + earth_radius : float, optional + Earth radius in meters + basename : str + folder + '/' + name of the different files the function saves + + """ + # Authors + # ------- + # by P. Peixoto in Dec 2021 + # based on MPAS-Tools from Mark Petersen, Phillip Wolfram, Xylar Asay-Davis + + # setup files for JIGSAW + opts = jig.jigsaw_jig_t() + opts.geom_file = basename + '.msh' + opts.jcfg_file = basename + '.jig' + opts.mesh_file = basename + '-MESH.msh' + opts.hfun_file = basename + '-HFUN.msh' + + # save HFUN data to file + hmat = jig.jigsaw_msh_t() + + hmat.mshID = 'ELLIPSOID-GRID' + hmat.xgrid = np.radians(x) + hmat.ygrid = np.radians(y) + hmat.value = cellWidth + jig.savemsh(opts.hfun_file, hmat) + + # define JIGSAW geometry + geom = jig.jigsaw_msh_t() + geom.mshID = 'ELLIPSOID-MESH' + geom.radii = earth_radius * 1e-3 * np.ones(3, float) + jig.savemsh(opts.geom_file, geom) + + # build mesh via JIGSAW! + opts.hfun_scal = 'absolute' + opts.hfun_hmax = float("inf") + opts.hfun_hmin = 0.0 + opts.mesh_dims = +2 # 2-dim. simplexes + # MARTA CHANGES + opts.mesh_iter = 500000 + # % OPTS.MESH_ITER - {default=+INF} max. number of mesh ref- + # % inement iterations. Set ITER=N to see progress after + # % N iterations. + opts.optm_qlim = 0.9375 + # % OPTS.OPTM_QLIM - {default=0.9375} threshold on mesh cost + # % function above which gradient-based optimisation is + # % attempted. + opts.optm_qtol = 1.0e-7 + # % OPTS.OPTM_QTOL - {default=1.E-04} tolerance on mesh cost + # % function for convergence. Iteration on a given node + # % is terminated if adjacent element cost-functions are + # % improved by less than QTOL. + + opts.optm_iter = 5000 + # % OPTS.OPTM_ITER - {default=16} max. number of mesh optim- + # % isation iterations. Set ITER=N to see progress after + # % N iterations. + + # new opts + # % OPTS.MESH_OFF2 - {default=0.90} radius-edge ratio target + # % for insertion of "shape"-type offcentres for 2-tria + # % elements. When refining an element II, offcentres + # % are positioned to form a new "frontal" element JJ + # % that satisfies JRAD <= OFF2. + opts.mesh_off2 = 0.97 + + # ----------------- + opts.verbosity = +1 + jig.savejig(opts.jcfg_file, opts) + + # Call jigsaw + subprocess.call(['jigsaw', opts.jcfg_file]) + + return opts.mesh_file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/mesh_generator.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/mesh_generator.py new file mode 100644 index 0000000..678eed7 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/mesh_generator.py @@ -0,0 +1,390 @@ +import os +import time + +import xarray as xr +import numpy as np +from scipy.interpolate import interp1d + +from mpas_tools.mesh.creation.jigsaw_to_netcdf import jigsaw_to_netcdf +from mpas_tools.mesh.conversion import convert +from mpas_tools.io import write_netcdf + +from vtxmpasmeshes.jigsaw_generator import jigsaw_gen_sph_grid +from vtxmpasmeshes.mpas_plots import view_resolution_map, \ + view_mpas_regional_mesh +from vtxmpasmeshes.dataset_utilities import distance_latlon_matrix + +PATH_LIMITED_AREA = '/home/marta/PycharmProjects/MPAS-Limited-Area' + + +def apply_resolution_at_distance(distances, ref_points, ref_resolutions): + f = interp1d(ref_points, ref_resolutions, bounds_error=False, + fill_value='extrapolate') + resolution = xr.apply_ufunc(f, distances) + return resolution + + +def doughnut_variable_resolution(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # 1st Variable Resolution Ring + # ------------------------------- + # From to = + -> linear increase + # from highresolution to lowresolution + kwargs['radius'] = kwargs['size'] + kwargs['margin'] + slope = (kwargs['lowresolution'] - kwargs['highresolution']) / kwargs['margin'] + d2, r2 = kwargs['radius'], kwargs['lowresolution'] + + # Fixed Low Resolution ring + # ------------------------------- + # From until =+ -> constant lowresolution + # - where the =10 * lowresolution + kwargs['buffer'] = 10 * kwargs['lowresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d3, r3 = kwargs['border'], kwargs['lowresolution'] + + # Crazy increase in cell size ring + # -------------------------------- + # From to -> linear increase with the same + # than before until we reach the reoslution + # - can be computed + deltares = kwargs['final_res_dist'] - kwargs['lowresolution'] + xmax = kwargs['border'] + deltares / slope + d4, r4 = xmax, kwargs['final_res_dist'] + d5, r5 = 2*xmax, kwargs['final_res_dist'] + + # Those are the points I fix + dists = np.array([d0, d1, d2, d3, d4, d5]) + resol = np.array([r0, r1, r2, r3, r4, r5]) + + return dists, resol, kwargs + + +def variable_resolution_latlonmap(grid, **kwargs): + + print('\n>> Creating a variable resolution map') + + # GRID + # Create a global lat/lon grid at high resolution + + highresolution = kwargs.get('highresolution', 10.) # grid size in km + print('\tResolution in km of lat/lon grid: %.1f' % highresolution) + + dist_degrees = highresolution / 110. + + nlat = int(180. / dist_degrees) + 1 + nlon = int(360. / dist_degrees) + 1 + + ds = xr.Dataset( + coords={ + 'lat': np.linspace(-90., 90., nlat), + 'lon': np.linspace(-180., 180., nlon), + } + ) + + # DISTANCE + # Compute distance from each point to the reference point + + lat_ref = kwargs.get('lat_ref', None) + if lat_ref is None: + lat_ref = 0. + lon_ref = kwargs.get('lon_ref', None) + if lon_ref is None: + lon_ref = 0. + kwargs.update({'lat_ref': lat_ref, 'lon_ref': lon_ref}) + + print('\tComputing the distance to the reference point ' + '(%.2f, %.2f)' % (lat_ref, lon_ref)) + dists = distance_latlon_matrix(ds.coords['lat'], ds.coords['lon'], + lat_ref=lat_ref, lon_ref=lon_ref, + do_tile=True) + + ds['distance'] = xr.DataArray(data=dists, dims=('lat', 'lon')) + + # RESOLUTION + # Set the resolution value at each point + print('\tComputing resolutions using technique %s' % grid) + + if grid == 'doughnut': + dists, resol, kwargs = doughnut_variable_resolution(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + else: + raise ValueError('!! Grid %s not implemented.' % grid) + + ds.attrs = kwargs + + return ds + + +def get_mesh_from_resolution(resolution_ds, basename='./mesh'): + print('\n>> Generating an MPAS mesh') + + # jigsaw + print('\n\t .- Jigsaw generation') + mesh_file = jigsaw_gen_sph_grid(resolution_ds['resolution'].values, + resolution_ds['lon'].values, + resolution_ds['lat'].values, + basename=basename) + + # mpas-tools + + print('\n\t .- Jigsaw to netCDF') + out_file_triangles = basename + '.triangles.nc' + jigsaw_to_netcdf(msh_filename=mesh_file, + output_name=out_file_triangles, + on_sphere=True, sphere_radius=1.0) + + print('\n\t .- Convert to MPAS format') + out_file_mpas = basename + '.grid.nc' + out_file_graph_info = basename + ".grid.graph.info" + write_netcdf( + convert(xr.open_dataset(out_file_triangles), + dir=os.path.dirname(basename), + graphInfoFileName=out_file_graph_info), + out_file_mpas) + + return out_file_mpas, out_file_graph_info + + +def cut_circular_region(mpas_global_file, + region_radius_meters, + regional_grid=None, + regional_grid_info=None, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000)) + + if region_radius_meters < 5000: + raise ValueError('Do you want a %.0fm radius region?' + 'That looks way too small. Maybe you passed ' + 'the radius in km instead as in meters.' + % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + os.system('cp ' + mpas_global_file + ' global.grid.nc') + + with open('points.txt', 'w') as f: + f.write('Name: circle\n') + f.write('Type: circle\n') + f.write('Point: %.4f, %.4f\n' % (lat_cen, lon_cen)) + f.write('radius: %.0f\n' % region_radius_meters) + + # If there are regional files we should erase them + os.system('rm -f circle.grid.nc') + os.system('rm -f circle.graph.info') + + # Execute create region + os.system(path_create_region + '/create_region points.txt ' + + mpas_global_file) + + if not os.path.exists('circle.grid.nc') or \ + not os.path.exists('circle.graph.info'): + raise AttributeError('The regions were not generated correctly') + + if regional_grid is not None: + os.system('cp circle.grid.nc ' + regional_grid) + + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + else: + regional_grid = 'circle.grid.nc' + + if regional_grid_info is not None: + os.system('cp circle.graph.info ' + regional_grid_info) + else: + regional_grid_info = 'circle.graph.info' + + return regional_grid, regional_grid_info + + +def cut_circular_region_beta(mpas_global_file, + region_radius_meters, + regional_grid=None, + regional_grid_info=None, + num_boundary_layers=8, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + create_region_exec = path_create_region + '/create_region_no_file' + if not os.path.isfile(create_region_exec): + raise IOError('Your MPAS-Limited-Area folder does not ' + 'contain the expected executable. Maybe you ' + 'have an old version? ' + create_region_exec) + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000)) + + if region_radius_meters < 5000: + raise ValueError('Do you want a %.0fm radius region?' + 'That looks way too small. Maybe you passed ' + 'the radius in km instead as in meters.' + % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + # If there are regional files we should erase them + if regional_grid is None: + regional_grid = 'circle.grid.nc' + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + + os.system('rm -f ' + regional_grid) + os.system('rm -f ' + regional_grid_info) + + # Execute create region + os.system(create_region_exec + ' ' + mpas_global_file + + ' --num_boundary_layers ' + str(num_boundary_layers) + + ' --oregion ' + regional_grid + + ' --ograph ' + regional_grid_info + + ' region.type:circle' + + ' region.radius:' + str(region_radius_meters) + + ' region.in_point:' + str(lat_cen) + ',' + str(lon_cen) + ) + + if not os.path.exists(regional_grid) or \ + not os.path.exists(regional_grid_info): + raise AttributeError('The regions were not generated correctly') + + return regional_grid, regional_grid_info + + +def full_generation_process(mpas_grid_file, grid, redo=True, + do_plots=True, do_region=False, **kwargs): + + if os.path.isfile(mpas_grid_file) and not redo: + print(' .. already available') + return + + graph_info_file = mpas_grid_file.replace('.nc', '.graph.info') + path_save = os.path.dirname(mpas_grid_file) + + os.system('rm -f ' + mpas_grid_file) + os.system('rm -f ' + graph_info_file) + + start_time = time.time() + resolution_ds = variable_resolution_latlonmap(grid, **kwargs) + duration_resolution = time.time() - start_time + print(' .. finished finding resolution map: %.3fs\n\n' % duration_resolution) + + border = resolution_ds.attrs['border'] + radius = resolution_ds.attrs['radius'] + lat_ref = resolution_ds.attrs['lat_ref'] + lon_ref = resolution_ds.attrs['lon_ref'] + + if do_plots: + print('Plotting') + start_time = time.time() + view_resolution_map(resolution_ds, + pdfname=path_save + '/resolution.pdf', + list_distances=[ + #1000, + 500, border, radius]) + duration_plots = time.time() - start_time + print(' .. finished doing resolution plots: %.3fs\n\n' % duration_plots) + + start_time = time.time() + tmp_mesh_file, tmp_graph_info = get_mesh_from_resolution(resolution_ds, + basename='mesh') + duration_gen = time.time() - start_time + print(' .. finished generating global mesh: %.3fs\n\n' % duration_gen) + + mpas_grid_file_tmp = mpas_grid_file + '.tmp' + if do_region: + start_time = time.time() + num_boundary_layers = kwargs.get('num_boundary_layers', 8) + cut_circular_region_beta(tmp_mesh_file, radius*1000, + regional_grid=mpas_grid_file_tmp, + regional_grid_info=graph_info_file, + num_boundary_layers=num_boundary_layers, + lat_cen=lat_ref, lon_cen=lon_ref) + duration_region = time.time() - start_time + print(' .. finished cutting region: %.3fs\n\n' % duration_region) + + if not os.path.isfile(mpas_grid_file_tmp) or \ + not os.path.isfile(graph_info_file): + raise IOError('The file we had to generate was not generated') + else: + duration_region = 0. + os.system('mv ' + tmp_mesh_file + ' ' + mpas_grid_file_tmp) + os.system('mv ' + tmp_graph_info + ' ' + graph_info_file) + + # Open dataset and update attributes + mpas_ds = xr.open_dataset(mpas_grid_file_tmp) + for name, value in resolution_ds.attrs.items(): + mpas_ds.attrs['vtx-param-' + str(name)] = value + if do_region: + mpas_ds.attrs['vtx-region-num_boundary_layers'] = num_boundary_layers + lowres = mpas_ds.attrs['vtx-param-lowresolution'] + region_border = radius + (num_boundary_layers * lowres) * 0.6 + mpas_ds.attrs['vtx-region_border'] = region_border + + # Update the duration of the steps + durations_process = { + 'resolution': duration_resolution, + 'generation': duration_gen, + 'region': duration_region, + 'total': duration_resolution + duration_gen + duration_region, + } + for name, value in durations_process.items(): + mpas_ds.attrs['vtx-duration-' + name] = '%.2f' % value + + print('\n MESH:\n') + print(mpas_ds) + mpas_ds.to_netcdf(mpas_grid_file) + + if not os.path.isfile(mpas_grid_file): + raise IOError('Could not update attributes of file ' + + mpas_grid_file_tmp) + + os.system('rm -f ' + mpas_grid_file_tmp) + + if do_plots: + if do_region: + print('Resolution Plots') + view_mpas_regional_mesh(mpas_grid_file, + outfile=path_save + '/resolution_mesh.png') + + return mpas_grid_file, graph_info_file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/mpas_plots.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/mpas_plots.py new file mode 100644 index 0000000..9c7d903 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/mpas_plots.py @@ -0,0 +1,303 @@ +import os + +import numpy as np +from shapely.geometry import Polygon +import math + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +from cartopy.geodesic import Geodesic +from matplotlib.backends.backend_pdf import PdfPages +from geopy.distance import distance + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file, \ + get_borders_at_distance, mpas_mesh_equivalent_wrf + +from vtxmpasmeshes.plot_utilities import plot_latlon_cartopy, \ + plot_mpas_darray, set_plot_kwargs, add_colorbar, \ + start_cartopy_map_axis, close_plot, add_cartopy_details, \ + get_plot_size, get_max_borders + + +def view_resolution_map(ds, pdfname=None, list_distances=None, **kwargs): + # ds is a resolution dataset ('distance' and 'resolution' dataset) + # we plot, for different distances, a + + if list_distances is None: + list_distances = [1000, 500, 200, 50] + + pdf = None + if pdfname is not None: + pdf = PdfPages(pdfname) + + # Region + # we don't want to plot too much + region = ds.where(ds['distance'] <= max(list_distances)) + region = region.dropna('lat', how='all').dropna('lon', how='all') + + # Find the center (place at distance zero) + my_zero = region['distance'].argmin(['lat', 'lon']) + mylat = int(my_zero['lat']) + mylon = int(my_zero['lon']) + + # Create a one-dimensional radial array from the center + axis = region.isel(lat=mylat, lon=range(mylon, region.dims['lon'])) + axis = axis.squeeze(drop=True) + axis = axis.assign_coords({'distance': axis['distance']}) + axis = axis.swap_dims({'lon': 'distance'}) + + # Add several plots to the pdf -> one for each limit distance + for di in list_distances: + print('\t .. plotting for distances <= %.0fkm' % di) + # radial lineplot subplot + plt.subplot(121) + axis['resolution'].where(axis['distance'] <= di).plot() + plt.title('Radial Resolution') + + # map of the area closer than a distance di + x = region['resolution'].where(region['distance'] <= di) + x = x.dropna('lat', how='all').dropna('lon', how='all') + ax = plt.subplot(122, projection=ccrs.PlateCarree()) + add_cartopy_details(ax) + plot_latlon_cartopy(x, ax=ax, title='Resolution map', **kwargs) + + fig = plt.gcf() + fig.suptitle('Resolution (km). Distance closer than %.0fkm' % di) + close_plot(fig, size_fig=[12, 8], pdf=pdf) + + if pdf is not None: + pdf.close() + + return + + +def plot_expected_resolution_rings(ds, rings=None, outfile=None, ax=None): + + # if ax=None -> initialize and close the plot + # if ax not None -> do not initialize nor close + final = False + if ax is None: + final = True + ax = start_cartopy_map_axis() + + # test that the dataset has the expected attributes + try: + lat = ds.attrs['vtx-param-lat_ref'] + lon = ds.attrs['vtx-param-lon_ref'] + except KeyError as e: + print('The dataset has to be an MPAS mesh created by the ' + 'vtx generation flow (attributes vtx-param-)') + raise e + + # rings of 'expected' limits on the resolution of the mesh + if rings is None: + rings = ['size', 'radius', 'border'] + gd = Geodesic() + for ring in rings: + rad = ds.attrs['vtx-param-' + ring] + cp = gd.circle(lon=lon, lat=lat, radius=rad * 1000) + geom = Polygon(cp) + ax.add_geometries((geom,), crs=ccrs.PlateCarree(), + facecolor='none', edgecolor='black', + linewidth=1.5, alpha=0.8) + + # close if needed + if final: + close_plot(outfile=outfile) + return + + +def plot_era5_grid(ax): + gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, + linewidth=1, color='gray', alpha=0.6, linestyle='-') + + gl.top_labels = False + gl.left_labels = False + gl.bottom_labels = False + gl.right_labels = False + + era5_lons = np.arange(-180, 180, 0.25) + era5_lats = np.arange(-90, 90, 0.25) + gl.xlocator = mpl.ticker.FixedLocator(era5_lons) + gl.ylocator = mpl.ticker.FixedLocator(era5_lats) + + +def plot_wrf_grid(ds, ax=None): + # test that the dataset has the expected attributes + try: + centerlat = ds.attrs['vtx-param-lat_ref'] + centerlon = ds.attrs['vtx-param-lon_ref'] + except KeyError as e: + print('The dataset has to be an MPAS mesh created by the ' + 'vtx generation flow (attributes vtx-param-)') + raise e + + wrf_details = mpas_mesh_equivalent_wrf(ds) + num_domains = int(wrf_details['max_domains']) + + colors = ['red', 'green', 'purple', 'orange'] + for domain in range(1, num_domains + 1): + + resol_km = int(wrf_details['d' + str(domain) + 'res']) + num_cells = int(wrf_details['d' + str(domain) + 'e_wesn']) - 1 + + len_grid = distance(kilometers=float(resol_km * num_cells)) / 2 + + maxlat = len_grid.destination(point=(centerlat, centerlon), + bearing=0).latitude + minlat = len_grid.destination(point=(centerlat, centerlon), + bearing=180).latitude + maxlon = len_grid.destination(point=(centerlat, centerlon), + bearing=90).longitude + minlon = len_grid.destination(point=(centerlat, centerlon), + bearing=270).longitude + + directions = {'positive': [0, 90], 'negative': [180, 270]} + + for cell in range(math.ceil(num_cells / 2)): + + d = distance( # cells resolution (max res) times + kilometers=float(resol_km * (cell + 1 / 2))) + for degrees in directions.values(): + vert = d.destination(point=(centerlat, centerlon), + bearing=degrees[0]) + hori = d.destination(point=(centerlat, centerlon), + bearing=degrees[1]) + + ax.plot([hori.longitude, hori.longitude], [minlat, maxlat], + linewidth=0.8, color=colors[domain - 1]) + ax.plot([minlon, maxlon], [vert.latitude, vert.latitude], + linewidth=0.8, color=colors[domain - 1]) + + +def view_mpas_regional_mesh(mpas_grid_file, outfile=None, + do_plot_resolution_rings=True, + do_plot_era5_grid=False, + do_plot_wrf_grid=False, + vname='resolution', + border_radius=None, + **kwargs): + + if vname != 'resolution': + full = True + else: + full = False + + ds = open_mpas_regional_file(mpas_grid_file, full=full) + + units = ds[vname].attrs.get('units', '') + ncells = str(len(ds[vname].values.flatten())) + name = os.path.basename(mpas_grid_file) + + # PLOT RESOLUTION + + ax = start_cartopy_map_axis(zorder=2) + plot_kwargs = set_plot_kwargs(da=ds[vname], **kwargs) + + # -------- + tit = vname + ': ' + name + ' (' + str(ncells) + ')' + array_plot_kwgs = {**plot_kwargs} + if 'border_radius' in kwargs: + if kwargs['border_radius'] is not None: + array_plot_kwgs['border_radius'] = kwargs['border_radius'] + + plot_mpas_darray(ds, vname, ax=ax, title=tit, + border_radius=border_radius, **array_plot_kwgs) + + if do_plot_era5_grid: + plot_era5_grid(ax) + if do_plot_resolution_rings: + plot_expected_resolution_rings(ds, ax=ax) + if do_plot_wrf_grid: + plot_wrf_grid(ds, ax=ax) + # -------- + + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=outfile) + + return ds + + +def compare_plot_mpas_regional_meshes(list_mesh_files, outfile=None, + border_radius=None, + vname='resolution', + do_plot_resolution_rings=True, + do_plot_era5_grid=True, + **kwargs): + + if vname != 'resolution': + full = True + else: + full = False + + names = [] + datasets = [] + for f in list_mesh_files: + name = os.path.basename(f).replace('.grid.nc', '') + datasets.append(open_mpas_regional_file(f, full=full)) + names.append(name) + + vars_list = [ds[vname] for ds in datasets] + plot_kwargs = set_plot_kwargs(list_darrays=vars_list, **kwargs) + + if border_radius is None: + max_borders = get_max_borders(datasets, + namelat='latitude', + namelon='longitude') + else: + # Find the center + # 1. try the kwargs + central_lat = kwargs.get('lat_ref', None) + central_lon = kwargs.get('lon_ref', None) + + for ds in datasets: + if central_lat is not None and central_lon is not None: + break + central_lat = ds.attrs.get('vtx-param-lat_ref', None) + central_lon = ds.attrs.get('vtx-param-lon_ref', None) + if central_lon is None or central_lat is None: + max_borders = get_max_borders(datasets, + namelat='latitude', + namelon='longitude') + else: + max_borders = get_borders_at_distance(border_radius, + centerlat=central_lat, + centerlon=central_lon, + ) + + nrows, ncols = get_plot_size(len(list_mesh_files)) + + fig_size = [5 * ncols, 5 * nrows] + fig, axs = plt.subplots(nrows=nrows, ncols=ncols+1, figsize=fig_size) + axs = axs.reshape([nrows, ncols + 1]) + g = mpl.gridspec.GridSpec(nrows=nrows, ncols=ncols+1) + + for m, name in enumerate(names): + i, j = m // ncols, m % ncols + + each_title = kwargs.get('each_title', '') + ncells = str(datasets[m].dims['nCells']) + each_title = each_title.replace('', name) + each_title = each_title.replace('', ncells) + + axs[i, j] = plt.subplot(g[i, j], projection=ccrs.PlateCarree()) + add_cartopy_details(axs[i, j]) + plot_mpas_darray(datasets[m], vname, + ax=axs[i, j], **plot_kwargs, + title=each_title, borders=max_borders) + if do_plot_era5_grid: + plot_era5_grid(axs[i, j]) + if do_plot_resolution_rings: + plot_expected_resolution_rings(datasets[m], ax=axs[i, j]) + + for ax in axs[:, -1]: + ax.axis('off') + + add_colorbar(axs[:, -1], label=vname + ' (km)', **plot_kwargs) + suptitle = kwargs.get('suptitle', '') + if suptitle != '': + plt.gcf().suptitle(suptitle, fontsize=16) + plt.subplots_adjust(top=0.9) + close_plot(outfile=outfile, size_fig=fig_size) + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/plot_utilities.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/plot_utilities.py new file mode 100644 index 0000000..eb50586 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/build/lib/vtxmpasmeshes/plot_utilities.py @@ -0,0 +1,330 @@ +import xarray as xr +import numpy as np + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature + +from vtxmpasmeshes.dataset_utilities import get_borders_at_distance, \ + get_center + + +# OPEN AND CLOSE PLOTS + +def start_cartopy_map_axis(zorder=1): + ax = plt.axes(projection=ccrs.PlateCarree()) # projection type + add_cartopy_details(ax, zorder=zorder) + return ax + + +def add_cartopy_details(ax, zorder=1): + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.coastlines(resolution='10m', zorder=zorder+1) + + gl = ax.gridlines(draw_labels=True, alpha=0.5, linestyle='--', + zorder=zorder+2) + gl.top_labels = False + gl.right_labels = False + + +def close_plot(fig=None, size_fig=None, pdf=None, outfile=None, + force_show=False): + + if size_fig is None: + size_fig = [10, 8] + + if fig is None: + fig = plt.gcf() + fig.set_size_inches(size_fig) + + if outfile is not None: + plt.savefig(outfile) + + if pdf is not None: + pdf.savefig(fig) + + if (outfile is None and pdf is None) or force_show: + plt.show() + + plt.close() + + +# HANDLE PLOT KWARGS FROM ALL PASSED KWARGS + +def set_plot_kwargs(da=None, list_darrays=None, **kwargs): + plot_kwargs = {k: v for k, v in kwargs.items() + if k in ['cmap', 'vmin', 'vmax'] + and v is not None} + + if 'cmap' not in plot_kwargs: + plot_kwargs['cmap'] = 'Spectral' + + vmin = plot_kwargs.get('vmin', None) + if vmin is None: + if da is not None: + vmin = np.min(da) + elif list_darrays is not None: + vmin = np.min([v.min() for v in list_darrays if v is not None]) + if vmin is not None: + plot_kwargs['vmin'] = vmin + + vmax = plot_kwargs.get('vmax', None) + if vmax is None: + if da is not None: + vmax = np.max(da) + elif list_darrays is not None: + vmax = np.max([v.max() for v in list_darrays if v is not None]) + + if vmax is not None: + plot_kwargs['vmax'] = vmax + + return plot_kwargs + + +# BORDERS OF THE PLOT + +def find_borders(lats, lons, margin='factor2'): + lats = lats.flatten() + lons = lons.flatten() + + limits = lons.min(), lons.max(), lats.min(), lats.max() + if 'factor' in margin: + delta = int(margin[-1]) + deltalat = np.abs(limits[1] - limits[0]) / (10 * delta) + deltalon = np.abs(limits[3] - limits[2]) / (10 * delta) + minlon = limits[0] - deltalon + maxlon = limits[1] + deltalon + minlat = limits[2] - deltalat + maxlat = limits[3] + deltalat + limits = minlon, maxlon, minlat, maxlat + elif 'cells' in margin: + delta = int(margin[-1]) + deltalat = np.abs(limits[1] - limits[0]) + deltalon = np.abs(limits[3] - limits[2]) + minlon = limits[0] - deltalon * delta + maxlon = limits[1] + deltalon * delta + minlat = limits[2] - deltalat * delta + maxlat = limits[3] + deltalat * delta + limits = minlon, maxlon, minlat, maxlat + + return limits + + +# BASIC LATLON PLOT + +def plot_latlon_cartopy(darray, ax=None, title='', borders=None, **kwargs): + # For a DataArray that has lat/lon coordinates + + # Start the axis + if ax is None: + ax = start_cartopy_map_axis(zorder=4) + + # Set the extent + if borders is None: + borders = find_borders(darray.lat.values, darray.lon.values) + # borders = [minlon, maxlon, minlat, maxlat] + ax.set_extent(borders, crs=ccrs.PlateCarree()) + + kwargs = set_plot_kwargs(da=darray, extend='both', **kwargs) + + # Plot the array (automatic xarray plot) + darray.plot(ax=ax, zorder=1, **kwargs) # plot the resolution + + ax.set_title(title) + return + + +# MPAS PLOT + +def colorvalue(val, cmap='Spectral', vmin=None, vmax=None): + """ + Given a value and the range max, min, it returns the associated + color of the desired cmap. + :param val: float + :param cmap: str + :param vmin: float (default None) + :param vmax: float (default None) + :return: cm(norm_val): color + """ + # Get a colormap instance, defaulting to rc values if name is None. + cm = mpl.cm.get_cmap(cmap, None) + if vmin is None: + vmin = xr.DataArray.min().values # min value of the array + if vmax is None: + vmax = xr.DataArray.max().values # max value of the array + if vmin == vmax: + # A class which, when called, linearly normalizes data into the + # [0.0, 1.0] interval. + norm_val = mpl.colors.Normalize(vmin=vmin - 1, vmax=vmax + 1, + clip=True)(val) + else: + norm_val = mpl.colors.Normalize(vmin=vmin, vmax=vmax, + clip=True)(val) + return cm(norm_val) + + +def plot_mpas_darray(ds, vname, ax=None, outfile=None, **kwargs): + + if vname not in ds.data_vars: + print('Unplottable Data Array ' + vname) + print(ds) + return + + da = ds[vname] + for coord in ['time', 'lev']: + if coord in da.dims: + print('Selecting first slice for ' + coord + '.') + da = da.isel({coord: 0}) + + final = False + if ax is None: + final = True + ax = start_cartopy_map_axis() + + borders = kwargs.get('borders', None) + if borders is None: + lats = ds['latitude'].values.flatten() + lons = ds['longitude'].values.flatten() + border_radius = kwargs.get('border_radius', None) + if border_radius is not None: + central_lat = kwargs.get('lat_ref', None) + central_lon = kwargs.get('lon_ref', None) + if central_lon is None or central_lat is None: + central_lat = ds.attrs.get('vtx-param-lat_ref', None) + central_lon = ds.attrs.get('vtx-param-lon_ref', None) + if central_lon is None or central_lat is None: + central_lat, central_lon = get_center(lats, lons) + borders = get_borders_at_distance(kwargs['border_radius'], + centerlat=central_lat, + centerlon=central_lon, + ) + else: + borders = find_borders(lats, lons) + + ax.set_extent(borders, crs=ccrs.PlateCarree()) + + plot_kwargs = set_plot_kwargs(da=da, **kwargs) + + if 'nCells' in ds[vname].dims: + plot_cells_mpas(ds, vname, ax, **plot_kwargs) + elif 'nVertices' in ds[vname].dims: + plot_dual_mpas(ds, vname, ax, **plot_kwargs) + else: + print('WARNING Impossible to plot!') + + units = da.attrs.get('units', '') + name = kwargs.get('name', '') + ncells = str(len(da.values.flatten())) + title = kwargs.get('title', '') + title = title.replace('', vname).replace('', units) + title = title.replace('', name).replace('', ncells) + ax.set_title(title) + + if final: + title_legend = kwargs.get('title_legend', ': ') + title_legend = title_legend.replace('', vname) + title_legend = title_legend.replace('', units) + add_colorbar(ax, label=title_legend, **plot_kwargs) + + close_plot(outfile=outfile) + return + + +def plot_cells_mpas(ds, vname, ax, **plot_kwargs): + for i, cell in enumerate(ds['nCells'].values): + value = ds[vname].sel(nCells=cell) + + vals = ds['verticesOnCell'].sel(nCells=cell).values + num_sides = int(ds['nEdgesOnCell'].sel(nCells=cell)) + vals = vals[:num_sides] - 1 + lats = ds['latitudeVertex'].sel(nVertices=vals) + lons = ds['longitudeVertex'].sel(nVertices=vals) + + color = colorvalue(value, **plot_kwargs) + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + + +def plot_dual_mpas(ds, vname, ax, **plot_kwargs): + for vertex in ds['nVertices'].values: + value = ds[vname].sel(nVertices=vertex) + + vals = ds['cellsOnVertex'].sel(nVertices=vertex).values + if 0 in vals: + # Border triangle + continue + vals = vals - 1 + lats = ds['latitude'].sel(nCells=vals) + lons = ds['longitude'].sel(nCells=vals) + + color = colorvalue(value, **plot_kwargs) + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + return + + +# TOOLS FOR MULTIPLE PLOTS (Also can be used for 1 plot) + +def add_colorbar(axs, fig=None, label=None, **plot_kwargs): + if fig is None: + fig = plt.gcf() + + try: + x = axs[0, 0] + except: + try: + x = axs[0] + n = len(axs) + except: + axs = np.array([axs]).reshape([1, 1]) + else: + axs = axs.reshape([n, 1]) + + cbar = fig.colorbar( + mpl.cm.ScalarMappable( + norm=mpl.colors.Normalize(vmin=plot_kwargs['vmin'], + vmax=plot_kwargs['vmax'], clip=True), + cmap=plot_kwargs['cmap']), + ax=axs[:, :], shrink=0.6) + cbar.ax.locator_params(nbins=10) + if label is not None: + cbar.set_label(label) + + return + + +def get_plot_size(numplots, nrows=None, ncols=None): + if nrows is not None and ncols is not None: + return nrows, ncols + + if nrows is not None: + ncols = int((numplots + 1) // nrows) + elif ncols is not None: + nrows = int((numplots + 1) // ncols) + else: + if numplots <= 3: + nrows, ncols = 1, numplots + elif numplots == 4: + nrows, ncols = 2, 2 + elif numplots <= 10: + ncols = 3 + nrows = int((numplots + 1) // ncols) + else: + ncols = 4 + nrows = int((numplots + 1) // ncols) + + return nrows, ncols + + +def get_max_borders(list_results, margin='factor2', namelat='latitude', + namelon='longitude'): + borders = np.array([find_borders(lats=ds[namelat].values, + lons=ds[namelon].values, + margin=margin) + for ds in list_results]) + max_borders = borders[:, 0].min(), borders[:, 1].max(), \ + borders[:, 2].min(), borders[:, 3].max() + return np.array(max_borders) diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/create_regional_mesh.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/create_regional_mesh.py new file mode 100644 index 0000000..2bafd16 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/create_regional_mesh.py @@ -0,0 +1,108 @@ +import os +import pandas as pd +from vtxmpasmeshes.mesh_generator import full_generation_process_gtm +import argparse + +# Create ArgumentParser object +parser = argparse.ArgumentParser(description= + 'Sensitivity test for varying mesh parameters.') +# Input arguments +parser.add_argument('--vtx_mpas_meshes_dir', type=str, help='vtx-mpas-meshes directory') +parser.add_argument('--exp_dir', type=str, help='root directory of experiment') +parser.add_argument('--meshes_dir', type=str, help='directory for saving meshes') +parser.add_argument('--N', type=str, help='number of partitions') +parser.add_argument('--lon', type=float, help='longitude for mesh center') +parser.add_argument('--lat', type=float, help='latitude for mesh center') +parser.add_argument('--inner_radius', type=float, help='inner radius (s)') +parser.add_argument('--outer_radius', type=float, help='outer radius (s+m)') +parser.add_argument('--n_layers', type=int, default=8, help='number of external layers') +parser.add_argument('--high_res', type=float, help='minimum grid-distance') +parser.add_argument('--low_res', type=float, help='maximum grid-distance') +parser.add_argument('--do_regional', type=str, default='y', + help='flag for building regional (y) or global (n) mesh') +parser.add_argument('--grid_type', type=str, default='doughnut', + help='type of grid to be constructed') + + +# Parse the command line arguments +args = parser.parse_args() + +# Set relevant directories +DATA_DIR = args.vtx_mpas_meshes_dir+'/data' +VTX_MPAS_MESHES_DIR=args.vtx_mpas_meshes_dir + +# Lon,lat of mesh center +lon_ref = args.lon +lat_ref = args.lat + +# Parameters +# These parameters define the changing in the resolution. Varying the distance +# from the center of mesh d, we define the expected grid spacing S as follows (see Bardaji, 2022): +## 0 < d < size --> S = highres +## size < d < size + margin --> S = highres + lambda*(d-size) +## size + margin < d < alpha (not defined here) --> S = lowres +## alpha < d < beta (not defined here) --> S = lowres + lambda*(d-(size+margin)) +size = args.inner_radius # s in the paper +highres = args.high_res # cgs in the paper +margin = args.outer_radius - args.inner_radius # m in the paper +lowres = args.low_res # mgs in the paper +numlayers = args.n_layers # layers outside requested nominal radius +grid_type = args.grid_type # type of grid to be constructed + +# Set main filename +name = (f"lat_{round(lat_ref)}_lon_{round(lon_ref)}_oradius_{round(args.outer_radius)}_iradius_{round(size)}"+ + f"_margin_{round(margin)}_hres_{round(highres)}_lres_{round(lowres)}") # 's' + str(size).zfill(2) + '_m' + str(margin).zfill(3) +radius = size+margin +region_border = radius + (numlayers*lowres)#*0.9 + +# Set specific filenames +regional_mesh = DATA_DIR + '/' + name + '.region.grid.nc' +regional_mesh_info = DATA_DIR + '/' + name + '.region.graph.info' +regional_mesh_plots = DATA_DIR + '/resolution*' + +# Run main script +if not os.path.exists(regional_mesh): + # Create a regional mesh at the desired location -> with 4 layers (?) + print ('creating regional mesh centered at chosen location') + full_generation_process_gtm( + regional_mesh, grid_type, + redo=False, do_plots=False, do_region=args.do_regional, + highresolution=highres, lowresolution=lowres, + num_boundary_layers=numlayers, + size=size, margin=margin, + lat_ref=lat_ref, lon_ref=lon_ref, + ) +else: + print("Mesh already exists -- nothing to be done.") + +# Save final output files +OUTPUT_DIR = args.meshes_dir + f'/{name}.region' +if not os.path.exists(OUTPUT_DIR): + os.system(f'mkdir {OUTPUT_DIR}') +os.system(f'mv {regional_mesh} {regional_mesh_info} {regional_mesh_plots} {OUTPUT_DIR}') +# Copy mesh files to run directory (one folder above mesh path) +os.system(f'cd {OUTPUT_DIR}; cp {regional_mesh} {regional_mesh_info} ../') + +# Copy relevant files for mesh generation +os.system(f'cp {VTX_MPAS_MESHES_DIR}/mesh* create_mesh.log {OUTPUT_DIR}') + +# Create block decomposition file +print ('N:',args.N) +os.system(f'gpmetis -minconn -contig -niter=200 {OUTPUT_DIR}/{name}.region.grid.graph.info {args.N}') + +# Remove temporary output files +os.system(f'rm {DATA_DIR}/*.nc') +os.system(f'rm -r {VTX_MPAS_MESHES_DIR}/mesh* {VTX_MPAS_MESHES_DIR}/tmp* points.txt') + +# Add file name to mesh_input_file.txt +print (args.exp_dir) +try: + # Open the file in append mode + with open(f'{args.exp_dir}/mesh_input_file.txt', 'a') as file: + # Append the line + file.write(f'file_name={name}.region' + '\n') + print(f'{name}.region added to mesh_input_file.txt.') + os.system(f'cp {args.exp_dir}/mesh_input_file.txt {OUTPUT_DIR}') + print(f'mesh_input_file.txt copied to {OUTPUT_DIR}') +except FileNotFoundError: + print('mesh_input_file.txt not found.') diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/create_regional_mesh_inwards.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/create_regional_mesh_inwards.py new file mode 100644 index 0000000..b2441f4 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/create_regional_mesh_inwards.py @@ -0,0 +1,103 @@ +import os +import pandas as pd +from vtxmpasmeshes.mesh_generator_inwards import full_generation_process_gtm +import argparse + +# Create ArgumentParser object +parser = argparse.ArgumentParser(description= + 'Sensitivity test for varying mesh parameters.') +# Input arguments +parser.add_argument('--vtx_mpas_meshes_dir', type=str, help='vtx-mpas-meshes directory') +parser.add_argument('--exp_dir', type=str, help='root directory of experiment') +parser.add_argument('--meshes_dir', type=str, help='directory for saving meshes') +parser.add_argument('--N', type=str, help='number of partitions') +parser.add_argument('--lon', type=float, help='longitude for mesh center') +parser.add_argument('--lat', type=float, help='latitude for mesh center') +parser.add_argument('--inner_radius', type=float, help='inner radius (s)') +parser.add_argument('--outer_radius', type=float, help='outer radius (s+m)') +parser.add_argument('--n_layers', type=int, default=8, help='number of external layers') +parser.add_argument('--high_res', type=float, help='minimum grid-distance') +parser.add_argument('--low_res', type=float, help='maximum grid-distance') +parser.add_argument('--do_regional', type=str, default='y', + help='flag for building regional (y) or global (n) mesh') +parser.add_argument('--grid_type', type=str, default='doughnut', + help='type of grid to be constructed') + + +# Parse the command line arguments +args = parser.parse_args() + +# Set relevant directories +DATA_DIR = args.vtx_mpas_meshes_dir+'/data' +VTX_MPAS_MESHES_DIR=args.vtx_mpas_meshes_dir + +# Lon,lat of mesh center +lon_ref = args.lon +lat_ref = args.lat + +# Parameters +# These parameters define the changing in the resolution. Varying the distance +# from the center of mesh d, we define the expected grid spacing S as follows (see Bardaji, 2022): +## 0 < d < size --> S = highres +## size < d < size + margin --> S = highres + lambda*(d-size) +## size + margin < d < alpha (not defined here) --> S = lowres +## alpha < d < beta (not defined here) --> S = lowres + lambda*(d-(size+margin)) +size = args.inner_radius # s in the paper +highres = args.high_res # cgs in the paper +margin = args.outer_radius - args.inner_radius # m in the paper +lowres = args.low_res # mgs in the paper +numlayers = args.n_layers # layers outside requested nominal radius +grid_type = args.grid_type # type of grid to be constructed + +# Set main filename +name = (f"lat_{round(lat_ref)}_lon_{round(lon_ref)}_oradius_{round(args.outer_radius)}_iradius_{round(size)}"+ + f"_margin_{round(margin)}_hres_{round(highres)}_lres_{round(lowres)}") # 's' + str(size).zfill(2) + '_m' + str(margin).zfill(3) +radius = size+margin +region_border = radius + (numlayers*lowres)#*0.9 + +# Set specific filenames +regional_mesh = DATA_DIR + '/' + name + '.region.grid.nc' +regional_mesh_info = DATA_DIR + '/' + name + '.region.grid.graph.info' +regional_mesh_plots = DATA_DIR + '/resolution*' + +# Run main script +if not os.path.exists(regional_mesh): + # Create a regional mesh at the desired location -> with 4 layers (?) + print ('creating regional mesh centered at chosen location') + full_generation_process_gtm( + regional_mesh, grid_type, + redo=False, do_plots=True, do_region=args.do_regional, + highresolution=highres, lowresolution=lowres, + num_boundary_layers=numlayers, + size=size, margin=margin, + lat_ref=lat_ref, lon_ref=lon_ref, + ) +else: + print("Mesh already exists -- nothing to be done.") + +# Save final output files +OUTPUT_DIR = args.meshes_dir + f'/{name}.region' +if not os.path.exists(OUTPUT_DIR): + os.system(f'mkdir {OUTPUT_DIR}') +os.system(f'mv {regional_mesh} {regional_mesh_info} {regional_mesh_plots} {OUTPUT_DIR}') + +# Create block decomposition file +print ('N:',args.N) +os.system(f'gpmetis -minconn -contig -niter=200 {OUTPUT_DIR}/{name}.region.grid.graph.info {args.N}') + +# Remove temporary output files +os.system(f'rm {DATA_DIR}/*.nc') +os.system(f'rm -r {VTX_MPAS_MESHES_DIR}/mesh* {VTX_MPAS_MESHES_DIR}/tmp* points.txt') + +# Add file name to input_file.txt +print (args.exp_dir) +try: + # Open the file in append mode + with open(f'{args.exp_dir}/input_file.txt', 'a') as file: + # Append the line + file.write(f'file_name={name}.region' + '\n') + print(f'{name}.region added to input_file.txt.') + os.system(f'cp {args.exp_dir}/input_file.txt {OUTPUT_DIR}') + print(f'input_file.txt copied to {OUTPUT_DIR}') +except FileNotFoundError: + print('input_file.txt not found.') diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/data/.gitkeep b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/dist/vtxmpasmeshes-0.0.1-py3.10.egg b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/dist/vtxmpasmeshes-0.0.1-py3.10.egg new file mode 100644 index 0000000..ad8d02d Binary files /dev/null and b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/dist/vtxmpasmeshes-0.0.1-py3.10.egg differ diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/environment.yml b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/environment.yml new file mode 100644 index 0000000..844e9fc --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/environment.yml @@ -0,0 +1,38 @@ +name: vtx-mpas-tools +channels: + - defaults +dependencies: + - python[version='>=3.7'] + - pyevtk + - sphinx_rtd_theme + - scikit-image + - hdf5 + - netcdf4 + - geometric_features[version='>=0.1.12'] + - dask + - matplotlib-base + - inpoly + - shapely + - numpy + - scipy + - progressbar2 + - sphinx + - pip + - cartopy + - pyamg + - python-igraph + - libnetcdf + - pyproj + - xarray + - mock + - ipykernel + - seaborn + - zarr + - notebook + - pandas + - geopy + - scikit-learn + - setuptools + - conda-forge::jigsaw[version='>=0.9.12'] + - conda-forge::jigsawpy[version='>=0.2.1'] + - conda-forge::mpas_tools diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/example_mesh.png b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/example_mesh.png new file mode 100644 index 0000000..499cc69 Binary files /dev/null and b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/example_mesh.png differ diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/example_resolution.png b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/example_resolution.png new file mode 100644 index 0000000..96db9e6 Binary files /dev/null and b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/example_resolution.png differ diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/compare_meshes.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/compare_meshes.py new file mode 100644 index 0000000..7e96391 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/compare_meshes.py @@ -0,0 +1,64 @@ +import argparse +import os + +from vtxmpasmeshes.mpas_plots import compare_plot_mpas_regional_meshes + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument('-gs', '--grids', default=[], + help='names of the grids', + type=lambda s: [item for item in s.split(',')] + ) + +parser.add_argument( + "-b", "--border", default=None, type=float, + help="Plot the area of this radius around the central point (km).", +) + +parser.add_argument( + "-vmin", "--vmin", default=None, type=float, + help="Minimum resolution color (km).", +) + +parser.add_argument( + "-vmax", "--vmax", default=None, type=float, + help="Maximum resolution color (km).", +) + +parser.add_argument( + "-cmap", "--cmap", default=None, type=str, + help="Color palette.", +) + +parser.add_argument( + "-o", "--outfile", type=str, default=None, + help="File to save the MPAS plots", +) + +# -e do draw era5 grid +parser.add_argument( + "-e", "--era5", action="store_true", + help="overlay era5 grid.", +) + +args = parser.parse_args() + +DATA_FOLDER = '/home/marta/PycharmProjects/vtx-mpas-meshes/data' + +grids = [] +for g in args.grids: + grid = DATA_FOLDER + '/' + g + '/' + g + '.grid.nc' + if not os.path.exists(grid): + raise IOError('File does not exist: ' + grid) + grids.append(grid) + +compare_plot_mpas_regional_meshes(grids, + outfile=args.outfile, + suptitle='Meshes comparison', + each_title=': cells', + border_radius=args.border, + vmin=args.vmin, + vmax=args.vmax, + cmap=args.cmap) diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/generate_mesh.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/generate_mesh.py new file mode 100644 index 0000000..c258ea7 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/generate_mesh.py @@ -0,0 +1,115 @@ +import argparse +import os + +from vtxmpasmeshes.mesh_generator import full_generation_process + +DATA_FOLDER = '/storage/guilherme_torresmendonca/projeto_nudging_mpas/' \ + 'vtx-mpas-meshes/data' +PATH_LIMITED_AREA = '/storage/guilherme_torresmendonca/MPAS-Limited-Area' + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument( + "-n", "--name", default="doughnut", type=str, + help="output basename for directory and files." +) + +parser.add_argument( + "-g", "--grid", type=str, default='doughnut', + help=""" + Grid option: \n + " doughnut": + area of a certain radius . + Linear increase of resolution to a certain value after km. + Keep the constant low resolution value for a while + (10*low_resolution)km and then increase it linearly + again until reaching 1000km (to save space). + The requested MPAS region should be circular and + have a radius of +. The buffer + generated by the MPAS-Limited-Area code will then + consist of a few "rings" of cells. + \n + """ +) + +parser.add_argument( + "-highr", "--highresolution", default=3, type=float, + help="Highest-resolution of grid (km).", +) + +parser.add_argument( + "-lowr", "--lowresolution", default=None, type=float, + help="Lowest-resolution of grid (km).", +) + +parser.add_argument( + "-size", "--size", default=None, type=float, + help="Radius of the highest-resolution area of the grid (km).", +) + +parser.add_argument( + "-margin", "--margin", default=None, type=float, + help="Size of the variable resolution boundary around the " + "high resolution area (km).", +) + +parser.add_argument( + "-lat", "--lat_ref", default=0., type=float, + help="Central latitude.", +) + +parser.add_argument( + "-lon", "--lon_ref", default=0., type=float, + help="Central longitude.", +) + +# -p generates plots +parser.add_argument( + "-p", "--withplots", action="store_true", + help="generate plots to view the mesh.", +) + +# -o overwrite +parser.add_argument( + "-o", "--overwrite", action="store_true", + help="overwrite existing folder.", +) + +args = parser.parse_args() + +if args.name == '': + raise ValueError('Please give a non trivial name.') + +folder = DATA_FOLDER + '/' + args.name + '/' + +if os.path.isdir(folder): + if not args.overwrite: + print('Sure to overwrite?') + raise IOError('For security, overwriting is disabled. Give ' + 'different tests different names or erase the' + 'existing folder: ' + folder) + else: + print('Overwriting folder ' + folder) + os.system('rm -rf ' + folder) + +os.system('mkdir -p ' + folder) +basename = folder + args.name + +mesh_file, mesh_graph_info = full_generation_process( + basename + '.grid.nc', + args.grid, + redo=args.overwrite, + do_plots=args.withplots, + highresolution=args.highresolution, + lowresolution=args.lowresolution, + size=args.size, + margin=args.margin, + lat_ref=args.lat_ref, + lon_ref=args.lon_ref, +) + +print('\n' + '*' * 30) +print('\nDONE. This is the mesh ' + mesh_file) diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/personalize_variable_resolution.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/personalize_variable_resolution.py new file mode 100644 index 0000000..4e7e568 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/personalize_variable_resolution.py @@ -0,0 +1,92 @@ +import argparse + +from vtxmpasmeshes.mesh_generator import variable_resolution_latlonmap +from vtxmpasmeshes.mpas_plots import view_resolution_map + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument( + "-g", "--grid", type=str, default='doughnut', + help=""" + Grid option: \n + " doughnut": + area of a certain radius . + Linear increase of resolution to a certain value after km. + Keep the constant low resolution value for a while + (10*low_resolution)km and then increase it linearly + again until reaching 100km (to save space). + The requested MPAS region should be circular and + have a radius of +. The buffer + generated by the MPAS-Limited-Area code will then + consist of a few "rings" of cells. + \n + """ +) + +parser.add_argument( + "-highr", "--highresolution", required=True, type=float, + help="Highest-resolution of grid (km).", +) + +parser.add_argument( + "-lowr", "--lowresolution", default=None, type=float, + help="Lowest-resolution of grid (km).", +) + +parser.add_argument( + "-size", "--size", default=None, type=float, + help="Radius of the highest-resolution area of the grid (km).", +) + +parser.add_argument( + "-margin", "--margin", default=None, type=float, + help="Size of the variable resolution boundary around the " + "high resolution area (km).", +) + +parser.add_argument( + "-lat", "--lat_ref", default=0., type=float, + help="Central latitude.", +) + +parser.add_argument( + "-lon", "--lon_ref", default=0., type=float, + help="Central longitude.", +) + +# -p generates plots +parser.add_argument( + "-p", "--withplots", action="store_true", + help="generate plots to view the resolution.", +) + +parser.add_argument( + "-pdf", "--pdfname", default=None, type=str, + help="pdffile where to save the resolution plots.", +) + +args = parser.parse_args() + +ds = variable_resolution_latlonmap(args.grid, + highresolution=args.highresolution, + lowresolution=args.lowresolution, + size=args.size, + margin=args.margin, + lat_ref=args.lat_ref, + lon_ref=args.lon_ref, + ) + +print(ds) + +if args.withplots or args.pdfname is not None: + print('Plotting') + view_resolution_map(ds, pdfname=args.pdfname, + list_distances=[1000, 500, + ds.attrs['border'], + ds.attrs['radius'], + ]) + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/sensitivity_test.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/sensitivity_test.py new file mode 100644 index 0000000..86e5366 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/sensitivity_test.py @@ -0,0 +1,302 @@ +import os + +import pandas as pd + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file +from vtxmpasmeshes.mesh_generator import full_generation_process, \ + cut_circular_region_beta +from vtxmpasmeshes.mpas_plots import compare_plot_mpas_regional_meshes, \ + view_mpas_regional_mesh, plot_era5_grid, plot_wrf_grid, \ + plot_expected_resolution_rings + +from vtxmpasmeshes.plot_utilities import plot_mpas_darray, \ + set_plot_kwargs, add_colorbar, \ + start_cartopy_map_axis, close_plot + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature + +DATA_FOLDER = '/home/marta/PycharmProjects/vtx-mpas-meshes/data/' \ + 'sensitivity-test-3' + +# SITE: perdigao +lat_ref = 39.7136 +lon_ref = -7.73 + +highres = 3 +lowres = 20 +numlayers = 8 + +details = {} +grids = [] +for margin in [#50, + #75, + #100, + 125, + #150, 250 + ]: + for size in [#15, + #20, 25, + 30, 35, + #50 + ]: + + name = 'senst_s' + str(size).zfill(2) + '_m' + str(margin).zfill(3) + folder = DATA_FOLDER + '/' + name + '/' + basename = folder + name + + global_mesh = basename + '.grid.nc' + if not os.path.exists(global_mesh): + os.system('mkdir -p ' + folder) + + # I do a global mesh centered at 0,0 -> to use in MPAS workflow + full_generation_process( + global_mesh, 'doughnut', + redo=False, do_plots=False, do_region=False, + highresolution=highres, lowresolution=lowres, + size=size, margin=margin, + lat_ref=0., lon_ref=0., + ) + + radius = size+margin + region_border = radius + (numlayers*lowres)*0.9 + configid = '99' + str(size).zfill(2) + str(margin).zfill(3) + details[name] = { + 'globalfile': global_mesh, + 'configid': configid, + 'size': size, + 'margin': margin, + 'radius': radius, + 'region_border': region_border, + } + + with open(DATA_FOLDER + '/config.' + configid + '.txt', 'w') as f: + f.write('mesh=' + name + '.grid.nc \n') + f.write('resolution=3' + '\n') + f.write('inner_size=' + str(size) + '\n') + f.write('radius=' + str(radius) + '\n') + f.write('region_border=' + str(region_border) + '\n') + f.write('num_boundary_layers=8' + '\n') + f.write('product=raw' + '\n') + f.write('max_num_domains=2' + '\n') + f.write('time_integration_order=2' + '\n') + f.write('two_way_nesting=false' + '\n') + f.write('stream_list=\'reduced\'' + '\n') + f.write('final_vars=\'reduced\'' + '\n') + f.write('levs=\'as_vortex\'' + '\n') + + regional_mesh = DATA_FOLDER + '/' + name + '.region.grid.nc' + if not os.path.exists(regional_mesh): + # I do a regional mesh at my location -> with 4 layers + full_generation_process( + regional_mesh, 'doughnut', + redo=False, do_plots=False, do_region=True, + highresolution=highres, lowresolution=lowres, + num_boundary_layers=numlayers, + size=size, margin=margin, + lat_ref=lat_ref, lon_ref=lon_ref, + ) + + f = DATA_FOLDER + '/' + name + '.mpaswrf_mesh.png' + if not os.path.isfile(f): + print('MPAS WRF Plots') + view_mpas_regional_mesh(regional_mesh, + outfile=f, + do_plot_resolution_rings=True, + do_plot_era5_grid=False, + do_plot_wrf_grid=True, + vname='resolution') + + vname = 'resolution' + units = 'km' + + ds = open_mpas_regional_file(regional_mesh, full=True) + + myats = ds.attrs + + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname]) + plot_mpas_darray(ds, vname, ax=ax, title='', lat_ref=0., + lon_ref=0., border_radius=None, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=DATA_FOLDER + '/' + name + '.mpasmesh.png', + size_fig=[6, 4]) + + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname]) + plot_mpas_darray(ds, vname, ax=ax, title='', lat_ref=0., + lon_ref=0., border_radius=None, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + plot_wrf_grid(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=DATA_FOLDER + '/' + name + '.mpaswrfmesh.png', + size_fig=[6, 4]) + + for border_radius in [size + 10, radius, region_border, + region_border + 200]: + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname].where(ds['cellDistance'] + <= border_radius)) + plot_mpas_darray(ds, vname, ax=ax, title='', + border_radius=border_radius, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + plot_wrf_grid(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + ax.set_title(str(int(border_radius)) + 'km zoom', fontsize=14) + close_plot(outfile=DATA_FOLDER + '/' + name + '.regionmesh.' + + str(border_radius) + '.png', size_fig=[6, 4]) + + regionalbig_mesh = DATA_FOLDER + '/' + name + '.regionbig.grid.nc' + if not os.path.exists(regionalbig_mesh): + cut_circular_region_beta(global_mesh, 2000 * 1000, + regional_grid=regionalbig_mesh, + num_boundary_layers=8, + lat_cen=0., lon_cen=0.) + + ds = open_mpas_regional_file(regionalbig_mesh, full=True, + lat_ref=0., lon_ref=0.) + + ds.attrs = myats + ds.attrs['vtx-param-lat_ref'] = 0. + ds.attrs['vtx-param-lon_ref'] = 0. + print(ds.attrs) + + for border_radius in [size + 10, radius, region_border, + 500, 1000, 3000, 6000]: + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname].where(ds['cellDistance'] + <= border_radius)) + plot_mpas_darray(ds, vname, ax=ax, title='', + border_radius=border_radius, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + ax.set_title(str(int(border_radius)) + 'km zoom', fontsize=14) + close_plot(outfile=DATA_FOLDER + '/' + name + '.mpasmesh.' + + str(border_radius) + '.png', size_fig=[6, 4]) + + f = DATA_FOLDER + '/' + name + '.resolution_mesh.png' + if not os.path.isfile(f): + print('Resolution Plots') + view_mpas_regional_mesh(regional_mesh, vname='resolution', + outfile=f) + + f = DATA_FOLDER + '/' + name + '.distortion_mesh.png' + if not os.path.isfile(f): + print('Distortion Plots') + view_mpas_regional_mesh(regional_mesh, vname='cellDistortion', + outfile=f, border_radius=size, + cmap='magma') + + print('\n' + '*' * 30) + print('\nDONE. This is the mesh ' + regional_mesh) + grids.append(regional_mesh) + + +info = pd.DataFrame.from_dict(details, orient='index') +print(info) +info.to_csv(DATA_FOLDER + '/info.csv') + + +kwargs_set = { + 'default': {}, + '150': {'border_radius': 150, 'vmin': 0}, + 'inner': {'border_radius': 30, 'vmin': 0}, +} + +for test, kwargs in kwargs_set.items(): + + f = DATA_FOLDER + '/distortion.' + test + '.png' + if not os.path.isfile(f): + compare_plot_mpas_regional_meshes(grids, + outfile=f, + suptitle='Meshes comparison: ' + 'Distortion', + vname='cellDistortion', + each_title=': ' + ' cells', + lat_ref=lat_ref, + lon_ref=lon_ref, + cmap='magma', + **kwargs + ) + + f = DATA_FOLDER + '/ratio_al.' + test + '.png' + if not os.path.isfile(f): + compare_plot_mpas_regional_meshes(grids, + outfile=f, + suptitle='Meshes comparison: ' + 'A/L Ratio', + vname='area_length_ratio', + each_title=': ' + ' cells', + lat_ref=lat_ref, + lon_ref=lon_ref, + cmap='magma', + **kwargs + ) +kwargs_set = { + 'default': {}, + '200': {'border_radius': 200, 'vmin': 3, 'vmax': 20}, + '50': {'border_radius': 50, 'vmin': 3, 'vmax': 15}, + 'inner': {'border_radius': 30, 'vmin': 2.7, 'vmax': 3.3}, +} + +for test, kwargs in kwargs_set.items(): + f = DATA_FOLDER + '/compare.' + test + '.png' + if not os.path.isfile(f): + compare_plot_mpas_regional_meshes(grids, + outfile=f, + suptitle='Meshes comparison', + each_title=': ' + ' cells', + lat_ref=lat_ref, + lon_ref=lon_ref, + **kwargs + ) diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/view_mpas_grid.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/view_mpas_grid.py new file mode 100644 index 0000000..d2db48b --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/examples/view_mpas_grid.py @@ -0,0 +1,27 @@ +import argparse +import os + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file +from vtxmpasmeshes.plot_utilities import plot_mpas_darray +from vtxmpasmeshes.mpas_plots import view_mpas_regional_mesh + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument( + "-g", "--grid", type=str, required=True, + help="Name of an MPAS grid.nc", +) + +parser.add_argument( + "-o", "--outfile", type=str, default=None, + help="File to save the MPAS plot", +) + +args = parser.parse_args() + +if not os.path.exists(args.grid): + raise IOError('File does not exist: ' + args.grid) + +view_mpas_regional_mesh(args.grid, outfile=args.outfile) \ No newline at end of file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test2_gtm.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test2_gtm.py new file mode 100644 index 0000000..5c297e9 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test2_gtm.py @@ -0,0 +1,191 @@ +import os + +import pandas as pd + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file +from vtxmpasmeshes.mesh_generator import full_generation_process, \ + cut_circular_region_beta, cut_circular_region +from vtxmpasmeshes.mpas_plots import compare_plot_mpas_regional_meshes, \ + view_mpas_regional_mesh, plot_era5_grid, plot_wrf_grid, \ + plot_expected_resolution_rings + +from vtxmpasmeshes.plot_utilities import plot_mpas_darray, \ + set_plot_kwargs, add_colorbar, \ + start_cartopy_map_axis, close_plot + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature +import sys +from importlib import reload + +DATA_FOLDER = '/storage/guilherme_torresmendonca/projeto_nudging_mpas/' \ + 'vtx-mpas-meshes/data' +PATH_LIMITED_AREA = '/storage/guilherme_torresmendonca/MPAS-Limited-Area' +sys.path.append('/storage/guilherme_torresmendonca/projeto_nudging_mpas/' \ + 'vtx-mpas-meshes/vtxmpasmeshes') + + +# SITE: perdigao +lat_ref = 39.7136 +lon_ref = -7.73 + +highres = 3 # cgs +lowres = 20 # mgs +numlayers = 8 # layers outside requested nominal radius + +details = {} +grids = [] +for margin in [#50, + #75, + 100, + #125, + #150, 250 + ]: + for size in [#15, + #20, 25, + 30,# 35, + #50 + ]: + + name = 'senst_s' + str(size).zfill(2) + '_m' + str(margin).zfill(3) + folder = DATA_FOLDER + '/' + name + '/' + basename = folder + name + + global_mesh = basename + '.grid.nc' + if not os.path.exists(global_mesh): + os.system('mkdir -p ' + folder) + + # I do a global mesh centered at 0,0 -> to use in MPAS workflow + print ('creating global mesh centered at 0,0 for mpas workflow') + full_generation_process( + global_mesh, 'doughnut', + redo=False, do_plots=False, do_region=False, + highresolution=highres, lowresolution=lowres, + size=size, margin=margin, + lat_ref=0., lon_ref=0., + ) + + radius = size+margin + region_border = radius + (numlayers*lowres)*0.9 + configid = '99' + str(size).zfill(2) + str(margin).zfill(3) + details[name] = { + 'globalfile': global_mesh, + 'configid': configid, + 'size': size, + 'margin': margin, + 'radius': radius, + 'region_border': region_border, + } + + with open(DATA_FOLDER + '/' + name + '/config.' + configid + '.txt', 'w') as f: + f.write('mesh=' + name + '.grid.nc \n') + f.write('resolution=3' + '\n') + f.write('inner_size=' + str(size) + '\n') + f.write('radius=' + str(radius) + '\n') + f.write('region_border=' + str(region_border) + '\n') + f.write('num_boundary_layers=8' + '\n') + f.write('product=raw' + '\n') + f.write('max_num_domains=2' + '\n') + f.write('time_integration_order=2' + '\n') + f.write('two_way_nesting=false' + '\n') + f.write('stream_list=\'reduced\'' + '\n') + f.write('final_vars=\'reduced\'' + '\n') + f.write('levs=\'as_vortex\'' + '\n') + + regional_mesh = DATA_FOLDER + '/' + name + '.region.grid.nc' + if not os.path.exists(regional_mesh): + # I do a regional mesh at my location -> with 4 layers + print ('creating regional mesh centered at chosen location') + full_generation_process( + regional_mesh, 'doughnut', + redo=False, do_plots=False, do_region=True, + highresolution=highres, lowresolution=lowres, + num_boundary_layers=numlayers, + size=size, margin=margin, + lat_ref=lat_ref, lon_ref=lon_ref, + ) + + f = DATA_FOLDER + '/' + name + '.mpaswrf_mesh.png' + if not os.path.isfile(f): + print('MPAS WRF Plots') + view_mpas_regional_mesh(regional_mesh, + outfile=f, + do_plot_resolution_rings=True, + do_plot_era5_grid=False, + do_plot_wrf_grid=True, + vname='resolution') + + vname = 'resolution' + units = 'km' + + ds = open_mpas_regional_file(regional_mesh, full=True) + + myats = ds.attrs + + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname]) + plot_mpas_darray(ds, vname, ax=ax, title='', lat_ref=0., + lon_ref=0., border_radius=None, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=DATA_FOLDER + '/' + name + '.mpasmesh.png', + size_fig=[6, 4]) + + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname]) + plot_mpas_darray(ds, vname, ax=ax, title='', lat_ref=0., + lon_ref=0., border_radius=None, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + plot_wrf_grid(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=DATA_FOLDER + '/' + name + '.mpaswrfmesh.png', + size_fig=[6, 4]) + + for border_radius in [size + 10, radius, region_border, + region_border + 200]: + ax = plt.axes(projection=ccrs.PlateCarree()) + zorder = 2 + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.stock_img() + ax.coastlines(resolution='10m', zorder=zorder + 1) + + gl = ax.gridlines(draw_labels=True, alpha=0., linestyle='--', + zorder=zorder + 2) + gl.top_labels = False + gl.right_labels = False + + plot_kwargs = set_plot_kwargs(ds[vname].where(ds['cellDistance'] + <= border_radius)) + plot_mpas_darray(ds, vname, ax=ax, title='', + border_radius=border_radius, + **plot_kwargs) + plot_expected_resolution_rings(ds, ax=ax) + plot_wrf_grid(ds, ax=ax) + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + ax.set_title(str(int(border_radius)) + 'km zoom', fontsize=14) + close_plot(outfile=DATA_FOLDER + '/' + name + '.regionmesh.' + + str(border_radius) + '.png', size_fig=[6, 4]) \ No newline at end of file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test_onlyregional_gtm.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test_onlyregional_gtm.py new file mode 100644 index 0000000..d46bd7e --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test_onlyregional_gtm.py @@ -0,0 +1,60 @@ +import os + +import pandas as pd + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file +from vtxmpasmeshes.mesh_generator import full_generation_process, \ + full_generation_process_gtm, cut_circular_region_beta, \ + cut_circular_region +from vtxmpasmeshes.mpas_plots import compare_plot_mpas_regional_meshes, \ + view_mpas_regional_mesh, plot_era5_grid, plot_wrf_grid, \ + plot_expected_resolution_rings + +from vtxmpasmeshes.plot_utilities import plot_mpas_darray, \ + set_plot_kwargs, add_colorbar, \ + start_cartopy_map_axis, close_plot + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature +import sys +from importlib import reload + +DATA_FOLDER = '/storage/guilherme_torresmendonca/projeto_nudging_mpas/' \ + 'vtx-mpas-meshes/data' + +#################################################################### +# USER INTERFACE # +#################################################################### +# Site: Perdigao +lat_ref = 39.7136 +lon_ref = -7.73 + +# Parameters +highres = 3 # cgs +lowres = 20 # mgs +numlayers = 8 # layers outside requested nominal radius +margin = 100 +size = 30 +#################################################################### + + +#################################################################### +name = 's' + str(size).zfill(2) + '_m' + str(margin).zfill(3) +radius = size+margin +region_border = radius + (numlayers*lowres)*0.9 + +regional_mesh = DATA_FOLDER + '/' + name + '.region.grid.nc' +if not os.path.exists(regional_mesh): + # Create a regional mesh at the desired location -> with 4 layers (?) + print ('creating regional mesh centered at chosen location') + full_generation_process_gtm( + regional_mesh, 'doughnut', + redo=False, do_plots=True, do_region=True, + highresolution=highres, lowresolution=lowres, + num_boundary_layers=numlayers, + size=size, margin=margin, + lat_ref=lat_ref, lon_ref=lon_ref, + ) +#################################################################### \ No newline at end of file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test_onlyregional_gtm_largermesh20240201.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test_onlyregional_gtm_largermesh20240201.py new file mode 100644 index 0000000..e75148d --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/gtm_tests/test_onlyregional_gtm_largermesh20240201.py @@ -0,0 +1,66 @@ +import os + +import pandas as pd + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file +from vtxmpasmeshes.mesh_generator import full_generation_process, \ + full_generation_process_gtm, cut_circular_region_beta, \ + cut_circular_region +from vtxmpasmeshes.mpas_plots import compare_plot_mpas_regional_meshes, \ + view_mpas_regional_mesh, plot_era5_grid, plot_wrf_grid, \ + plot_expected_resolution_rings + +from vtxmpasmeshes.plot_utilities import plot_mpas_darray, \ + set_plot_kwargs, add_colorbar, \ + start_cartopy_map_axis, close_plot + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature +import sys +from importlib import reload + +DATA_FOLDER = '/storage/guilherme_torresmendonca/projeto_nudging_mpas/' \ + 'vtx-mpas-meshes/data' + +#################################################################### +# USER INTERFACE # +#################################################################### +# Site: Perdigao +lat_ref = 39.7136 +lon_ref = -7.73 + +# Parameters +# These parameters define the changing in the resolution. Varying the distance +# from the center of mesh d, we define the expected grid spacing (S): +## 0 < d < size --> S = highres +## size < d < size + margin --> S = highres + lambda*(d-size) +## size + margin < d < alpha (not defined here) --> S = lowres +## alpha < d < beta (not defined here) --> S = lowres + lambda*(d-(size+margin)) +size = 30 # s in the paper +highres = 10 # cgs in the paper +margin = 200 # m in the paper +lowres = 20 # mgs in the paper +numlayers = 8 # layers outside requested nominal radius +#################################################################### + + +#################################################################### +name = 's' + str(size).zfill(2) + '_m' + str(margin).zfill(3) +radius = size+margin +region_border = radius + (numlayers*lowres)*0.9 + +regional_mesh = DATA_FOLDER + '/' + name + '.region.grid.nc' +if not os.path.exists(regional_mesh): + # Create a regional mesh at the desired location -> with 4 layers (?) + print ('creating regional mesh centered at chosen location') + full_generation_process_gtm( + regional_mesh, 'doughnut', + redo=False, do_plots=True, do_region=True, + highresolution=highres, lowresolution=lowres, + num_boundary_layers=numlayers, + size=size, margin=margin, + lat_ref=lat_ref, lon_ref=lon_ref, + ) +#################################################################### \ No newline at end of file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/notebooks/1. Resolution latlon plots.ipynb b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/notebooks/1. Resolution latlon plots.ipynb new file mode 100644 index 0000000..c441ebd --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/notebooks/1. Resolution latlon plots.ipynb @@ -0,0 +1,467 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d87dc29e", + "metadata": {}, + "source": [ + "# Obtain a map with the expected resolution at every lat/lon location" + ] + }, + { + "cell_type": "markdown", + "id": "c2358ca1", + "metadata": {}, + "source": [ + "## The 'doughnut' family of resolution profiles" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "780a808d", + "metadata": {}, + "outputs": [], + "source": [ + "from vtxmpasmeshes.mesh_generator import doughnut_variable_resolution\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "aeb306e8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 0. 40. 140. 390. 4821.81818182\n", + " 9643.63636364]\n", + "[ 3 3 25 25 1000 1000]\n", + "Default Parameters:\n", + "{'lowresolution': 25, 'highresolution': 3, 'size': 40, 'margin': 100, 'final_res_dist': 1000, 'radius': 140, 'buffer': 250, 'border': 390}\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "grid = 'doughnut'\n", + "\n", + "# my default resolution style is called 'doughnut'\n", + "\n", + "dists, resol, attrs = doughnut_variable_resolution()\n", + "\n", + "# The shape has a constant inner circle at high resolution, linear increase of resolution, \n", + "# and a low resolution ring followed by a \"crazy\" increase of resolution outside the \n", + "# region we want to focus in\n", + "\n", + "print(dists)\n", + "print(resol)\n", + "\n", + "print('Default Parameters:')\n", + "print(attrs)\n", + "\n", + "plt.scatter(dists, resol)\n", + "plt.plot(dists, resol)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "267f84fe", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# We can then find the resolution corresponding to any distance, to obtain a more detailed plot\n", + "\n", + "from vtxmpasmeshes.mesh_generator import apply_resolution_at_distance\n", + "\n", + "example_dists = np.arange(10, 500, 10)\n", + "# we pass the distances where we want to interpolate (linearly) the distance/resolution pairs \n", + "# that were the output of the doughnut_variable_resolution() function (ie, dists and resol)\n", + "result_resolution = apply_resolution_at_distance(example_dists, dists, resol)\n", + "\n", + "plt.scatter(example_dists, result_resolution)\n", + "plt.plot(example_dists, result_resolution)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b5c25c10", + "metadata": {}, + "source": [ + "## Personalizing 'doughnut' resolution profiles" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "269753a8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Custom Parameters\n", + "[ 0. 100. 200. 500. 3844.82758621\n", + " 7689.65517241]\n", + "[ 1 1 30 30 1000 1000]\n", + "{'highresolution': 1, 'lowresolution': 30, 'size': 100, 'margin': 100, 'final_res_dist': 1000, 'radius': 200, 'buffer': 300, 'border': 500}\n", + "Plot in a specific range\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "print('Custom Parameters')\n", + "\n", + "dists2, resol2, attrs2 = doughnut_variable_resolution(highresolution=1, lowresolution=30, size=100, margin=100)\n", + "\n", + "print(dists2)\n", + "print(resol2)\n", + "print(attrs2)\n", + "\n", + "print('Plot in a specific range')\n", + "\n", + "example_dists = np.arange(10, 500, 10)\n", + "result_resolution = apply_resolution_at_distance(example_dists, dists2, resol2)\n", + "\n", + "plt.scatter(example_dists, result_resolution)\n", + "plt.plot(example_dists, result_resolution)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "455626dc", + "metadata": {}, + "source": [ + "## Generating a latlon map with the resolution computed from the distance from a certain reference point" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "14e304b1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + ">> Creating a variable resolution map\n", + "\tResolution in km of lat/lon grid: 10.0\n", + "\tComputing the distance to the reference point (-30.00, -100.00)\n", + "\tComputing resolutions using technique doughnut\n", + "\n", + "Dimensions: (lat: 1981, lon: 3961)\n", + "Coordinates:\n", + " * lat (lat) float64 -90.0 -89.91 -89.82 -89.73 ... 89.82 89.91 90.0\n", + " * lon (lon) float64 -180.0 -179.9 -179.8 -179.7 ... 179.8 179.9 180.0\n", + "Data variables:\n", + " distance (lat, lon) float64 6.668e+03 6.668e+03 ... 1.334e+04 1.334e+04\n", + " resolution (lat, lon) float64 1e+03 1e+03 1e+03 1e+03 ... 1e+03 1e+03 1e+03\n", + "Attributes:\n", + " lat_ref: -30\n", + " lon_ref: -100\n", + " lowresolution: 25\n", + " highresolution: 3\n", + " size: 40\n", + " margin: 100\n", + " final_res_dist: 1000\n", + " radius: 140\n", + " buffer: 250\n", + " border: 390\n", + "\n", + "Direct plots\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from vtxmpasmeshes.mesh_generator import variable_resolution_latlonmap\n", + "\n", + "# We can generate a global resolution latlon map centered at the reference point:\n", + "lat_ref=-30\n", + "lon_ref=-100\n", + "ds = variable_resolution_latlonmap('doughnut', lat_ref=lat_ref, lon_ref=lon_ref)\n", + "\n", + "print(ds)\n", + " \n", + "print('\\nDirect plots')\n", + "ds['distance'].plot(cmap='magma_r')\n", + "plt.title('Distance from reference point (%.1f, %.1f)' % (lat_ref, lon_ref))\n", + "plt.show()\n", + "\n", + "\n", + "ds['resolution'].plot()\n", + "plt.title('Resolution map')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e23df232", + "metadata": {}, + "source": [ + "## Making nice plots of the resolution maps" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d28884cf", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'highresolution': 3, 'lowresolution': 20, 'size': 30, 'margin': 80, 'lat_ref': 51.0, 'lon_ref': -5.0}\n", + "\n", + ">> Creating a variable resolution map\n", + "\tResolution in km of lat/lon grid: 3.0\n", + "\tComputing the distance to the reference point (51.00, -5.00)\n", + "\tComputing resolutions using technique doughnut\n", + "\n", + "Dimensions: (lat: 6601, lon: 13201)\n", + "Coordinates:\n", + " * lat (lat) float64 -90.0 -89.97 -89.95 -89.92 ... 89.95 89.97 90.0\n", + " * lon (lon) float64 -180.0 -180.0 -179.9 -179.9 ... 179.9 180.0 180.0\n", + "Data variables:\n", + " distance (lat, lon) float64 1.567e+04 1.567e+04 ... 4.334e+03 4.334e+03\n", + " resolution (lat, lon) float64 1e+03 1e+03 1e+03 1e+03 ... 875.1 875.1 875.1\n", + "Attributes:\n", + " highresolution: 3\n", + " lowresolution: 20\n", + " size: 30\n", + " margin: 80\n", + " lat_ref: 51.0\n", + " lon_ref: -5.0\n", + " final_res_dist: 1000\n", + " radius: 110\n", + " buffer: 200\n", + " border: 310\n", + "\n", + "Direct plot\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Cartopy plots with km limits\n", + "\t .. plotting for distances <= 3000km\n" + ] + }, + { + "data": { + "image/png": "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Rd5xxx2MHDmSHj161On7YVkW5557Lo8//jh3332379QH+wRw1FFHsd9++9G0aVP+9Kc/MXz48KTj/vGPf2CaJitWrODEE09k5syZlSq3bM957Aox7rF582YeeeQRBg0axHvvvceJJ57o79N1nbPPPpvXXnsNqD/fjarYnSsAqplWFLsFL0wr4Oflm7j9pF40aaBGeCsUirplzZo12z5oD6C685BScv7553PFFVcwcuRIv33Dhg1Mnz6d6667zp8o5v7779+pPlRUVNC4ceMaRx28adv79+9P69atWbFiBQUFBTvVh6pYvXo1b7/9tjtQ9XJycnLIzs6utvyhruu0aNECXde57rrr6NWrV6VjDMOgdevWfPrppwghuPzyy5Nc5+35XD3zzDPceeed239iO0DDhg25+eab+eijjzjppJOYOXNm0v7PPvvMrz2+S74b3qDO2r5BvhBiRuB2WXVd2FoFQCBYAXB54G5VVgCsDZQgV6Sd5RvK+Ocn8zm8W1NO2q9VurujUCj2AsrLy9PdhVqhuvPYvHkzv/76K0II1q1bx9SpU3n44YdZuHAh77//PosWLQKgRYsWOy3IMzIyWLt27XbX+T7xxBNp2LAhkyZN2upU7tuLZVmUlpYSj8f59ddfAaf+tnchUBN++OGHrQ66zM/PB+Dqq6+mV69eTJ8+nYcffni7PletW7dm1qxZvPrqqwD+6/fqq69yzjnnAM5r9P7771NSUkJOTg4AEyZM4LLLHJ05dOhQvvrqK1auXEmrVs7/n//617+47rrrACeGMnPmTBYsWMA+++zD8OHDad68OePGjUvqy0knneRfFO2y70bdCPJ1UsqBgduEqp46tQLgVnpZowqAtYHYk8P7AwcOlDNmzEh3NxQ7gZSS85+dzqxlG/ns74fRqlFmurukUOwyhBAzpZQD0/TcbYGXgBaADUyQUj4shMgD3gA6AAXASCnlRvc+DwCH42Qwv3YdpiXA36SUj7jHPArMkFK+UNXz7i5/twsKCurFbITVncfnn3/OsGHDOPjgg7n00kvp1asXl156KR9//DHLli3j8ccf57nnnuPOO++kR48enHHGGTvVj88//5zevXvTokWLHbr/kiVLWLFiBZMnT+bBBx/c9h22woMPPkhFRQU33XTTDj9GRUUFpaWlNGnSpEbHL1u2jCVLltC+fXveeecdRo0a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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t .. plotting for distances <= 1000km\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t .. plotting for distances <= 500km\n" + ] + }, + { + "data": { + "image/png": "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T+WKK66gU6dOAEybNo2ZM2eSn59Pfn4+Y8aMSf0Bsa79d5TXf1P2LyLNV71U66DhWim12T3/+WKiCY+jR5ete2O11erdu/e6N9L9bzLXdVPB+h//+AfhcJjp06dz5JFHsssuu/D73/+eyy67jFtuuYWTTjoJgJtvvpnTTz+dJUuW8MILLwAwf/58KioqUtXpl19+ObWPffbZh/fee49hw4at97h69+5NKBRi6dKllJaWcsIJJ/xgm/79+7NgwQI6d+7MoEGDOOecc7jyyisBMMYwceJEnnzySY466igaGhpYuXIlH374IZdddhnHHXccI0aMWOtMRB3l9c/m/gXTIXuuNVwrpTa7SVMXMLh7ASP7dMr2UFQWrVmzhi5duuj+25ht28yfP5/q6mrmzp1LVVUVY8eOZeDAgTzyyCO888473HDDDfz85z8HoLy8nO2335777ruPHXbYAYCZM2dyySWX8OijjwJQXV3NMccck9pHdXU12223HWPGjOHwww9n++23Z5999vnRCnLy8Xfv3p1EIsGbb77Ju+++S1FREV999RVTpkxhzpw5ANTV1bFgwQIefvhhFi1aRFFREW+//TZLly7l5ZdfZr/99kvd7yGHHML777/PQw89hGVZnHPOOey555706dOHnj17Ytt2k/1nS0ff/9ZMw7VSarOatbyWafOrufzgoTq3dQdXU1OT1f+5b+37d12Xjz76iH//+990796dO+64g+rqajp16sTBBx/M8OHD+ctf/sIZZ5zBz372s1S4njt3Lo2NjRx//PFMmTIFx3F47bXXUsEa4K9//Su9evVi0aJF/P73vycnJ4enn36ajz76KNUSdPvtt3P22We3OLbmj19EGDduHOPGjUtdf/fddwPgeR7V1dXU1tayatUqnnzyScLhMFdffTX77LNPqq0k6fnnn0+d/vjjj7nrrrt4/PHHqayspKqqin/84x/84he/2Opf//ayf52KTyml2tjkikpsSzhih+x+JarU1iyRSDBixAiWLFlCdXU1+++/P++//z7//ve/ufXWW7nrrrs499xzufDCC7n88suxbZtjjjmGxx9/nCVLlvDwww/zyCOPpO7vl7/8Zep0KBTiscce4/TTT+fOO+/krLPOorS0lMsuu6xNHotlWZSUlFBSUkLfvn03qLd77NixjB07NnX+jTfe4Oyzz6aqqorjjz++LYarMghgd8C2EJ2KTym12bie4clpleyzTTe6F+rc1h1dtr+S3pr3/89//pMZM2bw7LPPAn5/dNeuXdl///2xbZvy8nIsy+Kmm25K9VCfcsopgD+LxBlnnMG+++7L7bffDsALL7zAo48+yvjx49lpp534/vvvufTSS9lzzz2ZMmXKRo0xG8//uHHjeO2117j77rv5z3/+Qzwe3+xjSNqa338dnYZrpdRm8873y1m6JsrRY3Ru69YgInNF5AsRmS4iU4PLrhKRhcFl00Xk4PW9bXB5LxF5XUSeFpGCjPusF5HuGdvVbur413fKtLayNe//mmuuAeCoo45KXVZSUsK+++7LDjvswAEHHMC9997b5DZ77bUXPXr4U2O++uqrdOrUidtuu41+/fpx8MEH87///Y+bb76Z0aNHA37LxVNPPUVpaelGjTFbz3+vXr346KOP+Oqrr9hrr71YvHhxVsaxNb//muxHWv+nvdNwrZTabCZVVNI5L8RPhurc1q1onDFme2PMmIzL/hZctr0x5oUNvO15wLnAv4CTMi5fAVzUesOG5cuXt+bd6f4z7LbbbpSXl/PMM89w6aWXAnD++edz++238/7775NIJH6w/9/97nfU1dWxYsUKli5dyrvvvovrukyYMIEpU6bQt29fjjrqKG6++WaqqqoYPHgw22+/Pccccwy/+c1vmsx5vT6y+fx3796d6667jj333JM99tiDgw8+mOnTp6emJNwctub3X0en4VoptVmsro/zyldLOXz73oQd/aenHbMBL/jJrBHdBxwrIiVZGZXaIJMnT2bOnDnsvPPOPPDAAwA8++yzTJs2jaeeeirVLpJUVVXFE088wfPPP0+XLl34+OOPWbp0KfPmzePCCy/k8MMP56qrrmLu3LnccccdlJSU0Lt3bz799FPuuOMOZs2axejRo5v0abd3IsL111/P5ZdfzosvvsgOO+zA0KFDN/iPBLV2Iv7y5639097p/+GUUpvFM58tJOZ6TNTlzluTAV4WkQoROTPj8nNE5HMRuU9EOm/gbW8D7gLOAh7KuLwWP2Cf31qDX5+FPtpSR9n/k08+yQMPPMDXX3/NvffeyxFHHIGINNn/tGnTcByHvfbaC4AvvviC448/ngMOOIBzzz03td2gQYM4//ymb4EzzjiDp556imOOOYYTTjiBefPmrde42sPzLyKc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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t .. plotting for distances <= 310km\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\t .. plotting for distances <= 110km\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "from vtxmpasmeshes.mpas_plots import view_resolution_map\n", + "\n", + "test = {'highresolution': 3, 'lowresolution': 20, 'size': 30, 'margin': 80, 'lat_ref': 51., 'lon_ref': -5.}\n", + "\n", + "print(test)\n", + "ds = variable_resolution_latlonmap(grid, **test)\n", + "print(ds)\n", + "\n", + "print('\\nDirect plot')\n", + "ds['resolution'].plot()\n", + "plt.show()\n", + "plt.title('Resolution map')\n", + "\n", + "# those are nicer plots\n", + "print('\\nCartopy plots with km limits')\n", + "view_resolution_map(ds, list_distances=[3000, 1000, 500, ds.attrs['border'], ds.attrs['radius']])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "vtx-mpas", + "language": "python", + "name": "vtx-mpas" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/plot_regional_cl.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/plot_regional_cl.py new file mode 100644 index 0000000..ab6be9d --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/plot_regional_cl.py @@ -0,0 +1,16 @@ +import os +import argparse +from vtxmpasmeshes.mpas_plots import view_mpas_regional_mesh + +# Create ArgumentParser object +parser = argparse.ArgumentParser(description= + 'Sensitivity test for varying mesh parameters.') +# Input arguments +parser.add_argument('--filename', type=str, default='circle.grid.nc') +parser.add_argument('--var', type=str, default='resolution') +parser.add_argument('--plot_rings', type=str, default=True) + +# Parse the command line arguments +args = parser.parse_args() + +view_mpas_regional_mesh(args.filename,outfile=f'{args.filename}_mesh.png',vname=args.var,do_plot_resolution_rings=eval(args.plot_rings)) diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/setup.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/setup.py new file mode 100644 index 0000000..fa6ae8b --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/setup.py @@ -0,0 +1,24 @@ +import setuptools + +dependencies = [ + 'xarray', + 'mpas-tools', + 'jigsaw', +] + +setuptools.setup( + name="vtxmpasmeshes", + version="0.0.1", + author="Marta Gil Bardaji, Gerard Cavero Siscart et al.", + author_email="marta.gil@vortexfdc.com", + description="MPAS and WRF for python", + packages=setuptools.find_packages(include=['vtxmpasmeshes']), + classifiers=[ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + ], + python_requires='>=3.7', + install_requires=dependencies, + maintainer='Marta Gil Bardaji', + maintainer_email='marta.gil@vortexfdc.com', +) \ No newline at end of file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes.egg-info/PKG-INFO b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes.egg-info/PKG-INFO new file mode 100644 index 0000000..3c8da20 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes.egg-info/PKG-INFO @@ -0,0 +1,11 @@ +Metadata-Version: 2.1 +Name: vtxmpasmeshes +Version: 0.0.1 +Summary: MPAS and WRF for python +Author: Marta Gil Bardaji, Gerard Cavero Siscart et al. +Author-email: marta.gil@vortexfdc.com +Maintainer: Marta Gil Bardaji +Maintainer-email: marta.gil@vortexfdc.com +Classifier: Programming Language :: Python :: 3 +Classifier: Operating System :: OS Independent +Requires-Python: >=3.7 diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/__init__.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/dataset_utilities.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/dataset_utilities.py new file mode 100644 index 0000000..5c99e37 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/dataset_utilities.py @@ -0,0 +1,534 @@ +import numpy as np +import xarray as xr +import math +from geopy.distance import distance + + +derived_variables = { + 'latCell': ['latitude'], + 'lonCell': ['longitude'], + 'latVertex': ['latitudeVertex'], + 'lonVertex': ['longitudeVertex'], + 'areaCell': ['area', 'resolution'], +} + + +def distance_latlon_matrix(lat, lon, lat_ref=0., lon_ref=0., do_tile=False): + if do_tile: + lat = np.tile(lat, (len(lon), 1)).transpose() + lon = np.tile(lon, (len(lat), 1)) + + lon, lat, lon_ref, lat_ref = map(np.radians, [lon, lat, lon_ref, lat_ref]) + + newlon = lon_ref - lon + newlat = lat_ref - lat + + haver_formula = np.sin(newlat / 2.0) ** 2 + np.cos(lat) * \ + np.cos(lat_ref) * np.sin(newlon / 2.0) ** 2 + + dist = 2 * np.arcsin(np.sqrt(haver_formula)) + km = 6367 * dist # 6367 for distance in KM for miles use 3958 + return km + + +def add_mpas_mesh_variables(ds, full=True, **kwargs): + for v in ds.data_vars: + if v not in derived_variables: + continue + + newvs = derived_variables[v] + + for newv in newvs: + if newv in ds: + #print(newv + ' already here') + continue + + if 'lat' in v or 'lon' in v: + ds[newv] = xr.apply_ufunc(np.rad2deg, ds[v]) + ds[newv] = ds[newv].where(ds[newv] <= 180.0, ds[newv] - 360.0) + ds[newv].attrs['units'] = 'degrees' + + elif newv == 'area': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1: + #print('need to correct to earth radius!!') + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + ds[newv] = (ds[v] / 10 ** 6) * correction_rad_earth**2 + ds[newv].attrs['units'] = 'km^2 (assuming areaCell in m^2)' + ds[newv].attrs['long_name'] = 'Area of the cell in km^2' + + elif newv == 'resolution': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1.0: + #print('need to correct to earth radius!!') + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + # km^2 (assuming areaCell in m^2) + area = (ds[v] / 10 ** 6) * correction_rad_earth**2 + + ds[newv] = 2 * (xr.apply_ufunc(np.sqrt, area / math.pi)) + ds[newv].attrs['units'] = 'km' + ds[newv].attrs['long_name'] = 'Resolution of the cell (approx)' + + if full: + ref_point = {} + for v in ['lat_ref', 'lon_ref']: + if v in kwargs: + ref_point[v] = kwargs[v] + ds = add_distance_to_reference(ds, **ref_point) + + ds = compute_metrics_edge_lengths(ds) + ds = compute_metrics_triangle_quality(ds) + + return ds + + +def get_center(lats, lons): + """ + Given 2 DataArrays of lats, lons, it returns the grid center lat, + lon. + :param lats: DataArray of latitudes + :param lons: DataArray of longitudes + :return: lat, lon: floats + """ + + lat = float(lats[abs(lats - lats.mean()).argmin()]) + lon = float(lons[abs(lons - lons.mean()).argmin()]) + + return lat, lon + + +def get_distance_to_center(lats, lons, + center_lat=None, center_lon=None): + """ + Using the haversine formula (spherical distance), it returns the + distance in km of each lat, lon point to the + central point. + """ + if center_lat is None or center_lon is None: + center_lat, center_lon = get_center(lats, lons) + + radius = 6371. # km + d_lat = np.radians(lats - center_lat) # lat distance in radians + d_lon = np.radians(lons - center_lon) # lon distance in radians + + a = (np.sin(d_lat / 2.) * np.sin(d_lat / 2.) + + np.cos(np.radians(center_lat)) * np.cos(np.radians(lats)) * + np.sin(d_lon / 2.) * np.sin(d_lon / 2.)) + c = 2. * np.arctan2(np.sqrt(a), np.sqrt(1. - a)) + d = radius * c + + return d + + +def compute_metrics_edge_lengths(ds): + distances = [] + + for i, cell in enumerate(ds['nCells'].values): + vals = ds['verticesOnCell'].sel(nCells=cell).values + + num_sides = int(ds['nEdgesOnCell'].sel(nCells=cell)) + vals = vals[:num_sides] - 1 + lats = ds['latitudeVertex'].values[vals] + lons = ds['longitudeVertex'].values[vals] + lat_ref = lats[-1] + lon_ref = lons[-1] + + my_cell_dists = [] + for i in range(ds.dims['maxEdges']): + if i >= num_sides: + my_cell_dists.append(np.nan) + continue + d = distance_latlon_matrix(lats[i], lons[i], + lat_ref=lat_ref, + lon_ref=lon_ref, do_tile=False) + + my_cell_dists.append(d) + lat_ref, lon_ref = lats[i], lons[i] + distances.append(my_cell_dists) + + ds['edgesLength'] = xr.DataArray(data=distances, + dims=('nCells', 'maxEdges')) + ds['edgesLength'].attrs = { + 'name': 'Length of edges', + 'units': 'km', + 'long_name': 'Haversine distance between adjacent vertices of a cell.' + } + + ds['mean_edgesLength'] = ds['edgesLength'].mean(dim='maxEdges') + ds['mean_edgesLength'].attrs = { + 'name': 'Mean edge length', + 'units': 'km', + 'long_name': 'Mean edge length of a cell.' + } + + ds['min_edgesLength'] = ds['edgesLength'].min(dim='maxEdges') + ds['min_edgesLength'].attrs = { + 'name': 'Minimum edge length', + 'units': 'km', + 'long_name': 'Minimum edge length of a cell.' + } + + ds['max_edgesLength'] = ds['edgesLength'].max(dim='maxEdges') + ds['max_edgesLength'].attrs = { + 'name': 'Maximum edge', + 'units': 'km', + 'long_name': 'Maximum edge length of a cell.' + } + + ds['rmse_edgesLength'] = xr.apply_ufunc(np.sqrt, + (ds['edgesLength'] ** 2).mean( + dim='maxEdges')) + ds['rmse_edgesLength'].attrs = { + 'name': 'Rmse edge length', + 'units': 'km', + 'long_name': 'Root mean squared edge length.' + } + + ds['ration_edgesLength'] = ds['min_edgesLength'] / ds['max_edgesLength'] + ds['ration_edgesLength'].attrs = { + 'name': 'Ratio of edge lengths', + 'units': '', + 'long_name': 'Ratio between minimum and maximum edge lengths ' + 'of a cell.' + } + + ds['cellDistortion'] = xr.apply_ufunc(np.sqrt, ( + (ds['edgesLength'] - ds['rmse_edgesLength']) ** 2).mean( + dim='maxEdges')) / ds['rmse_edgesLength'] + ds['cellDistortion'].attrs = { + 'name': 'Cell Distortion', + 'units': '', + 'long_name': 'Cell Distortion: Haversine distance between adjacent ' + 'vertices of a cell. ' + 'https://pedrosp.ime.usp.br/papers/PeixotoBarros2013.pdf' + } + return ds + + +def add_distance_to_reference(ds, **kwargs): + lat_ref = kwargs.get('lat_ref', ds.attrs.get('vtx-param-lat_ref', None)) + lon_ref = kwargs.get('lon_ref', ds.attrs.get('vtx-param-lon_ref', None)) + + if lat_ref is None or lon_ref is None: + print('WARNING Not enough info to add distance to center') + return ds + + d = get_distance_to_center(ds['latitude'].values, ds['longitude'].values, + center_lat=lat_ref, center_lon=lon_ref) + + ds['cellDistance'] = xr.DataArray(data=d, dims=('nCells')) + ds['cellDistance'].attrs = { + 'name': 'Distance to ref. point', + 'units': 'km', + 'long_name': 'Distance from cell center to reference point' + } + return ds + + +def open_mpas_regional_file(file, **kwargs): + ds = xr.open_dataset(file) + ds = add_mpas_mesh_variables(ds, **kwargs) + return ds + + +def compute_metrics_triangle_quality(ds): + distances = [] + circ_radius = [] + area_triangles = [] + for vertex in ds['nVertices']: + vals = ds['cellsOnVertex'].sel(nVertices=vertex).values + + if 0 in vals: + distances.append([np.nan, np.nan, np.nan]) + circ_radius.append(np.nan) + area_triangles.append(np.nan) + continue + + vals = vals - 1 + lats = ds['latitude'].sel(nCells=vals).values + lons = ds['longitude'].sel(nCells=vals).values + + lat_ref = lats[-1] + lon_ref = lons[-1] + + dis = [] + for i in range(3): + d = distance_latlon_matrix(lats[i], lons[i], + lat_ref=lat_ref, + lon_ref=lon_ref, do_tile=False) + dis.append(d) + lat_ref, lon_ref = lats[i], lons[i] + + # abc / np.sqrt( ( a + b + c ) ( b + c − a ) ( c + a − b ) ( a + b − c ) ) + radius_ball = dis[0] * dis[1] * dis[2] / np.sqrt( + (dis[0] + dis[1] + dis[2]) * (-dis[0] + dis[1] + dis[2]) * ( + dis[0] - dis[1] + dis[2]) * (dis[0] + dis[1] - dis[2])) + circ_radius.append(radius_ball) + + # sqrt(p ( p − a ) ( p − b ) ( p − c )) where p is half-perimeter + p = (dis[0] + dis[1] + dis[2]) / 2 + area = np.sqrt(p * (p - dis[0]) * (p - dis[1]) * (p - dis[2])) + area_triangles.append(area) + + distances.append(dis) + + ds['tsideLength'] = xr.DataArray(data=distances, + dims=('nVertices', 'vertexDegree')) + ds['tsideLength'].attrs = { + 'name': 'Length of sides for a triangle', + 'units': 'km', + 'long_name': 'Haversine distance between adjacent vertices of triangles (center ' + 'cells that surround a vertex).' + } + + ds['mean_tsideLength'] = ds['tsideLength'].mean(dim='vertexDegree') + ds['edgesLength'].attrs = { + 'name': 'Mean side length', + 'units': 'km', + 'long_name': 'Mean side length of a triangle.' + } + + ds['min_tsideLength'] = ds['tsideLength'].min(dim='vertexDegree') + ds['min_tsideLength'].attrs = { + 'name': 'Minimum side length', + 'units': 'km', + 'long_name': 'Minimum side length of a triangle.' + } + + ds['max_tsideLength'] = ds['tsideLength'].max(dim='vertexDegree') + ds['max_tsideLength'].attrs = { + 'name': 'Maximum side length', + 'units': 'km', + 'long_name': 'Maximum side length of a triangle.' + } + + ds['rmse_tsideLength'] = xr.apply_ufunc(np.sqrt, + (ds['tsideLength'] ** 2).mean( + dim='vertexDegree')) + ds['rmse_tsideLength'].attrs = { + 'name': 'Rmse side length', + 'units': 'km', + 'long_name': 'Root mean squared side length.' + } + + ds['ratio_tsideLength'] = ds['min_tsideLength'] / ds['max_tsideLength'] + ds['ratio_tsideLength'].attrs = { + 'name': 'Ratio of side lengths', + 'units': 'km', + 'long_name': 'Ratio between minimum and maximum side lengths of a triangle.' + } + + ds['triangleDistortion'] = xr.apply_ufunc(np.sqrt, ( + (ds['tsideLength'] - ds['rmse_tsideLength']) ** 2).mean( + dim='vertexDegree')) / ds['rmse_tsideLength'] + ds['triangleDistortion'].attrs = { + 'name': 'Triangle Distortion', + 'units': 'km', + 'long_name': 'Triangle Distortion: computed from the distance between cell centers surrounding a vertex.' + } + + # Circumscribing circle radius : + ds['circums_radius'] = xr.DataArray(data=circ_radius, dims=('nVertices')) + ds['circums_radius'].attrs = { + 'name': 'Radius of the circumscribing circle', + 'units': 'km', + 'long_name': 'Radius of the circumscribing circle of a triangle.' + } + + # https://gmd.copernicus.org/articles/10/2117/2017/gmd-10-2117-2017.pdf + # definition 2 (radius-edge ratio) + ds['radius_edge_ratio'] = ds['circums_radius'] / ds['min_tsideLength'] + ds['circums_radius'].attrs = { + 'name': 'Radius-edge ratio', + 'units': '', + 'long_name': 'The radius-edge ratio is a measure of element shape quality: circums_radius/min_tsideLength' + } + + # Area triangle: + # Definition 3 (area–length ratio) + ds['area_triangle'] = xr.DataArray(data=area_triangles, dims=('nVertices')) + ds['area_triangle'].attrs = { + 'name': 'Area of a triangle', + 'units': 'km', + 'long_name': 'Area of a triangle (from latlon distances).' + } + + ds['area_length_ratio'] = 4 * np.sqrt(3) / 3 * ds['area_triangle'] / ( + ds['rmse_tsideLength'] ** 2) + ds['area_length_ratio'].attrs = { + 'name': 'Area-length ratio', + 'units': 'km', + 'long_name': 'Area-length ratio: 4sqrt(3)/3 area/(rmse_tsideLength)**2' + } + + return ds + + +def get_borders_at_distance(distance_km, centerlat=0., centerlon=0.): + len_grid = distance(kilometers=distance_km) + + maxlat = len_grid.destination(point=(centerlat, centerlon), + bearing=0).latitude + minlat = len_grid.destination(point=(centerlat, centerlon), + bearing=180).latitude + maxlon = len_grid.destination(point=(centerlat, centerlon), + bearing=90).longitude + minlon = len_grid.destination(point=(centerlat, centerlon), + bearing=270).longitude + + return minlon, maxlon, minlat, maxlat + + +def find_min_number_wrf_cells(distance_km=None, resolution_km=None, + previous_domain_cells=0, + margin_cells_each_side=9, + force_buffer=False): + + if distance_km is not None and resolution_km is not None: + min_num_cells = int(distance_km / resolution_km) + # print(' - distance: %f' % distance_km) + # print(' - resolution_km: %f' % resolution_km) + # print(' - minimum number: %f' % min_num_cells) + else: + min_num_cells = 1 + + # num wrf cells has to be odd and multiple of 3. + # it also has to be >= 27 and > previous domain num cells / 3 + 18 + + if previous_domain_cells > 0: + # print(' - previous_domain_cells: %f' % previous_domain_cells) + at_least = int(previous_domain_cells / 3 + 2*margin_cells_each_side) + min_num_cells = max(min_num_cells, at_least) + + if force_buffer: + smallest_grid = int(2 * margin_cells_each_side) + min_num_cells = max(min_num_cells, smallest_grid) + + while not min_num_cells % 2 != 0 or not min_num_cells % 3 == 0: + min_num_cells += 1 + + return min_num_cells + + +def equivalent_wrf_domains(resolutions, diameters, + max_domains=2, silent=False): + + if len(resolutions) != len(diameters): + raise AttributeError('Resolutions and diameters list should ' + 'be same length') + + highresolution = int(resolutions[0]) + if resolutions[-1] is None: + num_domains = len(resolutions) + resol_nests = [int(highresolution * 3 ** i) for i in + range(max_domains)] + else: + lowresolution = int(resolutions[-1]) + + # Find resolution outer domain + options = [int(highresolution * 3 ** i) for i in range(max_domains)] + # find the option closest to lowresolution + dists = [abs(lowresolution - option) for option in options] + mindist = np.argmin(dists) + resol_nests = options[:(mindist + 1)] + num_domains = len(resol_nests) + + domains_def = { + 'max_domains': str(num_domains), + } + + num_cells = {} + for nest in range(num_domains): + # nest = 0 is the highest resolution / smaller domain + # but nest = 0 means highest domain = num_domains + # The outer nest is domain = 1 and nest = num_domains - 1 + domain = num_domains - nest + + # Resolution + domains_def['d' + str(domain) + 'res'] = str(resol_nests[nest]) + + # Number of cells + if nest == 0: + prev_num_cells = 0 + else: + prev_num_cells = num_cells[nest - 1] + + diameter = diameters[nest] + if diameter is None: + wrf_cells = find_min_number_wrf_cells( + previous_domain_cells=prev_num_cells, + margin_cells_each_side=9) + else: + wrf_cells = find_min_number_wrf_cells( + distance_km=diameter, resolution_km=resol_nests[nest], + previous_domain_cells=prev_num_cells) + num_cells[nest] = wrf_cells + + domains_def['d' + str(domain) + 'e_wesn'] = \ + str(wrf_cells + 1) + + if not silent: + print('\nNested n', nest, ' / Domain d', domain) + print('\tResolution:', resol_nests[nest], 'km') + print('\t' + str(wrf_cells) + 'x' + str(wrf_cells), + 'WRF cells of', resol_nests[nest], 'km resolution.') + + for domain in range(1, num_domains + 1): + nest = num_domains - domain + + if domain == 1: + if not silent: + print('Lowest Resolution domain') + dij = 1 + else: + if not silent: + print('Inner domain') + # quantes celes del domini superior (domain-1) ocupa? + upper_cells_total = num_cells[nest + 1] - 1 + upper_cells_covered = (num_cells[nest] - 1) / 3 + dij = int(((upper_cells_total - upper_cells_covered) / 2) + 1) + + # Starting ij + domains_def['d' + str(domain) + 'dij'] = str(dij) + + return domains_def + + +def mpas_mesh_equivalent_wrf(ds, **kwargs): + highresolution = kwargs.get('highresolution', + ds.attrs.get('vtx-param-highresolution', + None)) + size = kwargs.get('size', ds.attrs.get('vtx-param-size', None)) + lowresolution = kwargs.get('lowresolution', + ds.attrs.get('vtx-param-lowresolution', + None)) + regborder = kwargs.get('region_border', ds.attrs.get('vtx-region_border', + None)) + + if size is not None: + innerdiam = 2.*size + else: + innerdiam = None + + if regborder is not None: + outerdiam = 2.*regborder + else: + outerdiam = None + + if highresolution >= 3.: + ewrf = equivalent_wrf_domains([highresolution, lowresolution], + [innerdiam, outerdiam], silent=True) + else: + ewrf = equivalent_wrf_domains([highresolution, None, None], + [innerdiam, None, outerdiam], + max_domains=3, + silent=True) + + return ewrf + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/jigsaw_generator.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/jigsaw_generator.py new file mode 100644 index 0000000..d32e5b3 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/jigsaw_generator.py @@ -0,0 +1,104 @@ +# Marta Gil Bardaji, Vortex, marta.gil@vortexfdc.com +# May 2022 + +# Simplification of the script +# https://github.com/pedrospeixoto/MPAS-PXT/blob/master/grids/utilities/jigsaw/jigsaw_util.py +# by Pedro S. Peixoto Dec 2021 +# +# which is itself based on +# http://mpas-dev.github.io/MPAS-Tools/stable/mesh_creation.html#spherical-meshes +# and Jigsaw scripts: +# https://github.com/dengwirda/jigsaw-python/tree/master/tests + + +import numpy as np +import jigsawpy as jig +import subprocess + + +def jigsaw_gen_sph_grid(cellWidth, x, y, earth_radius=6371.0e3, + basename="mesh"): + """ + A function for building a jigsaw spherical mesh + + Parameters + ---------- + cellWidth : ndarray + The size of each cell in the resulting mesh as a function of space + x, y : ndarray + The x and y coordinates of each point in the cellWidth array + (lon and lat for spherical mesh) + earth_radius : float, optional + Earth radius in meters + basename : str + folder + '/' + name of the different files the function saves + + """ + # Authors + # ------- + # by P. Peixoto in Dec 2021 + # based on MPAS-Tools from Mark Petersen, Phillip Wolfram, Xylar Asay-Davis + + # setup files for JIGSAW + opts = jig.jigsaw_jig_t() + opts.geom_file = basename + '.msh' + opts.jcfg_file = basename + '.jig' + opts.mesh_file = basename + '-MESH.msh' + opts.hfun_file = basename + '-HFUN.msh' + + # save HFUN data to file + hmat = jig.jigsaw_msh_t() + + hmat.mshID = 'ELLIPSOID-GRID' + hmat.xgrid = np.radians(x) + hmat.ygrid = np.radians(y) + hmat.value = cellWidth + jig.savemsh(opts.hfun_file, hmat) + + # define JIGSAW geometry + geom = jig.jigsaw_msh_t() + geom.mshID = 'ELLIPSOID-MESH' + geom.radii = earth_radius * 1e-3 * np.ones(3, float) + jig.savemsh(opts.geom_file, geom) + + # build mesh via JIGSAW! + opts.hfun_scal = 'absolute' + opts.hfun_hmax = float("inf") + opts.hfun_hmin = 0.0 + opts.mesh_dims = +2 # 2-dim. simplexes + # MARTA CHANGES + opts.mesh_iter = 50000000 + # % OPTS.MESH_ITER - {default=+INF} max. number of mesh ref- + # % inement iterations. Set ITER=N to see progress after + # % N iterations. + opts.optm_qlim = 0.9375 + # % OPTS.OPTM_QLIM - {default=0.9375} threshold on mesh cost + # % function above which gradient-based optimisation is + # % attempted. + opts.optm_qtol = 1.0e-7 + # % OPTS.OPTM_QTOL - {default=1.E-04} tolerance on mesh cost + # % function for convergence. Iteration on a given node + # % is terminated if adjacent element cost-functions are + # % improved by less than QTOL. + + opts.optm_iter = 500000 + # % OPTS.OPTM_ITER - {default=16} max. number of mesh optim- + # % isation iterations. Set ITER=N to see progress after + # % N iterations. + + # new opts + # % OPTS.MESH_OFF2 - {default=0.90} radius-edge ratio target + # % for insertion of "shape"-type offcentres for 2-tria + # % elements. When refining an element II, offcentres + # % are positioned to form a new "frontal" element JJ + # % that satisfies JRAD <= OFF2. + opts.mesh_off2 = 0.97 + + # ----------------- + opts.verbosity = +1 + jig.savejig(opts.jcfg_file, opts) + + # Call jigsaw + subprocess.call(['jigsaw', opts.jcfg_file]) + + return opts.mesh_file diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mesh_generator.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mesh_generator.py new file mode 100644 index 0000000..f8ef39a --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mesh_generator.py @@ -0,0 +1,712 @@ +import os +import time + +import xarray as xr +import numpy as np +from scipy.interpolate import interp1d + +from mpas_tools.mesh.creation.jigsaw_to_netcdf import jigsaw_to_netcdf +from mpas_tools.mesh.conversion import convert +from mpas_tools.io import write_netcdf + +from vtxmpasmeshes.jigsaw_generator import jigsaw_gen_sph_grid +from vtxmpasmeshes.mpas_plots import view_resolution_map, \ + view_mpas_regional_mesh +from vtxmpasmeshes.dataset_utilities import distance_latlon_matrix + +PATH_LIMITED_AREA = '../../MPAS-Limited-Area' + + +def apply_resolution_at_distance(distances, ref_points, ref_resolutions): + f = interp1d(ref_points, ref_resolutions, bounds_error=False, + fill_value='extrapolate') + resolution = xr.apply_ufunc(f, distances) + return resolution + + +def doughnut_variable_resolution(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # 1st Variable Resolution Ring + # ------------------------------- + # From to = + -> linear increase + # from highresolution to lowresolution + kwargs['radius'] = kwargs['size'] + kwargs['margin'] + slope = (kwargs['lowresolution'] - kwargs['highresolution']) / kwargs['margin'] + d2, r2 = kwargs['radius'], kwargs['lowresolution'] + + # Fixed Low Resolution ring + # ------------------------------- + # From until =+ -> constant lowresolution + # - where the =10 * lowresolution + kwargs['buffer'] = kwargs['num_boundary_layers'] * kwargs['lowresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d3, r3 = kwargs['border'], kwargs['lowresolution'] + + # Crazy increase in cell size ring + # -------------------------------- + # From to -> linear increase with the same + # than before until we reach the reoslution + # - can be computed + slope_xmax = 0.05 + deltares = kwargs['final_res_dist'] - kwargs['lowresolution'] + xmax = kwargs['border'] + deltares / slope_xmax + d4, r4 = xmax, kwargs['final_res_dist'] + d5, r5 = 2*xmax, kwargs['final_res_dist'] + + # Those are the points I fix + dists = np.array([d0, d1, d2, d3, d4, d5]) + resol = np.array([r0, r1, r2, r3, r4, r5]) + + return dists, resol, kwargs + +def doughnut_variable_resolution_global(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # 1st Variable Resolution Ring + # ------------------------------- + # From to = + -> linear increase + # from highresolution to lowresolution + kwargs['radius'] = kwargs['size'] + kwargs['margin'] + slope = (kwargs['lowresolution'] - kwargs['highresolution']) / kwargs['margin'] + d2, r2 = kwargs['radius'], kwargs['lowresolution'] + + # Fixed Low Resolution ring + # ------------------------------- + # From until =+ -> constant lowresolution + # - where the =10 * lowresolution + kwargs['buffer'] = kwargs['num_boundary_layers'] * kwargs['lowresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d3, r3 = kwargs['border'], kwargs['lowresolution'] + + # Those are the points I fix + dists = np.array([d0, d1, d2, d3]) + resol = np.array([r0, r1, r2, r3]) + + return dists, resol, kwargs + +def constant_resolution(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # Boundary layers around it + # ------------------------------ + kwargs['radius'] = kwargs['size'] + kwargs['buffer'] = kwargs['num_boundary_layers'] * kwargs['highresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d2, r2 = kwargs['border'], kwargs['highresolution'] + + # Increase in resolution until final_res_dist + # ------------------------------ + slope_xmax = 0.05 + deltares = kwargs['final_res_dist'] - kwargs['highresolution'] + xmax = kwargs['border'] + deltares / slope_xmax + d3, r3 = xmax, kwargs['final_res_dist'] + d4, r4 = 2*xmax, kwargs['final_res_dist'] + + # Those are the points I fix + dists = np.array([d0, d1, d2, d3, d4]) + resol = np.array([r0, r1, r2, r3, r4]) + + return dists, resol, kwargs + +def constant_resolution_global(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # Boundary layers around it + # ------------------------------ + kwargs['radius'] = kwargs['size'] + kwargs['buffer'] = kwargs['num_boundary_layers'] * kwargs['highresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d2, r2 = kwargs['border'], kwargs['highresolution'] + + # Those are the points I fix + dists = np.array([d0, d1, d2]) + resol = np.array([r0, r1, r2]) + + return dists, resol, kwargs + +def variable_resolution_latlonmap(grid, do_region, **kwargs): + + print('\n>> Creating a variable resolution map') + + # GRID + # Create a global lat/lon grid at high resolution + + highresolution = kwargs.get('highresolution', 10.) # grid size in km + print('\tResolution in km of lat/lon grid: %.1f' % highresolution) + + if grid == 'constant': + dist_degrees = highresolution / 1000 #110. + elif grid == 'doughnut': + dist_degrees = highresolution / 200 + + + nlat = int(180. / dist_degrees) + 1 + nlon = int(360. / dist_degrees) + 1 + + ds = xr.Dataset( + coords={ + 'lat': np.linspace(-90., 90., nlat), + 'lon': np.linspace(-180., 180., nlon), + } + ) + + # DISTANCE + # Compute distance from each point to the reference point + + lat_ref = kwargs.get('lat_ref', None) + if lat_ref is None: + lat_ref = 0. + lon_ref = kwargs.get('lon_ref', None) + if lon_ref is None: + lon_ref = 0. + kwargs.update({'lat_ref': lat_ref, 'lon_ref': lon_ref}) + + print('\tComputing the distance to the reference point ' + '(%.2f, %.2f)' % (lat_ref, lon_ref)) + dists = distance_latlon_matrix(ds.coords['lat'], ds.coords['lon'], + lat_ref=lat_ref, lon_ref=lon_ref, + do_tile=True) + + ds['distance'] = xr.DataArray(data=dists, dims=('lat', 'lon')) + + # RESOLUTION + # Set the resolution value at each point + if grid == 'doughnut': + if do_region == 'y': + print('\tComputing resolutions using technique %s, regional.' % grid) + dists, resol, kwargs = doughnut_variable_resolution(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + elif do_region == 'n': + print('\tComputing resolutions using technique %s, global.' % grid) + dists, resol, kwargs = doughnut_variable_resolution_global(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + else: + raise ValueError('!! Flag do_regional should have either "y" or "n" values.') + elif grid == 'constant': + if do_region == 'y': + print('\tComputing resolutions using technique %s, regional.' % grid) + dists, resol, kwargs = constant_resolution(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + elif do_region == 'n': + print('\tComputing resolutions using technique %s, global.' % grid) + dists, resol, kwargs = constant_resolution_global(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + else: + raise ValueError('!! Grid %s not implemented.' % grid) + + ds.attrs = kwargs + + return ds + +def get_mesh_from_resolution(resolution_ds, basename='./mesh'): + print('\n>> Generating a MPAS mesh') + + # jigsaw + print('\n\t .- Jigsaw generation') + + mesh_file = jigsaw_gen_sph_grid(resolution_ds['resolution'].values, + resolution_ds['lon'].values, + resolution_ds['lat'].values, + basename=basename) + + # mpas-tools + + print('\n\t .- Jigsaw to netCDF') + out_file_triangles = basename + '.triangles.nc' + jigsaw_to_netcdf(msh_filename=mesh_file, + output_name=out_file_triangles, + on_sphere=True, sphere_radius=1.0) + + print('\n\t .- Convert to MPAS format') + out_file_mpas = basename + '.grid.nc' + out_file_graph_info = basename + ".graph.info" + write_netcdf( + convert(xr.open_dataset(out_file_triangles), + dir=os.path.dirname(basename), + graphInfoFileName=out_file_graph_info), + out_file_mpas) + + return out_file_mpas, out_file_graph_info + + +def cut_circular_region(mpas_global_file, + region_radius_meters, + regional_grid=None, + regional_grid_info=None, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000)) + + if region_radius_meters < 5000: + raise ValueError('Do you want a %.0fm radius region?' + 'That looks way too small. Maybe you passed ' + 'the radius in km instead as in meters.' + % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + os.system('cp ' + mpas_global_file + ' global.grid.nc') + + with open('points.txt', 'w') as f: + f.write('Name: circle\n') + f.write('Type: circle\n') + f.write('Point: %.4f, %.4f\n' % (lat_cen, lon_cen)) + f.write('radius: %.0f\n' % region_radius_meters) + + # If there are regional files we should erase them + os.system('rm -f circle.grid.nc') + os.system('rm -f circle.graph.info') + + # Execute create region + os.system(path_create_region + '/create_region points.txt ' + + mpas_global_file) + + if not os.path.exists('circle.grid.nc') or \ + not os.path.exists('circle.graph.info'): + raise AttributeError('The regions were not generated correctly') + + if regional_grid is not None: + os.system('cp circle.grid.nc ' + regional_grid) + + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + else: + regional_grid = 'circle.grid.nc' + + if regional_grid_info is not None: + os.system('cp circle.graph.info ' + regional_grid_info) + else: + regional_grid_info = 'circle.graph.info' + + return regional_grid, regional_grid_info + + +def cut_circular_region_beta(mpas_global_file, + region_radius_meters, + regional_grid=None, + regional_grid_info=None, + num_boundary_layers=8, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + create_region_exec = path_create_region + '/create_region_no_file' + + if not os.path.isfile(create_region_exec): + raise IOError('Your MPAS-Limited-Area folder does not ' + 'contain the expected executable. Maybe you ' + 'have an old version? ' + create_region_exec) + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000)) + + if region_radius_meters < 5000: + raise ValueError('Do you want a %.0fm radius region?' + 'That looks way too small. Maybe you passed ' + 'the radius in km instead as in meters.' + % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + # If there are regional files we should erase them + if regional_grid is None: + regional_grid = 'circle.grid.nc' + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + + os.system('rm -f ' + regional_grid) + os.system('rm -f ' + regional_grid_info) + + # Execute create region + os.system(create_region_exec + ' ' + mpas_global_file + + ' --num_boundary_layers ' + str(num_boundary_layers) + + ' --oregion ' + regional_grid + + ' --ograph ' + regional_grid_info + + ' region.type:circle' + + ' region.radius:' + str(region_radius_meters) + + ' region.in_point:' + str(lat_cen) + ',' + str(lon_cen) + ) + + if not os.path.exists(regional_grid) or \ + not os.path.exists(regional_grid_info): + raise AttributeError('The regions were not generated correctly') + + return regional_grid, regional_grid_info + +def cut_circular_region_gtm(mpas_global_file, + region_radius_meters, + n_layers, + boundary_layer_res, + regional_grid=None, + regional_grid_info=None, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000 + + n_layers*boundary_layer_res)) + + #if region_radius_meters < 5000: + # raise ValueError('Do you want a %.0fm radius region?' + # 'That looks way too small. Maybe you passed ' + # 'the radius in km instead as in meters.' + # % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + with open('points.txt', 'w') as f: + f.write('Name: circle\n') + f.write('Type: circle\n') + f.write('Point: %.4f, %.4f\n' % (lat_cen, lon_cen)) + f.write('radius: %.0f\n' % region_radius_meters) + + # If there are regional files we should erase them + if regional_grid is None: + regional_grid = 'circle.grid.nc' + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + os.system(f'rm -f {regional_grid}') + os.system(f'rm -f {regional_grid_info}') + + # Execute create region + os.system(path_create_region + '/create_region_n_layers_as_input points.txt ' + + mpas_global_file + f' {int(n_layers)}') + + if not os.path.exists('circle.grid.nc') or \ + not os.path.exists('circle.graph.info'): + raise AttributeError('The regions were not generated correctly') + + # Move generated files to right location + os.system('mv circle.grid.nc ' + regional_grid) + os.system('mv circle.graph.info ' + regional_grid_info) + + return regional_grid, regional_grid_info + +def full_generation_process(mpas_grid_file, grid, redo=True, + do_plots=True, do_region=False, **kwargs): + + if os.path.isfile(mpas_grid_file) and not redo: + print(' .. already available') + return + + graph_info_file = mpas_grid_file.replace('.nc', '.graph.info') + path_save = os.path.dirname(mpas_grid_file) + + os.system('rm -f ' + mpas_grid_file) + os.system('rm -f ' + graph_info_file) + + start_time = time.time() + resolution_ds = variable_resolution_latlonmap(grid, **kwargs) + duration_resolution = time.time() - start_time + print(' .. finished finding resolution map: %.3fs\n\n' % duration_resolution) + + border = resolution_ds.attrs['border'] + radius = resolution_ds.attrs['radius'] + lat_ref = resolution_ds.attrs['lat_ref'] + lon_ref = resolution_ds.attrs['lon_ref'] + + if do_plots: + print('Plotting') + start_time = time.time() + view_resolution_map(resolution_ds, + pdfname=path_save + '/resolution.pdf', + list_distances=[ + #1000, + 500, border, radius]) + duration_plots = time.time() - start_time + print(' .. finished doing resolution plots: %.3fs\n\n' % duration_plots) + + start_time = time.time() + tmp_mesh_file, tmp_graph_info = get_mesh_from_resolution(resolution_ds, + basename='mesh') + duration_gen = time.time() - start_time + print(' .. finished generating global mesh: %.3fs\n\n' % duration_gen) + + mpas_grid_file_tmp = mpas_grid_file + '.tmp' + if do_region: + start_time = time.time() + num_boundary_layers = kwargs.get('num_boundary_layers', 8) + print('cutting circular region') + cut_circular_region_beta(tmp_mesh_file, radius*1000, + regional_grid=mpas_grid_file_tmp, + regional_grid_info=graph_info_file, + num_boundary_layers=num_boundary_layers, + lat_cen=lat_ref, lon_cen=lon_ref, + ) + + duration_region = time.time() - start_time + print(' .. finished cutting region: %.3fs\n\n' % duration_region) + + if not os.path.isfile(mpas_grid_file_tmp) or \ + not os.path.isfile(graph_info_file): + raise IOError('The file we had to generate was not generated') + else: + duration_region = 0. + os.system('mv ' + tmp_mesh_file + ' ' + mpas_grid_file_tmp) + os.system('mv ' + tmp_graph_info + ' ' + graph_info_file) + + # Open dataset and update attributes + mpas_ds = xr.open_dataset(mpas_grid_file_tmp) + for name, value in resolution_ds.attrs.items(): + mpas_ds.attrs['vtx-param-' + str(name)] = value + if do_region: + mpas_ds.attrs['vtx-region-num_boundary_layers'] = num_boundary_layers + lowres = mpas_ds.attrs['vtx-param-lowresolution'] + region_border = radius + (num_boundary_layers * lowres) * 0.6 + mpas_ds.attrs['vtx-region_border'] = region_border + + # Update the duration of the steps + durations_process = { + 'resolution': duration_resolution, + 'generation': duration_gen, + 'region': duration_region, + 'total': duration_resolution + duration_gen + duration_region, + } + for name, value in durations_process.items(): + mpas_ds.attrs['vtx-duration-' + name] = '%.2f' % value + + print('\n MESH:\n') + print(mpas_ds) + mpas_ds.to_netcdf(mpas_grid_file) + + if not os.path.isfile(mpas_grid_file): + raise IOError('Could not update attributes of file ' + + mpas_grid_file_tmp) + + #os.system('rm -f ' + mpas_grid_file_tmp) + + if do_plots: + if do_region: + print('Resolution Plots') + view_mpas_regional_mesh(mpas_grid_file, + outfile=path_save + '/resolution_mesh.png') + + return mpas_grid_file, graph_info_file + +def full_generation_process_gtm(mpas_grid_file, grid, redo=True, + do_plots=True, do_region='y', **kwargs): + + if os.path.isfile(mpas_grid_file) and not redo: + print(' .. already available') + return + + graph_info_file = mpas_grid_file.replace('.grid.nc', '.graph.info') + path_save = os.path.dirname(mpas_grid_file) + + os.system('rm -f ' + mpas_grid_file) + os.system('rm -f ' + graph_info_file) + + start_time = time.time() + resolution_ds = variable_resolution_latlonmap(grid, do_region, **kwargs) + + duration_resolution = time.time() - start_time + print(' .. finished finding resolution map: %.3fs\n\n' % duration_resolution) + + border = resolution_ds.attrs['border'] + radius = resolution_ds.attrs['radius'] + lat_ref = resolution_ds.attrs['lat_ref'] + lon_ref = resolution_ds.attrs['lon_ref'] + + if do_plots: + print('Plotting') + start_time = time.time() + view_resolution_map(resolution_ds, + pdfname=path_save + '/resolution.pdf', + list_distances=[ + #radius, + border + ] + ) + duration_plots = time.time() - start_time + print(' .. finished doing resolution plots: %.3fs\n\n' % duration_plots) + + start_time = time.time() + tmp_mesh_file, tmp_graph_info = get_mesh_from_resolution(resolution_ds, + basename='mesh') + duration_gen = time.time() - start_time + print(' .. finished generating global mesh: %.3fs\n\n' % duration_gen) + + if do_region=='y': + start_time = time.time() + num_boundary_layers = kwargs.get('num_boundary_layers') + print ('number of boundary layers:', num_boundary_layers) + print('cutting circular region') + if grid == 'doughnut': + cutoff_radius = radius*1000 #border*1000 + boundary_layer_res = kwargs['lowresolution'] + elif grid == 'constant': + cutoff_radius = radius*1000 #kwargs['size']*1000 + boundary_layer_res = kwargs['highresolution'] + cut_circular_region_gtm(mpas_global_file=tmp_mesh_file, + region_radius_meters=cutoff_radius, #1000*(radius + (num_boundary_layers * lowresolution)), #radius*1000, + n_layers = num_boundary_layers, + boundary_layer_res=boundary_layer_res, + regional_grid=mpas_grid_file, + regional_grid_info=graph_info_file, + lat_cen=lat_ref, lon_cen=lon_ref + ) + duration_region = time.time() - start_time + print(' .. finished cutting region: %.3fs\n\n' % duration_region) + + if not os.path.isfile(mpas_grid_file) or \ + not os.path.isfile(graph_info_file): + raise IOError('The file we had to generate was not generated') + else: + duration_region = 0. + os.system('mv ' + tmp_mesh_file + ' ' + mpas_grid_file) + os.system('mv ' + tmp_graph_info + ' ' + graph_info_file) + + # Open dataset and update attributes + mpas_ds = xr.open_dataset(mpas_grid_file) + for name, value in resolution_ds.attrs.items(): + mpas_ds.attrs['vtx-param-' + str(name)] = value + if do_region == 'y': + mpas_ds.attrs['vtx-region-num_boundary_layers'] = num_boundary_layers + lowres = mpas_ds.attrs['vtx-param-lowresolution'] + region_border = radius + (num_boundary_layers * lowres) #* 0.6 + mpas_ds.attrs['vtx-region_border'] = region_border + + # Update the duration of the steps + durations_process = { + 'resolution': duration_resolution, + 'generation': duration_gen, + 'region': duration_region, + 'total': duration_resolution + duration_gen + duration_region, + } + for name, value in durations_process.items(): + mpas_ds.attrs['vtx-duration-' + name] = '%.2f' % value + + # Save final mesh + mpas_grid_file_for_plotting = mpas_grid_file.replace('.region.grid.nc', '.region_for_plotting.grid.nc') + print('\n MESH FOR MPAS WORKFLOW:\n') + print(mpas_grid_file) + print('\n MESH FOR PLOTTING:\n') + print(mpas_grid_file_for_plotting) + # Remove _FillValue attribute (if it exists) + for var in mpas_ds.variables: + #print ("removing FillValue from ",var) + #print (f"{var} encoding:", mpas_ds[var].encoding) + mpas_ds[var].encoding['_FillValue'] = None + #print (f"{var} encoding after removal:", mpas_ds[var].encoding) + + mpas_ds.to_netcdf(mpas_grid_file_for_plotting) + + if not os.path.isfile(mpas_grid_file): + raise IOError('Could not update attributes of file ' + + mpas_grid_file_for_plotting) + + + if do_plots: + if do_region: + print('Resolution Plots') + view_mpas_regional_mesh(mpas_grid_file_for_plotting, + outfile=path_save + '/resolution_mesh.png') + + return mpas_grid_file, graph_info_file + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mesh_generator_inwards.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mesh_generator_inwards.py new file mode 100644 index 0000000..71fd7b1 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mesh_generator_inwards.py @@ -0,0 +1,616 @@ +import os +import time + +import xarray as xr +import numpy as np +from scipy.interpolate import interp1d + +from mpas_tools.mesh.creation.jigsaw_to_netcdf import jigsaw_to_netcdf +from mpas_tools.mesh.conversion import convert +from mpas_tools.io import write_netcdf + +from vtxmpasmeshes.jigsaw_generator import jigsaw_gen_sph_grid +from vtxmpasmeshes.mpas_plots import view_resolution_map, \ + view_mpas_regional_mesh +from vtxmpasmeshes.dataset_utilities import distance_latlon_matrix + +PATH_LIMITED_AREA = '/storage/guilherme_torresmendonca/MPAS-Limited-Area' + + +def apply_resolution_at_distance(distances, ref_points, ref_resolutions): + f = interp1d(ref_points, ref_resolutions, bounds_error=False, + fill_value='extrapolate') + resolution = xr.apply_ufunc(f, distances) + return resolution + + +def doughnut_variable_resolution(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # 1st Variable Resolution Ring + # ------------------------------- + # From to = + -> linear increase + # from highresolution to lowresolution + kwargs['radius'] = kwargs['size'] + kwargs['margin'] + slope = (kwargs['lowresolution'] - kwargs['highresolution']) / kwargs['margin'] + d2, r2 = kwargs['radius'], kwargs['lowresolution'] + + # Fixed Low Resolution ring + # ------------------------------- + # From until =+ -> constant lowresolution + # - where the =10 * lowresolution + kwargs['buffer'] = kwargs['num_boundary_layers'] * kwargs['lowresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d3, r3 = kwargs['border'], kwargs['lowresolution'] + + # Crazy increase in cell size ring + # -------------------------------- + # From to -> linear increase with the same + # than before until we reach the reoslution + # - can be computed + slope_xmax = 0.05 + deltares = kwargs['final_res_dist'] - kwargs['lowresolution'] + xmax = kwargs['border'] + deltares / slope_xmax + d4, r4 = xmax, kwargs['final_res_dist'] + d5, r5 = 2*xmax, kwargs['final_res_dist'] + + # Those are the points I fix + dists = np.array([d0, d1, d2, d3, d4, d5]) + resol = np.array([r0, r1, r2, r3, r4, r5]) + + return dists, resol, kwargs + +def constant_resolution(**kwargs): + + # Setting parameters to the defaults if not passed as arguments + defaults = {'lowresolution': 25, + 'highresolution': 3, + 'size': 40, + 'margin': 100, + 'final_res_dist': 1000} + + for name, default in defaults.items(): + kwag = kwargs.get(name, None) + if kwag is None: + kwargs.update({name: default}) + + # Inner Circle + # ------------------------------ + # From distance 0 to -> constant highresolution + d0, r0 = 0., kwargs['highresolution'] + d1, r1 = kwargs['size'], kwargs['highresolution'] + + # Boundary layers around it + # ------------------------------ + kwargs['radius'] = kwargs['size'] + kwargs['buffer'] = kwargs['num_boundary_layers'] * kwargs['highresolution'] + kwargs['border'] = kwargs['radius'] + kwargs['buffer'] + d2, r2 = kwargs['border'], kwargs['highresolution'] + + # Increase in resolution until final_res_dist + # ------------------------------ + slope_xmax = 0.05 + deltares = kwargs['final_res_dist'] - kwargs['highresolution'] + xmax = kwargs['border'] + deltares / slope_xmax + d3, r3 = xmax, kwargs['final_res_dist'] + d4, r4 = 2*xmax, kwargs['final_res_dist'] + + # Those are the points I fix + dists = np.array([d0, d1, d2, d3, d4]) + resol = np.array([r0, r1, r2, r3, r4]) + + return dists, resol, kwargs + +def variable_resolution_latlonmap(grid, **kwargs): + + print('\n>> Creating a variable resolution map') + + # GRID + # Create a global lat/lon grid at high resolution + + highresolution = kwargs.get('highresolution', 10.) # grid size in km + print('\tResolution in km of lat/lon grid: %.1f' % highresolution) + + dist_degrees = highresolution / 110. + + nlat = int(180. / dist_degrees) + 1 + nlon = int(360. / dist_degrees) + 1 + + ds = xr.Dataset( + coords={ + 'lat': np.linspace(-90., 90., nlat), + 'lon': np.linspace(-180., 180., nlon), + } + ) + + # DISTANCE + # Compute distance from each point to the reference point + + lat_ref = kwargs.get('lat_ref', None) + if lat_ref is None: + lat_ref = 0. + lon_ref = kwargs.get('lon_ref', None) + if lon_ref is None: + lon_ref = 0. + kwargs.update({'lat_ref': lat_ref, 'lon_ref': lon_ref}) + + print('\tComputing the distance to the reference point ' + '(%.2f, %.2f)' % (lat_ref, lon_ref)) + dists = distance_latlon_matrix(ds.coords['lat'], ds.coords['lon'], + lat_ref=lat_ref, lon_ref=lon_ref, + do_tile=True) + + ds['distance'] = xr.DataArray(data=dists, dims=('lat', 'lon')) + + # RESOLUTION + # Set the resolution value at each point + print('\tComputing resolutions using technique %s' % grid) + if grid == 'doughnut': + dists, resol, kwargs = doughnut_variable_resolution(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + elif grid == 'constant': + dists, resol, kwargs = constant_resolution(**kwargs) + ds['resolution'] = apply_resolution_at_distance( + ds['distance'], ref_points=dists, ref_resolutions=resol) + else: + raise ValueError('!! Grid %s not implemented.' % grid) + + ds.attrs = kwargs + + return ds + +def get_mesh_from_resolution(resolution_ds, basename='./mesh'): + print('\n>> Generating a MPAS mesh') + + # jigsaw + print('\n\t .- Jigsaw generation') + mesh_file = jigsaw_gen_sph_grid(resolution_ds['resolution'].values, + resolution_ds['lon'].values, + resolution_ds['lat'].values, + basename=basename) + + # mpas-tools + + print('\n\t .- Jigsaw to netCDF') + out_file_triangles = basename + '.triangles.nc' + jigsaw_to_netcdf(msh_filename=mesh_file, + output_name=out_file_triangles, + on_sphere=True, sphere_radius=1.0) + + print('\n\t .- Convert to MPAS format') + out_file_mpas = basename + '.grid.nc' + out_file_graph_info = basename + ".grid.graph.info" + write_netcdf( + convert(xr.open_dataset(out_file_triangles), + dir=os.path.dirname(basename), + graphInfoFileName=out_file_graph_info), + out_file_mpas) + + return out_file_mpas, out_file_graph_info + + +def cut_circular_region(mpas_global_file, + region_radius_meters, + regional_grid=None, + regional_grid_info=None, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000)) + + if region_radius_meters < 5000: + raise ValueError('Do you want a %.0fm radius region?' + 'That looks way too small. Maybe you passed ' + 'the radius in km instead as in meters.' + % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + os.system('cp ' + mpas_global_file + ' global.grid.nc') + + with open('points.txt', 'w') as f: + f.write('Name: circle\n') + f.write('Type: circle\n') + f.write('Point: %.4f, %.4f\n' % (lat_cen, lon_cen)) + f.write('radius: %.0f\n' % region_radius_meters) + + # If there are regional files we should erase them + os.system('rm -f circle.grid.nc') + os.system('rm -f circle.graph.info') + + # Execute create region + os.system(path_create_region + '/create_region points.txt ' + + mpas_global_file) + + if not os.path.exists('circle.grid.nc') or \ + not os.path.exists('circle.graph.info'): + raise AttributeError('The regions were not generated correctly') + + if regional_grid is not None: + os.system('cp circle.grid.nc ' + regional_grid) + + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + else: + regional_grid = 'circle.grid.nc' + + if regional_grid_info is not None: + os.system('cp circle.graph.info ' + regional_grid_info) + else: + regional_grid_info = 'circle.graph.info' + + return regional_grid, regional_grid_info + + +def cut_circular_region_beta(mpas_global_file, + region_radius_meters, + regional_grid=None, + regional_grid_info=None, + num_boundary_layers=8, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + create_region_exec = path_create_region + '/create_region_no_file' + + if not os.path.isfile(create_region_exec): + raise IOError('Your MPAS-Limited-Area folder does not ' + 'contain the expected executable. Maybe you ' + 'have an old version? ' + create_region_exec) + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000)) + + if region_radius_meters < 5000: + raise ValueError('Do you want a %.0fm radius region?' + 'That looks way too small. Maybe you passed ' + 'the radius in km instead as in meters.' + % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + # If there are regional files we should erase them + if regional_grid is None: + regional_grid = 'circle.grid.nc' + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + + os.system('rm -f ' + regional_grid) + os.system('rm -f ' + regional_grid_info) + + # Execute create region + os.system(create_region_exec + ' ' + mpas_global_file + + ' --num_boundary_layers ' + str(num_boundary_layers) + + ' --oregion ' + regional_grid + + ' --ograph ' + regional_grid_info + + ' region.type:circle' + + ' region.radius:' + str(region_radius_meters) + + ' region.in_point:' + str(lat_cen) + ',' + str(lon_cen) + ) + + if not os.path.exists(regional_grid) or \ + not os.path.exists(regional_grid_info): + raise AttributeError('The regions were not generated correctly') + + return regional_grid, regional_grid_info + +def cut_circular_region_gtm(mpas_global_file, + region_radius_meters, + n_layers, + boundary_layer_res, + regional_grid=None, + regional_grid_info=None, + lat_cen=0., lon_cen=0., + path_create_region=PATH_LIMITED_AREA, + ): + + if not os.path.isdir(path_create_region): + raise IOError('The path to the MPAS-Limited-Area folder is not ' + 'correct. Pass it to the function ' + 'cut_circular_region_beta or define a correct ' + 'default in variable PATH_LIMITED_AREA (in ' + 'mesh_generator.py.') + + print('\n>> Cutting a circular region') + print('\t centered at %.4f, %.4f' % (lat_cen, lon_cen)) + print('\t with radius %.1fkm' % float(region_radius_meters/1000 + + n_layers*boundary_layer_res)) + + #if region_radius_meters < 5000: + # raise ValueError('Do you want a %.0fm radius region?' + # 'That looks way too small. Maybe you passed ' + # 'the radius in km instead as in meters.' + # % region_radius_meters) + + if not os.path.exists(mpas_global_file): + raise IOError('Wanted to use the MPAS global file %s but' + 'it does not seem to exist.' % mpas_global_file) + + with open('points.txt', 'w') as f: + f.write('Name: circle\n') + f.write('Type: circle\n') + f.write('Point: %.4f, %.4f\n' % (lat_cen, lon_cen)) + f.write('radius: %.0f\n' % region_radius_meters) + + # If there are regional files we should erase them + if regional_grid is None: + regional_grid = 'circle.grid.nc' + if regional_grid_info is None: + regional_grid_info = regional_grid.replace('.nc', '.graph.info') + os.system(f'rm -f {regional_grid}') + os.system(f'rm -f {regional_grid_info}') + + # Execute create region + os.system(path_create_region + '/create_region_n_layers_as_input_inwards points.txt ' + + mpas_global_file + f' {int(n_layers)}') + + if not os.path.exists('circle.grid.nc') or \ + not os.path.exists('circle.graph.info'): + raise AttributeError('The regions were not generated correctly') + + # Move generated files to right location + os.system('mv circle.grid.nc ' + regional_grid) + os.system('mv circle.graph.info ' + regional_grid_info) + + return regional_grid, regional_grid_info + +def full_generation_process(mpas_grid_file, grid, redo=True, + do_plots=True, do_region=False, **kwargs): + + if os.path.isfile(mpas_grid_file) and not redo: + print(' .. already available') + return + + graph_info_file = mpas_grid_file.replace('.nc', '.graph.info') + path_save = os.path.dirname(mpas_grid_file) + + os.system('rm -f ' + mpas_grid_file) + os.system('rm -f ' + graph_info_file) + + start_time = time.time() + resolution_ds = variable_resolution_latlonmap(grid, **kwargs) + duration_resolution = time.time() - start_time + print(' .. finished finding resolution map: %.3fs\n\n' % duration_resolution) + + border = resolution_ds.attrs['border'] + radius = resolution_ds.attrs['radius'] + lat_ref = resolution_ds.attrs['lat_ref'] + lon_ref = resolution_ds.attrs['lon_ref'] + + if do_plots: + print('Plotting') + start_time = time.time() + view_resolution_map(resolution_ds, + pdfname=path_save + '/resolution.pdf', + list_distances=[ + #1000, + 500, border, radius]) + duration_plots = time.time() - start_time + print(' .. finished doing resolution plots: %.3fs\n\n' % duration_plots) + + start_time = time.time() + tmp_mesh_file, tmp_graph_info = get_mesh_from_resolution(resolution_ds, + basename='mesh') + duration_gen = time.time() - start_time + print(' .. finished generating global mesh: %.3fs\n\n' % duration_gen) + + mpas_grid_file_tmp = mpas_grid_file + '.tmp' + if do_region: + start_time = time.time() + num_boundary_layers = kwargs.get('num_boundary_layers', 8) + print('cutting circular region') + cut_circular_region_beta(tmp_mesh_file, radius*1000, + regional_grid=mpas_grid_file_tmp, + regional_grid_info=graph_info_file, + num_boundary_layers=num_boundary_layers, + lat_cen=lat_ref, lon_cen=lon_ref, + ) + + duration_region = time.time() - start_time + print(' .. finished cutting region: %.3fs\n\n' % duration_region) + + if not os.path.isfile(mpas_grid_file_tmp) or \ + not os.path.isfile(graph_info_file): + raise IOError('The file we had to generate was not generated') + else: + duration_region = 0. + os.system('mv ' + tmp_mesh_file + ' ' + mpas_grid_file_tmp) + os.system('mv ' + tmp_graph_info + ' ' + graph_info_file) + + # Open dataset and update attributes + mpas_ds = xr.open_dataset(mpas_grid_file_tmp) + for name, value in resolution_ds.attrs.items(): + mpas_ds.attrs['vtx-param-' + str(name)] = value + if do_region: + mpas_ds.attrs['vtx-region-num_boundary_layers'] = num_boundary_layers + lowres = mpas_ds.attrs['vtx-param-lowresolution'] + region_border = radius + (num_boundary_layers * lowres) * 0.6 + mpas_ds.attrs['vtx-region_border'] = region_border + + # Update the duration of the steps + durations_process = { + 'resolution': duration_resolution, + 'generation': duration_gen, + 'region': duration_region, + 'total': duration_resolution + duration_gen + duration_region, + } + for name, value in durations_process.items(): + mpas_ds.attrs['vtx-duration-' + name] = '%.2f' % value + + print('\n MESH:\n') + print(mpas_ds) + mpas_ds.to_netcdf(mpas_grid_file) + + if not os.path.isfile(mpas_grid_file): + raise IOError('Could not update attributes of file ' + + mpas_grid_file_tmp) + + #os.system('rm -f ' + mpas_grid_file_tmp) + + if do_plots: + if do_region: + print('Resolution Plots') + view_mpas_regional_mesh(mpas_grid_file, + outfile=path_save + '/resolution_mesh.png') + + return mpas_grid_file, graph_info_file + +def full_generation_process_gtm(mpas_grid_file, grid, redo=True, + do_plots=True, do_region='y', **kwargs): + + if os.path.isfile(mpas_grid_file) and not redo: + print(' .. already available') + return + + graph_info_file = mpas_grid_file.replace('.nc', '.graph.info') + path_save = os.path.dirname(mpas_grid_file) + + os.system('rm -f ' + mpas_grid_file) + os.system('rm -f ' + graph_info_file) + + start_time = time.time() + resolution_ds = variable_resolution_latlonmap(grid, **kwargs) + duration_resolution = time.time() - start_time + print(' .. finished finding resolution map: %.3fs\n\n' % duration_resolution) + + border = resolution_ds.attrs['border'] + radius = resolution_ds.attrs['radius'] + lat_ref = resolution_ds.attrs['lat_ref'] + lon_ref = resolution_ds.attrs['lon_ref'] + + if do_plots: + print('Plotting') + start_time = time.time() + view_resolution_map(resolution_ds, + pdfname=path_save + '/resolution.pdf', + list_distances=[ + radius, + border + ] + ) + duration_plots = time.time() - start_time + print(' .. finished doing resolution plots: %.3fs\n\n' % duration_plots) + + start_time = time.time() + tmp_mesh_file, tmp_graph_info = get_mesh_from_resolution(resolution_ds, + basename='mesh') + duration_gen = time.time() - start_time + print(' .. finished generating global mesh: %.3fs\n\n' % duration_gen) + + if do_region=='y': + start_time = time.time() + num_boundary_layers = kwargs.get('num_boundary_layers') + print ('number of boundary layers:', num_boundary_layers) + print('cutting circular region') + if grid == 'doughnut': + cutoff_radius = radius*1000 #border*1000 + boundary_layer_res = kwargs['lowresolution'] + elif grid == 'constant': + cutoff_radius = radius*1000 #kwargs['size']*1000 + boundary_layer_res = kwargs['highresolution'] + cut_circular_region_gtm(mpas_global_file=tmp_mesh_file, + region_radius_meters=cutoff_radius, #1000*(radius + (num_boundary_layers * lowresolution)), #radius*1000, + n_layers = num_boundary_layers, + boundary_layer_res=boundary_layer_res, + regional_grid=mpas_grid_file, + regional_grid_info=graph_info_file, + lat_cen=lat_ref, lon_cen=lon_ref + ) + duration_region = time.time() - start_time + print(' .. finished cutting region: %.3fs\n\n' % duration_region) + + if not os.path.isfile(mpas_grid_file) or \ + not os.path.isfile(graph_info_file): + raise IOError('The file we had to generate was not generated') + else: + duration_region = 0. + os.system('mv ' + tmp_mesh_file + ' ' + mpas_grid_file) + os.system('mv ' + tmp_graph_info + ' ' + graph_info_file) + + # Open dataset and update attributes + mpas_ds = xr.open_dataset(mpas_grid_file) + for name, value in resolution_ds.attrs.items(): + mpas_ds.attrs['vtx-param-' + str(name)] = value + if do_region == 'y': + mpas_ds.attrs['vtx-region-num_boundary_layers'] = num_boundary_layers + lowres = mpas_ds.attrs['vtx-param-lowresolution'] + region_border = radius + (num_boundary_layers * lowres) #* 0.6 + mpas_ds.attrs['vtx-region_border'] = region_border + + # Update the duration of the steps + durations_process = { + 'resolution': duration_resolution, + 'generation': duration_gen, + 'region': duration_region, + 'total': duration_resolution + duration_gen + duration_region, + } + for name, value in durations_process.items(): + mpas_ds.attrs['vtx-duration-' + name] = '%.2f' % value + + # Save final mesh + mpas_grid_file_for_plotting = mpas_grid_file.replace('.region.grid.nc', '.region_for_plotting.grid.nc') + print('\n MESH FOR MPAS WORKFLOW:\n') + print(mpas_grid_file) + print('\n MESH FOR PLOTTING:\n') + print(mpas_grid_file_for_plotting) + # Remove _FillValue attribute (if it exists) + for var in mpas_ds.variables: + #print ("removing FillValue from ",var) + #print (f"{var} encoding:", mpas_ds[var].encoding) + mpas_ds[var].encoding['_FillValue'] = None + #print (f"{var} encoding after removal:", mpas_ds[var].encoding) + + mpas_ds.to_netcdf(mpas_grid_file_for_plotting) + + if not os.path.isfile(mpas_grid_file): + raise IOError('Could not update attributes of file ' + + mpas_grid_file_for_plotting) + + + if do_plots: + if do_region: + print('Resolution Plots') + view_mpas_regional_mesh(mpas_grid_file_for_plotting, + outfile=path_save + '/resolution_mesh.png') + + return mpas_grid_file, graph_info_file + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mpas_plots.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mpas_plots.py new file mode 100644 index 0000000..4ee39f5 --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/mpas_plots.py @@ -0,0 +1,305 @@ +import os + +import numpy as np +from shapely.geometry import Polygon +import math + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +from cartopy.geodesic import Geodesic +from matplotlib.backends.backend_pdf import PdfPages +from geopy.distance import distance + +from vtxmpasmeshes.dataset_utilities import open_mpas_regional_file, \ + get_borders_at_distance, mpas_mesh_equivalent_wrf + +from vtxmpasmeshes.plot_utilities import plot_latlon_cartopy, \ + plot_mpas_darray, set_plot_kwargs, add_colorbar, \ + start_cartopy_map_axis, close_plot, add_cartopy_details, \ + get_plot_size, get_max_borders, plot_mpas_darray_gtm + + +def view_resolution_map(ds, pdfname=None, list_distances=None, **kwargs): + # ds is a resolution dataset ('distance' and 'resolution' dataset) + # we plot, for different distances, a + + if list_distances is None: + list_distances = [1000, 500, 200, 50] + + pdf = None + if pdfname is not None: + pdf = PdfPages(pdfname) + + # Region + # we don't want to plot too much + region = ds.where(ds['distance'] <= max(list_distances)) + region = region.dropna('lat', how='all').dropna('lon', how='all') + + # Find the center (place at distance zero) + my_zero = region['distance'].argmin(['lat', 'lon']) + mylat = int(my_zero['lat']) + mylon = int(my_zero['lon']) + + # Create a one-dimensional radial array from the center + axis = region.isel(lat=mylat, lon=range(mylon, region.dims['lon'])) + axis = axis.squeeze(drop=True) + axis = axis.assign_coords({'distance': axis['distance']}) + axis = axis.swap_dims({'lon': 'distance'}) + + # Add several plots to the pdf -> one for each limit distance + for di in list_distances: + print('\t .. plotting for distances <= %.0fkm' % di) + # radial lineplot subplot + plt.subplot(121) + axis['resolution'].where(axis['distance'] <= di).plot() + plt.title('Radial Resolution') + + # map of the area closer than a distance di + x = region['resolution'].where(region['distance'] <= di) + x = x.dropna('lat', how='all').dropna('lon', how='all') + ax = plt.subplot(122, projection=ccrs.PlateCarree()) + add_cartopy_details(ax) + plot_latlon_cartopy(x, ax=ax, title='Resolution map', **kwargs) + + fig = plt.gcf() + fig.suptitle('Resolution (km). Distance closer than %.0fkm' % di) + close_plot(fig, size_fig=[12, 8], pdf=pdf) + + if pdf is not None: + pdf.close() + + return + + +def plot_expected_resolution_rings(ds, rings=None, outfile=None, ax=None): + + # if ax=None -> initialize and close the plot + # if ax not None -> do not initialize nor close + final = False + if ax is None: + final = True + ax = start_cartopy_map_axis() + + # test that the dataset has the expected attributes + try: + lat = ds.attrs['vtx-param-lat_ref'] + lon = ds.attrs['vtx-param-lon_ref'] + except KeyError as e: + print('The dataset has to be an MPAS mesh created by the ' + 'vtx generation flow (attributes vtx-param-)') + raise e + + # rings of 'expected' limits on the resolution of the mesh + if rings is None: + rings = ['size', 'radius', 'border'] + gd = Geodesic() + for ring in rings: + rad = ds.attrs['vtx-param-' + ring] + cp = gd.circle(lon=lon, lat=lat, radius=rad * 1000) + geom = Polygon(cp) + ax.add_geometries((geom,), crs=ccrs.PlateCarree(), + facecolor='none', edgecolor='black', + linewidth=1.5, alpha=0.8) + + # close if needed + if final: + close_plot(outfile=outfile) + return + + +def plot_era5_grid(ax): + gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, + linewidth=1, color='gray', alpha=0.6, linestyle='-') + + gl.top_labels = False + gl.left_labels = False + gl.bottom_labels = False + gl.right_labels = False + + era5_lons = np.arange(-180, 180, 0.25) + era5_lats = np.arange(-90, 90, 0.25) + gl.xlocator = mpl.ticker.FixedLocator(era5_lons) + gl.ylocator = mpl.ticker.FixedLocator(era5_lats) + + +def plot_wrf_grid(ds, ax=None): + # test that the dataset has the expected attributes + try: + centerlat = ds.attrs['vtx-param-lat_ref'] + centerlon = ds.attrs['vtx-param-lon_ref'] + except KeyError as e: + print('The dataset has to be an MPAS mesh created by the ' + 'vtx generation flow (attributes vtx-param-)') + raise e + + wrf_details = mpas_mesh_equivalent_wrf(ds) + num_domains = int(wrf_details['max_domains']) + + colors = ['red', 'green', 'purple', 'orange'] + for domain in range(1, num_domains + 1): + + resol_km = int(wrf_details['d' + str(domain) + 'res']) + num_cells = int(wrf_details['d' + str(domain) + 'e_wesn']) - 1 + + len_grid = distance(kilometers=float(resol_km * num_cells)) / 2 + + maxlat = len_grid.destination(point=(centerlat, centerlon), + bearing=0).latitude + minlat = len_grid.destination(point=(centerlat, centerlon), + bearing=180).latitude + maxlon = len_grid.destination(point=(centerlat, centerlon), + bearing=90).longitude + minlon = len_grid.destination(point=(centerlat, centerlon), + bearing=270).longitude + + directions = {'positive': [0, 90], 'negative': [180, 270]} + + for cell in range(math.ceil(num_cells / 2)): + + d = distance( # cells resolution (max res) times + kilometers=float(resol_km * (cell + 1 / 2))) + for degrees in directions.values(): + vert = d.destination(point=(centerlat, centerlon), + bearing=degrees[0]) + hori = d.destination(point=(centerlat, centerlon), + bearing=degrees[1]) + + ax.plot([hori.longitude, hori.longitude], [minlat, maxlat], + linewidth=0.8, color=colors[domain - 1]) + ax.plot([minlon, maxlon], [vert.latitude, vert.latitude], + linewidth=0.8, color=colors[domain - 1]) + + +def view_mpas_regional_mesh(mpas_grid_file, outfile=None, + do_plot_resolution_rings=True, + do_plot_era5_grid=False, + do_plot_wrf_grid=False, + vname='resolution', + border_radius=None, + **kwargs): + + if vname != 'resolution': + full = True + else: + full = False + + ds = open_mpas_regional_file(mpas_grid_file, full=full) + + units = ds[vname].attrs.get('units', '') + ncells = str(len(ds[vname].values.flatten())) + name = os.path.basename(mpas_grid_file) + + # PLOT RESOLUTION + + ax = start_cartopy_map_axis(zorder=2) + plot_kwargs = set_plot_kwargs(da=ds[vname], **kwargs) + + # -------- + tit = vname + ': ' + name + ' (' + str(ncells) + ')' + array_plot_kwgs = {**plot_kwargs} + if 'border_radius' in kwargs: + if kwargs['border_radius'] is not None: + array_plot_kwgs['border_radius'] = kwargs['border_radius'] + + #plot_mpas_darray(ds, vname, ax=ax, title=tit, + # border_radius=border_radius, **array_plot_kwgs) + plot_mpas_darray_gtm(ds, vname, ax=ax, title=tit, + border_radius=border_radius, **array_plot_kwgs) + + if do_plot_era5_grid: + plot_era5_grid(ax) + if do_plot_resolution_rings: + plot_expected_resolution_rings(ds, ax=ax) + if do_plot_wrf_grid: + plot_wrf_grid(ds, ax=ax) + # -------- + + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=outfile) + + return ds + + +def compare_plot_mpas_regional_meshes(list_mesh_files, outfile=None, + border_radius=None, + vname='resolution', + do_plot_resolution_rings=True, + do_plot_era5_grid=True, + **kwargs): + + if vname != 'resolution': + full = True + else: + full = False + + names = [] + datasets = [] + for f in list_mesh_files: + name = os.path.basename(f).replace('.grid.nc', '') + datasets.append(open_mpas_regional_file(f, full=full)) + names.append(name) + + vars_list = [ds[vname] for ds in datasets] + plot_kwargs = set_plot_kwargs(list_darrays=vars_list, **kwargs) + + if border_radius is None: + max_borders = get_max_borders(datasets, + namelat='latitude', + namelon='longitude') + else: + # Find the center + # 1. try the kwargs + central_lat = kwargs.get('lat_ref', None) + central_lon = kwargs.get('lon_ref', None) + + for ds in datasets: + if central_lat is not None and central_lon is not None: + break + central_lat = ds.attrs.get('vtx-param-lat_ref', None) + central_lon = ds.attrs.get('vtx-param-lon_ref', None) + if central_lon is None or central_lat is None: + max_borders = get_max_borders(datasets, + namelat='latitude', + namelon='longitude') + else: + max_borders = get_borders_at_distance(border_radius, + centerlat=central_lat, + centerlon=central_lon, + ) + + nrows, ncols = get_plot_size(len(list_mesh_files)) + + fig_size = [5 * ncols, 5 * nrows] + fig, axs = plt.subplots(nrows=nrows, ncols=ncols+1, figsize=fig_size) + axs = axs.reshape([nrows, ncols + 1]) + g = mpl.gridspec.GridSpec(nrows=nrows, ncols=ncols+1) + + for m, name in enumerate(names): + i, j = m // ncols, m % ncols + + each_title = kwargs.get('each_title', '') + ncells = str(datasets[m].dims['nCells']) + each_title = each_title.replace('', name) + each_title = each_title.replace('', ncells) + + axs[i, j] = plt.subplot(g[i, j], projection=ccrs.PlateCarree()) + add_cartopy_details(axs[i, j]) + plot_mpas_darray(datasets[m], vname, + ax=axs[i, j], **plot_kwargs, + title=each_title, borders=max_borders) + if do_plot_era5_grid: + plot_era5_grid(axs[i, j]) + if do_plot_resolution_rings: + plot_expected_resolution_rings(datasets[m], ax=axs[i, j]) + + for ax in axs[:, -1]: + ax.axis('off') + + add_colorbar(axs[:, -1], label=vname + ' (km)', **plot_kwargs) + suptitle = kwargs.get('suptitle', '') + if suptitle != '': + plt.gcf().suptitle(suptitle, fontsize=16) + plt.subplots_adjust(top=0.9) + close_plot(outfile=outfile, size_fig=fig_size) + diff --git a/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/plot_utilities.py b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/plot_utilities.py new file mode 100644 index 0000000..7d71fce --- /dev/null +++ b/sources/CGFD-USP-Create-Mesh/vtx-mpas-meshes/vtxmpasmeshes/plot_utilities.py @@ -0,0 +1,421 @@ +import xarray as xr +import numpy as np + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature + +from vtxmpasmeshes.dataset_utilities import get_borders_at_distance, \ + get_center + + +# OPEN AND CLOSE PLOTS + +def start_cartopy_map_axis(zorder=1): + ax = plt.axes(projection=ccrs.PlateCarree()) # projection type + add_cartopy_details(ax, zorder=zorder) + return ax + + +def add_cartopy_details(ax, zorder=1): + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.coastlines(resolution='10m', zorder=zorder+1) + + gl = ax.gridlines(draw_labels=True, alpha=0.5, linestyle='--', + zorder=zorder+2) + gl.top_labels = False + gl.right_labels = False + + +def close_plot(fig=None, size_fig=None, pdf=None, outfile=None, + force_show=False): + + if size_fig is None: + size_fig = [10, 8] + + if fig is None: + fig = plt.gcf() + fig.set_size_inches(size_fig) + + if outfile is not None: + plt.savefig(outfile, dpi=300) + + if pdf is not None: + pdf.savefig(fig) + + if (outfile is None and pdf is None) or force_show: + plt.show() + + plt.close() + + +# HANDLE PLOT KWARGS FROM ALL PASSED KWARGS + +def set_plot_kwargs(da=None, list_darrays=None, **kwargs): + plot_kwargs = {k: v for k, v in kwargs.items() + if k in ['cmap', 'vmin', 'vmax'] + and v is not None} + + if 'cmap' not in plot_kwargs: + #plot_kwargs['cmap'] = 'Spectral' + plot_kwargs['cmap'] = 'Reds_r' + + vmin = plot_kwargs.get('vmin', None) + if vmin is None: + if da is not None: + vmin = np.min(da) + elif list_darrays is not None: + vmin = np.min([v.min() for v in list_darrays if v is not None]) + if vmin is not None: + plot_kwargs['vmin'] = vmin + + vmax = plot_kwargs.get('vmax', None) + if vmax is None: + if da is not None: + vmax = np.max(da) + elif list_darrays is not None: + vmax = np.max([v.max() for v in list_darrays if v is not None]) + + if vmax is not None: + plot_kwargs['vmax'] = vmax + + return plot_kwargs + + +# BORDERS OF THE PLOT + +def find_borders(lats, lons, margin='factor2'): + lats = lats.flatten() + lons = lons.flatten() + + limits = lons.min(), lons.max(), lats.min(), lats.max() + if 'factor' in margin: + delta = int(margin[-1]) + deltalat = np.abs(limits[1] - limits[0]) / (10 * delta) + deltalon = np.abs(limits[3] - limits[2]) / (10 * delta) + minlon = limits[0] - deltalon + maxlon = limits[1] + deltalon + minlat = limits[2] - deltalat + maxlat = limits[3] + deltalat + limits = minlon, maxlon, minlat, maxlat + elif 'cells' in margin: + delta = int(margin[-1]) + deltalat = np.abs(limits[1] - limits[0]) + deltalon = np.abs(limits[3] - limits[2]) + minlon = limits[0] - deltalon * delta + maxlon = limits[1] + deltalon * delta + minlat = limits[2] - deltalat * delta + maxlat = limits[3] + deltalat * delta + limits = minlon, maxlon, minlat, maxlat + + return limits + + +# BASIC LATLON PLOT + +def plot_latlon_cartopy(darray, ax=None, title='', borders=None, **kwargs): + # For a DataArray that has lat/lon coordinates + + # Start the axis + if ax is None: + ax = start_cartopy_map_axis(zorder=4) + + # Set the extent + if borders is None: + borders = find_borders(darray.lat.values, darray.lon.values) + # borders = [minlon, maxlon, minlat, maxlat] + ax.set_extent(borders, crs=ccrs.PlateCarree()) + + kwargs = set_plot_kwargs(da=darray, extend='both', **kwargs) + + # Plot the array (automatic xarray plot) + darray.plot(ax=ax, zorder=1, **kwargs) # plot the resolution + + ax.set_title(title) + return + + +# MPAS PLOT + +def colorvalue(val, cmap='Spectral', vmin=None, vmax=None): + """ + Given a value and the range max, min, it returns the associated + color of the desired cmap. + :param val: float + :param cmap: str + :param vmin: float (default None) + :param vmax: float (default None) + :return: cm(norm_val): color + """ + # Get a colormap instance, defaulting to rc values if name is None. + cm = mpl.cm.get_cmap(cmap, None) + if vmin is None: + vmin = xr.DataArray.min().values # min value of the array + if vmax is None: + vmax = xr.DataArray.max().values # max value of the array + if vmin == vmax: + # A class which, when called, linearly normalizes data into the + # [0.0, 1.0] interval. + norm_val = mpl.colors.Normalize(vmin=vmin - 1, vmax=vmax + 1, + clip=True)(val) + else: + norm_val = mpl.colors.Normalize(vmin=vmin, vmax=vmax, + clip=True)(val) + return cm(norm_val) + + +def plot_mpas_darray(ds, vname, ax=None, outfile=None, **kwargs): + + if vname not in ds.data_vars: + print('Unplottable Data Array ' + vname) + print(ds) + return + + da = ds[vname] + for coord in ['time', 'lev']: + if coord in da.dims: + print('Selecting first slice for ' + coord + '.') + da = da.isel({coord: 0}) + + final = False + if ax is None: + final = True + ax = start_cartopy_map_axis() + + borders = kwargs.get('borders', None) + if borders is None: + lats = ds['latitude'].values.flatten() + lons = ds['longitude'].values.flatten() + border_radius = kwargs.get('border_radius', None) + if border_radius is not None: + central_lat = kwargs.get('lat_ref', None) + central_lon = kwargs.get('lon_ref', None) + if central_lon is None or central_lat is None: + central_lat = ds.attrs.get('vtx-param-lat_ref', None) + central_lon = ds.attrs.get('vtx-param-lon_ref', None) + if central_lon is None or central_lat is None: + central_lat, central_lon = get_center(lats, lons) + borders = get_borders_at_distance(kwargs['border_radius'], + centerlat=central_lat, + centerlon=central_lon, + ) + else: + borders = find_borders(lats, lons) + + ax.set_extent(borders, crs=ccrs.PlateCarree()) + + plot_kwargs = set_plot_kwargs(da=da, **kwargs) + + if 'nCells' in ds[vname].dims: + plot_cells_mpas(ds, vname, ax, **plot_kwargs) + elif 'nVertices' in ds[vname].dims: + plot_dual_mpas(ds, vname, ax, **plot_kwargs) + else: + print('WARNING Impossible to plot!') + + units = da.attrs.get('units', '') + name = kwargs.get('name', '') + ncells = str(len(da.values.flatten())) + title = kwargs.get('title', '') + title = title.replace('', vname).replace('', units) + title = title.replace('', name).replace('', ncells) + ax.set_title(title) + + if final: + title_legend = kwargs.get('title_legend', ': ') + title_legend = title_legend.replace('', vname) + title_legend = title_legend.replace('', units) + add_colorbar(ax, label=title_legend, **plot_kwargs) + + close_plot(outfile=outfile) + return + +def plot_mpas_darray_gtm(ds, vname, ax=None, outfile=None, **kwargs): + + if vname not in ds.data_vars: + print('Unplottable Data Array ' + vname) + print(ds) + return + + da = ds[vname] + for coord in ['Time', 'nVertLevels']: + if coord in da.dims: + if coord == 'Time': + print('Selecting first slice for ' + coord + '.') + da = da.isel({coord: 0}) + else: + print('Selecting slice 2 for ' + coord + '.') + da = da.isel({coord: 2}) + + final = False + if ax is None: + final = True + ax = start_cartopy_map_axis() + + borders = kwargs.get('borders', None) + if borders is None: + lats = ds['latitude'].values.flatten() + lons = ds['longitude'].values.flatten() + border_radius = kwargs.get('border_radius', None) + if border_radius is not None: + central_lat = kwargs.get('lat_ref', None) + central_lon = kwargs.get('lon_ref', None) + if central_lon is None or central_lat is None: + central_lat = ds.attrs.get('vtx-param-lat_ref', None) + central_lon = ds.attrs.get('vtx-param-lon_ref', None) + if central_lon is None or central_lat is None: + central_lat, central_lon = get_center(lats, lons) + borders = get_borders_at_distance(kwargs['border_radius'], + centerlat=central_lat, + centerlon=central_lon, + ) + else: + borders = find_borders(lats, lons) + + ax.set_extent(borders, crs=ccrs.PlateCarree()) + + plot_kwargs = set_plot_kwargs(da=da, **kwargs) + + if 'nCells' in ds[vname].dims: + #plot_cells_mpas(ds, vname, ax, **plot_kwargs) + # GTM: test to plot 3D vars for t=0 and l=0 + plot_cells_mpas_3D(ds, vname, ax, da, **plot_kwargs) + elif 'nVertices' in ds[vname].dims: + plot_dual_mpas(ds, vname, ax, **plot_kwargs) + else: + print('WARNING Impossible to plot!') + + units = da.attrs.get('units', '') + name = kwargs.get('name', '') + ncells = str(len(da.values.flatten())) + title = kwargs.get('title', '') + title = title.replace('', vname).replace('', units) + title = title.replace('', name).replace('', ncells) + ax.set_title(title) + + if final: + title_legend = kwargs.get('title_legend', ': ') + title_legend = title_legend.replace('', vname) + title_legend = title_legend.replace('', units) + add_colorbar(ax, label=title_legend, **plot_kwargs) + + close_plot(outfile=outfile) + return + + + +def plot_cells_mpas(ds, vname, ax, **plot_kwargs): + for i, cell in enumerate(ds['nCells'].values): + value = ds[vname].sel(nCells=cell) + + vals = ds['verticesOnCell'].sel(nCells=cell).values + num_sides = int(ds['nEdgesOnCell'].sel(nCells=cell)) + vals = vals[:num_sides] - 1 + lats = ds['latitudeVertex'].sel(nVertices=vals) + lons = ds['longitudeVertex'].sel(nVertices=vals) + + color = colorvalue(value, **plot_kwargs) + + print (color) + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + +def plot_cells_mpas_3D(ds, vname, ax, da, **plot_kwargs): + for i, cell in enumerate(ds['nCells'].values): + #value = ds[vname].sel(nCells=cell) + value = da.sel(nCells=cell) + + vals = ds['verticesOnCell'].sel(nCells=cell).values + num_sides = int(ds['nEdgesOnCell'].sel(nCells=cell)) + vals = vals[:num_sides] - 1 + lats = ds['latitudeVertex'].sel(nVertices=vals) + lons = ds['longitudeVertex'].sel(nVertices=vals) + + color = colorvalue(value, **plot_kwargs) + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + +def plot_dual_mpas(ds, vname, ax, **plot_kwargs): + for vertex in ds['nVertices'].values: + value = ds[vname].sel(nVertices=vertex) + + vals = ds['cellsOnVertex'].sel(nVertices=vertex).values + if 0 in vals: + # Border triangle + continue + vals = vals - 1 + lats = ds['latitude'].sel(nCells=vals) + lons = ds['longitude'].sel(nCells=vals) + + color = colorvalue(value, **plot_kwargs) + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + return + + +# TOOLS FOR MULTIPLE PLOTS (Also can be used for 1 plot) + +def add_colorbar(axs, fig=None, label=None, **plot_kwargs): + if fig is None: + fig = plt.gcf() + + try: + x = axs[0, 0] + except: + try: + x = axs[0] + n = len(axs) + except: + axs = np.array([axs]).reshape([1, 1]) + else: + axs = axs.reshape([n, 1]) + + cbar = fig.colorbar( + mpl.cm.ScalarMappable( + norm=mpl.colors.Normalize(vmin=plot_kwargs['vmin'], + vmax=plot_kwargs['vmax'], clip=True), + cmap=plot_kwargs['cmap']), + ax=axs[:, :], shrink=0.6) + cbar.ax.locator_params(nbins=10) + if label is not None: + cbar.set_label(label) + + return + + +def get_plot_size(numplots, nrows=None, ncols=None): + if nrows is not None and ncols is not None: + return nrows, ncols + + if nrows is not None: + ncols = int((numplots + 1) // nrows) + elif ncols is not None: + nrows = int((numplots + 1) // ncols) + else: + if numplots <= 3: + nrows, ncols = 1, numplots + elif numplots == 4: + nrows, ncols = 2, 2 + elif numplots <= 10: + ncols = 3 + nrows = int((numplots + 1) // ncols) + else: + ncols = 4 + nrows = int((numplots + 1) // ncols) + + return nrows, ncols + + +def get_max_borders(list_results, margin='factor2', namelat='latitude', + namelon='longitude'): + borders = np.array([find_borders(lats=ds[namelat].values, + lons=ds[namelon].values, + margin=margin) + for ds in list_results]) + max_borders = borders[:, 0].min(), borders[:, 1].max(), \ + borders[:, 2].min(), borders[:, 3].max() + return np.array(max_borders) diff --git a/sources/CGFD-USP-Post-Proc/mpas_animate.py b/sources/CGFD-USP-Post-Proc/mpas_animate.py new file mode 100644 index 0000000..df33465 --- /dev/null +++ b/sources/CGFD-USP-Post-Proc/mpas_animate.py @@ -0,0 +1,848 @@ + +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Script to create animations of scalar fields (and optionally vectors) on native MPAS grids + +Based on: mpas_plot.py +Created: Oct 2025 by Danilo Couto de Souza +Last edited: Oct 2022 + +Usage examples: + # Animate surface variable + python mpas_animate.py -f "history.*.nc" -v surface_pressure -o animation.mp4 + + # Animate 3D variable at level 10 + python mpas_animate.py -f "history.*.nc" -v theta -l 10 -o temp_animation.mp4 + + # Animate with wind vectors (u,v) + python mpas_animate.py -f "history.*.nc" -v theta -l 10 -u uReconstructZonal -v_wind uReconstructMeridional -o wind_animation.mp4 + + # Specify time range + python mpas_animate.py -f "history.*.nc" -v surface_pressure --tmin 0 --tmax 10 -o animation.gif + +""" + +import math +import os +import glob +import argparse +from multiprocessing import Pool, cpu_count + +import xarray as xr +import numpy as np + +import matplotlib as mpl +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import cartopy.crs as ccrs + +from tqdm import tqdm + +# Derived variables mapping (from mpas_plot.py) +derived_variables = { + 'latCell': ['latitude'], + 'lonCell': ['longitude'], + 'latVertex': ['latitudeVertex'], + 'lonVertex': ['longitudeVertex'], + 'areaCell': ['area', 'resolution'], +} + + +def add_mpas_mesh_variables(ds, full=True, **kwargs): + """Add derived variables to MPAS dataset (from mpas_plot.py)""" + for v in ds.data_vars: + if v not in derived_variables: + continue + + newvs = derived_variables[v] + + for newv in newvs: + if newv in ds: + continue + + if 'lat' in v or 'lon' in v: + ds[newv] = xr.apply_ufunc(np.rad2deg, ds[v]) + ds[newv] = ds[newv].where(ds[newv] <= 180.0, ds[newv] - 360.0) + ds[newv].attrs['units'] = 'degrees' + + elif newv == 'area': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1: + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + ds[newv] = (ds[v] / 10 ** 6) * correction_rad_earth**2 + ds[newv].attrs['units'] = 'km^2 (assuming areaCell in m^2)' + ds[newv].attrs['long_name'] = 'Area of the cell in km^2' + + elif newv == 'resolution': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1.0: + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + area = (ds[v] / 10 ** 6) * correction_rad_earth**2 + ds[newv] = 2 * (xr.apply_ufunc(np.sqrt, area / math.pi)) + ds[newv].attrs['units'] = 'km' + ds[newv].attrs['long_name'] = 'Resolution of the cell (approx)' + + return ds + + +def open_mpas_file(file, **kwargs): + """Open MPAS file and add derived variables""" + ds = xr.open_dataset(file) + ds = add_mpas_mesh_variables(ds, **kwargs) + return ds + + +def add_cartopy_details(ax, zorder=1): + """Add coastlines and gridlines to map""" + ax.coastlines(resolution='10m', zorder=zorder+1, linewidth=0.1) + gl = ax.gridlines(draw_labels=True, alpha=0.5, linestyle='--', + zorder=zorder+2, linewidth=0.5) + gl.top_labels = False + gl.right_labels = False + + +def get_vim_vmax(da, clip=False): + """Returns good vmin and vmax values to plot da field""" + truemaxval = da.max().values + trueminval = da.min().values + + if (trueminval <= 0) and (truemaxval > 0): + if truemaxval > abs(trueminval): + slice = da.values[da.values > 0] + else: + slice = -da.values[da.values <= 0] + sigma = np.std(slice) + m = np.mean(slice) + if clip: + maxval = min(truemaxval, m+4*sigma) + else: + maxval = truemaxval + minval = -maxval + elif (truemaxval >= 0): + minval = trueminval + sigma = np.std(da.values) + m = np.mean(da.values) + if clip: + maxval = min(truemaxval, m+4*sigma) + else: + maxval = truemaxval + else: + maxval = truemaxval + sigma = np.std(da.values) + m = np.mean(da.values) + if clip: + minval = max(trueminval, m-4*sigma) + else: + minval = trueminval + + return minval, maxval + + +def set_plot_kwargs(da=None, clip=False, list_darrays=None, **kwargs): + """Set plot kwargs including colorbar limits""" + plot_kwargs = {k: v for k, v in kwargs.items() + if k in ['cmap', 'vmin', 'vmax'] + and v is not None} + + if 'cmap' not in plot_kwargs: + plot_kwargs['cmap'] = 'Spectral' + + vmin = plot_kwargs.get('vmin', None) + if vmin is None: + if da is not None: + vmin, _ = get_vim_vmax(da, clip) + elif list_darrays is not None: + vmin = np.min([v.min() for v in list_darrays if v is not None]) + + if vmin is not None: + plot_kwargs['vmin'] = vmin + + vmax = plot_kwargs.get('vmax', None) + if vmax is None: + if da is not None: + _, vmax = get_vim_vmax(da, clip) + elif list_darrays is not None: + vmax = np.max([v.max() for v in list_darrays if v is not None]) + + if vmax is not None: + plot_kwargs['vmax'] = vmax + + return plot_kwargs + + +def colorvalue(val, da, vmin=None, vmax=None, cmap='Spectral'): + """Get color for a value based on colormap and range""" + cm = mpl.colormaps[cmap] + if vmin is None: + vmin = da.min().values + if vmax is None: + vmax = da.max().values + + if vmin == vmax: + norm_val = mpl.colors.Normalize(vmin=vmin - 1, vmax=vmax + 1, clip=True)(val) + else: + norm_val = mpl.colors.Normalize(vmin=vmin, vmax=vmax, clip=True)(val) + + return cm(norm_val) + + +def add_colorbar(axs, fig=None, label=None, extend='both', **plot_kwargs): + """Add colorbar to figure with extend option""" + if fig is None: + fig = plt.gcf() + + try: + x = axs[0, 0] + except: + try: + x = axs[0] + n = len(axs) + except: + axs = np.array([axs]).reshape([1, 1]) + else: + axs = axs.reshape([n, 1]) + + cbar = fig.colorbar( + mpl.cm.ScalarMappable( + norm=mpl.colors.Normalize(vmin=plot_kwargs['vmin'], + vmax=plot_kwargs['vmax'], clip=True), + cmap=plot_kwargs['cmap']), + ax=axs[:, :], shrink=0.6, extend=extend) + cbar.ax.locator_params(nbins=10) + if label is not None: + cbar.set_label(label) + + return + + +def _process_cell(args): + """Helper function to process a single cell (for parallel execution)""" + cell, da_values, ds_grid_dict, plot_kwargs, plotEdge = args + + value = da_values[cell] + vertices = ds_grid_dict['verticesOnCell'][cell] + num_sides = ds_grid_dict['nEdgesOnCell'][cell] + + if 0 in vertices[:num_sides]: + return None # Border cell + + vertices = vertices[:num_sides] - 1 + lats = ds_grid_dict['latitudeVertex'][vertices] + lons = ds_grid_dict['longitudeVertex'][vertices] + + # Get color + vmin = plot_kwargs['vmin'] + vmax = plot_kwargs['vmax'] + cmap = plot_kwargs.get('cmap', 'Spectral') + cm = mpl.colormaps[cmap] + + if vmin == vmax: + norm_val = mpl.colors.Normalize(vmin=vmin - 1, vmax=vmax + 1, clip=True)(value) + else: + norm_val = mpl.colors.Normalize(vmin=vmin, vmax=vmax, clip=True)(value) + + color = cm(norm_val) + + # Check for polygons at the border of the map (+/- 180 longitude) + if lons.max() > 170 and lons.min() < -170: + lons = np.where(lons >= 170.0, lons - 360.0, lons) + + if plotEdge: + edgecolor = 'grey' + lw = 0.05 + else: + edgecolor = None + lw = None + + return (lons, lats, color, edgecolor, lw) + + +def _render_frame(args): + """Render a single frame in parallel (more efficient than parallelizing cells)""" + frame_idx, file, vname, level, u_var, v_var, plotEdge, gridfile, plot_kwargs, stride, \ + lat_min, lat_max, lon_min, lon_max, dpi, extend = args + + # Create figure for this frame + fig = plt.figure(figsize=(12, 8)) + ax = plt.axes(projection=ccrs.PlateCarree()) + + # Set map extent + if (lat_min is not None and lat_max is not None and + lon_min is not None and lon_max is not None): + ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree()) + else: + ax.set_extent([-180.0, 180, -90.0, 90.0], crs=ccrs.PlateCarree()) + + add_cartopy_details(ax, zorder=2) + + # Load data + ds_frame = open_mpas_file(file) + da_frame = ds_frame[vname].isel(Time=0) + + if level is not None: + da_frame = da_frame.isel(nVertLevels=level) + + # Plot cells + if 'nCells' in da_frame.dims: + plot_cells_mpas_fast(da_frame, ds_frame, ax, plotEdge, + gridfile=gridfile, show_progress=False, n_jobs=1, **plot_kwargs) + + # Plot wind vectors if requested + if u_var is not None and v_var is not None: + u_frame = ds_frame[u_var].isel(Time=0) + v_frame = ds_frame[v_var].isel(Time=0) + + if level is not None: + u_frame = u_frame.isel(nVertLevels=level) + v_frame = v_frame.isel(nVertLevels=level) + + add_wind_vectors(ax, ds_frame, u_frame, v_frame, stride=stride) + + # Set title + filename = os.path.basename(file) + title = f'{vname}' + if level is not None: + title += f' (Level {level})' + title += f'\n{filename}' + ax.set_title(title, fontsize=12) + + # Add colorbar + units = ds_frame[vname].attrs.get('units', '') + add_colorbar(ax, fig=fig, label=f'{vname} ({units})', extend=extend, **plot_kwargs) + + # Save frame to temporary file + temp_file = f'_temp_frame_{frame_idx:04d}.png' + fig.savefig(temp_file, dpi=dpi, bbox_inches='tight') + plt.close(fig) + + return temp_file + + +def plot_cells_mpas_fast(da, ds, ax, plotEdge=False, gridfile=None, show_progress=True, n_jobs=1, **plot_kwargs): + """ + Plot cells on MPAS grid (optimized for animation - no edge plotting by default) + + Parameters: + ----------- + n_jobs : int, ignored (kept for compatibility, parallelization is done at frame level) + """ + # GTM: check if grid properties needed for plotting are in ds + grid_properties = ['verticesOnCell', 'nEdgesOnCell'] + + if set(grid_properties).issubset(set(ds.keys())): + ds_grid = ds + else: + try: + ds_grid = open_mpas_file(gridfile) + if not set(grid_properties).issubset(set(ds_grid.keys())): + raise RuntimeError(f"Recovery of {grid_properties} failed.") + except: + raise RuntimeError(f"{grid_properties} not found in dataset or grid file.") + + cells = ds['nCells'].values + + # Always use sequential processing (parallelization is at frame level now) + cell_iterator = tqdm(cells, desc=" Plotting cells", leave=False) if show_progress else cells + + for cell in cell_iterator: + value = da.sel(nCells=cell) + vertices = ds_grid['verticesOnCell'].sel(nCells=cell).values + num_sides = int(ds_grid['nEdgesOnCell'].sel(nCells=cell)) + + if 0 in vertices[:num_sides]: + continue # Border cell + + vertices = vertices[:num_sides] - 1 + lats = ds_grid['latitudeVertex'].sel(nVertices=vertices) + lons = ds_grid['longitudeVertex'].sel(nVertices=vertices) + + color = colorvalue(value, da, vmin=plot_kwargs['vmin'], vmax=plot_kwargs['vmax'], + cmap=plot_kwargs.get('cmap', 'Spectral')) + + # Check for polygons at the border of the map (+/- 180 longitude) + if max(lons) > 170 and min(lons) < -170: + lons = xr.where(lons >= 170.0, lons - 360.0, lons) + + if plotEdge: + edgecolor = 'grey' + lw = 0.05 + else: + edgecolor = None + lw = None + + ax.fill(lons, lats, edgecolor=edgecolor, linewidth=lw, facecolor=color) + + +def add_wind_vectors(ax, ds, u_da, v_da, stride=10, scale=None, **kwargs): + """ + Add wind vectors to the plot + + Parameters: + ----------- + ax : matplotlib axis + ds : xarray dataset with grid info + u_da : xarray DataArray with u component (zonal) + v_da : xarray DataArray with v component (meridional) + stride : int, plot every Nth vector to avoid overcrowding + scale : float, scaling factor for arrows + """ + # Get cell centers + lats = ds['latitude'].values[::stride] + lons = ds['longitude'].values[::stride] + + # Get wind components + u = u_da.values[::stride] + v = v_da.values[::stride] + + # Remove NaN values + mask = ~(np.isnan(u) | np.isnan(v)) + lats = lats[mask] + lons = lons[mask] + u = u[mask] + v = v[mask] + + # Plot quiver + if scale is None: + scale = np.nanmax(np.sqrt(u**2 + v**2)) * 50 + + ax.quiver(lons, lats, u, v, + transform=ccrs.PlateCarree(), + scale=scale, + width=0.002, + headwidth=3, + headlength=4, + color='black', + alpha=0.7, + zorder=10) + + +def load_mpas_files(file_pattern): + """ + Load multiple MPAS files and sort by time + + Parameters: + ----------- + file_pattern : str, glob pattern for files (e.g., "history.*.nc") + + Returns: + -------- + list of file paths sorted by name + """ + files = sorted(glob.glob(file_pattern)) + if len(files) == 0: + raise FileNotFoundError(f"No files found matching pattern: {file_pattern}") + return files + + +def create_animation(file_pattern, vname, + outfile='animation.mp4', + level=None, + u_var=None, v_var=None, + plotEdge=False, + clip=False, + gridfile=None, + lat_min=None, lat_max=None, + lon_min=None, lon_max=None, + tmin=None, tmax=None, + fps=5, + dpi=150, + stride=15, + n_jobs=1, + extend='both', + **kwargs): + """ + Create animation of MPAS field from multiple files + + Parameters: + ----------- + file_pattern : str, glob pattern for input files + vname : str, variable name to plot + outfile : str, output file (mp4, gif, etc) + level : int, vertical level (None for surface variables) + u_var, v_var : str, u and v wind component variable names (optional) + plotEdge : bool, whether to plot cell edges + clip : bool, whether to clip outliers + gridfile : str, additional grid file if needed + lat_min, lat_max, lon_min, lon_max : float, map extent + tmin, tmax : int, time indices to animate + fps : int, frames per second + dpi : int, dots per inch for output + stride : int, stride for wind vectors + """ + + # Load files + print(f"Loading files matching: {file_pattern}") + files = load_mpas_files(file_pattern) + print(f"Found {len(files)} files") + + # Load first file to get grid info and set up plot + ds = open_mpas_file(files[0]) + + if vname not in ds.data_vars: + print(f'Variable {vname} not found in dataset') + print('Available variables:', list(ds.keys())[:20], '...') + return + + # Check if variable has vertical levels + has_levels = 'nVertLevels' in ds[vname].dims + + if has_levels and level is None: + print(f"Variable {vname} has vertical levels but no level specified.") + print(f"Using level 0 by default. Available levels: {ds['nVertLevels'].values}") + level = 0 + + if not has_levels and level is not None: + print(f"Warning: Variable {vname} is a surface field. Ignoring level parameter.") + level = None + + # Check wind variables + plot_wind = (u_var is not None) and (v_var is not None) + if plot_wind: + if u_var not in ds.data_vars or v_var not in ds.data_vars: + print(f"Wind variables {u_var} or {v_var} not found. Skipping wind vectors.") + plot_wind = False + + # Collect all data arrays for consistent colorbar + print("\n" + "="*60) + print("STEP 1: Loading all time steps to determine color scale") + print("="*60) + all_data = [] + for file in tqdm(files, desc="Loading files"): + ds_temp = open_mpas_file(file) + da_temp = ds_temp[vname].isel(Time=0) + if level is not None: + da_temp = da_temp.isel(nVertLevels=level) + all_data.append(da_temp) + + # Apply time range if specified + if tmin is not None or tmax is not None: + tmin = tmin if tmin is not None else 0 + tmax = tmax if tmax is not None else len(all_data) + all_data = all_data[tmin:tmax] + files = files[tmin:tmax] + print(f"Applied time range: frames {tmin} to {tmax}") + + # Set plot kwargs with consistent color scale + plot_kwargs = set_plot_kwargs(da=None, clip=clip, list_darrays=all_data, **kwargs) + + print(f"\n{'='*60}") + print(f"STEP 2: Rendering frames") + print(f"{'='*60}") + print(f" Number of frames: {len(files)}") + print(f" Color scale: vmin={plot_kwargs['vmin']:.3e}, vmax={plot_kwargs['vmax']:.3e}") + print(f" Colormap: {plot_kwargs['cmap']}") + print(f" FPS: {fps}") + print(f" DPI: {dpi}") + if plot_wind: + print(f" Wind vectors: YES (stride={stride})") + else: + print(f" Wind vectors: NO") + + if n_jobs > 1: + # Parallel frame rendering (MUCH MORE EFFICIENT!) + print(f" Parallel workers: {n_jobs}") + print(f" Mode: Each worker renders complete frames") + + # Prepare arguments for parallel processing + args_list = [ + (i, files[i], vname, level, u_var if plot_wind else None, v_var if plot_wind else None, + plotEdge, gridfile, plot_kwargs, stride, lat_min, lat_max, lon_min, lon_max, dpi, extend) + for i in range(len(files)) + ] + + # Render frames in parallel + with Pool(processes=n_jobs) as pool: + temp_files = list(tqdm(pool.imap(_render_frame, args_list), + total=len(files), desc=" Rendering frames")) + + # Create animation from temporary PNG files + print(f"\n{'='*60}") + print(f"STEP 3: Combining frames into animation") + print(f"{'='*60}") + + # Read images and create animation + from PIL import Image + images = [Image.open(f) for f in temp_files] + + print(f" Saving animation to: {outfile}") + if outfile.endswith('.gif'): + images[0].save(outfile, save_all=True, append_images=images[1:], + duration=int(1000/fps), loop=0, optimize=False) + print(f" Format: GIF") + else: + # For MP4, use ffmpeg via subprocess or imageio + try: + import imageio + with imageio.get_writer(outfile, fps=fps) as writer: + for img_file in tqdm(temp_files, desc=" Writing video"): + img = imageio.imread(img_file) + writer.append_data(img) + print(f" Format: MP4 (using imageio)") + except ImportError: + print(" Warning: imageio not found, using ffmpeg directly") + # Fall back to using ffmpeg directly via subprocess + import subprocess + with open('_temp_filelist.txt', 'w') as f: + for i, img_file in enumerate(temp_files): + f.write(f"file '{img_file}'\n") + f.write(f"duration {1.0/fps}\n") + subprocess.run(['ffmpeg', '-f', 'concat', '-safe', '0', '-i', '_temp_filelist.txt', + '-c:v', 'libx264', '-pix_fmt', 'yuv420p', outfile, '-y'], + check=True) + os.remove('_temp_filelist.txt') + print(f" Format: MP4 (using ffmpeg)") + + # Clean up temporary files + print(f" Cleaning up {len(temp_files)} temporary files...") + for f in temp_files: + os.remove(f) + + print(f"\n{'='*60}") + print(f"SUCCESS! Animation saved to:") + print(f" {os.path.abspath(outfile)}") + print(f"{'='*60}") + + else: + # Sequential animation (original matplotlib animation approach) + print(f" Mode: Sequential (use -j > 1 for parallel speedup)") + + # Set up figure and axis + fig = plt.figure(figsize=(12, 8)) + ax = plt.axes(projection=ccrs.PlateCarree()) + + # Set map extent + if (lat_min is not None and lat_max is not None and + lon_min is not None and lon_max is not None): + ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree()) + else: + ax.set_extent([-180.0, 180, -90.0, 90.0], crs=ccrs.PlateCarree()) + + add_cartopy_details(ax, zorder=2) + + # Add colorbar + units = ds[vname].attrs.get('units', '') + add_colorbar(ax, fig=fig, label=f'{vname} ({units})', extend=extend, **plot_kwargs) + + # Animation update function + def update_frame(frame_idx): + print(f"\n=== Frame {frame_idx+1}/{len(files)} ===") + filename = os.path.basename(files[frame_idx]) + print(f" File: {filename}") + + ax.clear() + print(" Clearing axis and adding map details...") + add_cartopy_details(ax, zorder=2) + + # Set extent again (cleared by ax.clear()) + if (lat_min is not None and lat_max is not None and + lon_min is not None and lon_max is not None): + ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree()) + else: + ax.set_extent([-180.0, 180, -90.0, 90.0], crs=ccrs.PlateCarree()) + + # Load data for this frame + print(f" Loading data...") + ds_frame = open_mpas_file(files[frame_idx]) + da_frame = ds_frame[vname].isel(Time=0) + + if level is not None: + da_frame = da_frame.isel(nVertLevels=level) + + # Plot cells + if 'nCells' in da_frame.dims: + print(f" Plotting {len(ds_frame['nCells'])} cells...") + plot_cells_mpas_fast(da_frame, ds_frame, ax, plotEdge, + gridfile=gridfile, show_progress=True, n_jobs=1, **plot_kwargs) + else: + print(f" Warning: Cannot plot variable with dimensions {da_frame.dims}") + return + + # Plot wind vectors if requested + if plot_wind: + print(f" Adding wind vectors...") + u_frame = ds_frame[u_var].isel(Time=0) + v_frame = ds_frame[v_var].isel(Time=0) + + if level is not None: + u_frame = u_frame.isel(nVertLevels=level) + v_frame = v_frame.isel(nVertLevels=level) + + add_wind_vectors(ax, ds_frame, u_frame, v_frame, stride=stride) + + # Set title + title = f'{vname}' + if level is not None: + title += f' (Level {level})' + title += f'\n{filename}' + ax.set_title(title, fontsize=12) + + print(f" Frame {frame_idx+1}/{len(files)} complete!") + + # Create animation + print(f"\n{'='*60}") + print(f"STEP 3: Generating animation frames") + print(f"{'='*60}") + anim = animation.FuncAnimation(fig, update_frame, frames=len(files), + interval=1000/fps, repeat=True) + + # Save animation + print(f"\n{'='*60}") + print(f"STEP 4: Saving animation") + print(f"{'='*60}") + print(f" Output file: {outfile}") + + if outfile.endswith('.gif'): + writer = animation.PillowWriter(fps=fps) + print(f" Format: GIF (using PillowWriter)") + else: + writer = animation.FFMpegWriter(fps=fps, bitrate=1800) + print(f" Format: MP4 (using FFMpegWriter)") + + print(f" Saving... (this may take a while)") + anim.save(outfile, writer=writer, dpi=dpi) + plt.close() + + print(f"\n{'='*60}") + print(f"SUCCESS! Animation saved to:") + print(f" {os.path.abspath(outfile)}") + print(f"{'='*60}") + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument( + "-f", "--files", type=str, required=True, + help="File pattern for MPAS data files (e.g., 'history.*.nc')", + ) + + parser.add_argument( + "-o", "--outfile", type=str, default='mpas_animation.mp4', + help="Output animation file (mp4, gif, etc)", + ) + + parser.add_argument( + "-v", "--var", type=str, required=True, + help="Variable to animate", + ) + + parser.add_argument( + "-l", "--level", type=int, default=None, + help="Vertical level (for 3D variables only)", + ) + + parser.add_argument( + "-u", "--u_wind", type=str, default=None, + help="U (zonal) wind component variable name (optional)", + ) + + parser.add_argument( + "-v_wind", "--v_wind", type=str, default=None, + help="V (meridional) wind component variable name (optional)", + ) + + parser.add_argument( + "-g", "--grid", type=str, default='no', + help="Draw grid edges: yes or no (default: no for better performance)", + ) + + parser.add_argument( + "-c", "--clip", type=str, default='no', + help="Clip values greater than (expected_val + 4*std): yes or no", + ) + + parser.add_argument( + "-gf", "--gridfile", type=str, default=None, + help="Additional file containing grid properties", + ) + + # Map extent + parser.add_argument("-lat_min", type=float, default=None, + help="Minimum latitude for zoom") + parser.add_argument("-lat_max", type=float, default=None, + help="Maximum latitude for zoom") + parser.add_argument("-lon_min", type=float, default=None, + help="Minimum longitude for zoom") + parser.add_argument("-lon_max", type=float, default=None, + help="Maximum longitude for zoom") + + # Time range + parser.add_argument("--tmin", type=int, default=None, + help="Starting time index (default: 0)") + parser.add_argument("--tmax", type=int, default=None, + help="Ending time index (default: all)") + + # Animation parameters + parser.add_argument("--fps", type=int, default=5, + help="Frames per second (default: 5)") + parser.add_argument("--dpi", type=int, default=150, + help="DPI for output (default: 150)") + parser.add_argument("--stride", type=int, default=15, + help="Stride for wind vectors (plot every Nth vector, default: 15)") + + # Parallelization + parser.add_argument("-j", "--jobs", type=int, default=1, + help="Number of parallel workers for cell plotting (default: 1, use -1 for all CPUs)") + + # Color scale + parser.add_argument("--vmin", type=float, default=None, + help="Minimum value for color scale (e.g., 90000 for pressure)") + parser.add_argument("--vmax", type=float, default=None, + help="Maximum value for color scale (e.g., 103500 for pressure)") + parser.add_argument("--cmap", type=str, default='Spectral', + help="Colormap name (default: Spectral). Examples: viridis, plasma, coolwarm, RdBu_r") + parser.add_argument("--extend", type=str, default='both', + help="Colorbar extend option: 'both', 'neither', 'min', 'max' (default: both)") + + args = parser.parse_args() + + # Parse grid option + plotEdge = args.grid.lower() in ['yes', 'y'] + + # Parse clip option + clip = args.clip.lower() in ['yes', 'y'] + + # Determine number of jobs + n_jobs = args.jobs + if n_jobs == -1: + n_jobs = cpu_count() + print(f"Using all available CPUs: {n_jobs}") + elif n_jobs > 1: + print(f"Using {n_jobs} parallel workers") + + # Create animation + create_animation( + file_pattern=args.files, + vname=args.var, + outfile=args.outfile, + level=args.level, + u_var=args.u_wind, + v_var=args.v_wind, + plotEdge=plotEdge, + clip=clip, + gridfile=args.gridfile, + lat_min=args.lat_min, + lat_max=args.lat_max, + lon_min=args.lon_min, + lon_max=args.lon_max, + tmin=args.tmin, + tmax=args.tmax, + fps=args.fps, + dpi=args.dpi, + stride=args.stride, + n_jobs=n_jobs, + vmin=args.vmin, + vmax=args.vmax, + cmap=args.cmap, + extend=args.extend, + ) diff --git a/sources/CGFD-USP-Post-Proc/mpas_plot.py b/sources/CGFD-USP-Post-Proc/mpas_plot.py new file mode 100755 index 0000000..30b9e64 --- /dev/null +++ b/sources/CGFD-USP-Post-Proc/mpas_plot.py @@ -0,0 +1,542 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Script to plot sclar fields on native MPAS grids + +Originally From: ?? +Edited: Danilo in 2023 +Last edited: Nov 2023 by P. Peixoto (ppeixoto@usp.br) +Last edited: Nov 2023 by F.A.V.B. Alves (fbalves@usp.br) +Last edited: Mar 2024 by G. Torres Mendonça (guilherme.torresmendonca@ime.usp.br) +Last edited: Oct 2025 by G. Torres Mendonça (guilherme.torresmendonca@ime.usp.br) +""" + +import math +import os + +import xarray as xr +import numpy as np + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs + +import argparse + +from tqdm import tqdm + +def add_mpas_mesh_variables(ds, full=True, **kwargs): + for v in ds.data_vars: + if v not in derived_variables: + continue + + newvs = derived_variables[v] + + for newv in newvs: + if newv in ds: + #print(newv + ' already here') + continue + + if 'lat' in v or 'lon' in v: + ds[newv] = xr.apply_ufunc(np.rad2deg, ds[v]) + ds[newv] = ds[newv].where(ds[newv] <= 180.0, ds[newv] - 360.0) + ds[newv].attrs['units'] = 'degrees' + + elif newv == 'area': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1: + # need to correct to earth radius + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + ds[newv] = (ds[v] / 10 ** 6) * correction_rad_earth**2 + ds[newv].attrs['units'] = 'km^2 (assuming areaCell in m^2)' + ds[newv].attrs['long_name'] = 'Area of the cell in km^2' + + elif newv == 'resolution': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1.0: + #print('need to correct to earth radius!!') + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + # km^2 (assuming areaCell in m^2) + area = (ds[v] / 10 ** 6) * correction_rad_earth**2 + + ds[newv] = 2 * (xr.apply_ufunc(np.sqrt, area / math.pi)) + ds[newv].attrs['units'] = 'km' + ds[newv].attrs['long_name'] = 'Resolution of the cell (approx)' + + return ds + + +def open_mpas_file(file, **kwargs): + + ds = xr.open_dataset(file) + + ds = add_mpas_mesh_variables(ds, **kwargs) + + return ds + +def start_cartopy_map_axis(zorder=1): + + ax = plt.axes(projection=ccrs.PlateCarree()) # projection type + + add_cartopy_details(ax, zorder=zorder) + + return ax + +def add_cartopy_details(ax, zorder=1): + + #Country boarders + #ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder, linewidth=0.1) + + #Coastlines + ax.coastlines(resolution='10m', zorder=zorder+1, linewidth=0.1) + + # Reference gridlines + gl = ax.gridlines(draw_labels=True, alpha=0.5, linestyle='--', + zorder=zorder+2, linewidth=0.5) + gl.top_labels = False + gl.right_labels = False + +def set_plot_kwargs(da=None, clip=False, list_darrays=None, **kwargs): + plot_kwargs = {k: v for k, v in kwargs.items() + if k in ['cmap', 'vmin', 'vmax'] + and v is not None} + + if 'cmap' not in plot_kwargs: + plot_kwargs['cmap'] = 'Spectral_r' + + vmin = plot_kwargs.get('vmin', None) + if vmin is None: + if da is not None: + vmin,_ = get_vim_vmax(da,clip) + #vmin = np.min(da) + elif list_darrays is not None: + vmin = np.min([v.min() for v in list_darrays if v is not None]) + + if vmin is not None: + plot_kwargs['vmin'] = vmin + + vmax = plot_kwargs.get('vmax', None) + if vmax is None: + if da is not None: + _,vmax = get_vim_vmax(da,clip) + #vmax = np.max(da) + elif list_darrays is not None: + vmax = np.max([v.max() for v in list_darrays if v is not None]) + + if vmax is not None: + plot_kwargs['vmax'] = vmax + + return plot_kwargs + +def get_vim_vmax(da,clip=False): + #Returns good vmin and vmax values to plot da field + + truemaxval = da.max().values + trueminval = da.min().values + + # Use same range for negative and positive values (zero will always have the same color) + if (trueminval <= 0) and (truemaxval > 0): + if truemaxval > abs(trueminval): + slice = da.values[ da.values > 0] + else: + slice = -da.values[ da.values <= 0] + sigma = np.std(slice) + m = np.mean(slice) + if clip: + maxval = min(truemaxval,m+4*sigma) + else: + maxval = truemaxval + minval = -maxval + + # Clip values at mean + 4*std so we still get good color resolution if the solution has a small number of very large numbers + elif (truemaxval >= 0): + minval = trueminval + sigma = np.std(da.values) + m = np.mean(da.values) + if clip: + maxval = min(truemaxval,m+4*sigma) + else: + maxval = truemaxval + else: + maxval = truemaxval + sigma = np.std(da.values) + m = np.mean(da.values) + if clip: + minval = max(trueminval,m-4*sigma) + else: + minval = trueminval + + return minval, maxval + +def colorvalue(val, da, vmin=None, vmax=None, cmap='Spectral_r'): + """ + Given a value and the range max, min, it returns the associated + color of the desired cmap. + :param val: float + :param da: xarray data + :param vmin: float (default None) + :param vmax: float (default None) + :param cmap: str + :return: cm(norm_val): color + """ + + # Get a colormap instance, defaulting to rc values if name is None. + cm = mpl.colormaps[cmap] #cm.get_cmap(cmap, None) + if vmin is None: + vmin = da.min().values #xr.DataArray.min().values # min value of the array + if vmax is None: + vmax = da.max().values #xr.DataArray.max().values # max value of the array + + if vmin == vmax: + # A class which, when called, linearly normalizes data into the + # [0.0, 1.0] interval. + norm_val = mpl.colors.Normalize(vmin=vmin - 1, vmax=vmax + 1, clip=True)(val) + else: + norm_val = mpl.colors.Normalize(vmin=vmin, vmax=vmax, clip=True)(val) + + return cm(norm_val) + +def plot_cells_mpas(da, ds, ax, plotEdge=True, gridfile=None, **plot_kwargs): + # da: specific xarray to be plotted (time/level filtered) + # ds: general xarray with grid structure, require for grid propreties + # plotEdge: wether the cell edge should be visible or not. For high-resolution grids figure looks better if plotEdge=False + + # GTM: check if grid properties needed for plotting are in ds + grid_properties = ['verticesOnCell', 'nEdgesOnCell'] + + if set(grid_properties).issubset(set(ds.keys())): + print (f"{grid_properties} found in dataset.") + ds_grid = ds + else: + print (f"{grid_properties} not found in dataset. "+ + "Trying to recover them from additional grid file.") + try: + # Open additional grid file + ds_grid = open_mpas_file(gridfile) + if set(grid_properties).issubset(set(ds_grid.keys())): + print (f"{grid_properties} found in additional grid file.") + except: + raise RuntimeError(f"Recovery of {grid_properties} failed.") + + # ax = start_cartopy_map_axis() + print("Generating grid plot and plotting variable. This may take a while...") + for cell in tqdm(ds['nCells'].values): + + value = da.sel(nCells=cell) + + # GTM: now grid properties are taken from ds_grid, defined above + vertices = ds_grid['verticesOnCell'].sel(nCells=cell).values + num_sides = int(ds_grid['nEdgesOnCell'].sel(nCells=cell)) + + if 0 in vertices[:num_sides]: + # Border cell + continue + + # Cel indexation in MPAS starts in 1 (saved in verticesOnCell), + # but for indexing in XARRAY starts with 0 (so -1 the indexes) + vertices = vertices[:num_sides] - 1 + + lats = ds_grid['latitudeVertex'].sel(nVertices=vertices) + lons = ds_grid['longitudeVertex'].sel(nVertices=vertices) + + #Set color + color = colorvalue(value, da, vmin=plot_kwargs['vmin'], vmax=plot_kwargs['vmax']) + + # Check if there are polygons at the boarder of the map (+/- 180 longitude) + # Shift +360 deg the negative longitude + if max(lons) > 170 and min(lons) < -170 : + lons = xr.where(lons >= 170.0, lons - 360.0, lons) + + if plotEdge: + edgecolor = 'grey' + lw = 0.1 + else: + edgecolor = None + lw = None + + ax.fill(lons, lats, edgecolor=edgecolor, linewidth=lw, facecolor=color) + + return + +def plot_dual_mpas(da, ds, ax, plotEdge=True, **plot_kwargs): + + #Loop over all Voronoi cell vertices - which are triangle circumcentres + print("Generating grid plot and plotting variable. This may take a while...") + for vertex in tqdm(ds['nVertices'].values): + + #Triangle value + value = da.sel(nVertices=vertex) + + #The triangle is formed by connecting 3 cell nodes + cells = ds['cellsOnVertex'].sel(nVertices=vertex).values + + if 0 in cells: + # Border triangle + continue + + #Indexing given from mpas starts in 1, so adjust to start in 0 + cells = cells - 1 + lats = ds['latitude'].sel(nCells=cells) + lons = ds['longitude'].sel(nCells=cells) + + #Set color + color = colorvalue(value, da, vmin=plot_kwargs['vmin'], vmax=plot_kwargs['vmax']) + + # Check if there are polygons at the boarder of the map (+/- 180 longitude) + # Shift +360 deg the negative longitude + if max(lons) > 170 and min(lons) < -170 : + lons = xr.where(lons >= 170.0, lons - 360.0, lons) + + if plotEdge: + edgecolor = 'grey' + lw = 0.1 + else: + edgecolor = None + lw = None + + # Plot polygons and variable + ax.fill(lons, lats, edgecolor=edgecolor, linewidth=lw, facecolor=color) + + return + +def add_colorbar(axs, fig=None, label=None, **plot_kwargs): + if fig is None: + fig = plt.gcf() + + try: + x = axs[0, 0] + except: + try: + x = axs[0] + n = len(axs) + except: + axs = np.array([axs]).reshape([1, 1]) + else: + axs = axs.reshape([n, 1]) + + cbar = fig.colorbar( + mpl.cm.ScalarMappable( + norm=mpl.colors.Normalize(vmin=plot_kwargs['vmin'], + vmax=plot_kwargs['vmax'], clip=True), + cmap=plot_kwargs['cmap']), + ax=axs[:, :], shrink=0.6) + cbar.ax.locator_params(nbins=10) + if label is not None: + cbar.set_label(label) + + return + +def close_plot(fig=None, size_fig=None, pdf=None, outfile=None, + force_show=False): + + if size_fig is None: + size_fig = [10, 8] + + if fig is None: + fig = plt.gcf() + fig.set_size_inches(size_fig) + + if outfile is not None: + plt.savefig(outfile, dpi=800) + + if pdf is not None: + pdf.savefig(fig, dpi=800) + + if (outfile is None and pdf is None) or force_show: + plt.show() + + plt.close() + + +def plot_mpas_darray(ds, vname, time=None, level=None, ax=None, outfile=None, + title=None, plotEdge=True, clip=False, gridfile=None, lat_min=None, lat_max=None, lon_min=None, lon_max=None, **kwargs): + + ## plot_mpas_darray + da = ds[vname] + + if 'Time' in da.dims: + print() + if time not in da['Time'].values: + print("Proposed time slice not available:", time," Timesteps:", da['Time'].values) + print(" Setting time slice to zero.") + time = 0 + else: + print('Selecting time slice '+ str(time) + '.') + + da = da.isel({'Time': time}) + + + if 'nVertLevels' in da.dims: + print() + if level not in da['nVertLevels'].values: + print("Proposed vertical level slice not available.", level," Levels:", da['nVertLevels'].values) + print(" Setting level to zero.") + level = 0 + else: + print('Selecting vertical level '+ str(time) + '.') + + da = da.isel({'nVertLevels': level}) + print("\n Data to be plotted") + print(da) + print() + + # Ajusta o domínio espacial se limites de zoom forem fornecidos + if (lat_min is not None and lat_max is not None and lon_min is not None and lon_max is not None): + ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree()) + else: + ax.set_extent([-180.0, 180, -90.0, 90.0], crs=ccrs.PlateCarree()) + + plot_kwargs = set_plot_kwargs(da=da, clip=clip, **kwargs) + + if 'nCells' in da.dims: #Plot on Voronoi cells + plot_cells_mpas(da, ds, ax, plotEdge, gridfile=gridfile, **plot_kwargs) + + elif 'nVertices' in da.dims: #Plot on Triangles + plot_dual_mpas(da, ds, ax, plotEdge, **plot_kwargs) + + else: # TO DO: Implement ploting edge quantities + print('WARNING Impossible to plot!') + + + if title == None: + title = vname + + ax.set_title(title) + + add_colorbar(ax, label=vname + ' (' + da.attrs.get('units', '') + ')', **plot_kwargs) + + return + +def view_mpas_mesh(mpas_grid_file, outfile=None, + vname='resolution', + time=None, + level=None, + plotEdge=True, + clip=False, + gridfile=None, + lat_min=None, + lat_max=None, + lon_min=None, + lon_max=None, + **kwargs): + + ds = open_mpas_file(mpas_grid_file) + + if vname not in ds.data_vars: + print('Unplottable Data Array ' + vname) + print('Available variables:', list(ds.keys())) + return + + units = ds[vname].attrs.get('units', '') + ncells = str(len(ds[vname].values.flatten())) + name = os.path.basename(mpas_grid_file) + print(vname, units, ncells, name, ds[vname]) + + ax = start_cartopy_map_axis(zorder=2) + + tit = vname + ': ' + name + ' (' + str(ncells) + ')' + if time is not None: + tit = tit + " Timestep="+str(time) + if level is not None: + tit = tit + " Level="+str(level) + + plot_mpas_darray(ds, vname, time=time, level=level, ax=ax, + title=tit, plotEdge=plotEdge, clip=clip, + gridfile=gridfile, + lat_min=lat_min, lat_max=lat_max, lon_min=lon_min, lon_max=lon_max, + **kwargs) + + close_plot(outfile=outfile) + + +if __name__ == "__main__": + + derived_variables = { + 'latCell': ['latitude'], + 'lonCell': ['longitude'], + 'latVertex': ['latitudeVertex'], + 'lonVertex': ['longitudeVertex'], + 'areaCell': ['area', 'resolution'], + } + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument( + "-f", "--infile", type=str, required=True, + help="Name of an MPAS grid or data file (.nc)", + ) + + parser.add_argument( + "-o", "--outfile", type=str, default=None, + help="File to save the MPAS plot", + ) + parser.add_argument( + "-v", "--var", type=str, default='resolution', + help="Variable to be plotted", + ) + + parser.add_argument( + "-l", "--level", type=int, default=None, + help="Vertical level", + ) + + parser.add_argument( + "-t", "--time", type=int, default=None, + help="Time step", + ) + + parser.add_argument( + "-g", "--grid", type=str, default='yes', + help="Draw grid edges: yes or no", + ) + + parser.add_argument( + "-c", "--clip", type=str, default='no', + help="Clip values grater than (expected_val + 4*std): yes or no", + ) + + # GTM: option to supply additional file containing grid properties of infile + parser.add_argument( + "-gf", "--gridfile", type=str, default=None, + help="Name of additional file that contains grid properties of MPAS" + + " infile (.nc; for use only when infile does not contain these properties)", + ) + + parser.add_argument('-vmin', default=None) + parser.add_argument('-vmax', default=None) + + # Zoom arguments + parser.add_argument("-lat_min", type=float, default=None, help="Minimum latitude for zoom") + parser.add_argument("-lat_max", type=float, default=None, help="Maximum latitude for zoom") + parser.add_argument("-lon_min", type=float, default=None, help="Minimum longitude for zoom") + parser.add_argument("-lon_max", type=float, default=None, help="Maximum longitude for zoom") + + args = parser.parse_args() + + + if not os.path.exists(args.infile): + raise IOError('File does not exist: ' + args.infile) + + if args.grid in ['no', 'No', 'N', 'n']: + plotEdge=False + else: + plotEdge=True + + if args.clip in ['yes', 'Yes', 'Y', 'y']: + clip=True + else: + clip=False + + view_mpas_mesh(args.infile, outfile=args.outfile, time=args.time, + level=args.level, vname=args.var, plotEdge=plotEdge, + clip=clip, gridfile=args.gridfile, + lat_min=args.lat_min, lat_max=args.lat_max, lon_min=args.lon_min, lon_max=args.lon_max, + vmin=args.vmin, vmax=args.vmax) diff --git a/sources/CGFD-USP-Post-Proc/mpas_plot_grid.py b/sources/CGFD-USP-Post-Proc/mpas_plot_grid.py new file mode 100755 index 0000000..a33766e --- /dev/null +++ b/sources/CGFD-USP-Post-Proc/mpas_plot_grid.py @@ -0,0 +1,343 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Oct 7 17:17:43 2022 + +@author: daniloceano +""" + +import math +import os + +import xarray as xr +import numpy as np + +import matplotlib as mpl +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature +from geopy.distance import distance + +import argparse + +def add_mpas_mesh_variables(ds, full=True, **kwargs): + for v in ds.data_vars: + if v not in derived_variables: + continue + + newvs = derived_variables[v] + + for newv in newvs: + if newv in ds: + #print(newv + ' already here') + continue + + if 'lat' in v or 'lon' in v: + ds[newv] = xr.apply_ufunc(np.rad2deg, ds[v]) + ds[newv] = ds[newv].where(ds[newv] <= 180.0, ds[newv] - 360.0) + ds[newv].attrs['units'] = 'degrees' + + elif newv == 'area': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1: + # need to correct to earth radius + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + ds[newv] = (ds[v] / 10 ** 6) * correction_rad_earth**2 + ds[newv].attrs['units'] = 'km^2 (assuming areaCell in m^2)' + ds[newv].attrs['long_name'] = 'Area of the cell in km^2' + + elif newv == 'resolution': + radius_circle = ds.attrs.get('sphere_radius', 1.0) + if radius_circle == 1.0: + #print('need to correct to earth radius!!') + correction_rad_earth = 6371220.0 + else: + correction_rad_earth = 1 + + # km^2 (assuming areaCell in m^2) + area = (ds[v] / 10 ** 6) * correction_rad_earth**2 + + ds[newv] = 2 * (xr.apply_ufunc(np.sqrt, area / math.pi)) + ds[newv].attrs['units'] = 'km' + ds[newv].attrs['long_name'] = 'Resolution of the cell (approx)' + + return ds + + +def open_mpas_file(file, **kwargs): + ds = xr.open_dataset(file) + ds = add_mpas_mesh_variables(ds, **kwargs) + return ds + +def start_cartopy_map_axis(zorder=1): + ax = plt.axes(projection=ccrs.PlateCarree()) # projection type + add_cartopy_details(ax, zorder=zorder) + return ax + +def add_cartopy_details(ax, zorder=1): + ax.add_feature(cfeature.BORDERS, linestyle=':', zorder=zorder) + ax.coastlines(resolution='10m', zorder=zorder+1) + + gl = ax.gridlines(draw_labels=True, alpha=0.5, linestyle='--', + zorder=zorder+2) + gl.top_labels = False + gl.right_labels = False + +def set_plot_kwargs(da=None, list_darrays=None, **kwargs): + plot_kwargs = {k: v for k, v in kwargs.items() + if k in ['cmap', 'vmin', 'vmax'] + and v is not None} + + if 'cmap' not in plot_kwargs: + plot_kwargs['cmap'] = 'Spectral' + + vmin = plot_kwargs.get('vmin', None) + if vmin is None: + if da is not None: + vmin = np.min(da) + elif list_darrays is not None: + vmin = np.min([v.min() for v in list_darrays if v is not None]) + if vmin is not None: + plot_kwargs['vmin'] = vmin + + vmax = plot_kwargs.get('vmax', None) + if vmax is None: + if da is not None: + vmax = np.max(da) + elif list_darrays is not None: + vmax = np.max([v.max() for v in list_darrays if v is not None]) + + if vmax is not None: + plot_kwargs['vmax'] = vmax + + return plot_kwargs + +def colorvalue(val, cmap='Spectral', vmin=None, vmax=None): + """ + Given a value and the range max, min, it returns the associated + color of the desired cmap. + :param val: float + :param cmap: str + :param vmin: float (default None) + :param vmax: float (default None) + :return: cm(norm_val): color + """ + # Get a colormap instance, defaulting to rc values if name is None. + cm = mpl.colormaps[cmap] #cm.get_cmap(cmap, None) + if vmin is None: + vmin = xr.DataArray.min().values # min value of the array + if vmax is None: + vmax = xr.DataArray.max().values # max value of the array + if vmin == vmax: + # A class which, when called, linearly normalizes data into the + # [0.0, 1.0] interval. + norm_val = mpl.colors.Normalize(vmin=vmin - 1, vmax=vmax + 1, + clip=True)(val) + else: + norm_val = mpl.colors.Normalize(vmin=vmin, vmax=vmax, + clip=True)(val) + return cm(norm_val) + +def plot_cells_mpas(ds, vname, ax, **plot_kwargs): + + # ax = start_cartopy_map_axis() + + + for i, cell in enumerate(ds['nCells'].values): + value = ds[vname].sel(nCells=cell) + + vals = ds['verticesOnCell'].sel(nCells=cell).values + num_sides = int(ds['nEdgesOnCell'].sel(nCells=cell)) + vals = vals[:num_sides] - 1 + lats = ds['latitudeVertex'].sel(nVertices=vals) + lons = ds['longitudeVertex'].sel(nVertices=vals) + + + color = colorvalue(value, **plot_kwargs) + + ## For some reason, when plotting from -180 to 180 + # gives a strange mesh plot (actually, any value higher than + # 179 gives the strange result) + + if all(j for j in lons >= -179) and all(j for j in lons <= 179): + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + + +def plot_dual_mpas(ds, vname, ax, **plot_kwargs): + for vertex in ds['nVertices'].values: + value = ds[vname].sel(nVertices=vertex) + + vals = ds['cellsOnVertex'].sel(nVertices=vertex).values + if 0 in vals: + # Border triangle + continue + vals = vals - 1 + lats = ds['latitude'].sel(nCells=vals) + lons = ds['longitude'].sel(nCells=vals) + + color = colorvalue(value, **plot_kwargs) + + ax.fill(lons, lats, edgecolor=None, linewidth=0.0, + facecolor=color) + +def add_colorbar(axs, fig=None, label=None, **plot_kwargs): + if fig is None: + fig = plt.gcf() + + try: + x = axs[0, 0] + except: + try: + x = axs[0] + n = len(axs) + except: + axs = np.array([axs]).reshape([1, 1]) + else: + axs = axs.reshape([n, 1]) + + cbar = fig.colorbar( + mpl.cm.ScalarMappable( + norm=mpl.colors.Normalize(vmin=plot_kwargs['vmin'], + vmax=plot_kwargs['vmax'], clip=True), + cmap=plot_kwargs['cmap']), + ax=axs[:, :], shrink=0.6) + cbar.ax.locator_params(nbins=10) + if label is not None: + cbar.set_label(label) + + return + +def close_plot(fig=None, size_fig=None, pdf=None, outfile=None, + force_show=False): + + if size_fig is None: + size_fig = [10, 8] + + if fig is None: + fig = plt.gcf() + fig.set_size_inches(size_fig) + + if outfile is not None: + plt.savefig(outfile, dpi=800) + + if pdf is not None: + pdf.savefig(fig, dpi=800) + + if (outfile is None and pdf is None) or force_show: + plt.show() + + plt.close() + + +def plot_mpas_darray(ds, vname, ax=None, outfile=None, **kwargs): + + ## plot_mpas_darray + if vname not in ds.data_vars: + print('Unplottable Data Array ' + vname) + print(ds) + + da = ds[vname] + for coord in ['time', 'lev']: + if coord in da.dims: + print('Selecting first slice for ' + coord + '.') + da = da.isel({coord: 0}) + + # final = False + # if ax is None: + # final = True + # ax = start_cartopy_map_axis() + + ax.set_extent([-180.0, 180,-90.0, 90.0], + crs=ccrs.PlateCarree()) + + plot_kwargs = set_plot_kwargs(da=da, **kwargs) + + if 'nCells' in ds[vname].dims: + plot_cells_mpas(ds, vname, ax, **plot_kwargs) + # elif 'nVertices' in ds[vname].dims: + # plot_dual_mpas(ds, vname, ax, **plot_kwargs) + else: + print('WARNING Impossible to plot!') + + + units = da.attrs.get('units', '') + name = kwargs.get('name', '') + ncells = str(len(da.values.flatten())) + title = kwargs.get('title', '') + title = title.replace('', vname).replace('', units) + title = title.replace('', name).replace('', ncells) + title = vname + ax.set_title(title) + + # if final: + # title_legend = kwargs.get('title_legend', ': ') + # title_legend = title_legend.replace('', vname) + # title_legend = title_legend.replace('', units) + # add_colorbar(ax, label=title_legend, **plot_kwargs) + + # close_plot(outfile=outfile) + +def view_mpas_mesh(mpas_grid_file, outfile=None, + do_plot_resolution_rings=True, + vname='resolution', + border_radius=None, + **kwargs): + + ds = open_mpas_file(mpas_grid_file) + + units = ds[vname].attrs.get('units', '') + ncells = str(len(ds[vname].values.flatten())) + name = os.path.basename(mpas_grid_file) + + ax = start_cartopy_map_axis(zorder=2) + plot_kwargs = set_plot_kwargs(da=ds[vname]) + + # -------- + tit = vname + ': ' + name + ' (' + str(ncells) + ')' + array_plot_kwgs = {**plot_kwargs} + if 'border_radius' in kwargs: + if kwargs['border_radius'] is not None: + array_plot_kwgs['border_radius'] = kwargs['border_radius'] + + plot_mpas_darray(ds, vname, ax=ax, title=tit, + border_radius=border_radius, **array_plot_kwgs) + + + add_colorbar(ax, label=vname + ' (' + units + ')', **plot_kwargs) + close_plot(outfile=outfile) + + +if __name__ == "__main__": + + derived_variables = { + 'latCell': ['latitude'], + 'lonCell': ['longitude'], + 'latVertex': ['latitudeVertex'], + 'lonVertex': ['longitudeVertex'], + 'areaCell': ['area', 'resolution'], + } + + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument( + "-g", "--grid", type=str, required=True, + help="Name of an MPAS grid.nc", + ) + + parser.add_argument( + "-o", "--outfile", type=str, default=None, + help="File to save the MPAS plot", + ) + args = parser.parse_args() + + if not os.path.exists(args.grid): + raise IOError('File does not exist: ' + args.grid) + + view_mpas_mesh(args.grid, outfile=args.outfile) \ No newline at end of file diff --git a/sources/MPAS-Limited-Area/README.md b/sources/MPAS-Limited-Area/README.md new file mode 100644 index 0000000..bb1cf2f --- /dev/null +++ b/sources/MPAS-Limited-Area/README.md @@ -0,0 +1,259 @@ +# Last edited: Oct 2025 by G. Torres Mendonça (guilherme.torresmendonca@ime.usp.br) + +# MPAS Limited-Area - v2.2 + +MPAS Limited-Area is a python tool that takes an MPAS global grid and produces +a regional area grid given a region specifications. Regions can be specified in +a number of different ways, making limited-area extensible and flexible. + +# Download and Installing + +To download this command line script, clone this repository into the location +of your choosing. To install it, add the base directory to your path +environment variable: + +``` +$ git clone git@github.com:MiCurry/MPAS-Limited-Area.git +$ setenv PATH ${PATH}:/path/to/MPAS-Limited-Area +``` + +Then, run the `create_region` command-line script: +```Bash +$ # Running the script with no arguments will produce a usage output +Usage: create_region [-h] [-v VERBOSE] points grid create_region +create_region: error: the following arguments are required: points, grid +``` + +**Note**: It may be necessary to install the dependencies for this program if +they have not been currently installed by you, or your administrator. You can +install all the dependencies for this repository by running `pip install -r +requirements.txt`. This will install all the necessary dependencies needed to +run this program. + +It may also be necessary to update the Python 'shebang' (`#!/usr/bin/env +python`) at the top of the `create_region` script, depending on your python +environment. For instance, if you have multiple installations of python, you +may need to specify which python to use within the shebang i.e.: + +``` +#!/user/bin/env python3 +``` +or +``` +#!/user/bin/env python2 +``` + +# Running + +`create_region` can create regional subsets from global MPAS grid files or MPAS +static files. + +At any point in time, you can pass the `-h` or `--help` flag to `create_region` +to generate a help message, usage statement and a list of options. The command +line usage is: + +``` bash +$ create_region [options] points grid +``` + +Where `points` is a points specification file, and where `grid` is a global +MPAS NetCDF grid file. You'll find example points file in the points-example +directory within the docs directory of this repository and below in the *Points +Syntax* section. + +## Notes on creating regions from .grid.nc files + +When creating region subsets from `grid.nc` files, it is important to take a +few things into account. Because of the way the init_atmosphere model +interpolates some static data, it is possible to create incorrect static +feilds on a concave mesh, during the static interpolation of the +init_atmosphere model. + +Creating a mesh that is either **concave** in overall shape, or spans +significant longitudes near the poles will cause init_atmosphere model +to incorrectly interpolate some static fields. + +Thus, when subsetting a region of a `grid.nc` file, it is import to ensure +the subsetted region's shape is **convex** in shape. + +If you would like to have a convex region or region that spans many longitudes +you can avoid this problem to by simply using this program on meshes that contain +statc fields (i.e. `static.nc` files). + +## Notes on Creating Large Regions (nCells >= 2,000,000) + +If the region you create is significantly large ( >= 2,000,000 grid cells) you +will need to change the NetCDF file version of the regional grid file. To do +this, you can change the `format` keyword argument of the `LimitedArea` +initialization call within the `create_region` script to `NETCDF3_64BIT_DATA`: + +``` Python +regional_area = LimitedArea(args.grid, + args.points, + format='NETCDF3_64BIT_DATA', + **kwargs) +``` + +# Points (pts) Syntax + +A number of pts syntax files are available in `docs/points-examples`. + +The points syntax is a simple file format that can be used to specify a region. +There are a number of different methods for defining or generating a region. +Currently these include: `Polygon/Custom`, `Ellipse`, `Circle`, and `Channel`. + +Each method will differ slightly in the syntax used to describe a region, but a +number of keywords will be required by each method. + +Each pts file will need to specify the following keywords followed by an +appropriate value: + + 1. `Name:` - The desired name of your region. The specified keyword will be + appended to the outputed region. + 2. `Type:` - The method for generating the region [custom/circle] + 3. `Point: `- A latitude, longitude coordinate separated by a comma of a point + that is inside the desired region. **Note**: For the circle + method and ellipse method, this point will be used as the center + of the circle and ellipse. `Point` is not used with the channel + method. + +The value after `Name:` will be the name of the new regional mesh. + +If the `Name` within the pts file was set to be the following: +``` +Name: region_name +``` + +Then the resulting regional MPAS grid will be named the following: +`region_name.grid.nc` if the region was created from the +`x1.10242.grid.nc`. + +## Polygon + +A polygon points file would look like the following: +``` +Name: Desired_name_of_region +Type: custom +Point: lat, lon # Point that inside the region +lat1, lon1 # List of points specifying the region +lat2, lon2 +lat3, lon3 +... +latN, LonN +``` + +For the polygon method, the value of `Type:` must be specified as `custom`. +The value of `Point:` must be a latitude, longitude point that lies within the +desired region in degrees. + +After the `Point` specification, any number of coordinate points (in degrees) +that define the desired boundary can be listed. Points should be listed in +counter-clockwise order. + +An example polygon method for defining CONUS region (`conus.custom.pts`): +``` +Name: conus +Type: custom +Point: 40.0, -100.0 +50.0, -129.0 +50.0, -65.0 +20.0, -65.0 +20.0, -129.0 +``` + +**NOTE:** When creating regional meshes with the polygon method it is +necessary to **not create concave** regions. Doing so will result in MPAS +init_atmosphere producing erroneous results while interpolating static fields. +Please see the section on [concave regions](#concave). + +## Circle + +The circle method produces a regional circle subset of a global grid given a +center point (`Point`) and a radius from that point (`Radius`). + +An example circle points specification would look like the following: +``` +Name: my_circle +Type: circle +Point: 53.5, -4.5 +Radius: 655000.0 # Meters +``` + +Here `Point` is used to specify the center of the circle and `Radius` is used +to specify the radius of the circle (in meters). **NOTE**: The radius must +be larger then at least the smallest grid cell, else unexpected behavior will +occur. + +An example circle method for defining a circle around Colorado, USA is: +``` +Name: colorado +Type: circle +Point: 40.0, -105.0 +radius: 400000.0 +``` + +## Ellipse + +The ellipse method produces an ellipse shape region and is specified by a +semi-major and semi-minor axis length, as well as an orientation: + +``` +Name: my_ellipse +Type: ellipse +Point: 55.0, 93.0 # Latitude, Longitude (degrees) +Semi-major-axis: 6500000 # Meters +Semi-minor-axis: 3000000 # Meters +Orientation-angle: 15.0 # Clockwise rotation from due north (degrees) +``` + +## Equatorial Channel + +The equatorial channel method can be used to specify a channel parallel to the +equator, across longitudes and between two latitude points. + +For instance, one can specify a region between the tropics as: + +``` +Name: tropics +Type: channel +Upper-lat: 23.43676 +lower-lat: -23.43676 +``` + +### **Caution on creating channels of `grid.nc` files** + +Depending on the location of a specified channel, erroneous results can be +caused during some interpolation static fields by the init_atmosphere core. +This will cause erroneous results within result `static.nc` files and will +cause resulting files to be unusable. + +Thus, it is **highly** recommended to only use the channel method upon +`static.nc` files. Doing so will avoid this problem and will also save time +interpolating the static fields on different regions. + +# Reporting Bugs + +If you encounter a bug and wish to report it, please do so on this Github +repository's Issues page! Thank you! + +# Release Notes + +## 2.2 +* Update usage of 'numpy' for compatibility with NumPy 2.x + +## 2.1 +* Regions created from init.nc files are named as name.init.nc + +## 2.0 + +* Added ability to subset fields dimensioned by time + +## 1.1 + +* Change units for specifying the radius in the circle points method from + kilometers to meters. + +## 1.0 + +* Initial public release +* Subsets mpas grid.nc and static.nc files diff --git a/sources/MPAS-Limited-Area/create_region b/sources/MPAS-Limited-Area/create_region new file mode 100755 index 0000000..1016812 --- /dev/null +++ b/sources/MPAS-Limited-Area/create_region @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +from __future__ import absolute_import, division, print_function +import argparse +from limited_area.limited_area import LimitedArea + +if __name__ == "__main__": + description = ("Create a limited area MPAS grid from a global MPAS grid" + " and a file that specifies the regional area boundary.") + + epilog = ("For more information please see: " + "https://github.com/MiCurry/MPAS-Limited-Area") + + + parser = argparse.ArgumentParser(description=description, + epilog=epilog) + + required = parser.add_argument_group('Required', "Limited Area requires a" + " MPAS Grid as well as a" + " file specifying the" + " limited area.") + + options = parser.add_argument_group('Options', "Options to generating the" + " MPAS limited area.") + + + required.add_argument('points', + help='Points file specifying the MPAS regional area', + type=str) + required.add_argument('grid', + nargs='?', + default=None, + help=('Global MPAS grid file. Either a grid.nc or' + ' static.nc file'), + type=str) + + options.add_argument('-v', '--verbose', + help='Turn on verbose setting 0-5', + type=int, + default=0) + + options.add_argument('-p', '--plot', + help='Produce a plot of the region rather than subsetting', + action='store_true') + + args, unkown = parser.parse_known_args() + + if args.plot: + print('===== Making a plot only! ======') + else: + if args.grid is None: + import sys + print('Error: If the -p/--plot option is not specified, a netCDF file') + print(' to subset must be provided.') + sys.exit(1) + + DEBUG = args.verbose + if DEBUG > 0: + print("DEBUG: DEBUG set to verbose level ", DEBUG, '\n') + + if DEBUG > 1: + print("DEBUG: Grid File: ", args.grid) + print("DEBUG: Points File: ", args.points) + + + kwargs = { 'DEBUG' : DEBUG } + + regional_area = LimitedArea(args.grid, + args.points, + args.plot, + format='NETCDF3_64BIT_OFFSET', + **kwargs) + + regional_area.gen_region(**kwargs) + + + if DEBUG > 0: + print("DEBUG: Limited Area Creation Finished") + + + diff --git a/sources/MPAS-Limited-Area/create_region_n_layers_as_input b/sources/MPAS-Limited-Area/create_region_n_layers_as_input new file mode 100755 index 0000000..b077e89 --- /dev/null +++ b/sources/MPAS-Limited-Area/create_region_n_layers_as_input @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +from __future__ import absolute_import, division, print_function +import argparse +from limited_area.limited_area_n_layers_as_input import LimitedArea_n_layers_as_input +import argparse + +if __name__ == "__main__": + description = ("Create a limited area MPAS grid from a global MPAS grid" + " and a file that specifies the regional area boundary.") + + epilog = ("For more information please see: " + "https://github.com/MiCurry/MPAS-Limited-Area") + + + parser = argparse.ArgumentParser(description=description, + epilog=epilog) + + required = parser.add_argument_group('Required', "Limited Area requires a" + " MPAS Grid as well as a" + " file specifying the" + " limited area.") + + options = parser.add_argument_group('Options', "Options to generating the" + " MPAS limited area.") + + + required.add_argument('points', + help='Points file specifying the MPAS regional area', + type=str) + required.add_argument('grid', + help=('Global MPAS grid file. Either a grid.nc or' + ' static.nc file'), + type=str) + required.add_argument('n_layers', + help=('Number of external boundary layers'), + type=int) + options.add_argument('-v', '--verbose', + help='Turn on verbose setting 0-5', + type=int, + default=0) + + args, unkown = parser.parse_known_args() + + + DEBUG = args.verbose + if DEBUG > 0: + print("DEBUG: DEBUG set to verbose level ", DEBUG, '\n') + + if DEBUG > 1: + print("DEBUG: Grid File: ", args.grid) + print("DEBUG: Points File: ", args.points) + + + kwargs = { 'DEBUG' : DEBUG } + + regional_area = LimitedArea_n_layers_as_input(args.grid, + args.points, + format='NETCDF3_64BIT_OFFSET', + n_layers=args.n_layers, + **kwargs) + + regional_area.gen_region(**kwargs) + + + if DEBUG > 0: + print("DEBUG: Limited Area Creation Finished") + + + diff --git a/sources/MPAS-Limited-Area/docs/points-examples/conus.custom.pts b/sources/MPAS-Limited-Area/docs/points-examples/conus.custom.pts new file mode 100644 index 0000000..d065a02 --- /dev/null +++ b/sources/MPAS-Limited-Area/docs/points-examples/conus.custom.pts @@ -0,0 +1,7 @@ +Name: conus +Type: custom +Point: 40.0, -100.0 +50.0, -129.0 +50.0, -65.0 +20.0, -65.0 +20.0, -129.0 diff --git a/sources/MPAS-Limited-Area/docs/points-examples/india.circle.pts b/sources/MPAS-Limited-Area/docs/points-examples/india.circle.pts new file mode 100644 index 0000000..a239a59 --- /dev/null +++ b/sources/MPAS-Limited-Area/docs/points-examples/india.circle.pts @@ -0,0 +1,4 @@ +Name: india +Type: circle +Point: 20.0, 80.0 +radius: 2000000.0 # Meters diff --git a/sources/MPAS-Limited-Area/docs/points-examples/japan.ellipse.pts b/sources/MPAS-Limited-Area/docs/points-examples/japan.ellipse.pts new file mode 100644 index 0000000..b361888 --- /dev/null +++ b/sources/MPAS-Limited-Area/docs/points-examples/japan.ellipse.pts @@ -0,0 +1,6 @@ +Name: japan +Type: ellipse +Point: 38.0, 138.0 +Semi-major-axis: 1580000 # Meters +Semi-minor-axis: 1000000 # Meters +Orientation-angle: 45 diff --git a/sources/MPAS-Limited-Area/docs/points-examples/pnw.custom.pts b/sources/MPAS-Limited-Area/docs/points-examples/pnw.custom.pts new file mode 100644 index 0000000..f879340 --- /dev/null +++ b/sources/MPAS-Limited-Area/docs/points-examples/pnw.custom.pts @@ -0,0 +1,7 @@ +Name: pnw +Type: Custom +Point: 45.0, -120.0 +50.000, -129.000 +50.000, -115.000 +41.500, -115.0000 +41.500, -129.000 diff --git a/sources/MPAS-Limited-Area/docs/points-examples/tropics.channel.pts b/sources/MPAS-Limited-Area/docs/points-examples/tropics.channel.pts new file mode 100644 index 0000000..9d3a665 --- /dev/null +++ b/sources/MPAS-Limited-Area/docs/points-examples/tropics.channel.pts @@ -0,0 +1,4 @@ +Name: tropics +Type: channel +ulat: 23.43676 +llat: -23.43676 diff --git a/sources/MPAS-Limited-Area/limited_area/__init__.py b/sources/MPAS-Limited-Area/limited_area/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sources/MPAS-Limited-Area/limited_area/limited_area.py b/sources/MPAS-Limited-Area/limited_area/limited_area.py new file mode 100644 index 0000000..6fc51e1 --- /dev/null +++ b/sources/MPAS-Limited-Area/limited_area/limited_area.py @@ -0,0 +1,583 @@ +from __future__ import absolute_import, division, print_function +import argparse +import os +import sys + +import numpy as np + +from limited_area.mesh import MeshHandler +from limited_area.mesh import latlon_to_xyz +from limited_area.mesh import sphere_distance +from limited_area.region_spec import RegionSpec + +class LimitedArea(): + """ Facilitate creating a regional MPAS mesh from a global MPAS mesh """ + num_boundary_layers = 8 + INSIDE = 1 + UNMARKED = 0 + + def __init__(self, + mesh_file, + region, + plotting, + regionFormat='points', + format='NETCDF3_64BIT_OFFSET', + *args, + **kwargs): + """ Init function for Limited Area + + Check to see if mesh file exists and it is the correct type. Check to + see that the region file exist and finally set the regionSpec to the + requested regionFormat + + + Keyword arguments: + mesh_files -- Path to a valid MPAS Mesh file + region -- Path to pts file region specification + + DEBUG -- Debug value used to turn on debug output, default == 0 + markNeighbors -- Algorithm choice for choosing relaxation layers - Default + is mark neighbor search + """ + + # Keyword arguments + self._DEBUG_ = kwargs.get('DEBUG', 0) + self.boundary = kwargs.get('markNeighbors', 'search') + self.plotting = plotting + self.cdf_format = format + + # Check to see that all of the meshes exists and that they are + # valid netCDF files. + if not self.plotting: + if os.path.isfile(mesh_file): + self.mesh = MeshHandler(mesh_file, 'r', *args, **kwargs) + else: + print("ERROR: Mesh file was not found", mesh_file) + sys.exit(-1) + + # Check to see the points file exists and if it exists, then parse it + # and see that is is specified correctly! + self.region_file = region + self.regionSpec = RegionSpec(*args, **kwargs) + + # Choose the algorithm to mark relaxation region + if self.boundary == None: + # Possibly faster for larger regions + self.mark_neighbors = self._mark_neighbors + elif self.boundary == 'search': + # Possibly faster for smaller regions + self.mark_neighbors = self._mark_neighbors_search + + + def gen_region(self, *args, **kwargs): + """ Generate the boundary region of the given region for the given mesh(es). """ + + # Call the regionSpec to generate `name, in_point, boundaries` + name, inPoint, boundaries= self.regionSpec.gen_spec(self.region_file, self.plotting, **kwargs) + + if self.plotting: + self.plot_region(inPoint, boundaries, name) + return + + if self._DEBUG_ > 0: + print("DEBUG: Region Spec has been generated") + print("DEBUG: Region Name: ", name) + print("DEBUG: In Point: ", inPoint) + print("DEBUG: # of boundaries: ", len(boundaries)) + + # For each mesh, create a regional mesh and save it + print('\n') + print('Creating a regional mesh of ', self.mesh.fname) + + # Mark boundaries + # A specification may have multiple, discontiguous boundaries, + # so, create a unmarked, filled bdyMaskCell and pass it to + # mark_boundary for each boundary. + print('Marking ', end=''); sys.stdout.flush() + bdyMaskCell = np.full(self.mesh.nCells, self.UNMARKED) + i = 1 + for boundary in boundaries: + print("boundary ", i, "... ", end=''); sys.stdout.flush(); i += 1 + bdyMaskCell = self.mark_boundary(self.mesh, boundary, bdyMaskCell) + + # Find the nearest cell to the inside point + inCell = self.mesh.nearest_cell(inPoint[0], inPoint[1]) + + # Flood fill from the inside point + print('\nFilling region ...') + bdyMaskCell = self.flood_fill(self.mesh, inCell, bdyMaskCell) + + # Mark the neighbors + print('Creating boundary layer:', end=' '); sys.stdout.flush() + for layer in range(1, self.num_boundary_layers + 1): + print(layer, ' ...', end=' '); sys.stdout.flush() + self.mark_neighbors(self.mesh, layer, bdyMaskCell, inCell=inCell) + print('DONE!') + + if self._DEBUG_ > 2: + print("DEBUG: bdyMaskCells count:") + print("DEBUG: 0: ", len(bdyMaskCell[bdyMaskCell == 0])) + print("DEBUG: 1: ", len(bdyMaskCell[bdyMaskCell == 1])) + print("DEBUG: 2: ", len(bdyMaskCell[bdyMaskCell == 2])) + print("DEBUG: 3: ", len(bdyMaskCell[bdyMaskCell == 3])) + print("DEBUG: 4: ", len(bdyMaskCell[bdyMaskCell == 4])) + print("DEBUG: 5: ", len(bdyMaskCell[bdyMaskCell == 5])) + print("DEBUG: 6: ", len(bdyMaskCell[bdyMaskCell == 6])) + print("DEBUG: 7: ", len(bdyMaskCell[bdyMaskCell == 7])) + print("DEBUG: 8: ", len(bdyMaskCell[bdyMaskCell == 8])) + print('\n') + + bdyMaskCell_cp = bdyMaskCell + + # Mark the edges + print('Marking region edges ...') + bdyMaskEdge = self.mark_edges(self.mesh, + bdyMaskCell, + *args, + **kwargs) + + # Mark the vertices + print('Marking region vertices...') + bdyMaskVertex = self.mark_vertices(self.mesh, + bdyMaskCell, + *args, + **kwargs) + + + # Subset the grid into a new region: + print('Subsetting mesh fields into the specified region mesh...') + regionFname = self.create_regional_fname(name, self.mesh) + regionalMesh = self.mesh.subset_fields(regionFname, + bdyMaskCell, + bdyMaskEdge, + bdyMaskVertex, + inside=self.INSIDE, + unmarked=self.UNMARKED, + format=self.cdf_format, + *args, + **kwargs) + + print('Copying global attributes...') + self.mesh.copy_global_attributes(regionalMesh) + + print("Created a regional mesh: ", regionFname) + + print('Creating graph partition file...', end=' '); sys.stdout.flush() + graphFname = regionalMesh.create_graph_file(self.create_partiton_fname(name, self.mesh,)) + print(graphFname) + + self.mesh.mesh.close() + regionalMesh.mesh.close() + + return regionFname, graphFname + + def create_partiton_fname(self, name, mesh, **kwargs): + """ Generate the filename for the regional graph.info file""" + return name+'.graph.info' + + + def create_regional_fname(self, name, mesh, **kwargs): + """ Generate the filename for the regional mesh file. Depending on what "type" of MPAS file + we are using, either static, grid or init, try to rename the region file as that type (i.e. + x1.2562.static.nc becomes name.static.nc). + + If a file name is ambiguous, or the file name does not contain: static, init, or grid, + rename the region file to be region. """ + # Static files + if 'static' in mesh.fname and not ('grid' in mesh.fname or 'init' in mesh.fname): + meshType = 'static' + # Grid files + elif 'grid' in mesh.fname and not ('static' in mesh.fname or 'init' in mesh.fname): + meshType = 'grid' + # Initialization Data + elif 'init' in mesh.fname and not ('static' in mesh.fname or 'grid' in mesh.fname): + meshType = 'init' + else: + meshType = 'region' + + return name+'.'+meshType+'.nc' + + + # Mark_neighbors_search - Faster for smaller regions ?? + def _mark_neighbors_search(self, mesh, layer, bdyMaskCell, *args, **kwargs): + """ Mark the relaxation layers using a search and return an updated bdyMaskCell with + those relaxation layers + + mesh -- The global MPAS mesh + layer -- The relaxation layer + bdyMaskCell -- The global mask marking the regional cell subset + inCell -- A point that is inside the regional area + + """ + inCell = kwargs.get('inCell', None) + if inCell == None: + print("ERROR: In cell not found within _mark_neighbors_search") + + stack = [inCell] + while len(stack) > 0: + iCell = stack.pop() + for i in range(mesh.nEdgesOnCell[iCell]): + j = mesh.cellsOnCell[iCell, i] - 1 + if layer > bdyMaskCell[j] >= self.INSIDE: + bdyMaskCell[j] = -bdyMaskCell[j] + stack.append(j) + elif bdyMaskCell[j] == 0: + bdyMaskCell[j] = layer + + bdyMaskCell[:] = abs(bdyMaskCell[:]) + + + # mark_neighbors - Faster for larger regions ?? + def _mark_neighbors(self, mesh, nType, bdyMaskCell, *args, **kwargs): + """ Mark a relaxation layers of nType + + mesh -- The global MPAS mesh + nType -- The current relaxation cell that will be marked on bdyMaskCell + bdyMaskCell -- The global mask marking the regional cell subset + """ + + for iCell in range(mesh.nCells): + if bdyMaskCell[iCell] == self.UNMARKED: + for i in range(mesh.nEdgesOnCell[iCell]): + v = mesh.cellsOnCell[iCell, i] - 1 + if bdyMaskCell[v] == 0: + bdyMaskCell[v] == nType + + + def flood_fill(self, mesh, inCell, bdyMaskCell): + """ Mark the interior points of the regional mesh and return and updated + bdyMaskCell. + + mesh -- Global MPAS Mesh + inCell -- A point that is inside the specified region + bdyMaskCell -- The global mask marking which global cells are interior, relaxation + and those that are outside. + """ + if self._DEBUG_ > 1: + print("DEBUG: Flood filling with flood_fill") + + stack = [inCell] + while len(stack) > 0: + iCell = stack.pop() + for i in range(mesh.nEdgesOnCell[iCell]): + j = mesh.cellsOnCell[iCell, i] - 1 + if bdyMaskCell[j] == self.UNMARKED: + bdyMaskCell[j] = self.INSIDE + stack.append(j) + + return bdyMaskCell + + + def mark_edges(self, mesh, bdyMaskCell, *args, **kwargs): + """ Mark the edges that are in the specified region and return + bdyMaskEdge. """ + + bdyMaskEdge = bdyMaskCell[mesh.cellsOnEdge[:,:]-1].min(axis=1) + bdyMaskEdge = np.where(bdyMaskEdge > 0, + bdyMaskEdge, + bdyMaskCell[mesh.cellsOnEdge[:,:]-1].max(axis=1)) + + if self._DEBUG_ > 2: + print("DEBUG: bdyMaskEdges count:") + print("DEBUG: 0: ", len(bdyMaskEdge[bdyMaskEdge == 0])) + print("DEBUG: 1: ", len(bdyMaskEdge[bdyMaskEdge == 1])) + print("DEBUG: 2: ", len(bdyMaskEdge[bdyMaskEdge == 2])) + print("DEBUG: 3: ", len(bdyMaskEdge[bdyMaskEdge == 3])) + print("DEBUG: 4: ", len(bdyMaskEdge[bdyMaskEdge == 4])) + print("DEBUG: 5: ", len(bdyMaskEdge[bdyMaskEdge == 5])) + print("DEBUG: 6: ", len(bdyMaskEdge[bdyMaskEdge == 6])) + print("DEBUG: 7: ", len(bdyMaskEdge[bdyMaskEdge == 7])) + print("DEBUG: 8: ", len(bdyMaskEdge[bdyMaskEdge == 8])) + print('\n') + + return bdyMaskEdge + + + def mark_vertices(self, mesh, bdyMaskCell, *args, **kwargs): + """ Mark the vertices that are in the spefied region and return + bdyMaskVertex.""" + + bdyMaskVertex = bdyMaskCell[mesh.cellsOnVertex[:,:]-1].min(axis=1) + bdyMaskVertex = np.where(bdyMaskVertex > 0, + bdyMaskVertex, + bdyMaskCell[mesh.cellsOnVertex[:,:]-1].max(axis=1)) + + if self._DEBUG_ > 2: + print("DEBUG: bdyMaskVertex count:") + print("DEBUG: 0: ", len(bdyMaskVertex[bdyMaskVertex == 0])) + print("DEBUG: 1: ", len(bdyMaskVertex[bdyMaskVertex == 1])) + print("DEBUG: 2: ", len(bdyMaskVertex[bdyMaskVertex == 2])) + print("DEBUG: 3: ", len(bdyMaskVertex[bdyMaskVertex == 3])) + print("DEBUG: 4: ", len(bdyMaskVertex[bdyMaskVertex == 4])) + print("DEBUG: 5: ", len(bdyMaskVertex[bdyMaskVertex == 5])) + print("DEBUG: 6: ", len(bdyMaskVertex[bdyMaskVertex == 6])) + print("DEBUG: 7: ", len(bdyMaskVertex[bdyMaskVertex == 7])) + print("DEBUG: 8: ", len(bdyMaskVertex[bdyMaskVertex == 8])) + print('\n') + + return bdyMaskVertex + + + # Mark Boundary points + def mark_boundary(self, mesh, points, bdyMaskCell, *args, **kwargs): + """ Mark the nearest cell to each of the cords in points + as a boundary cell and return bdyMaskCell. + + mesh - The global mesh + inPoint - A point that lies within the regional area + points - A list of points that define the boundary of the desired + region as flatten list of lat, lon coordinates. i.e: + + [lat0, lon0, lat1, lon1, lat2, lon2, ..., latN, lonN] + """ + if self._DEBUG_ > 0: + print("DEBUG: Marking the boundary points: ") + + boundaryCells = [] + + # Find the nearest cells to the list of given boundary points + for i in range(0, len(points), 2): + boundaryCells.append(mesh.nearest_cell(points[i], + points[i + 1])) + + + + if self._DEBUG_ > 0: + print("DEBUG: Num Boundary Cells: ", len(boundaryCells)) + + # Mark the boundary cells that were given as input + for bCells in boundaryCells: + bdyMaskCell[bCells] = self.INSIDE + + # For each boundaryCells, mark the current cell as the source cell + # and the next (or the first element if the current is the last) as + # the target cell. + # + # Then, determine the great-arc angle between the source and taget + # cell, and then for each cell, starting at the source cell, + # calculate the great-arc angle between the cells on the current + # cell and the target cell, and then add the cell with the smallest + # angle. + for i in range(len(boundaryCells)): + sourceCell = boundaryCells[i] + targetCell = boundaryCells[(i + 1) % len(boundaryCells)] + + # If we are already at the next target cell, there is no need + # to connect sourceCell with targetCell, and we can skip to + # the next pair of boundary points + if sourceCell == targetCell: + continue + + pta = latlon_to_xyz(mesh.latCells[sourceCell], + mesh.lonCells[sourceCell], + 1.0) + ptb = latlon_to_xyz(mesh.latCells[targetCell], + mesh.lonCells[targetCell], + 1.0) + + pta = np.cross(pta, ptb) + temp = np.linalg.norm(pta) + pta = pta / temp + iCell = sourceCell + while iCell != targetCell: + bdyMaskCell[iCell] = self.INSIDE + minangle = np.inf + mindist = sphere_distance(mesh.latCells[iCell], + mesh.lonCells[iCell], + mesh.latCells[targetCell], + mesh.lonCells[targetCell], + 1.0) + for j in range(mesh.nEdgesOnCell[iCell]): + v = mesh.cellsOnCell[iCell, j] - 1 + dist = sphere_distance(mesh.latCells[v], + mesh.lonCells[v], + mesh.latCells[targetCell], + mesh.lonCells[targetCell], + 1.0) + if dist > mindist: + continue + pt = latlon_to_xyz(mesh.latCells[v], mesh.lonCells[v], 1.0) + angle = np.dot(pta, pt) + angle = abs(0.5 * np.pi - np.arccos(angle)) + if angle < minangle: + minangle = angle + k = v + iCell = k + + return bdyMaskCell + + + # Plot the specified region + def plot_region(self, inPoint, boundaries, region_name): + """ Create an plot showing the user-specified region. + The region boundary is plotted as a blue line on an orthographic + projection with a simple color-filled map background. + + inPoint - A point that lies within the regional area. + boundaries - A list of lists of latitude and longitude coordinates + of a boundary. + + [[lat0, lon0, lat1, lon1, lat2, lon2, ..., latN, lonN], [...]] + + Note: Coordinates are in radians. + """ + + try: + import cartopy.crs as ccrs + import cartopy.feature as cfeature + except: + print('Could not import cartopy!') + return + + try: + import matplotlib.pyplot as plt + import matplotlib.ticker as mticker + import matplotlib.patches as mpatches + except: + print('Could not import matplotlib!') + return + + import math + + rad2deg = 180.0 / math.pi + + if len(boundaries) == 2: + proj = ccrs.PlateCarree(rad2deg * inPoint[1]) + ax = plt.axes(projection=proj) + + latbdy = np.concatenate((np.flip(boundaries[0][0::2]), boundaries[1][0::2])) * rad2deg + lonbdy = np.concatenate((np.flip(boundaries[0][1::2]), boundaries[1][1::2])) * rad2deg + + ax.set_extent((-180.0, 180.0, -90.0, 90.0), crs=ccrs.PlateCarree()) + + else: + proj = ccrs.Stereographic(rad2deg * inPoint[0], rad2deg * inPoint[1]) + ax = plt.axes(projection=proj) + + lonbdy, latbdy = self.ccw_order(inPoint[1] * rad2deg, inPoint[0] * rad2deg, + boundaries[0][1::2] * rad2deg,boundaries[0][0::2] * rad2deg, + proj) + + # Logic to determine the "extent" (roughly, the diameter in meters) + # of the region given the latbdy and lonbdy arrays + # Convert all points from lat,lon coordinates to x,y + # distances (in meters) from the inPoint + xy=proj.transform_points(ccrs.PlateCarree(), lonbdy, latbdy) + + # Find the extents of the box bounding these points and the + # diameter (length of diagonal) + min_x = min(xy[:,0]) + max_x = max(xy[:,0]) + min_y = min(xy[:,1]) + max_y = max(xy[:,1]) + diameter = math.sqrt((max_y-min_y)**2+(max_x-min_x)**2) + + extent = diameter + scaling = 0.5 * 1.25 + ax.set_extent([-scaling * extent, scaling * extent, -scaling * extent, scaling * extent], crs=proj) + + # Place latbdy and lonbdy in clockwise order to cause the filled polygon + # to be everything except the region + latbdy = latbdy[::-1] + lonbdy = lonbdy[::-1] + + ax.add_feature(cfeature.OCEAN) + ax.add_feature(cfeature.LAND) + ax.add_feature(cfeature.COASTLINE, linewidth=0.1) + ax.add_feature(cfeature.BORDERS, linewidth=0.1) + ax.add_feature(cfeature.LAKES, linewidth=0.1) + ax.add_feature(cfeature.RIVERS, linewidth=0.1) + ax.add_feature(cfeature.STATES, linewidth=0.1) + + gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, + linewidth=0.1, color='black', alpha=1.0, linestyle='--') + + xticks = np.arange(-180, 180, 10) + yticks = np.arange(-90, 90, 10) + + gl.ylocator = mticker.FixedLocator(yticks) + gl.xlocator = mticker.FixedLocator(xticks) + + # Hack for plotting polygons when all latitudes are the same. + if np.min(latbdy) == np.max(latbdy): + if np.min(latbdy) == 0.0: + latbdy[0] = latbdy[0] + 0.000001 + else: + latbdy[0] = latbdy[0] * 0.999999 + + nbdy = len(lonbdy) + poly_corners = np.zeros((nbdy+1, 2), np.float64) + poly_corners[0:nbdy,0] = np.asarray(lonbdy) + poly_corners[0:nbdy,1] = np.asarray(latbdy) + poly_corners[nbdy,:] = poly_corners[0,:] + + poly = mpatches.Polygon(poly_corners, closed=True, ec='black', fill=True, lw=0.1, fc='black', alpha=0.3, transform=ccrs.Geodetic()) + ax.add_patch(poly) + + for boundary in boundaries: + latbdy = boundary[0::2] * rad2deg + lonbdy = boundary[1::2] * rad2deg + + nbdy = len(lonbdy) + + lon_corners = np.zeros((nbdy+1), np.float64) + lon_corners[0:nbdy] = np.asarray(lonbdy) + lon_corners[nbdy] = lon_corners[0] + + lat_corners = np.zeros((nbdy+1), np.float64) + lat_corners[0:nbdy] = np.asarray(latbdy) + lat_corners[nbdy] = lat_corners[0] + + plt.plot(lon_corners, lat_corners, + color='blue', linewidth=0.5, + transform=ccrs.Geodetic() + ) + + print('Saving plot to region.png') + plt.savefig('region.png', dpi=150, bbox_inches='tight') + + + def plane_angle(self, ax, ay, bx, by, cx, cy): + """ Computes the angle between the vectors AB and AC. + """ + + import math + + b = [bx - ax, by - ay] + c = [cx - ax, cy - ay] + + arg = np.dot(b, c) / np.linalg.norm(b) / np.linalg.norm(c) + arg = max(-1.0,min(1.0, arg)) + theta = math.acos(arg) + if np.cross([bx - ax, by - ay], [cx - ax, cy - ay]) < 0.0: + theta = -theta + + return theta + + + def ccw_order(self, cenLon, cenLat, lons, lats, proj): + """ Place arrays of longitude and latitude in counter-clockwise (CCW) + order. The cenLon and cenLat values define a point that is within the + polygon described by the lons and lats arrays. + + Latitude and longitude coordinates are in degrees. + """ + + import cartopy.crs as ccrs + + cenLonProj, cenLatProj = proj.transform_point(cenLon, cenLat, ccrs.PlateCarree()) + coordsProj = proj.transform_points(ccrs.PlateCarree(), lons, lats) + + stride = max(1, int(lons.size / 360)) + + lonsProj = coordsProj[::stride,0] + latsProj = coordsProj[::stride,1] + + sumangle = 0.0 + for i in range(lonsProj.size): + sumangle = sumangle + self.plane_angle(cenLonProj, cenLatProj, lonsProj[i-1], latsProj[i-1], lonsProj[i], latsProj[i]) + + if sumangle > 0.0: + return lons, lats + else: + return lons[::-1], lats[::-1] diff --git a/sources/MPAS-Limited-Area/limited_area/limited_area_n_layers_as_input.py b/sources/MPAS-Limited-Area/limited_area/limited_area_n_layers_as_input.py new file mode 100644 index 0000000..a246ba4 --- /dev/null +++ b/sources/MPAS-Limited-Area/limited_area/limited_area_n_layers_as_input.py @@ -0,0 +1,402 @@ +from __future__ import absolute_import, division, print_function +import argparse +import os +import sys + +import numpy as np + +from limited_area.mesh import MeshHandler +from limited_area.mesh import latlon_to_xyz +from limited_area.mesh import sphere_distance +from limited_area.region_spec import RegionSpec + +class LimitedArea_n_layers_as_input(): + """ Facilitate creating a regional MPAS mesh from a global MPAS mesh """ + #num_boundary_layers = 8 + INSIDE = 1 + UNMARKED = 0 + + def __init__(self, + mesh_file, + region, + regionFormat='points', + format='NETCDF3_64BIT_OFFSET', + n_layers=1, + *args, + **kwargs): + """ Init function for Limited Area + + Check to see if mesh file exists and it is the correct type. Check to + see that the region file exist and finally set the regionSpec to the + requested regionFormat + + + Keyword arguments: + mesh_files -- Path to a valid MPAS Mesh file + region -- Path to pts file region specification + + DEBUG -- Debug value used to turn on debug output, default == 0 + markNeighbors -- Algorithm choice for choosing relaxation layers - Default + is mark neighbor search + """ + + # Keyword arguments + self._DEBUG_ = kwargs.get('DEBUG', 0) + self.boundary = kwargs.get('markNeighbors', 'search') + self.cdf_format = format + self.num_boundary_layers = n_layers + + # Check to see that all of the meshes exists and that they are + # valid netCDF files. + if os.path.isfile(mesh_file): + self.mesh = MeshHandler(mesh_file, 'r', *args, **kwargs) + else: + print("ERROR: Mesh file was not found", mesh_file) + sys.exit(-1) + + # Check to see the points file exists and if it exists, then parse it + # and see that is is specified correctly! + self.region_file = region + self.regionSpec = RegionSpec(*args, **kwargs) + + # Choose the algorithm to mark relaxation region + if self.boundary == None: + # Possibly faster for larger regions + self.mark_neighbors = self._mark_neighbors + elif self.boundary == 'search': + # Possibly faster for smaller regions + self.mark_neighbors = self._mark_neighbors_search + + def gen_region(self, *args, **kwargs): + """ Generate the boundary region of the given region for the given mesh(es). """ + + # Call the regionSpec to generate `name, in_point, boundaries` + name, inPoint, boundaries= self.regionSpec.gen_spec(self.region_file, **kwargs) + + if self._DEBUG_ > 0: + print("DEBUG: Region Spec has been generated") + print("DEBUG: Region Name: ", name) + print("DEBUG: In Point: ", inPoint) + print("DEBUG: # of boundaries: ", len(boundaries)) + + # For each mesh, create a regional mesh and save it + print('\n') + print('Creating a regional mesh of ', self.mesh.fname) + + # Mark boundaries + # A specification may have multiple, discontiguous boundaries, + # so, create a unmarked, filled bdyMaskCell and pass it to + # mark_boundary for each boundary. + print('Marking ', end=''); sys.stdout.flush() + bdyMaskCell = np.full(self.mesh.nCells, self.UNMARKED) + i = 1 + for boundary in boundaries: + print("boundary ", i, "... ", end=''); sys.stdout.flush(); i += 1 + bdyMaskCell = self.mark_boundary(self.mesh, boundary, bdyMaskCell) + + # Find the nearest cell to the inside point + inCell = self.mesh.nearest_cell(inPoint[0], inPoint[1]) + + # Flood fill from the inside point + print('\nFilling region ...') + bdyMaskCell = self.flood_fill(self.mesh, inCell, bdyMaskCell) + + # Mark the neighbors + print('Creating boundary layer:', end=' '); sys.stdout.flush() + for layer in range(1, self.num_boundary_layers + 1): + print(layer, ' ...', end=' '); sys.stdout.flush() + self.mark_neighbors(self.mesh, layer, bdyMaskCell, inCell=inCell) + print('DONE!') + + if self._DEBUG_ > 2: + print("DEBUG: bdyMaskCells count:") + print("DEBUG: 0: ", len(bdyMaskCell[bdyMaskCell == 0])) + print("DEBUG: 1: ", len(bdyMaskCell[bdyMaskCell == 1])) + print("DEBUG: 2: ", len(bdyMaskCell[bdyMaskCell == 2])) + print("DEBUG: 3: ", len(bdyMaskCell[bdyMaskCell == 3])) + print("DEBUG: 4: ", len(bdyMaskCell[bdyMaskCell == 4])) + print("DEBUG: 5: ", len(bdyMaskCell[bdyMaskCell == 5])) + print("DEBUG: 6: ", len(bdyMaskCell[bdyMaskCell == 6])) + print("DEBUG: 7: ", len(bdyMaskCell[bdyMaskCell == 7])) + print("DEBUG: 8: ", len(bdyMaskCell[bdyMaskCell == 8])) + print('\n') + + bdyMaskCell_cp = bdyMaskCell + + # Mark the edges + print('Marking region edges ...') + bdyMaskEdge = self.mark_edges(self.mesh, + bdyMaskCell, + *args, + **kwargs) + + # Mark the vertices + print('Marking region vertices...') + bdyMaskVertex = self.mark_vertices(self.mesh, + bdyMaskCell, + *args, + **kwargs) + + + # Subset the grid into a new region: + print('Subsetting mesh fields into the specified region mesh...') + regionFname = self.create_regional_fname(name, self.mesh) + regionalMesh = self.mesh.subset_fields(regionFname, + bdyMaskCell, + bdyMaskEdge, + bdyMaskVertex, + inside=self.INSIDE, + unmarked=self.UNMARKED, + format=self.cdf_format, + *args, + **kwargs) + + print('Copying global attributes...') + self.mesh.copy_global_attributes(regionalMesh) + + print("Created a regional mesh: ", regionFname) + + print('Creating graph partition file...', end=' '); sys.stdout.flush() + graphFname = regionalMesh.create_graph_file(self.create_partiton_fname(name, self.mesh,)) + print(graphFname) + + self.mesh.mesh.close() + regionalMesh.mesh.close() + + return regionFname, graphFname + + def create_partiton_fname(self, name, mesh, **kwargs): + """ Generate the filename for the regional graph.info file""" + return name+'.graph.info' + + + def create_regional_fname(self, name, mesh, **kwargs): + """ Generate the filename for the regional mesh file. Depending on what "type" of MPAS file + we are using, either static, grid or init, try to rename the region file as that type (i.e. + x1.2562.static.nc becomes name.static.nc). + + If a file name is ambiguous, or the file name does not contain: static, init, or grid, + rename the region file to be region. """ + # Static files + if 'static' in mesh.fname and not ('grid' in mesh.fname or 'init' in mesh.fname): + meshType = 'static' + # Grid files + elif 'grid' in mesh.fname and not ('static' in mesh.fname or 'init' in mesh.fname): + meshType = 'grid' + # Initialization Data + elif 'init' in mesh.fname and not ('static' in mesh.fname or 'grid' in mesh.fname): + meshType = 'init' + else: + meshType = 'region' + + return name+'.'+meshType+'.nc' + + + # Mark_neighbors_search - Faster for smaller regions ?? + def _mark_neighbors_search(self, mesh, layer, bdyMaskCell, *args, **kwargs): + """ Mark the relaxation layers using a search and return an updated bdyMaskCell with + those relaxation layers + + mesh -- The global MPAS mesh + layer -- The relaxation layer + bdyMaskCell -- The global mask marking the regional cell subset + inCell -- A point that is inside the regional area + + """ + inCell = kwargs.get('inCell', None) + if inCell == None: + print("ERROR: In cell not found within _mark_neighbors_search") + + stack = [inCell] + while len(stack) > 0: + iCell = stack.pop() + for i in range(mesh.nEdgesOnCell[iCell]): + j = mesh.cellsOnCell[iCell, i] - 1 + if layer > bdyMaskCell[j] >= self.INSIDE: + bdyMaskCell[j] = -bdyMaskCell[j] + stack.append(j) + elif bdyMaskCell[j] == 0: + bdyMaskCell[j] = layer + + bdyMaskCell[:] = abs(bdyMaskCell[:]) + + + # mark_neighbors - Faster for larger regions ?? + def _mark_neighbors(self, mesh, nType, bdyMaskCell, *args, **kwargs): + """ Mark a relaxation layers of nType + + mesh -- The global MPAS mesh + nType -- The current relaxation cell that will be marked on bdyMaskCell + bdyMaskCell -- The global mask marking the regional cell subset + """ + + for iCell in range(mesh.nCells): + if bdyMaskCell[iCell] == self.UNMARKED: + for i in range(mesh.nEdgesOnCell[iCell]): + v = mesh.cellsOnCell[iCell, i] - 1 + if bdyMaskCell[v] == 0: + bdyMaskCell[v] == nType + + + def flood_fill(self, mesh, inCell, bdyMaskCell): + """ Mark the interior points of the regional mesh and return and updated + bdyMaskCell. + + mesh -- Global MPAS Mesh + inCell -- A point that is inside the specified region + bdyMaskCell -- The global mask marking which global cells are interior, relaxation + and those that are outside. + """ + if self._DEBUG_ > 1: + print("DEBUG: Flood filling with flood_fill") + + stack = [inCell] + while len(stack) > 0: + iCell = stack.pop() + for i in range(mesh.nEdgesOnCell[iCell]): + j = mesh.cellsOnCell[iCell, i] - 1 + if bdyMaskCell[j] == self.UNMARKED: + bdyMaskCell[j] = self.INSIDE + stack.append(j) + + return bdyMaskCell + + + def mark_edges(self, mesh, bdyMaskCell, *args, **kwargs): + """ Mark the edges that are in the specified region and return + bdyMaskEdge. """ + + bdyMaskEdge = bdyMaskCell[mesh.cellsOnEdge[:,:]-1].min(axis=1) + bdyMaskEdge = np.where(bdyMaskEdge > 0, + bdyMaskEdge, + bdyMaskCell[mesh.cellsOnEdge[:,:]-1].max(axis=1)) + + if self._DEBUG_ > 2: + print("DEBUG: bdyMaskEdges count:") + print("DEBUG: 0: ", len(bdyMaskEdge[bdyMaskEdge == 0])) + print("DEBUG: 1: ", len(bdyMaskEdge[bdyMaskEdge == 1])) + print("DEBUG: 2: ", len(bdyMaskEdge[bdyMaskEdge == 2])) + print("DEBUG: 3: ", len(bdyMaskEdge[bdyMaskEdge == 3])) + print("DEBUG: 4: ", len(bdyMaskEdge[bdyMaskEdge == 4])) + print("DEBUG: 5: ", len(bdyMaskEdge[bdyMaskEdge == 5])) + print("DEBUG: 6: ", len(bdyMaskEdge[bdyMaskEdge == 6])) + print("DEBUG: 7: ", len(bdyMaskEdge[bdyMaskEdge == 7])) + print("DEBUG: 8: ", len(bdyMaskEdge[bdyMaskEdge == 8])) + print('\n') + + return bdyMaskEdge + + + def mark_vertices(self, mesh, bdyMaskCell, *args, **kwargs): + """ Mark the vertices that are in the spefied region and return + bdyMaskVertex.""" + + bdyMaskVertex = bdyMaskCell[mesh.cellsOnVertex[:,:]-1].min(axis=1) + bdyMaskVertex = np.where(bdyMaskVertex > 0, + bdyMaskVertex, + bdyMaskCell[mesh.cellsOnVertex[:,:]-1].max(axis=1)) + + if self._DEBUG_ > 2: + print("DEBUG: bdyMaskVertex count:") + print("DEBUG: 0: ", len(bdyMaskVertex[bdyMaskVertex == 0])) + print("DEBUG: 1: ", len(bdyMaskVertex[bdyMaskVertex == 1])) + print("DEBUG: 2: ", len(bdyMaskVertex[bdyMaskVertex == 2])) + print("DEBUG: 3: ", len(bdyMaskVertex[bdyMaskVertex == 3])) + print("DEBUG: 4: ", len(bdyMaskVertex[bdyMaskVertex == 4])) + print("DEBUG: 5: ", len(bdyMaskVertex[bdyMaskVertex == 5])) + print("DEBUG: 6: ", len(bdyMaskVertex[bdyMaskVertex == 6])) + print("DEBUG: 7: ", len(bdyMaskVertex[bdyMaskVertex == 7])) + print("DEBUG: 8: ", len(bdyMaskVertex[bdyMaskVertex == 8])) + print('\n') + + return bdyMaskVertex + + + # Mark Boundary points + def mark_boundary(self, mesh, points, bdyMaskCell, *args, **kwargs): + """ Mark the nearest cell to each of the cords in points + as a boundary cell and return bdyMaskCell. + + mesh - The global mesh + inPoint - A point that lies within the regional area + points - A list of points that define the boundary of the desired + region as flatten list of lat, lon coordinates. i.e: + + [lat0, lon0, lat1, lon1, lat2, lon2, ..., latN, lonN] + """ + if self._DEBUG_ > 0: + print("DEBUG: Marking the boundary points: ") + + boundaryCells = [] + + # Find the nearest cells to the list of given boundary points + for i in range(0, len(points), 2): + boundaryCells.append(mesh.nearest_cell(points[i], + points[i + 1])) + + + + if self._DEBUG_ > 0: + print("DEBUG: Num Boundary Cells: ", len(boundaryCells)) + + # Mark the boundary cells that were given as input + for bCells in boundaryCells: + bdyMaskCell[bCells] = self.INSIDE + + # For each boundaryCells, mark the current cell as the source cell + # and the next (or the first element if the current is the last) as + # the target cell. + # + # Then, determine the great-arc angle between the source and taget + # cell, and then for each cell, starting at the source cell, + # calculate the great-arc angle between the cells on the current + # cell and the target cell, and then add the cell with the smallest + # angle. + for i in range(len(boundaryCells)): + sourceCell = boundaryCells[i] + targetCell = boundaryCells[(i + 1) % len(boundaryCells)] + + # If we are already at the next target cell, there is no need + # to connect sourceCell with targetCell, and we can skip to + # the next pair of boundary points + if sourceCell == targetCell: + continue + + pta = latlon_to_xyz(mesh.latCells[sourceCell], + mesh.lonCells[sourceCell], + 1.0) + ptb = latlon_to_xyz(mesh.latCells[targetCell], + mesh.lonCells[targetCell], + 1.0) + + pta = np.cross(pta, ptb) + temp = np.linalg.norm(pta) + pta = pta / temp + iCell = sourceCell + while iCell != targetCell: + bdyMaskCell[iCell] = self.INSIDE + minangle = np.Infinity + mindist = sphere_distance(mesh.latCells[iCell], + mesh.lonCells[iCell], + mesh.latCells[targetCell], + mesh.lonCells[targetCell], + 1.0) + for j in range(mesh.nEdgesOnCell[iCell]): + v = mesh.cellsOnCell[iCell, j] - 1 + dist = sphere_distance(mesh.latCells[v], + mesh.lonCells[v], + mesh.latCells[targetCell], + mesh.lonCells[targetCell], + 1.0) + if dist > mindist: + continue + pt = latlon_to_xyz(mesh.latCells[v], mesh.lonCells[v], 1.0) + angle = np.dot(pta, pt) + angle = abs(0.5 * np.pi - np.arccos(angle)) + if angle < minangle: + minangle = angle + k = v + iCell = k + + return bdyMaskCell + diff --git a/sources/MPAS-Limited-Area/limited_area/mesh.py b/sources/MPAS-Limited-Area/limited_area/mesh.py new file mode 100644 index 0000000..c26ff6c --- /dev/null +++ b/sources/MPAS-Limited-Area/limited_area/mesh.py @@ -0,0 +1,469 @@ +from __future__ import absolute_import, division, print_function +import sys +import os + +import numpy as np +from netCDF4 import Dataset + +""" mesh.py - Handle NetCDF file operations as well as helpful +calculations upon on MPAS grid. """ + +class MeshHandler: + """ Handle the operations related to NetCDF/MPAS grids. """ + + def __init__(self, fname, mode, format='NETCDF3_64BIT_OFFSET', *args, **kwargs): + """ Open fname with mode, for either reading, or creating + + fname - A valid netCDF4 file OR, if `mode==w` then a name of a + desired netCDF that will be created for writing. + mode - Mode for opening the file, options are 'r' and 'w' for read + and write respectively. + format - NetCDF file format for the regional mesh. This is only used + if `mode==w`. For more information on NetCDF versions see the + netCDF4 Python documentation found here: + + http://unidata.github.io/netcdf4-python/netCDF4/index.html#netCDF4.Dataset.__init__ + """ + self._DEBUG_ = kwargs.get('DEBUG', 0) + self.fname = fname + + if mode == 'r': + if self.check_file(fname): + self._load_vars() + return + else: + sys.exit(-1) + elif mode == 'w': + self.create_file(fname, mode, format) + + + def create_file(self, fname, mode, format): + """ Create and open a new NetCDF file with name fname and access mode mode + with the NetCDF file version being format. """ + try: + self.mesh = Dataset(fname, mode, format=format) + return + except: + print("ERROR: There was a problem creating the file ", fname) + sys.exit(-1) + + + def check_file(self, fname): + """ Check to see that fname exists and it is a valid NetCDF file """ + if os.path.isfile(fname): + try: + self.mesh = Dataset(fname, 'r') + return True + except OSError as E: + print("ERROR: ", E) + print("ERROR: This file was not a valid NetCDF file") + sys.exit(-1) + else: + print("ERROR: This file did not exist!") + return False + + def _load_vars(self): + """ Pre-load variables to avoid multiple, unnecessary IO calls + + Pulling variables from a netCDF4 interface like the following: + ```self.mesh.variables['lonCell']{[:]```, will read it from disk + each time, thus we can pre-load the variables into memory to reduce + I/O calls. + """ + if self._DEBUG_ > 2: + print("DEBUG: In Load Vars") + + # Dimensions + self.nCells = self.mesh.dimensions['nCells'].size + self.nEdges = self.mesh.dimensions['nEdges'].size + self.maxEdges = self.mesh.dimensions['maxEdges'].size + self.nVertices = self.mesh.dimensions['nVertices'].size + self.vertexDegree = self.mesh.dimensions['vertexDegree'].size + + # Variables + self.latCells = self.mesh.variables['latCell'][:] + self.lonCells = self.mesh.variables['lonCell'][:] + + self.nEdgesOnCell = self.mesh.variables['nEdgesOnCell'][:] + self.cellsOnCell = self.mesh.variables['cellsOnCell'][:] + self.cellsOnEdge = self.mesh.variables['cellsOnEdge'][:] + self.cellsOnVertex = self.mesh.variables['cellsOnVertex'][:] + + self.indexToCellIDs = self.mesh.variables['indexToCellID'][:] + self.indexToEdgeIDs = self.mesh.variables['indexToEdgeID'][:] + self.indexToVertexIDs = self.mesh.variables['indexToVertexID'][:] + + # Attributes + self.sphere_radius = self.mesh.sphere_radius + + self.variables = { 'latCells' : self.latCells, + 'lonCells' : self.lonCells, + 'nEdgesOnCell' : self.nEdgesOnCell, + 'cellsOnCell' : self.cellsOnCell, + 'cellsOnEdge' : self.cellsOnEdge, + 'cellsOnVertex' : self.cellsOnVertex, + 'indexToCellID' : self.indexToCellIDs, + 'indexToEdgeID' : self.indexToEdgeIDs, + 'indexToVertexID' : self.indexToVertexIDs + } + + + def nearest_cell(self, lat, lon): + """ Find the nearest cell of this mesh to lat and lon + + lat - Latitude - Radians + lon - Longitude - Radians + """ + nearest_cell = 0 # Start at the first cell + current_cell = -1 + + while (nearest_cell != current_cell): + current_cell = nearest_cell + current_distance = sphere_distance(self.latCells[current_cell], + self.lonCells[current_cell], + lat, + lon, + self.sphere_radius) + + nearest_cell = current_cell + nearest_distance = current_distance + + for edges in range(self.nEdgesOnCell[current_cell]): + iCell = self.cellsOnCell[current_cell, edges] - 1 + if (iCell <= self.nCells): + iDistance = sphere_distance(self.latCells[iCell], + self.lonCells[iCell], + lat, + lon, + self.sphere_radius) + + if (iDistance <= nearest_distance): + nearest_cell = iCell + nearest_distance = iDistance + + + if self._DEBUG_ > 3: + print("DEBUG: nearest_cell latLon: ", nearest_cell, '\t', + self.latCells[nearest_cell] * (180.0/np.pi), + self.lonCells[nearest_cell] * (180.0/np.pi), + ' Given lat lon: ', lat * (180.0/np.pi), lon * (180.0/np.pi)) + + + return nearest_cell + + def create_graph_file(self, graphFname): + """ Create a graph.info file for the current mesh """ + + # In the limited_area program, this function will always create + # a graph.info file for a regional mesh. Thus, the variables here + # are not preloaded and are being read from disk + nCells = self.mesh.dimensions['nCells'].size + nEdges = self.mesh.dimensions['nEdges'].size + + nEdgesOnCell = self.mesh.variables['nEdgesOnCell'][:] + cellsOnCell = self.mesh.variables['cellsOnCell'][:] + cellsOnEdge = self.mesh.variables['cellsOnEdge'][:] + + lines = [] + line = '' + + nEdgesInterior = 0 + + for i in range(nEdges): + if (cellsOnEdge[i,0] > 0 and cellsOnEdge[i,1] > 0): + nEdgesInterior = nEdgesInterior + 1 + + with open(graphFname, 'w') as f: + f.write(str(nCells)+' '+str(nEdgesInterior)+'\n') + for i in range(nCells): + for j in range(nEdgesOnCell[i]): + if (cellsOnCell[i,j] > 0): + f.write(str(cellsOnCell[i,j])+' ') + f.write('\n') + + return graphFname + + def subset_fields(self, + regionalFname, + bdyMaskCell, + bdyMaskEdge, + bdyMaskVertex, + inside, + unmarked, + format='NETCDF3_64BIT_OFFSET', + *args, + **kwargs): + """ Subset the current mesh and return a new regional mesh with + subsetted fields + + regionalFname -- Desired filename for the regional subset + bdyMaskCell -- Global mesh mask denoting regional cells + bdyMaskEdge -- Global mesh mask denoting regional edges + bdyMaskVertex -- Global mesh mask denoting regional vertices + inside -- The integer value that was used to mark the + cells, edges, vertices as being 'inside' the + regional within the bdyMasks + unmarked -- The integer value that was used to mark cells, + edges, vertices as being 'outside' of the regional + mesh. + """ + + # Don't pass on DEBUG to the regional mess - tone down output + kwargs.pop('DEBUG') + + indexingFields = {} + indexingFields['indexToCellID'] = bdyMaskCell + indexingFields['indexToEdgeID'] = bdyMaskEdge + indexingFields['indexToVertexID'] = bdyMaskVertex + indexingFields['cellsOnEdge'] = bdyMaskCell + indexingFields['edgesOnCell'] = bdyMaskEdge + indexingFields['edgesOnEdge'] = bdyMaskEdge + indexingFields['cellsOnCell'] = bdyMaskCell + indexingFields['verticesOnCell'] = bdyMaskVertex + indexingFields['verticesOnEdge'] = bdyMaskVertex + indexingFields['edgesOnVertex'] = bdyMaskEdge + indexingFields['cellsOnVertex'] = bdyMaskCell + + glbBdyCellIDs = self.indexToCellIDs[np.where(bdyMaskCell != unmarked)] - 1 + glbBdyEdgeIDs = self.indexToEdgeIDs[np.where(bdyMaskEdge != unmarked)] - 1 + glbBdyVertexIDs = self.indexToVertexIDs[np.where(bdyMaskVertex != unmarked)] - 1 + + + if self._DEBUG_ > 0: + print("DEBUG: nCells of new region: ", len(glbBdyCellIDs)) + print("DEBUG: nEdges of new region: ", len(glbBdyEdgeIDs)) + print("DEBUG: nVertex of new region: ", len(glbBdyVertexIDs)) + + # Check to see the user didn't mess specifying the region. If + # len(bdyIndexToCellIDs) == nCells, then the specification was probably not + # specified correctly + force = False + if len(glbBdyCellIDs) == self.nCells and not force: + print("ERROR: The number of Cells in the specified region ", + "(", len(glbBdyCellIDs), ")") + print("ERROR: appears to be equal number of cells in the global mesh", + "(", self.nCells, ")") + print("ERROR: which means there was perhaps a problem in specifying the") + print("ERROR: region. Please insure your region specification is correct") + sys.exit(-1) + + # Create a new grid + region = MeshHandler(regionalFname, 'w', format=format, *args, **kwargs) + + # Dimensions - Create dimensions + for dim in self.mesh.dimensions: + if dim == 'nCells': + region.mesh.createDimension(dim, + len(glbBdyCellIDs)) + elif dim == 'nEdges': + region.mesh.createDimension(dim, + len(glbBdyEdgeIDs)) + elif dim == 'nVertices': + region.mesh.createDimension(dim, + len(glbBdyVertexIDs)) + else: + if self.mesh.dimensions[dim].isunlimited(): + region.mesh.createDimension(dim, + None) + else: + region.mesh.createDimension(dim, + self.mesh.dimensions[dim].size) + + # Make boundary Mask's between 0 and the number of specified relaxation + # layers + region.mesh.createVariable('bdyMaskCell', 'i4', ('nCells',)) + region.mesh.createVariable('bdyMaskEdge', 'i4', ('nEdges',)) + region.mesh.createVariable('bdyMaskVertex', 'i4', ('nVertices')) + + region.mesh.variables['bdyMaskCell'][:] = bdyMaskCell[bdyMaskCell != 0] - 1 + region.mesh.variables['bdyMaskEdge'][:] = bdyMaskEdge[bdyMaskEdge != 0] - 1 + region.mesh.variables['bdyMaskVertex'][:] = bdyMaskVertex[bdyMaskVertex != 0] - 1 + + scan(bdyMaskCell) + scan(bdyMaskEdge) + scan(bdyMaskVertex) + + # Variables - Create Variables + for var in self.mesh.variables: + # If we're subsetting a static file, don't copy variables for bdyMaskCell, + # bdyMaskEdge or bdyMaskVertex if they exist in the static file as they have + # been created by this program + if var != 'bdyMaskCell' and var != 'bdyMaskEdge' and var != 'bdyMaskVertex': + region.mesh.createVariable(var, self.mesh.variables[var].dtype, + self.mesh.variables[var].dimensions) + try: + region.mesh.variables[var].units = self.mesh.variables[var].units + region.mesh.variables[var].long_name = self.mesh.variables[var].long_name + except: + pass + + # Subset global variables into the regional mesh and write them + # to the regional mesh - re-indexing if necessary + for var in self.mesh.variables: + # If subsetting a static file, don't copy any bdyMask variables, as we + # created them above + if var == 'bdyMaskCell' or var == 'bdyMaskEdge' or var == 'bdyMaskVertex': + continue + + print("Copying variable ", var, "...", end=' ', sep=''); sys.stdout.flush() + if var in self.variables: + arrTemp = self.variables[var] # Use the pre-loaded variable if possible + else: + arrTemp = self.mesh.variables[var][:] # Else, read it from disk + + if 'nCells' in self.mesh.variables[var].dimensions: + if var in indexingFields: + region.mesh.variables[var][:] = reindex_field(arrTemp[glbBdyCellIDs], + indexingFields[var]) + print('Done!') + else: + print('') + if 'Time' in region.mesh.variables[var].dimensions: + region.mesh.variables[var][:] = arrTemp[:, glbBdyCellIDs] + else: + region.mesh.variables[var][:] = arrTemp[glbBdyCellIDs] + elif 'nEdges' in self.mesh.variables[var].dimensions: + if var in indexingFields: + region.mesh.variables[var][:] = reindex_field(arrTemp[glbBdyEdgeIDs], + indexingFields[var]) + print('Done!') + else: + print('') + if 'Time' in region.mesh.variables[var].dimensions: + region.mesh.variables[var][:] = arrTemp[:, glbBdyEdgeIDs] + else: + region.mesh.variables[var][:] = arrTemp[glbBdyEdgeIDs] + elif 'nVertices' in self.mesh.variables[var].dimensions: + if var in indexingFields: + region.mesh.variables[var][:] = reindex_field(arrTemp[glbBdyVertexIDs], + indexingFields[var]) + print('Done!') + else: + print('') + if 'Time' in region.mesh.variables[var].dimensions: + region.mesh.variables[var][:] = arrTemp[:, glbBdyVertexIDs] + else: + region.mesh.variables[var][:] = arrTemp[glbBdyVertexIDs] + else: + print('') + region.mesh.variables[var][:] = arrTemp + + + return region + + def copy_global_attributes(self, region): + """ Copy the global attributes into the regional mesh, but not 'np' """ + region.mesh.on_a_sphere = self.mesh.on_a_sphere + region.mesh.sphere_radius = self.mesh.sphere_radius + + +def scan(arr): + """ For values within bdyMaskCell/Vertex/Edge etc. assign them + values of their edges, cells etc.""" + arr[arr > 0] = np.arange(1, len(arr[arr > 0])+1) + + +def reindex_field(field, mmap): + """ Re-index fields to be in range of their dimensions """ + print('reindexing field ...', end=' '); sys.stdout.flush() + return mmap[field[:]-1] + + + +def latlon_to_xyz(lat, lon, radius): + """ Calculate and return x, y, z coordinations of lat, lon on the sphere that has + radius, radius. + lat - Latitude + lon - Longitude + radius - Radius of sphere + """ + z = radius * np.sin(lat) + x = radius * np.cos(lon) * np.cos(lat) + y = radius * np.sin(lon) * np.cos(lat) + + return np.array([x, y, z]) + + +def xyz_to_latlon(point): + """ Convert a Cartesian coordinate point into a latitude, + longitude point in radians """ + x = point[0] + y = point[1] + z = point[2] + + eps = float(1.0e-10) + lat = np.arcsin(z) + + if np.fabs(x) > eps: + if np.fabs(y) > eps: + lon = np.arctan(np.fabs(y/x)) + + if x <= 0.0 and y >= 0.0: + lon = np.pi - lon + elif x <= 0.0 and y <= 0.0: + lon = lon + np.pi + elif x >= 0.0 and y <= 0.0: + lon = 2.0 * np.pi - lon + else: + if x > 0.0: + lon = 0.0 + else: + lon = np.pi + + elif np.fabs(y) > eps: + if y > 0.0: + lon = 0.5 * np.pi + else: + lon = 1.5 * np.pi + else: + lon = 0.0 + + return lat, lon + + +def sphere_distance(lat1, lon1, lat2, lon2, radius, **kwargs): + """ Calculate the sphere distance between point1 and point2. + + lat1 - Float - Radians - -pi:pi + lon1 - Float - Radians - 0:2*pi + lat2 - Float - Radians - -pi:pi + lon2 - Float - Radians - 0:2*pi + radius - Radius of the earth (or sphere) - Units can be ignored + + """ + return (2 * radius * np.arcsin( + np.sqrt( + np.sin(0.5 * (lat2 - lat1))**2 + + np.cos(lat1) + * np.cos(lat2) + * np.sin(0.5 * (lon2 - lon1))**2))) + + +def rotate_about_vector(X, U, theta): + """ Rotates the point X through an angle theta about the vector U + + X - [x, y, z] - The point to be rotated + U - [u, v, w] - The point to rotate X around + theta - The angle to rotate X around U + + Reference: https://sites.google.com/site/glennmurray/Home/rotation-matrices-and-formulas/rotation-about-an-arbitrary-axis-in-3-dimensions + """ + + x = X[0] + y = X[1] + z = X[2] + + u = U[0] + v = U[1] + w = U[2] + + vw2 = v*v + w*w + uw2 = u*u + w*w + uv2 = u*u + v*v + m = np.sqrt(u*u + v*v + w*w) + + xp = (u*(u*x+v*y+w*z) + (x*vw2+u*(-v*y-w*z))*np.cos(theta) + m*(-w*y+v*z)*np.sin(theta))/(m*m) + yp = (v*(u*x+v*y+w*z) + (y*uw2+v*(-u*x-w*z))*np.cos(theta) + m*( w*x-u*z)*np.sin(theta))/(m*m) + zp = (w*(u*x+v*y+w*z) + (z*uv2+w*(-u*x-v*y))*np.cos(theta) + m*(-v*x+u*y)*np.sin(theta))/(m*m) + + return np.array([xp, yp, zp]) diff --git a/sources/MPAS-Limited-Area/limited_area/points.py b/sources/MPAS-Limited-Area/limited_area/points.py new file mode 100644 index 0000000..81539c6 --- /dev/null +++ b/sources/MPAS-Limited-Area/limited_area/points.py @@ -0,0 +1,140 @@ +from __future__ import absolute_import, division, print_function +import os +import sys + +""" Parse the points file, and output a representation that can be passed back +that can be used to. + +File Examples: + +# Circle +``` +Name: Colorado +Type: Circle +center: 38.9386, -105.6875 +radius: 385.5 km +``` + +# Square +``` +Name: CONUS +Type: Square +left_lon: -126.0 +right_lon: -64.0 +up_lat: 50.0 +lower_lat: 25.0 +``` + +# Custom +``` +Name: pnw +Type: Custom +Point: 45.0, -118.0 +50.000, -129.000 +50.000, -115.000 +41.500, -115.0000 +41.500, -129.000 +``` + +# Ellipse +``` +Name: Japan +Type: ellipse +Point: 37.9, 138.4 +Semi-major-axis: 800000.0 +Semi-minor-axis: 400000.0 +Orientation-angle: 45.0 +``` + +# Example +``` +Name: +Type: +Point: Lat, Lon +Lat1, Lon1 +Lat2, Lon2 +Lat3, Lon3 +Lat4, Lon4 +... +LatN, LonN +""" + +def PointsParser(self, file, *args, **kwargs): + """ Parse file for our points syntax and set variables + accordingly (self.variable ...)""" + + self.points = [] + + # Kwargs + self._DEBUG_ = kwargs.get('DEBUG', 0) + + if not os.path.isfile(file): + print("ERROR: This points file could not be found") + sys.exit(-1) + else: + self.points_file = open(file, 'r') + + line_number = 0 + for line in self.points_file: + line_number += 1 + + if '#' in line: + line = line.split('#')[0] + line = line.strip() + + if ':' in line: + lhs = line.split(':')[0] + rhs = line.split(':')[1] + lhs = lhs.strip() + rhs = rhs.strip() + + if lhs == 'Name' or lhs == 'name': + # TODO: Do some error checking of the name + self.name = rhs + # Check to see if the type matches our avaiable types + elif lhs == 'Type' or lhs == 'type': + if rhs == 'Custom' or rhs == 'custom': + self.type = 'custom' + elif rhs == 'Channel' or rhs == 'channel': + self.type = 'channel' + elif rhs == 'Circle' or rhs == 'circle': + self.type = 'circle' + elif rhs == 'Ellipse' or rhs == 'ellipse': + self.type = 'ellipse' + else: + print("ERROR: This is not a valid points type: ", rhs) + sys.exit(-1) + elif lhs == 'Point' or lhs == 'point': + if ',' in rhs: + + self.in_point = [float(rhs.split(',')[0]), + float(rhs.split(',')[1])] + elif lhs == 'Radius' or lhs == 'radius': + self.radius = float(rhs) + elif lhs == 'Semi-major-axis' or lhs == 'semi-major-axis': + self.semimajor = float(rhs) + elif lhs == 'Semi-minor-axis' or lhs == 'semi-minor-axis': + self.semiminor = float(rhs) + elif lhs == 'Orientation-angle' or lhs == 'orientation-angle': + self.orientation = float(rhs) + elif lhs == 'uLat' or lhs == 'Upper-lat' or lhs == 'upper-lat' or lhs == 'ulat': + self.ulat = float(rhs) + elif lhs == 'lLat' or lhs == 'Lower-lat' or lhs == 'lower-lat' or lhs == 'llat': + self.llat = float(rhs) + elif line == 'keyword': # Then we have a keyword option + pass + elif ',' in line: # Then we have a coordinate point + lat = float(line.split(',')[0]) + lon = float(line.split(',')[1]) + + self.points.append(lat) + self.points.append(lon) + + self.points_file.close() + del(self.points_file) + + +if __name__ == "__main__": + print(sys.argv[1]) + parse_points(sys.argv[1]) + diff --git a/sources/MPAS-Limited-Area/limited_area/region_spec.py b/sources/MPAS-Limited-Area/limited_area/region_spec.py new file mode 100644 index 0000000..90d8c89 --- /dev/null +++ b/sources/MPAS-Limited-Area/limited_area/region_spec.py @@ -0,0 +1,262 @@ +from __future__ import absolute_import, division, print_function + +import os +import sys +import types +import numpy as np + +from limited_area.points import PointsParser +from limited_area.mesh import latlon_to_xyz, xyz_to_latlon +from limited_area.mesh import rotate_about_vector +import numpy as np + +EARTH_RADIUS = 6371229 # Meters + +""" region_spec.py - Provide a number of operations for defining a +region. """ + +if sys.version_info[0] > 2: + create_bound_method = types.MethodType +else: + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + +def normalize_cords(lat, lon): + """ Returned lat, and lon to be in radians and the same + range as MPAS - Lat: -pi/2 to pi/2 - Lon: 0 to 2*pi + + Lat - Latitude in degrees + Lon - Longitude in degrees + + """ + lat *= np.pi / 180.0 + lon *= np.pi / 180.0 + + return lat, lon + + +class RegionSpec: + """ RegionSpec - Method for generating regional specifications + Region spec works upon a contract. It will need the following + information when it is called: + + filename - Path to the file that is to be read + + And will then return, the following: + + filename - Output filename (if desired and specified in the specification file) + points array - A 1-dimensional list of lat lon cords specifying boundary + in counter clockwise order + in-point - pair of points that inside the boundary + algorithm choice - The desired algorithm for choosing boundary points and + relaxation layers (if specified within the specification file) + """ + # TODO: Update __init__ with fileName + def __init__(self, *args, **kwargs): + """ init for region Spec + + Keyword Arguments: + DEBUG - Debug value for verbose output - Default 0 + """ + # Keyword Args + self._DEBUG_ = kwargs.get('DEBUG', 0) + self._gen_spec = create_bound_method(PointsParser, self) + + def gen_spec(self, fileName, *args, **kwargs): + """ Generate the specifications and return, name, in point and a list of points. + + Call the method we bound above, and then do any processing here + to do things like convert coordinates to radians, or anything else + we need to get return contract variables. + + fileName - The file that specifies the region + + Return values: + name - The name of the region + in_point - A point that is within the region + points - A 1-Dimensional list of latitude and longitude points + (in degrees) that list the boundary points of the region + in counter-clockwise. ie: [lat1, lon1, lat2, lon2, ... , latN, lonN] + """ + + self._gen_spec(fileName, *args, **kwargs) + + if self.type == 'custom': + if self._DEBUG_ > 0: + print("DEBUG: Using a custom polygon for generating a region") + + self.points = np.array(self.points) + + # Convert the points to radians and set them to be between + # Lon: 0 to 2*Pi and Lat: -pi to +pi + for cord in range(0, len(self.points), 2): + self.points[cord], self.points[cord+1] = normalize_cords( + self.points[cord], + self.points[cord+1]) + + self.in_point[0], self.in_point[1] = normalize_cords( + self.in_point[0], + self.in_point[1]) + + return self.name, self.in_point, [self.points] + elif self.type == 'circle': + if self._DEBUG_ > 0: + print("DEBUG: Using the circle method for region generation") + + self.in_point[0], self.in_point[1] = normalize_cords( + self.in_point[0], + self.in_point[1]) + + # Divide by sphere radius to get radius upon sphere + self.radius = self.radius / EARTH_RADIUS + self.points = self.circle(self.in_point[0], self.in_point[1], self.radius) + return self.name, self.in_point, [self.points.flatten()] + elif self.type == 'ellipse': + if self._DEBUG_ > 0: + print("DEBUG: Using the ellipse method for region generation") + + # Convert ellipse center point from degrees to radians + self.in_point[0], self.in_point[1] = normalize_cords( + self.in_point[0], + self.in_point[1]) + + self.points = self.ellipse(self.in_point[0], self.in_point[1], + self.semimajor, self.semiminor, + self.orientation) + return self.name, self.in_point, [self.points.flatten()] + elif self.type == 'channel': + if self._DEBUG_ > 0: + print("DEBUG: Using the channel method for region generation") + + if self.ulat == self.llat: + print("ERROR: Upper and lower latitude for channel specification") + print("ERROR: cannot be equal") + print("ERROR: Upper-lat: ", self.ulat) + print("ERROR: Lower-lat: ", self.llat) + sys.exit(-1) + + self.ulat, self.llat = normalize_cords(self.ulat, self.llat) + + self.boundaries = [] + + upperBdy = np.empty([100, 2]) + lowerBdy = np.empty([100, 2]) + + upperBdy[:,0] = self.ulat + upperBdy[:,1] = np.linspace(0.0, 2.0 * np.pi, 100) + + lowerBdy[:,0] = self.llat + lowerBdy[:,1] = np.linspace(0.0, 2.0 * np.pi, 100) + + self.in_point = np.array([(self.ulat + self.llat) / 2, 0]) + + self.boundaries.append(upperBdy.flatten()) + self.boundaries.append(lowerBdy.flatten()) + + return self.name, self.in_point, self.boundaries + + def circle(self, center_lat, center_lon, radius): + """ Return a list of latitude and longitude points in degrees that + area radius away from (center_lat, center_lon) + + center_lat - Circle center latitude in radians + center_lon - Circle center longitude in radians + radius - Radius of desire circle in radians upon the unit sphere + + """ + + P = [] + + if self._DEBUG_ > 1: + print("DEBUG: center_lat: ", center_lat, + " center_lon: ", center_lon, + " radius: ", radius) + + + C = latlon_to_xyz(center_lat, center_lon, 1.0) + + # Find a point not equal to C or -C + K = np.zeros(3) + K[0] = 1 + K[1] = 0 + K[2] = 0 + + if abs(np.dot(K,C)) >= 0.9: + K[0] = 0 + K[1] = 1 + K[2] = 0 + + + # S is then a vector orthogonal to C + S = np.cross(C, K) + S = S / np.linalg.norm(S) + + P0 = rotate_about_vector(C, S, radius) + + for r in np.linspace(0.0, 2.0*np.pi, 100): + P.append(rotate_about_vector(P0, C, r)) + + ll = [] + # TODO: The efficiency here can be improved for memory + # and probably comp time + for i in range(len(P)): + ll.append(xyz_to_latlon(P[i])) # Convert back to latlon + + return np.array(ll) + + def ellipse(self, center_lat, center_lon, semi_major, semi_minor, orientation): + """ Return a list of points that form an ellipse around [center_lat, center_lon] + + center_lat - The center latitude of the ellipse in degrees + center_lon - The center longitude of the ellipse in degrees + semi_major - The length of the semi_major axies in meters + semi_minor - The legnth of the semi_minor axies in meters + orientaiton - The orientation of the desired ellipse, rotated clockwise from north. + + Given the center_lat and center_lon of an ellipse, create a region that forms an ellipse + with the semi major axies length being == `semi_major` and the semi minor axies being == + `semi_minor` and rotate the ellipse clockwise by `orientation` from due North. + + """ + + P = [] + + # Convert ellipse center from (lat,lon) to Cartesian + C = latlon_to_xyz(center_lat, center_lon, 1.0) + + # Convert semi-major and semi-minor axis lengths from meters to radians + semi_major = semi_major / EARTH_RADIUS + semi_minor = semi_minor / EARTH_RADIUS + + # Convert orientation angle to radians + orientation = orientation * np.pi / 180.0 + + # Find a point not equal to C or -C + K = np.zeros(3) + K[0] = 0 + K[1] = 0 + K[2] = 1 + + if abs(np.dot(K,C)) >= 0.9: + K[0] = 1 + K[1] = 0 + K[2] = 0 + + # S is then a vector orthogonal to C + S = np.cross(C, K) + S = S / np.linalg.norm(S) + + for r in np.linspace(0.0, 2.0*np.pi, 100): + radius = np.sqrt((semi_major * np.cos(r))**2 + (semi_minor * np.sin(r))**2) + P0 = rotate_about_vector(C, S, radius) + ang = np.arctan2(semi_minor * np.sin(r), semi_major * np.cos(r)) + P.append(rotate_about_vector(P0, C, ang-orientation)) + + ll = [] + # TODO: The efficency here can be improved for memory + # and probably comp time + for i in range(len(P)): + ll.append(xyz_to_latlon(P[i])) # Convert back to latlon + + return np.array(ll) diff --git a/sources/MPAS-Limited-Area/requirements.txt b/sources/MPAS-Limited-Area/requirements.txt new file mode 100644 index 0000000..f933c51 --- /dev/null +++ b/sources/MPAS-Limited-Area/requirements.txt @@ -0,0 +1,2 @@ +numpy +netCDF4