From 2999fdbf915b26cfc19c8cf70377ade996eac9dc Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 15:25:20 +0900 Subject: [PATCH 01/98] Enable to output arbitrary names/units of axes. --- FElib/src/file/scale_file_base_meshfield.F90 | 115 +++++------ .../src/file/scale_file_common_meshfield.F90 | 193 ++++++++++-------- .../src/file/scale_file_history_meshfield.F90 | 67 +++--- .../src/file/scale_file_restart_meshfield.F90 | 66 +++++- FElib/src/mesh/scale_localmesh_base.F90 | 13 +- FElib/src/mesh/scale_mesh_base.F90 | 42 +++- FElib/src/mesh/scale_mesh_base1d.F90 | 79 +++---- FElib/src/mesh/scale_mesh_base2d.F90 | 18 +- FElib/src/mesh/scale_mesh_base3d.F90 | 18 +- FElib/src/mesh/scale_mesh_cubedom3d.F90 | 3 +- .../src/mesh/scale_mesh_cubedspheredom2d.F90 | 17 +- 11 files changed, 385 insertions(+), 246 deletions(-) diff --git a/FElib/src/file/scale_file_base_meshfield.F90 b/FElib/src/file/scale_file_base_meshfield.F90 index 90a6638b..e985e5fe 100644 --- a/FElib/src/file/scale_file_base_meshfield.F90 +++ b/FElib/src/file/scale_file_base_meshfield.F90 @@ -14,17 +14,20 @@ module scale_file_base_meshfield FILE_FILE_MAX use scale_file_common_meshfield, only: & - FILE_common_meshfield_diminfo, & - MF1D_DTYPE_NUM => FILE_COMMON_MESHFILED1D_DIMTYPE_NUM, & - MF2D_DTYPE_NUM => FILE_COMMON_MESHFILED2D_DIMTYPE_NUM, & - MF3D_DTYPE_NUM => FILE_COMMON_MESHFILED3D_DIMTYPE_NUM, & - MF1D_DIMTYPE_X => FILE_COMMON_MESHFILED1D_DIMTYPEID_X, & - MF2D_DIMTYPE_X => FILE_COMMON_MESHFILED2D_DIMTYPEID_X, & - MF2D_DIMTYPE_Y => FILE_COMMON_MESHFILED2D_DIMTYPEID_Y, & - MF3D_DIMTYPE_X => FILE_COMMON_MESHFILED3D_DIMTYPEID_X, & - MF3D_DIMTYPE_Y => FILE_COMMON_MESHFILED3D_DIMTYPEID_Y, & - MF3D_DIMTYPE_Z => FILE_COMMON_MESHFILED3D_DIMTYPEID_Z, & + FILE_common_meshfield_diminfo, & get_dtype => File_common_meshfield_get_dtype + use scale_mesh_base1d, only: & + MF1D_DIMTYPE_X => MeshBase1D_DIMTYPEID_X, & + MF1D_DTYPE_NUM => MeshBase1D_DIMTYPE_NUM + use scale_mesh_base2d, only: & + MF2D_DIMTYPE_X => MeshBase2D_DIMTYPEID_X, & + MF2D_DIMTYPE_Y => MeshBase2D_DIMTYPEID_Y, & + MF2D_DTYPE_NUM => MeshBase2D_DIMTYPE_NUM + use scale_mesh_base3d, only: & + MF3D_DIMTYPE_X => MeshBase3D_DIMTYPEID_X, & + MF3D_DIMTYPE_Y => MeshBase3D_DIMTYPEID_Y, & + MF3D_DIMTYPE_Z => MeshBase3D_DIMTYPEID_Z, & + MF3D_DTYPE_NUM => MeshBase3D_DIMTYPE_NUM use scale_element_base, only: elementbase1D, elementbase2D, elementbase3D use scale_mesh_base1d, only: MeshBase1D @@ -84,15 +87,12 @@ module scale_file_base_meshfield procedure :: FILE_base_meshfield_read_var1d_local procedure :: FILE_base_meshfield_read_var2d procedure :: FILE_base_meshfield_read_var2d_local - procedure :: FILE_base_meshfield_read_var2d_cubedsphere procedure :: FILE_base_meshfield_read_var3d procedure :: FILE_base_meshfield_read_var3d_local generic :: Read_Var => & FILE_base_meshfield_read_var1d, FILE_base_meshfield_read_var1d_local, & FILE_base_meshfield_read_var2d, FILE_base_meshfield_read_var2d_local, & FILE_base_meshfield_read_var3d, FILE_base_meshfield_read_var3d_local - generic :: Read_Var_cubedsphere => & - FILE_base_meshfield_read_var2d_cubedsphere !- procedure :: Get_commonInfo => FILE_base_meshfield_get_commonInfo @@ -118,7 +118,7 @@ subroutine FILE_base_meshfield_Init( this, & ! (inout) integer, intent(in) :: var_num class(MeshBase1D), target, optional, intent(in) :: mesh1D class(MeshRectDom2D), target, optional, intent(in) :: mesh2D - class(MeshCubedSphereDom2D), target, optional, intent(in) :: meshCubedSPhere2D + class(MeshCubedSphereDom2D), target, optional, intent(in) :: meshCubedSphere2D class(MeshCubeDom3D), target, optional, intent(in) :: mesh3D logical, intent(in), optional :: force_uniform_grid @@ -148,12 +148,12 @@ subroutine FILE_base_meshfield_Init( this, & ! (inout) allocate( this%dimsinfo(MF2D_DTYPE_NUM) ) call File_common_meshfield_get_dims( mesh2D, this%dimsinfo(:) ) end if - if (present(meshCubedSPhere2D)) then - this%meshCS2D => meshCubedSPhere2D + if (present(meshCubedSphere2D)) then + this%meshCS2D => meshCubedSphere2D check_specify_mesh = .true. allocate( this%dimsinfo(MF2D_DTYPE_NUM) ) - call File_common_meshfield_get_dims( meshCubedSPhere2D, this%dimsinfo(:) ) + call File_common_meshfield_get_dims( meshCubedSphere2D, this%dimsinfo(:) ) end if if (present(mesh3D)) then this%mesh3D => mesh3D @@ -376,7 +376,8 @@ subroutine FILE_base_meshfield_write_var2d( this, & ! (inout) FILE_opened, & FILE_Write use scale_file_common_meshfield, only: & - File_common_meshfield_put_field2D_cartesbuf + File_common_meshfield_put_field2D_cartesbuf, & + File_common_meshfield_put_field2D_cubedsphere_cartesbuf implicit none class(FILE_base_meshfield), intent(inout) :: this @@ -395,8 +396,13 @@ subroutine FILE_base_meshfield_write_var2d( this, & ! (inout) dims(1) = this%dimsinfo(MF2D_DIMTYPE_X)%size dims(2) = this%dimsinfo(MF2D_DIMTYPE_Y)%size allocate( buf(dims(1),dims(2)) ) - call File_common_meshfield_put_field2D_cartesbuf( this%mesh2D, field2d, buf(:,:), & - this%force_uniform_grid ) + if ( associated(this%mesh2D) ) then + call File_common_meshfield_put_field2D_cartesbuf( this%mesh2D, field2d, buf(:,:), & + this%force_uniform_grid ) + else if ( associated(this%meshCS2D) ) then + call File_common_meshfield_put_field2D_cubedsphere_cartesbuf( & + this%meshCS2D, field2d, buf(:,:) ) + end if call FILE_Write( this%vars_ncid(vid), buf(:,:), & ! (in) sec_str, sec_end, start=start ) ! (in) @@ -595,48 +601,7 @@ subroutine FILE_base_meshfield_read_var2d( this, & ! (inout) use scale_file, only: & FILE_Read use scale_file_common_meshfield, only: & - File_common_meshfield_set_cartesbuf_field2D - - implicit none - - class(FILE_base_meshfield), intent(inout) :: this - integer, intent(in) :: dim_typeid - character(*), intent(in) :: varname - class(MeshField2D), intent(inout) :: field2d - integer, intent(in), optional :: step - logical, intent(in), optional :: allow_missing - - real(RP), allocatable :: buf(:,:) - integer :: dims(2) - integer :: start(2) ! start offset of globale variable - !------------------------------------------------- - - if ( this%fid /= -1 ) then - start(:) = 1 - dims(1) = this%dimsinfo(MF2D_DIMTYPE_X)%size - dims(2) = this%dimsinfo(MF2D_DIMTYPE_Y)%size - allocate( buf(dims(1),dims(2)) ) - - call FILE_Read( this%fid, varname, & ! (in) - buf(:,:), & ! (out) - step=step, allow_missing=allow_missing ) ! (in) - - call File_common_meshfield_set_cartesbuf_field2D( this%mesh2D, buf(:,:), & - field2d ) - end if - - return - end subroutine FILE_base_meshfield_read_var2d - - subroutine FILE_base_meshfield_read_var2d_cubedsphere( & - this, & ! (inout) - dim_typeid, varname, & ! (in) - field2d, & ! (inout) - step, allow_missing ) ! (in) - - use scale_file, only: & - FILE_Read - use scale_file_common_meshfield, only: & + File_common_meshfield_set_cartesbuf_field2D, & File_common_meshfield_set_cartesbuf_field2D_cubedsphere implicit none @@ -663,13 +628,18 @@ subroutine FILE_base_meshfield_read_var2d_cubedsphere( & buf(:,:), & ! (out) step=step, allow_missing=allow_missing ) ! (in) - call File_common_meshfield_set_cartesbuf_field2D_cubedsphere( & - this%meshCS2D, buf(:,:), & - field2d ) + if ( associated( this%meshCS2D) ) then + call File_common_meshfield_set_cartesbuf_field2D_cubedsphere( & + this%meshCS2D, buf(:,:), & + field2d ) + else if ( associated( this%mesh2D) ) then + call File_common_meshfield_set_cartesbuf_field2D( this%mesh2D, buf(:,:), & + field2d ) + end if end if return - end subroutine FILE_base_meshfield_read_var2d_cubedsphere + end subroutine FILE_base_meshfield_read_var2d subroutine FILE_base_meshfield_read_var2d_local( this, & ! (inout) dim_typeid, varname, lcmesh, i0_s, j0_s, & ! (in) @@ -860,7 +830,8 @@ subroutine def_axes( this, & ! (in) end do end if - if ( associated(this%mesh2D) ) then + if ( associated(this%mesh2D) & + .or. associated(this%meshCS2D) ) then do d=1, 2 call FILE_Def_Axis( this%fid, & this%dimsinfo(d)%name, this%dimsinfo(d)%desc, this%dimsinfo(d)%unit, & @@ -904,7 +875,7 @@ subroutine write_axes( this, & ! (in) call FILE_Write_Axis( this%fid, this%dimsinfo(1)%name, x(:), start(1:1) ) end if - if ( associated(this%mesh2D) ) then + if ( associated(this%mesh2D) ) then allocate( x(this%dimsinfo(1)%size), y(this%dimsinfo(2)%size) ) call File_common_meshfield_get_axis( this%mesh2D, this%dimsinfo, x(:), y(:), this%force_uniform_grid ) @@ -912,6 +883,14 @@ subroutine write_axes( this, & ! (in) call FILE_Write_Axis( this%fid, this%dimsinfo(2)%name, y(:), start(2:2) ) end if + if ( associated(this%meshCS2D) ) then + allocate( x(this%dimsinfo(1)%size), y(this%dimsinfo(2)%size) ) + call File_common_meshfield_get_axis( this%meshCS2D, this%dimsinfo, x(:), y(:) ) + + call FILE_Write_Axis( this%fid, this%dimsinfo(1)%name, x(:), start(1:1) ) + call FILE_Write_Axis( this%fid, this%dimsinfo(2)%name, y(:), start(2:2) ) + end if + if ( associated(this%mesh3D) ) then allocate( x(this%dimsinfo(1)%size), y(this%dimsinfo(2)%size), z(this%dimsinfo(3)%size) ) call File_common_meshfield_get_axis( this%mesh3D, this%dimsinfo, x(:), y(:), z(:), this%force_uniform_grid ) diff --git a/FElib/src/file/scale_file_common_meshfield.F90 b/FElib/src/file/scale_file_common_meshfield.F90 index 18376c2f..5751f111 100644 --- a/FElib/src/file/scale_file_common_meshfield.F90 +++ b/FElib/src/file/scale_file_common_meshfield.F90 @@ -9,9 +9,19 @@ module scale_file_common_meshfield use scale_io use scale_element_base, only: elementbase1D, elementbase2D, elementbase3D - use scale_mesh_base1d, only: MeshBase1D - use scale_mesh_base2d, only: MeshBase2D - use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_base, only: MeshDimInfo + use scale_mesh_base1d, only: MeshBase1D, & + MeshBase1D_DIMTYPEID_X, MeshBase1D_DIMTYPEID_XT, & + MeshBase1D_DIMTYPE_NUM + use scale_mesh_base2d, only: MeshBase2D, & + MeshBase2D_DIMTYPEID_X, MeshBase2D_DIMTYPEID_Y, & + MeshBase2D_DIMTYPEID_XY, MeshBase2D_DIMTYPEID_XYT, & + MeshBase2D_DIMTYPE_NUM + use scale_mesh_base3d, only: MeshBase3D, & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_ZT, MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_XYZT, & + MeshBase3D_DIMTYPE_NUM + use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D @@ -85,26 +95,6 @@ module scale_file_common_meshfield ! !----------------------------------------------------------------------------- - ! 1D - integer, public :: FILE_COMMON_MESHFILED1D_DIMTYPE_NUM = 2 - integer, public :: FILE_COMMON_MESHFILED1D_DIMTYPEID_X = 1 - integer, public :: FILE_COMMON_MESHFILED1D_DIMTYPEID_XT = 2 - - ! 2D - integer, public :: FILE_COMMON_MESHFILED2D_DIMTYPE_NUM = 4 - integer, public :: FILE_COMMON_MESHFILED2D_DIMTYPEID_X = 1 - integer, public :: FILE_COMMON_MESHFILED2D_DIMTYPEID_Y = 2 - integer, public :: FILE_COMMON_MESHFILED2D_DIMTYPEID_XY = 3 - integer, public :: FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT = 4 - - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPE_NUM = 6 - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPEID_X = 1 - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPEID_Y = 2 - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPEID_Z = 3 - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZ = 4 - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZT = 5 - integer, public :: FILE_COMMON_MESHFILED3D_DIMTYPEID_ZT = 6 - !-------------------- ! !++ Private procedures @@ -120,16 +110,21 @@ subroutine File_common_meshfield_get_dims1D( mesh1D, dimsinfo ) implicit none class(MeshBase1D), target, intent(in) :: mesh1D - type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(FILE_COMMON_MESHFILED1D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase1D_DIMTYPE_NUM) integer :: i_size + type(MeshDimInfo), pointer :: diminfo !------------------------------------------------- i_size = mesh1D%NeG * mesh1D%refElem1D%Np - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED1D_DIMTYPEID_X), & - "x", "X-coordinate", "X", 1, (/ "x" /), (/ i_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED1D_DIMTYPEID_XT), & - "xt", "X-coordinate", "XT", 1, (/ "x" /), (/ i_size /) ) + + dimInfo => mesh1D%dimInfo(MeshBase1D_DIMTYPEID_X) + call set_dimension( dimsinfo(MeshBase1D_DIMTYPEID_X), & + dimInfo, "X", 1, (/ dimInfo%name /), (/ i_size /) ) + + dimInfo => mesh1D%dimInfo(MeshBase1D_DIMTYPEID_XT) + call set_dimension( dimsinfo(MeshBase1D_DIMTYPEID_XT), & + dimInfo, "XT", 1, (/ dimInfo%name /), (/ i_size /) ) return end subroutine File_common_meshfield_get_dims1D @@ -139,8 +134,8 @@ subroutine File_common_meshfield_get_axis1D( mesh1D, dimsinfo, x, & implicit none class(MeshBase1D), target, intent(in) :: mesh1D - type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(FILE_COMMON_MESHFILED1D_DIMTYPE_NUM) - real(DP), intent(out) :: x(dimsinfo(FILE_COMMON_MESHFILED1D_DIMTYPEID_X)%size) + type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(MeshBase1D_DIMTYPE_NUM) + real(DP), intent(out) :: x(dimsinfo(MeshBase1D_DIMTYPEID_X)%size) logical, intent(in), optional :: force_uniform_grid integer :: n @@ -318,13 +313,16 @@ subroutine File_common_meshfield_get_dims2D( mesh2D, dimsinfo ) implicit none class(MeshRectDom2D), target, intent(in) :: mesh2D - type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase2D_DIMTYPE_NUM) type(ElementBase2D), pointer :: refElem type(LocalMesh2D), pointer :: lcmesh integer :: i, j, n integer :: i_size, j_size + type(MeshDimInfo), pointer :: diminfo + type(MeshDimInfo), pointer :: diminfo_x + type(MeshDimInfo), pointer :: diminfo_y !------------------------------------------------- i_size = 0 @@ -341,16 +339,24 @@ subroutine File_common_meshfield_get_dims2D( mesh2D, dimsinfo ) j_size = j_size + lcmesh%NeY * lcmesh%refElem2D%Nfp end do - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_X), & - "x", "X-coordinate", "X", 1, (/ "x" /), (/ i_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_Y), & - "y", "Y-coordinate", "Y", 1, (/ "y" /), (/ j_size /) ) - - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_XY), & - "xy", "XY-coordinate", "XY", 2, (/ "x", "y" /), (/ i_size, j_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT), & - "xyt", "XY-coordinate", "XYT", 2, (/ "x", "y" /), (/ i_size, j_size /) ) - + diminfo_x => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_X) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_X), & + dimInfo_x, "X", 1, (/ diminfo_x%name /), (/ i_size /) ) + + diminfo_y => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_Y) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_Y), & + diminfo_y, "Y", 1, (/ diminfo_y%name /), (/ j_size /) ) + + diminfo => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_XY) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_XY), & + diminfo, "XY", 2, (/ diminfo_x%name, diminfo_y%name /), & + (/ i_size, j_size /) ) + + diminfo => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_XYT) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_XYT), & + diminfo, "XYT", 2, (/ diminfo_x%name, diminfo_y%name /), & + (/ i_size, j_size /) ) + return end subroutine File_common_meshfield_get_dims2D @@ -358,13 +364,17 @@ subroutine File_common_meshfield_get_dims2D_cubedsphere( mesh2D, dimsinfo ) implicit none class(MeshCubedSphereDom2D), target, intent(in) :: mesh2D - type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase2D_DIMTYPE_NUM) type(ElementBase2D), pointer :: refElem type(LocalMesh2D), pointer :: lcmesh integer :: i, j, n integer :: i_size, j_size + + type(MeshDimInfo), pointer :: diminfo + type(MeshDimInfo), pointer :: diminfo_x + type(MeshDimInfo), pointer :: diminfo_y !------------------------------------------------- i_size = 0 @@ -383,15 +393,23 @@ subroutine File_common_meshfield_get_dims2D_cubedsphere( mesh2D, dimsinfo ) j_size = j_size * size(mesh2D%rcdomIJP2LCMeshID,3) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_X), & - "x", "X-coordinate", "X", 1, (/ "x" /), (/ i_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_Y), & - "y", "Y-coordinate", "Y", 1, (/ "y" /), (/ j_size /) ) + diminfo_x => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_X) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_X), & + dimInfo_x, "X", 1, (/ diminfo_x%name /), (/ i_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_XY), & - "xy", "XY-coordinate", "XY", 2, (/ "x", "y" /), (/ i_size, j_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT), & - "xyt", "XY-coordinate", "XYT", 2, (/ "x", "y" /), (/ i_size, j_size /) ) + diminfo_y => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_Y) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_Y), & + diminfo_y, "Y", 1, (/ diminfo_y%name /), (/ j_size /) ) + + diminfo => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_XY) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_XY), & + diminfo, "XY", 2, (/ diminfo_x%name, diminfo_y%name /), & + (/ i_size, j_size /) ) + + diminfo => mesh2D%dimInfo(MeshBase2D_DIMTYPEID_XYT) + call set_dimension( dimsinfo(MeshBase2D_DIMTYPEID_XYT), & + diminfo, "XYT", 2, (/ diminfo_x%name, diminfo_y%name /), & + (/ i_size, j_size /) ) return end subroutine File_common_meshfield_get_dims2D_cubedsphere @@ -401,9 +419,9 @@ subroutine File_common_meshfield_get_axis2D( mesh2D, dimsinfo, x, y, & implicit none class(MeshRectDom2D), target, intent(in) :: mesh2D - type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPE_NUM) - real(DP), intent(out) :: x(dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_X)%size) - real(DP), intent(out) :: y(dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_Y)%size) + type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(MeshBase2D_DIMTYPE_NUM) + real(DP), intent(out) :: x(dimsinfo(MeshBase2D_DIMTYPEID_X)%size) + real(DP), intent(out) :: y(dimsinfo(MeshBase2D_DIMTYPEID_Y)%size) logical, intent(in), optional :: force_uniform_grid integer :: n @@ -470,9 +488,9 @@ subroutine File_common_meshfield_get_axis2D_cubedsphere( mesh2D, dimsinfo, x, y implicit none class(MeshCubedSphereDom2D), target, intent(in) :: mesh2D - type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPE_NUM) - real(DP), intent(out) :: x(dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_X)%size) - real(DP), intent(out) :: y(dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPEID_Y)%size) + type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(MeshBase2D_DIMTYPE_NUM) + real(DP), intent(out) :: x(dimsinfo(MeshBase2D_DIMTYPEID_X)%size) + real(DP), intent(out) :: y(dimsinfo(MeshBase2D_DIMTYPEID_Y)%size) integer :: ni, nj, np, n integer :: k @@ -805,13 +823,18 @@ subroutine File_common_meshfield_get_dims3D( mesh3D, dimsinfo ) implicit none class(MeshCubeDom3D), target, intent(in) :: mesh3D - type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase3D_DIMTYPE_NUM) type(LocalMesh3D), pointer :: lcmesh integer :: i, j, k, n integer :: icount, jcount, kcount integer :: i_size, j_size, k_size + + type(MeshDimInfo), pointer :: dimInfo + type(MeshDimInfo), pointer :: dimInfo_x + type(MeshDimInfo), pointer :: dimInfo_y + type(MeshDimInfo), pointer :: dimInfo_z !------------------------------------------------- i_size = 0 @@ -835,22 +858,31 @@ subroutine File_common_meshfield_get_dims3D( mesh3D, dimsinfo ) k_size = k_size + lcmesh%NeZ * lcmesh%refElem3D%Nnode_v end do - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_X), & - "x", "X-coordinate", "X", 1, (/ "x" /), (/ i_size /) ) - - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_Y), & - "y", "Y-coordinate", "Y", 1, (/ "y" /), (/ j_size /) ) - - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_Z), & - "z", "Z-coordinate", "Z", 1, (/ "z" /), (/ k_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_ZT), & - "zt", "Z-coordinate", "ZT", 1, (/ "z" /), (/ k_size /) ) + diminfo_x => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_X) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_X), & + dimInfo_x, "X", 1, (/ diminfo_x%name /), (/ i_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZ), & - "xyz", "XYZ-coordinate", "XYZ", 3, (/ "x", "y", "z" /), (/ i_size, j_size, k_size /) ) - call set_dimension( dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZT), & - "xyzt", "XYZ-coordinate", "XYZT", 3, (/ "x", "y", "z" /), (/ i_size, j_size, k_size /) ) + diminfo_y => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_Y) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Y), & + diminfo_y, "Y", 1, (/ diminfo_y%name /), (/ j_size /) ) + diminfo_z => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_Z) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Z), & + diminfo_z, "Z", 1, (/ diminfo_z%name /), (/ k_size /) ) + + diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_ZT) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_ZT), & + diminfo, "ZT", 1, (/ diminfo_z%name /), (/ k_size /) ) + + diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_XYZ) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_XYZ), & + diminfo, "XYZ", 3, (/ diminfo_x%name, diminfo_y%name, diminfo_z%name /), & + (/ i_size, j_size, k_size /) ) + + diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_XYZT) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_XYZT), & + diminfo, "XYZT", 3, (/ diminfo_x%name, diminfo_y%name, diminfo_z%name /), & + (/ i_size, j_size, k_size /) ) return end subroutine File_common_meshfield_get_dims3D @@ -860,10 +892,10 @@ subroutine File_common_meshfield_get_axis3D( mesh3D, dimsinfo, x, y, z, & implicit none class(MeshCubeDom3D), target, intent(in) :: mesh3D - type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPE_NUM) - real(DP), intent(out) :: x(dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_X)%size) - real(DP), intent(out) :: y(dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_Y)%size) - real(DP), intent(out) :: z(dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPEID_Z)%size) + type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(MeshBase3D_DIMTYPE_NUM) + real(DP), intent(out) :: x(dimsinfo(MeshBase3D_DIMTYPEID_X)%size) + real(DP), intent(out) :: y(dimsinfo(MeshBase3D_DIMTYPEID_Y)%size) + real(DP), intent(out) :: z(dimsinfo(MeshBase3D_DIMTYPEID_Z)%size) logical, intent(in), optional :: force_uniform_grid integer :: n, kelem @@ -1197,12 +1229,11 @@ subroutine get_uniform_grid1D( pos1D, Np ) return end subroutine get_uniform_grid1D - subroutine set_dimension( dim, name, desc, dim_type, ndims, dims, count ) + subroutine set_dimension( dim, diminfo, dim_type, ndims, dims, count ) implicit none type(FILE_common_meshfield_diminfo), intent(out) :: dim - character(*), intent(in) :: name - character(*), intent(in) :: desc + type(MeshDimInfo), intent(in) :: diminfo character(*), intent(in) :: dim_type integer, intent(in) :: ndims character(len=*), intent(in) :: dims(ndims) @@ -1211,9 +1242,9 @@ subroutine set_dimension( dim, name, desc, dim_type, ndims, dims, count ) integer :: d !---------------------------------------------------- - dim%name = name - dim%unit = "m" - dim%desc = desc + dim%name = diminfo%name + dim%unit = diminfo%unit + dim%desc = diminfo%desc dim%type = dim_type dim%ndim = ndims dim%size = 1 diff --git a/FElib/src/file/scale_file_history_meshfield.F90 b/FElib/src/file/scale_file_history_meshfield.F90 index 9d65e939..79fb4e7d 100644 --- a/FElib/src/file/scale_file_history_meshfield.F90 +++ b/FElib/src/file/scale_file_history_meshfield.F90 @@ -252,16 +252,16 @@ end subroutine FILE_HISTORY_meshfield_put3D subroutine set_dim_axis1D() use scale_file_common_meshfield, only: & - FILE_COMMON_MESHFILED1D_DIMTYPE_NUM, & - DIMTYPE_X => FILE_COMMON_MESHFILED1D_DIMTYPEID_X, & - DIMTYPE_XT => FILE_COMMON_MESHFILED1D_DIMTYPEID_XT, & FILE_common_meshfield_diminfo, & File_common_meshfield_get_dims1D, & File_common_meshfield_get_axis1D - + use scale_mesh_base1d, only: & + DIMTYPE_NUM => MeshBase1D_DIMTYPE_NUM, & + DIMTYPE_X => MeshBase1D_DIMTYPEID_X + implicit none - type(FILE_common_meshfield_diminfo) :: dimsinfo(FILE_COMMON_MESHFILED1D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo) :: dimsinfo(DIMTYPE_NUM) real(RP), allocatable :: x(:) integer :: start(1,1), count(1,1) character(len=H_SHORT) :: dims(1,1) @@ -277,14 +277,14 @@ subroutine set_dim_axis1D() x ) ! (out) start(:,:) = 1 - do n=1, FILE_COMMON_MESHFILED1D_DIMTYPE_NUM + do n=1, DIMTYPE_NUM ndim = dimsinfo(n)%ndim dims(1:ndim,1) = dimsinfo(n)%dims(1:ndim) count(1:ndim,1) = dimsinfo(n)%count(1:ndim) call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) end do - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%type, & + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, & dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) return @@ -292,17 +292,17 @@ end subroutine set_dim_axis1D subroutine set_dim_axis2D() use scale_file_common_meshfield, only: & - FILE_COMMON_MESHFILED2D_DIMTYPE_NUM, & - DIMTYPE_X => FILE_COMMON_MESHFILED2D_DIMTYPEID_X, & - DIMTYPE_Y => FILE_COMMON_MESHFILED2D_DIMTYPEID_Y, & - DIMTYPE_XYT => FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT, & FILE_common_meshfield_diminfo, & File_common_meshfield_get_dims2D, & File_common_meshfield_get_axis2D - + use scale_mesh_base2d, only: & + DIMTYPE_NUM => MeshBase2D_DIMTYPE_NUM, & + DIMTYPE_X => MeshBase2D_DIMTYPEID_X, & + DIMTYPE_Y => MeshBase2D_DIMTYPEID_Y + implicit none - type(FILE_common_meshfield_diminfo) :: dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo) :: dimsinfo(DIMTYPE_NUM) real(RP), allocatable :: x(:), y(:) integer :: start(2,1), count(2,1) character(len=H_SHORT) :: dims(2,1) @@ -320,32 +320,33 @@ subroutine set_dim_axis2D() start(:,:) = 1 - do n=1, FILE_COMMON_MESHFILED2D_DIMTYPE_NUM + do n=1, DIMTYPE_NUM ndim = dimsinfo(n)%ndim dims(1:ndim,1) = dimsinfo(n)%dims(1:ndim) count(1:ndim,1) = dimsinfo(n)%count(1:ndim) call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) end do - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%type, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%type, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) return end subroutine set_dim_axis2D subroutine set_dim_axis3D() use scale_file_common_meshfield, only: & - FILE_COMMON_MESHFILED3D_DIMTYPE_NUM, & - DIMTYPE_X => FILE_COMMON_MESHFILED3D_DIMTYPEID_X, & - DIMTYPE_Y => FILE_COMMON_MESHFILED3D_DIMTYPEID_Y, & - DIMTYPE_Z => FILE_COMMON_MESHFILED3D_DIMTYPEID_Z, & FILE_common_meshfield_diminfo, & File_common_meshfield_get_dims3D, & File_common_meshfield_get_axis3D + use scale_mesh_base3d, only: & + DIMTYPE_NUM => MeshBase3D_DIMTYPE_NUM, & + DIMTYPE_X => MeshBase3D_DIMTYPEID_X, & + DIMTYPE_Y => MeshBase3D_DIMTYPEID_Y, & + DIMTYPE_Z => MeshBase3D_DIMTYPEID_Z implicit none - type(FILE_common_meshfield_diminfo) :: dimsinfo(FILE_COMMON_MESHFILED3D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo) :: dimsinfo(DIMTYPE_NUM) real(RP), allocatable :: x(:), y(:), z(:) integer :: start(3,1), count(3,1) character(len=H_SHORT) :: dims(3,1) @@ -363,33 +364,33 @@ subroutine set_dim_axis3D() x, y, z ) ! (out) start(:,:) = 1 - do n=1, FILE_COMMON_MESHFILED3D_DIMTYPE_NUM + do n=1, DIMTYPE_NUM ndim = dimsinfo(n)%ndim dims(1:ndim,1) = dimsinfo(n)%dims(1:ndim) count(1:ndim,1) = dimsinfo(n)%count(1:ndim) call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) end do - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%type, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%type, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%type, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%desc, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:)) return end subroutine set_dim_axis3D subroutine set_dim_axis2D_cubedsphere() use scale_file_common_meshfield, only: & - FILE_COMMON_MESHFILED2D_DIMTYPE_NUM, & - DIMTYPE_X => FILE_COMMON_MESHFILED2D_DIMTYPEID_X, & - DIMTYPE_Y => FILE_COMMON_MESHFILED2D_DIMTYPEID_Y, & - DIMTYPE_XYT => FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT, & FILE_common_meshfield_diminfo, & File_common_meshfield_get_dims, & File_common_meshfield_get_axis + use scale_mesh_base2d, only: & + DIMTYPE_NUM => MeshBase2D_DIMTYPE_NUM, & + DIMTYPE_X => MeshBase2D_DIMTYPEID_X, & + DIMTYPE_Y => MeshBase2D_DIMTYPEID_Y implicit none - type(FILE_common_meshfield_diminfo) :: dimsinfo(FILE_COMMON_MESHFILED2D_DIMTYPE_NUM) + type(FILE_common_meshfield_diminfo) :: dimsinfo(DIMTYPE_NUM) real(RP), allocatable :: x(:), y(:) integer :: start(2,1), count(2,1) character(len=H_SHORT) :: dims(2,1) @@ -408,15 +409,15 @@ subroutine set_dim_axis2D_cubedsphere() start(:,:) = 1 - do n=1, FILE_COMMON_MESHFILED2D_DIMTYPE_NUM + do n=1, DIMTYPE_NUM ndim = dimsinfo(n)%ndim dims(1:ndim,1) = dimsinfo(n)%dims(1:ndim) count(1:ndim,1) = dimsinfo(n)%count(1:ndim) call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) end do - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%type, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%type, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) return end subroutine set_dim_axis2D_cubedsphere diff --git a/FElib/src/file/scale_file_restart_meshfield.F90 b/FElib/src/file/scale_file_restart_meshfield.F90 index ed93007e..2a26d1e3 100644 --- a/FElib/src/file/scale_file_restart_meshfield.F90 +++ b/FElib/src/file/scale_file_restart_meshfield.F90 @@ -31,13 +31,19 @@ module scale_file_restart_meshfield use scale_file_base_meshfield, only: & FILE_base_meshfield - use scale_file_common_meshfield, only: & - MF1D_DTYPE_NUM => FILE_COMMON_MESHFILED1D_DIMTYPE_NUM, & - MF2D_DTYPE_NUM => FILE_COMMON_MESHFILED2D_DIMTYPE_NUM, & - MF3D_DTYPE_NUM => FILE_COMMON_MESHFILED3D_DIMTYPE_NUM, & - MF3D_DIMTYPE_X => FILE_COMMON_MESHFILED3D_DIMTYPEID_X, & - MF3D_DIMTYPE_Y => FILE_COMMON_MESHFILED3D_DIMTYPEID_Y, & - MF3D_DIMTYPE_Z => FILE_COMMON_MESHFILED3D_DIMTYPEID_Z + + use scale_mesh_base1d, only: & + MF1D_DIMTYPE_X => MeshBase1D_DIMTYPEID_X, & + MF1D_DTYPE_NUM => MeshBase1D_DIMTYPE_NUM + use scale_mesh_base2d, only: & + MF2D_DIMTYPE_X => MeshBase2D_DIMTYPEID_X, & + MF2D_DIMTYPE_Y => MeshBase2D_DIMTYPEID_Y, & + MF2D_DTYPE_NUM => MeshBase2D_DIMTYPE_NUM + use scale_mesh_base3d, only: & + MF3D_DIMTYPE_X => MeshBase3D_DIMTYPEID_X, & + MF3D_DIMTYPE_Y => MeshBase3D_DIMTYPEID_Y, & + MF3D_DIMTYPE_Z => MeshBase3D_DIMTYPEID_Z, & + MF3D_DTYPE_NUM => MeshBase3D_DIMTYPE_NUM !----------------------------------------------------------------------------- implicit none @@ -75,11 +81,17 @@ module scale_file_restart_meshfield procedure :: FILE_restart_meshfield_component_def_var generic :: Def_var => FILE_restart_meshfield_component_def_var procedure :: End_def => FILE_restart_meshfield_component_enddef + procedure :: FILE_restart_meshfield_component_write_var2d procedure :: FILE_restart_meshfield_component_write_var3d - generic :: Write_var => FILE_restart_meshfield_component_write_var3d + generic :: Write_var => & + FILE_restart_meshfield_component_write_var2d, & + FILE_restart_meshfield_component_write_var3d procedure :: Close => FILE_restart_meshfield_component_close + procedure :: FILE_restart_meshfield_component_read_var2d procedure :: FILE_restart_meshfield_component_read_var3d - generic :: Read_Var => FILE_restart_meshfield_component_read_var3d + generic :: Read_Var => & + FILE_restart_meshfield_component_read_var2d, & + FILE_restart_meshfield_component_read_var3d procedure :: Final => FILE_restart_meshfield_component_Final end type @@ -327,6 +339,22 @@ subroutine FILE_restart_meshfield_component_enddef( this ) return end subroutine FILE_restart_meshfield_component_enddef + subroutine FILE_restart_meshfield_component_write_var2d( this, & + vid, field2d ) + + use scale_time, only: TIME_NOWDAYSEC + implicit none + + class(FILE_restart_meshfield_component), intent(inout) :: this + integer, intent(in) :: vid + class(MeshField2D), intent(in) :: field2d + !-------------------------------------------------- + + call this%base%Write_var2D( vid, field2d, TIME_NOWDAYSEC, TIME_NOWDAYSEC ) + + return + end subroutine FILE_restart_meshfield_component_write_var2d + subroutine FILE_restart_meshfield_component_write_var3d( this, & vid, field3d ) @@ -343,6 +371,26 @@ subroutine FILE_restart_meshfield_component_write_var3d( this, & return end subroutine FILE_restart_meshfield_component_write_var3d + subroutine FILE_restart_meshfield_component_read_var2d( this, & + dim_typeid, varname, field2d, step, allow_missing ) + + + implicit none + + class(FILE_restart_meshfield_component), intent(inout) :: this + integer, intent(in) :: dim_typeid + character(*), intent(in) :: varname + class(MeshField2D), intent(inout) :: field2d + integer, intent(in), optional :: step + logical, intent(in), optional :: allow_missing + !------------------------------------------------------ + + call this%base%Read_Var( & + dim_typeid, varname, field2d, step, allow_missing ) + + return + end subroutine FILE_restart_meshfield_component_read_var2d + subroutine FILE_restart_meshfield_component_read_var3d( this, & dim_typeid, varname, field3d, step, allow_missing ) diff --git a/FElib/src/mesh/scale_localmesh_base.F90 b/FElib/src/mesh/scale_localmesh_base.F90 index 58f457d0..dbe8cd5b 100644 --- a/FElib/src/mesh/scale_localmesh_base.F90 +++ b/FElib/src/mesh/scale_localmesh_base.F90 @@ -6,6 +6,8 @@ module scale_localmesh_base !++ used modules ! use scale_precision + use scale_io + use scale_element_base, only: elementbase !----------------------------------------------------------------------------- @@ -16,7 +18,7 @@ module scale_localmesh_base ! !++ Public type & procedure ! - + type, public :: LocalMeshBase integer :: Ne integer :: NeS @@ -58,7 +60,7 @@ module scale_localmesh_base real(DP), allocatable :: G_ij(:,:,:,:) real(DP), allocatable :: GIJ(:,:,:,:) - real(DP), allocatable :: Gsqrt(:,:) + real(DP), allocatable :: Gsqrt(:,:) end type LocalMeshBase public :: LocalMeshBase_Init @@ -86,14 +88,14 @@ module scale_localmesh_base ! contains - subroutine LocalMeshBase_Init( this, refElem, dims, myrank ) + subroutine LocalMeshBase_Init( this, refElem, ndim, myrank ) use scale_prc, only: PRC_myrank implicit none class(LocalMeshBase), intent(inout) :: this class(ElementBase), intent(in), target :: refElem - integer, intent(in) :: dims + integer, intent(in) :: ndim integer, intent(in), optional :: myrank !----------------------------------------------------------------------------- @@ -134,8 +136,7 @@ subroutine LocalMeshBase_Final( this, is_generated ) deallocate( this%G_ij, this%GIJ, this%Gsqrt ) end if end if - + return end subroutine LocalMeshBase_Final - end module scale_localmesh_base \ No newline at end of file diff --git a/FElib/src/mesh/scale_mesh_base.F90 b/FElib/src/mesh/scale_mesh_base.F90 index 50fbd504..ada835b0 100644 --- a/FElib/src/mesh/scale_mesh_base.F90 +++ b/FElib/src/mesh/scale_mesh_base.F90 @@ -5,7 +5,9 @@ module scale_mesh_base ! !++ used modules ! - use scale_precision + use scale_precision + use scale_io + use scale_element_base, only: ElementBase use scale_localmesh_base, only: LocalMeshBase @@ -17,6 +19,13 @@ module scale_mesh_base ! !++ Public type & procedure ! + + type, public :: MeshDimInfo + character(len=H_SHORT) :: name + character(len=H_MID) :: desc + character(len=H_SHORT) :: unit + end type MeshDimInfo + type, abstract, public :: Meshbase integer :: LOCAL_MESH_NUM integer :: PRC_NUM @@ -29,9 +38,12 @@ module scale_mesh_base integer, allocatable :: PRCrank_globalMap(:) class(ElementBase), pointer :: refElem + type(MeshDimInfo), allocatable :: dimInfo(:) + logical :: isGenerated contains procedure(MeshBase_get_localmesh), deferred :: GetLocalMesh + procedure :: SetDimInfo => MeshBase_SetDimInfo end type MeshBase interface @@ -63,15 +75,16 @@ end subroutine MeshBase_get_localmesh ! contains - subroutine MeshBase_Init(this, & - refElem, NLocalMeshPerPrc, NsideTile, & - nprocs ) + subroutine MeshBase_Init( this, & + ndimtype, refElem, NLocalMeshPerPrc, NsideTile, & + nprocs ) use scale_prc, only: & PRC_nprocs implicit none class(MeshBase), intent(inout) :: this + integer, intent(in) :: ndimtype class(ElementBase), intent(in), target :: refElem integer, intent(in) :: NLocalMeshPerPrc integer, intent(in) :: NsideTile @@ -96,6 +109,7 @@ subroutine MeshBase_Init(this, & allocate( this%tilePanelID_globalMap(NsideTile, this%LOCAL_MESH_NUM_global) ) allocate( this%tileID_global2localMap(this%LOCAL_MESH_NUM_global) ) allocate( this%PRCRank_globalMap(this%LOCAL_MESH_NUM_global) ) + allocate( this%dimInfo(ndimtype) ) this%isGenerated = .false. @@ -114,6 +128,7 @@ subroutine MeshBase_Final( this ) deallocate( this%tilePanelID_globalMap ) deallocate( this%tileID_global2localMap ) deallocate( this%PRCRank_globalMap ) + deallocate( this%dimInfo ) return end subroutine MeshBase_Final @@ -144,4 +159,23 @@ subroutine MeshBase_setGeometricInfo( mesh, ndim ) return end subroutine MeshBase_setGeometricInfo + + subroutine MeshBase_SetDimInfo( this, & + dimID, name, unit, desc ) + implicit none + class(MeshBase), intent(inout) :: this + integer, intent(in) :: dimId + character(len=*), intent(in) :: name + character(len=*), intent(in) :: unit + character(len=*), intent(in) :: desc + + !----------------------------------------------- + + this%dimInfo(dimId)%name = name + this%dimInfo(dimId)%unit = unit + this%dimInfo(dimID)%desc = desc + + return + end subroutine MeshBase_SetDimInfo + end module scale_mesh_base \ No newline at end of file diff --git a/FElib/src/mesh/scale_mesh_base1d.F90 b/FElib/src/mesh/scale_mesh_base1d.F90 index 54c1ded7..a0f0818a 100644 --- a/FElib/src/mesh/scale_mesh_base1d.F90 +++ b/FElib/src/mesh/scale_mesh_base1d.F90 @@ -52,6 +52,9 @@ end subroutine Meshbase1d_generate ! !++ Public parameters & variables ! + integer, public :: MeshBase1D_DIMTYPE_NUM = 2 + integer, public :: MeshBase1D_DIMTYPEID_X = 1 + integer, public :: MeshBase1D_DIMTYPEID_XT = 2 !----------------------------------------------------------------------------- ! @@ -106,9 +109,10 @@ subroutine Meshbase1d_Init( this, & end if this%refElem1D => refElem - call MeshBase_Init( this, & - refElem, NLocalMeshPerPrc, 2, & - nprocs ) + call MeshBase_Init( this, & + MeshBase1D_DIMTYPE_NUM, refElem, & + NLocalMeshPerPrc, 2, & + nprocs ) this%Nprc = this%PRC_NUM @@ -117,6 +121,9 @@ subroutine Meshbase1d_Init( this, & call LocalMesh1D_Init( this%lcmesh_list(n), refElem, myrank ) end do + call this%SetDimInfo( MeshBase1D_DIMTYPEID_X, "x", "m", "X-coordinate" ) + call this%SetDimInfo( MeshBase1D_DIMTYPEID_XT, "xt", "m", "X-coordinate" ) + return end subroutine Meshbase1d_Init @@ -242,7 +249,7 @@ subroutine Meshbase1D_assignDomID( this, & return end subroutine Meshbase1D_assignDomID - subroutine MeshBase1D_setupLocalDom( mesh, & + subroutine MeshBase1D_setupLocalDom( lcmesh, & tileID, panelID, & i, Nprc, & dom_xmin, dom_xmax, & @@ -257,7 +264,7 @@ subroutine MeshBase1D_setupLocalDom( mesh, & use scale_localmesh_base, only: BCTYPE_INTERIOR implicit none - type(LocalMesh1D), intent(inout) :: mesh + type(LocalMesh1D), intent(inout) :: lcmesh integer, intent(in) :: tileID integer, intent(in) :: panelID integer, intent(in) :: i @@ -271,57 +278,57 @@ subroutine MeshBase1D_setupLocalDom( mesh, & real(RP) :: FX_lc(Ne+1) !----------------------------------------------------------------------------- - elem => mesh%refElem1D - mesh%tileID = tileID - mesh%panelID = panelID + elem => lcmesh%refElem1D + lcmesh%tileID = tileID + lcmesh%panelID = panelID !-- - mesh%Ne = Ne - mesh%Nv = Ne + 1 - mesh%NeS = 1 - mesh%NeE = mesh%Ne - mesh%NeA = mesh%Ne + 2 + lcmesh%Ne = Ne + lcmesh%Nv = Ne + 1 + lcmesh%NeS = 1 + lcmesh%NeE = lcmesh%Ne + lcmesh%NeA = lcmesh%Ne + 2 !delx = (dom_xmax - dom_xmin)/dble(Nprc) FX_lc(:) = Fx((i-1)*Ne+1:i*Ne) - mesh%xmin = FX_lc(1) - mesh%xmax = FX_lc(Ne+1) + lcmesh%xmin = FX_lc(1) + lcmesh%xmax = FX_lc(Ne+1) - allocate(mesh%pos_ev(mesh%Nv,1)) - allocate( mesh%EToV(mesh%Ne,2) ) - allocate( mesh%EToE(mesh%Ne,elem%Nfaces) ) - allocate( mesh%EToF(mesh%Ne,elem%Nfaces) ) - allocate( mesh%BCType(mesh%refElem%Nfaces,mesh%Ne) ) - allocate( mesh%VMapM(elem%NfpTot, mesh%Ne) ) - allocate( mesh%VMapP(elem%NfpTot, mesh%Ne) ) - allocate( mesh%MapM(elem%NfpTot, mesh%Ne) ) - allocate( mesh%MapP(elem%NfpTot, mesh%Ne) ) + allocate(lcmesh%pos_ev(lcmesh%Nv,1)) + allocate( lcmesh%EToV(lcmesh%Ne,2) ) + allocate( lcmesh%EToE(lcmesh%Ne,elem%Nfaces) ) + allocate( lcmesh%EToF(lcmesh%Ne,elem%Nfaces) ) + allocate( lcmesh%BCType(lcmesh%refElem%Nfaces,lcmesh%Ne) ) + allocate( lcmesh%VMapM(elem%NfpTot, lcmesh%Ne) ) + allocate( lcmesh%VMapP(elem%NfpTot, lcmesh%Ne) ) + allocate( lcmesh%MapM(elem%NfpTot, lcmesh%Ne) ) + allocate( lcmesh%MapP(elem%NfpTot, lcmesh%Ne) ) - mesh%BCType(:,:) = BCTYPE_INTERIOR + lcmesh%BCType(:,:) = BCTYPE_INTERIOR !---- - call MeshUtil1D_genLineDomain( mesh%pos_ev, mesh%EToV, & ! (out) - mesh%Ne, mesh%xmin, mesh%xmax, FX=FX_lc ) ! (in) + call MeshUtil1D_genLineDomain( lcmesh%pos_ev, lcmesh%EToV, & ! (out) + lcmesh%Ne, lcmesh%xmin, lcmesh%xmax, FX=FX_lc ) ! (in) !--- - call MeshBase1D_setGeometricInfo( mesh ) + call MeshBase1D_setGeometricInfo( lcmesh ) !--- - call MeshUtil1D_genConnectivity( mesh%EToE, mesh%EToF, & ! (out) - & mesh%EToV, mesh%Ne, elem%Nfaces ) ! (in) + call MeshUtil1D_genConnectivity( lcmesh%EToE, lcmesh%EToF, & ! (out) + & lcmesh%EToV, lcmesh%Ne, elem%Nfaces ) ! (in) !--- - call MeshUtil1D_BuildInteriorMap( mesh%VmapM, mesh%VMapP, mesh%MapM, mesh%MapP, & - & mesh%pos_en, mesh%pos_ev, mesh%EToE, mesh%EtoF, mesh%EtoV, & - & elem%Fmask, mesh%Ne, elem%Np, elem%Nfp, elem%Nfaces, mesh%Nv ) + call MeshUtil1D_BuildInteriorMap( lcmesh%VmapM, lcmesh%VMapP, lcmesh%MapM, lcmesh%MapP, & + & lcmesh%pos_en, lcmesh%pos_ev, lcmesh%EToE, lcmesh%EtoF, lcmesh%EtoV, & + & elem%Fmask, lcmesh%Ne, elem%Np, elem%Nfp, elem%Nfaces, lcmesh%Nv ) - call MeshUtil1D_genPatchBoundaryMap( mesh%VMapB, mesh%MapB, mesh%VMapP, & - & mesh%pos_en, mesh%xmin, mesh%xmax, & - & elem%Fmask, mesh%Ne, elem%Np, elem%Nfp, elem%Nfaces, mesh%Nv) + call MeshUtil1D_genPatchBoundaryMap( lcmesh%VMapB, lcmesh%MapB, lcmesh%VMapP, & + & lcmesh%pos_en, lcmesh%xmin, lcmesh%xmax, & + & elem%Fmask, lcmesh%Ne, elem%Np, elem%Nfp, elem%Nfaces, lcmesh%Nv) return end subroutine MeshBase1D_setupLocalDom diff --git a/FElib/src/mesh/scale_mesh_base2d.F90 b/FElib/src/mesh/scale_mesh_base2d.F90 index 5e0141d3..751459b0 100644 --- a/FElib/src/mesh/scale_mesh_base2d.F90 +++ b/FElib/src/mesh/scale_mesh_base2d.F90 @@ -45,7 +45,12 @@ end subroutine MeshBase2D_generate ! !++ Public parameters & variables ! - + integer, public :: MeshBase2D_DIMTYPE_NUM = 4 + integer, public :: MeshBase2D_DIMTYPEID_X = 1 + integer, public :: MeshBase2D_DIMTYPEID_Y = 2 + integer, public :: MeshBase2D_DIMTYPEID_XY = 3 + integer, public :: MeshBase2D_DIMTYPEID_XYT = 4 + !----------------------------------------------------------------------------- ! !++ Private procedure @@ -73,14 +78,21 @@ subroutine MeshBase2D_Init(this, & !----------------------------------------------------------------------------- this%refElem2D => refElem - call MeshBase_Init( this, refElem, NLocalMeshPerPrc, 4, & - nprocs ) + call MeshBase_Init( this, & + MeshBase2D_DIMTYPE_NUM, refElem, & + NLocalMeshPerPrc, 4, & + nprocs ) allocate( this%lcmesh_list(this%LOCAL_MESH_NUM) ) do n=1, this%LOCAL_MESH_NUM call LocalMesh2D_Init( this%lcmesh_list(n), refElem, myrank ) end do + call this%SetDimInfo( MeshBase2D_DIMTYPEID_X, "x", "m", "X-coordinate" ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_Y, "y", "m", "Y-coordinate" ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_XY, "xy", "m", "XY-coordinate" ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, "xyt", "m", "XY-coordinate" ) + return end subroutine MeshBase2D_Init diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index 240b3d8d..3012dc94 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -54,6 +54,13 @@ end subroutine MeshBase3D_getMesh2D ! !++ Public parameters & variables ! + integer, public :: MeshBase3D_DIMTYPE_NUM = 6 + integer, public :: MeshBase3D_DIMTYPEID_X = 1 + integer, public :: MeshBase3D_DIMTYPEID_Y = 2 + integer, public :: MeshBase3D_DIMTYPEID_Z = 3 + integer, public :: MeshBase3D_DIMTYPEID_XYZ = 4 + integer, public :: MeshBase3D_DIMTYPEID_XYZT = 5 + integer, public :: MeshBase3D_DIMTYPEID_ZT = 6 !----------------------------------------------------------------------------- ! @@ -83,13 +90,22 @@ subroutine MeshBase3D_Init(this, & !----------------------------------------------------------------------------- this%refElem3D => refElem - call MeshBase_Init( this, refElem, NLocalMeshPerPrc, NsideTile, nproc ) + call MeshBase_Init( this, & + MeshBase3D_DIMTYPE_NUM, refElem, & + NLocalMeshPerPrc, NsideTile, nproc ) allocate( this%lcmesh_list(this%LOCAL_MESH_NUM) ) do n=1, this%LOCAL_MESH_NUM call LocalMesh3D_Init( this%lcmesh_list(n), refElem, myrank ) end do + call this%SetDimInfo( MeshBase3D_DIMTYPEID_X, "x", "m", "X-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_Y, "y", "m", "Y-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_Z, "z", "m", "Z-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_ZT, "z", "m", "Z-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, "xyz", "m", "XYZ-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, "xyzt", "m", "XYZ-coordinate" ) + return end subroutine MeshBase3D_Init diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index ee9343ac..668cf332 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -307,7 +307,6 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & lcmesh%panelID = panelID !-- - lcmesh%Ne = NeX * NeY * NeZ lcmesh%Ne2D = NeX * NeY lcmesh%Nv = (NeX + 1)*(NeY + 1)*(NeZ + 1) @@ -319,6 +318,7 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & lcmesh%NeY = NeY lcmesh%NeZ = NeZ + !-- delx = (dom_xmax - dom_xmin)/dble(NprcX) dely = (dom_ymax - dom_ymin)/dble(NprcY) FZ_lc(:) = Fz((k-1)*NeZ+1:k*NeZ+1) @@ -329,6 +329,7 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & lcmesh%zmin = FZ_lc(1) lcmesh%zmax = FZ_lc(NeZ+1) + !- allocate( lcmesh%pos_ev(lcmesh%Nv,3) ) allocate( lcmesh%EToV(lcmesh%Ne,elem%Nv) ) allocate( lcmesh%EToE(lcmesh%Ne,elem%Nfaces) ) diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 index d7d81b64..1e73578a 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 @@ -9,8 +9,11 @@ module scale_mesh_cubedspheredom2d use scale_precision use scale_mesh_base2d, only: & - MeshBase2D, MeshBase2D_Init, MeshBase2D_Final, & - MeshBase2D_setGeometricInfo + MeshBase2D, MeshBase2D_Init, MeshBase2D_Final, & + MeshBase2D_setGeometricInfo, & + MeshBase2D_DIMTYPE_NUM, & + MeshBase2D_DIMTYPEID_X, MeshBase2D_DIMTYPEID_Y, & + MeshBase2D_DIMTYPEID_XY, MeshBase2D_DIMTYPEID_XYT use scale_localmesh_2d, only: & LocalMesh2D @@ -90,6 +93,11 @@ subroutine MeshCubedSphereDom2D_Init(this, & call MeshBase2D_Init( this, refElem, NLocalMeshPerPrc, & nproc, myrank ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_X, "x", "1", "X-coordinate" ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_Y, "y", "1", "Y-coordinate" ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_XY, "xy", "1", "XY-coordinate" ) + call this%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, "xyt", "1", "XY-coordinate" ) + return end subroutine MeshCubedSphereDom2D_Init @@ -265,9 +273,8 @@ subroutine MeshCubedSphereDom2D_setupLocalDom( lcmesh, & elem => lcmesh%refElem2D lcmesh%tileID = tileID lcmesh%panelID = panelID - + !-- - lcmesh%Ne = NeX * NeY lcmesh%Nv = (NeX + 1)*(NeY + 1) lcmesh%NeS = 1 @@ -277,6 +284,7 @@ subroutine MeshCubedSphereDom2D_setupLocalDom( lcmesh, & lcmesh%NeX = NeX lcmesh%NeY = NeY + !-- delx = ( dom_xmax - dom_xmin ) / dble(NprcX) dely = ( dom_ymax - dom_ymin ) / dble(NprcY) @@ -285,6 +293,7 @@ subroutine MeshCubedSphereDom2D_setupLocalDom( lcmesh, & lcmesh%ymin = dom_ymin + (j-1)*dely lcmesh%ymax = dom_ymin + j *dely + !-- allocate( lcmesh%pos_ev(lcmesh%Nv,2) ) allocate( lcmesh%EToV(lcmesh%Ne,elem%Nv) ) allocate( lcmesh%EToE(lcmesh%Ne,elem%Nfaces) ) From 7e19f00f348a60e08bf69653cf891c6830f09c33 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 15:27:59 +0900 Subject: [PATCH 02/98] Implement a global shallow water model with cubed sphere mesh. --- FElib/src/Makefile | 3 +- FElib/src/data/scale_meshfieldcomm_base.F90 | 13 - .../scale_meshfieldcomm_cubedspheredom2d.F90 | 97 +- FElib/src/depend | 4 +- Mkinclude | 1 + model/global_shallow_water/src/Makefile | 146 +++ .../src/global_shallow_water.F90 | 295 ++++++ .../src/global_shallow_water_init.F90 | 183 ++++ model/global_shallow_water/src/mod_exp.F90 | 143 +++ .../src/mod_globalsw_component.F90 | 219 ++++ model/global_shallow_water/src/mod_sw_bnd.F90 | 79 ++ model/global_shallow_water/src/mod_sw_dyn.F90 | 932 ++++++++++++++++++ .../src/mod_sw_dyn_vars.F90 | 311 ++++++ .../global_shallow_water/src/mod_sw_mesh.F90 | 159 +++ .../global_shallow_water/src/mod_sw_vars.F90 | 873 ++++++++++++++++ .../src/util/mod_user.F90 | 110 +++ 16 files changed, 3544 insertions(+), 24 deletions(-) create mode 100644 model/global_shallow_water/src/Makefile create mode 100644 model/global_shallow_water/src/global_shallow_water.F90 create mode 100644 model/global_shallow_water/src/global_shallow_water_init.F90 create mode 100644 model/global_shallow_water/src/mod_exp.F90 create mode 100644 model/global_shallow_water/src/mod_globalsw_component.F90 create mode 100644 model/global_shallow_water/src/mod_sw_bnd.F90 create mode 100644 model/global_shallow_water/src/mod_sw_dyn.F90 create mode 100644 model/global_shallow_water/src/mod_sw_dyn_vars.F90 create mode 100644 model/global_shallow_water/src/mod_sw_mesh.F90 create mode 100644 model/global_shallow_water/src/mod_sw_vars.F90 create mode 100644 model/global_shallow_water/src/util/mod_user.F90 diff --git a/FElib/src/Makefile b/FElib/src/Makefile index 1e61a042..3b4da62c 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -95,7 +95,8 @@ OBJS_NAME_FLUID_DYN_SOLVER = \ scale_atm_dyn_dgm_nonhydro3d_hevi.o \ scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o \ scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.o \ - scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.o + scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.o \ + scale_atm_dyn_dgm_globalsw.o OBJS_NAME_TURBULENCE = \ scale_atm_phy_tb_dgm_smg.o diff --git a/FElib/src/data/scale_meshfieldcomm_base.F90 b/FElib/src/data/scale_meshfieldcomm_base.F90 index 97ccc7a5..cc53797f 100644 --- a/FElib/src/data/scale_meshfieldcomm_base.F90 +++ b/FElib/src/data/scale_meshfieldcomm_base.F90 @@ -86,19 +86,6 @@ subroutine MeshFieldCommBase_get(this, field_list, varid_s) integer, intent(in) :: varid_s end subroutine MeshFieldCommBase_get - subroutine MeshFieldComm_get_vec( this, & - & varid_s, U, V, u1, u2 ) - - import MeshFieldCommBase - import MeshFieldBase - class(MeshFieldCommBase), intent(in) :: this - integer, intent(in) :: varid_s - class(MeshFieldBase), intent(inout) :: U - class(MeshFieldBase), intent(inout) :: V - class(MeshFieldBase), intent(inout), optional :: u1 - class(MeshFieldBase), intent(inout), optional :: u2 - end subroutine MeshFieldComm_get_vec - subroutine MeshFieldCommBase_Exchange(this) import MeshFieldCommBase class(MeshFieldCommBase), intent(inout) :: this diff --git a/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 index 0d08471c..b48359a5 100644 --- a/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 +++ b/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 @@ -28,14 +28,20 @@ module scale_meshfieldcomm_cubedspheredom2d !++ Public type & procedure ! + type :: VecCovariantComp + type(MeshField2D), pointer :: u1 => null() + type(MeshField2D), pointer :: u2 => null() + end type type, public, extends(MeshFieldCommBase) :: MeshFieldCommCubedSphereDom2D class(MeshCubedSphereDom2D), pointer :: mesh2d + type(VecCovariantComp), allocatable :: vec_covariant_comp_ptrlist(:) contains - procedure, public :: Init => MeshFieldCommCubedSphereDom2D_Init - procedure, public :: Put => MeshFieldCommCubedSphereDom2D_put - procedure, public :: Get => MeshFieldCommCubedSphereDom2D_get + procedure, public :: Init => MeshFieldCommCubedSphereDom2D_Init + procedure, public :: Put => MeshFieldCommCubedSphereDom2D_put + procedure, public :: Get => MeshFieldCommCubedSphereDom2D_get procedure, public :: Exchange => MeshFieldCommCubedSphereDom2D_exchange + procedure, public :: SetCovariantVec => MeshFieldCommCubedSphereDom2D_set_covariantvec procedure, public :: Final => MeshFieldCommCubedSphereDom2D_Final end type MeshFieldCommCubedSphereDom2D @@ -46,9 +52,9 @@ module scale_meshfieldcomm_cubedspheredom2d !----------------------------------------------------------------------------- ! - !++ Private procedure + !++ Private type & procedure ! - + !----------------------------------------------------------------------------- ! !++ Private parameters & variables @@ -72,8 +78,12 @@ subroutine MeshFieldCommCubedSphereDom2D_Init( this, & this%mesh2d => mesh2d lcmesh => mesh2d%lcmesh_list(1) bufsize_per_field = 2*(lcmesh%NeX + lcmesh%NeY)*lcmesh%refElem2D%Nfp - call MeshFieldCommBase_Init( this, sfield_num, hvfield_num, bufsize_per_field, 4, mesh2d) + call MeshFieldCommBase_Init( this, sfield_num, hvfield_num, bufsize_per_field, 4, mesh2d ) + if (hvfield_num > 0) then + allocate( this%vec_covariant_comp_ptrlist(hvfield_num) ) + end if + return end subroutine MeshFieldCommCubedSphereDom2D_Init @@ -84,11 +94,30 @@ subroutine MeshFieldCommCubedSphereDom2D_Final( this ) class(MeshFieldCommCubedSphereDom2D), intent(inout) :: this !----------------------------------------------------------------------------- + if ( this%hvfield_num > 0 ) then + deallocate( this%vec_covariant_comp_ptrlist ) + end if + call MeshFieldCommBase_Final( this ) return end subroutine MeshFieldCommCubedSphereDom2D_Final + subroutine MeshFieldCommCubedSphereDom2D_set_covariantvec( & + this, hvfield_ID, u1, u2 ) + implicit none + class(MeshFieldCommCubedSphereDom2D), intent(inout) :: this + integer, intent(in) :: hvfield_ID + type(MeshField2D), intent(in), target :: u1 + type(MeshField2D), intent(in), target :: u2 + !-------------------------------------------------------------- + + this%vec_covariant_comp_ptrlist(hvfield_ID)%u1 => u1 + this%vec_covariant_comp_ptrlist(hvfield_ID)%u2 => u2 + + return + end subroutine MeshFieldCommCubedSphereDom2D_set_covariantvec + subroutine MeshFieldCommCubedSphereDom2D_put(this, field_list, varid_s) implicit none class(MeshFieldCommCubedSphereDom2D), intent(inout) :: this @@ -121,16 +150,44 @@ subroutine MeshFieldCommCubedSphereDom2D_get(this, field_list, varid_s) integer :: i integer :: n type(Localmesh2d), pointer :: lcmesh + + integer :: varnum + integer :: varid_e + integer :: varid_vec_s + type(MeshField2D), pointer :: u1, u2 !----------------------------------------------------------------------------- - do i=1, size(field_list) + varnum = size(field_list) + + do i=1, varnum do n=1, this%mesh2d%LOCAL_MESH_NUM lcmesh => this%mesh2d%lcmesh_list(n) call MeshFieldCommBase_set_bounddata( this%recv_buf(:,varid_s+i-1,n), lcmesh%refElem, lcmesh, & !(in) - field_list(i)%field2d%local(n)%val ) !(out) + field_list(i)%field2d%local(n)%val ) !(out) end do end do + varid_e = varid_s + varnum - 1 + if ( varid_e > this%sfield_num ) then + do i=1, this%hvfield_num + + varid_vec_s = this%sfield_num + 2*i - 1 + if ( varid_vec_s > varid_e ) exit + + if ( associated(this%vec_covariant_comp_ptrlist(i)%u1 ) & + .and. associated(this%vec_covariant_comp_ptrlist(i)%u2 ) ) then + + do n=1, this%mesh2d%LOCAL_MESH_NUM + call set_boundary_data2D_u1u2( & + this%recv_buf(:,varid_vec_s,n), this%recv_buf(:,varid_vec_s+1,n), & ! (in) + lcmesh%refElem2D, lcmesh, lcmesh%G_ij, & ! (in) + this%vec_covariant_comp_ptrlist(i)%u1%local(n)%val, & ! (out) + this%vec_covariant_comp_ptrlist(i)%u2%local(n)%val ) ! (out) + end do + end if + end do + end if + return end subroutine MeshFieldCommCubedSphereDom2D_get @@ -255,7 +312,6 @@ subroutine MeshFieldCommCubedSphereDom2D_exchange( this ) fpos2D, f, is_f(f), Nnode_LCMeshFace(f), 2 ) ire = irs + commdata%Nnode_LCMeshFace - 1 - this%recv_buf(irs:ire,:,n) = 1.0_RP do varid=this%sfield_num+1, this%field_num_tot-1, 2 call CubedSphereCnv_LonLat2CSVec( & lcmesh%panelID, lcfpos2D(:,1), lcfpos2D(:,2), Nnode_LCMeshFace(f), & @@ -315,4 +371,27 @@ subroutine extract_boundary_data2D( var, refElem, mesh, buf ) return end subroutine extract_boundary_data2D + subroutine set_boundary_data2D_u1u2( buf_U, buf_V, & + elem, mesh, G_ij, & + u1, u2) + + implicit none + + type(ElementBase2D), intent(in) :: elem + type(LocalMesh2D), intent(in) :: mesh + real(DP), intent(in) :: buf_U(elem%Nfp * mesh%NeX * 4) + real(DP), intent(in) :: buf_V(elem%Nfp * mesh%NeX * 4) + real(DP), intent(in) :: G_ij(elem%Np * mesh%Ne,2,2) + real(DP), intent(inout) :: u1(elem%Np * mesh%NeA) + real(DP), intent(inout) :: u2(elem%Np * mesh%NeA) + !------------------------------------------------------------ + + u1(elem%Np*mesh%NeE+1:elem%Np*mesh%NeE+size(buf_U)) & + = G_ij(mesh%VmapB,1,1) * buf_U(:) + G_ij(mesh%VmapB,1,2) * buf_V(:) + u2(elem%Np*mesh%NeE+1:elem%Np*mesh%NeE+size(buf_U)) & + = G_ij(mesh%VmapB,2,1) * buf_U(:) + G_ij(mesh%VmapB,2,2) * buf_V(:) + + return + end subroutine set_boundary_data2D_u1u2 + end module scale_meshfieldcomm_cubedspheredom2d \ No newline at end of file diff --git a/FElib/src/depend b/FElib/src/depend index d5d089f0..cc7dd1e1 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -1,3 +1,4 @@ +$(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.o: fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_gmres.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.o: fluid_dyn_solver/scale_atm_dyn_dgm_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro2d.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o @@ -17,7 +18,7 @@ $(OBJ_DIR)/scale_element_line.o: element/scale_element_line.F90 $(DEPENDLIB) $(O $(OBJ_DIR)/scale_element_modalfilter.o: element/scale_element_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_element_quadrilateral.o: element/scale_element_quadrilateral.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o $(OBJ_DIR)/scale_file_base_meshfield.o: file/scale_file_base_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o -$(OBJ_DIR)/scale_file_common_meshfield.o: file/scale_file_common_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_polynominal.o +$(OBJ_DIR)/scale_file_common_meshfield.o: file/scale_file_common_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_polynominal.o $(OBJ_DIR)/scale_file_history_meshfield.o: file/scale_file_history_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_file_monitor_meshfield.o: file/scale_file_monitor_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_file_restart_meshfield.o: file/scale_file_restart_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_base_meshfield.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o @@ -62,6 +63,7 @@ $(OBJ_DIR)/scale_timeint_rk_butcher_tab.o: common/scale_timeint_rk_butcher_tab.F $(OBJ_DIR)/scale_variableinfo.o: data/scale_variableinfo.F90 $(DEPENDLIB) MODS = \ + $(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro2d.mod \ diff --git a/Mkinclude b/Mkinclude index 62fefa30..704c4ac1 100644 --- a/Mkinclude +++ b/Mkinclude @@ -17,6 +17,7 @@ endif DCUTILSDIR = $(TOPDIR)/dc_utils SCALEFELIBDIR = $(TOPDIR)/FElib +GLOBALSWDIR = $(TOPDIR)/model/global_shallow_water ATMNONHYDRO2DDIR = $(TOPDIR)/model/atm_nonhydro2d ATMNONHYDRO3DDIR = $(TOPDIR)/model/atm_nonhydro3d diff --git a/model/global_shallow_water/src/Makefile b/model/global_shallow_water/src/Makefile new file mode 100644 index 00000000..891b3cf6 --- /dev/null +++ b/model/global_shallow_water/src/Makefile @@ -0,0 +1,146 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../..) +BUILD_DIR = ./.libs +SYSDEP_DIR = $(TOPDIR)/sysdep + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + +BINNAME = global_shallow_water +INITNAME = global_shallow_water_init + +BINS = $(BINDIR)/$(BINNAME)$(POSTFIX) \ + $(BINDIR)/$(INITNAME)$(POSTFIX) + +LIBS = $(LIBDIR)/libScaleFECore.a + +VERSION = $(shell git rev-parse --short HEAD 2> /dev/null) +ifeq ($(VERSION),) + VERSION = $(shell cat VERSION) +else + VERSION := $(VERSION) +endif + +VPATH = \ + $(BUILD_DIR): \ + util: + +OBJS = \ + mod_user.o \ + mod_exp.o \ + mod_globalsw_component.o \ + mod_sw_dyn.o \ + mod_sw_dyn_vars.o \ + mod_sw_vars.o \ + mod_sw_bnd.o \ + mod_sw_mesh.o + + +all: + $(MAKE) build + $(MAKE) install + +build: + $(MAKE) info + $(MAKE) makelib + @echo;echo "Entering scale-dg global shallow water ...";echo "Current version is " $(VERSION) + mkdir -p $(BUILD_DIR) + $(MAKE) $(subst $(BINDIR),$(BUILD_DIR),$(BINS)) + @echo "Complete making scale-dg-globalsw ." + +install: + mkdir -p $(BINDIR) + $(MAKE) $(BINS) + +info: + @$(MAKE) -C $(SCALEFELIBDIR)/src --no-print-directory info + @echo + @echo "SCALE-DG" + @$(MAKE) --no-print-directory conflog + +makelib: + $(MAKE) -C $(SCALEFELIBDIR)/src + +$(BUILD_DIR)/$(BINNAME)$(POSTFIX): $(BUILD_DIR)/$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o $(LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) + +$(BUILD_DIR)/$(INITNAME)$(POSTFIX) : $(BUILD_DIR)/$(INITNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o $(LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) + +$(BUILD_DIR)/$(BINNAME).o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o +$(BUILD_DIR)/$(INITNAME).o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o +$(BUILD_DIR)/mod_user.o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(SUB_OBJS)) $(BUILD_DIR)/mod_exp.o + +$(BINDIR)/$(BINNAME)$(POSTFIX) : $(BUILD_DIR)/$(BINNAME)$(POSTFIX) + install $< $@ + +$(BINDIR)/$(INITNAME)$(POSTFIX) : $(BUILD_DIR)/$(INITNAME)$(POSTFIX) + install $< $@ + +allclean: distclean + $(MAKE) -C $(SCALEFELIBDIR)/src allclean + rm -f $(BINDIR)/$(BINNAME)* + rm -f $(BINDIR)/$(PPNAME)* + rm -rf $(TOPDIR)/bin + + +distclean: clean + rm -f $(BINDIR)/$(BINNAME) + +clean: + rm -rf $(BUILD_DIR) + rm -f *.o *.mod *.lst *~ + +.SUFFIXES: +.SUFFIXES: .o .F90 .mod + +%.mod: %.F90 + $(MAKE) $(patsubst %.F90,%.o,$<) + +$(BUILD_DIR)/%.o: %.F90 + $(FC) $(FFLAGS) $(ADDITIONAL_FFLAGS) -DVERSION_MACRO=\"$(VERSION)\" -I$(BUILD_DIR) -I$(MODDIR) $(CONTRIB_INCLUDE) -I$(SCALEFELIBDIR)/include $(SCALE_NETCDF_INCLUDE) $(MODDIROPT) $(BUILD_DIR) -o $@ -c $< + +.PHONY : clean distclean allclean + +include $(TOPDIR)/utils/make/Make_environments + + +$(BUILD_DIR)/$(BINNAME).o: \ + $(BUILD_DIR)/mod_globalsw_component.o \ + $(BUILD_DIR)/mod_user.o + +$(BUILD_DIR)/$(INITNAME).o: \ + $(BUILD_DIR)/mod_globalsw_component.o \ + $(BUILD_DIR)/mod_user.o + +$(BUILD_DIR)/mod_globalsw_component.o: \ + $(BUILD_DIR)/mod_sw_dyn.o + +$(BUILD_DIR)/mod_sw_dyn.o: \ + $(BUILD_DIR)/mod_sw_dyn_vars.o \ + $(BUILD_DIR)/mod_sw_vars.o \ + $(BUILD_DIR)/mod_sw_bnd.o + +$(BUILD_DIR)/mod_user.o: \ + mod_user.F90 \ + $(BUILD_DIR)/mod_globalsw_component.o \ + $(BUILD_DIR)/mod_sw_vars.o \ + $(BUILD_DIR)/mod_exp.o + +$(BUILD_DIR)/mod_exp.o: \ + $(BUILD_DIR)/mod_sw_vars.o + +$(BUILD_DIR)/mod_sw_vars.o: \ + $(BUILD_DIR)/mod_sw_mesh.o + +$(BUILD_DIR)/mod_sw_dyn_vars.o: \ + $(BUILD_DIR)/mod_sw_mesh.o + +$(BUILD_DIR)/mod_sw_bnd.o: \ + $(BUILD_DIR)/mod_sw_mesh.o diff --git a/model/global_shallow_water/src/global_shallow_water.F90 b/model/global_shallow_water/src/global_shallow_water.F90 new file mode 100644 index 00000000..0e0d0bd0 --- /dev/null +++ b/model/global_shallow_water/src/global_shallow_water.F90 @@ -0,0 +1,295 @@ +!------------------------------------------------------------------------------- +!> Program global shallow water (a launcher of main routine) +!! +!! @par Description +!! global shallow water model +!! which is discretized by a discontinuous galerkin method. +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +program global_shallow_water + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_file_history, only: & + FILE_HISTORY_set_nowdate + + use scale_time_manager, only: & + TIME_manager_checkstate, TIME_manager_advance, & + TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP, TIME_NSTEP, & + TIME_DOresume, TIME_DOend + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_write + + use mod_globalsw_component, only: & + GlobalSWComponent + + use mod_user, only: & + USER_update, USER_calc_tendency + + implicit none + + integer :: nowstep + character(len=H_MID) :: timelabel + + type(GlobalSWComponent) :: swmodel + !------------------------------------------------------- + + call init() + + LOG_NEWLINE + LOG_PROGRESS(*) 'START TIMESTEP' + call PROF_setprefx('MAIN') + call PROF_rapstart('Loop', 0) + + do + !******************************************* + + ! report current time + call TIME_manager_checkstate() + + if (TIME_DOresume) then + ! set state from restart files + call restart_read() + call FILE_HISTORY_meshfield_write() + end if + + !* Advance time ********************************* + call TIME_manager_advance() + call FILE_HISTORY_set_nowdate( TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP ) + + if ( swmodel%IsActivated() .and. swmodel%time_manager%do_step ) then + call swmodel%update() + end if + + !- USER + call USER_update + + !* restart and monitor output ******************* + ! if ( swmodel%IsActivated() ) call swmodel%vars%Monitor() + ! call restart_write + ! call FILE_MONITOR_meshfield_write('MAIN', TIME_NOWSTEP) + + !* calc tendencies and diagnostices ************* + if ( swmodel%IsActivated() .and. swmodel%time_manager%do_step ) then + call swmodel%calc_tendency() + end if + + !- USER + call USER_calc_tendency + + !* output history files ************************* + + if ( swmodel%IsActivated() ) call swmodel%vars%History() + + call FILE_HISTORY_meshfield_write() + + !******************************************* + if (TIME_DOend) exit + + if( IO_L ) call flush(IO_FID_LOG) + end do + + call PROF_rapend('Loop', 0) + + LOG_PROGRESS(*) 'END TIMESTEP' + LOG_NEWLINE + + !########## Finalize ########## + call final() + +contains + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + subroutine restart_read() + implicit none + !-------------------------------------------- + + call swmodel%vars%Read_restart_file( swmodel%mesh ) + + !- History & Monitor + call swmodel%vars%History() + !call swmodel%vars%Monitor() + + return + end subroutine restart_read + + subroutine update() + use mod_user, only: USER_update + implicit none + + integer :: tm_process_id + logical :: is_update + integer :: inner_itr + !------------------------------------------------------------------------ + + !- ATMOS + if ( swmodel%dyn_proc%IsActivated() ) then + call PROF_start('GlobalSW_dynamics', 1) + tm_process_id = swmodel%dyn_proc%tm_process_id + is_update = swmodel%time_manager%Do_process( tm_process_id ) + + LOG_PROGRESS(*) 'shallow water / dynamics' + do inner_itr=1, swmodel%time_manager%Get_process_inner_itr_num( tm_process_id ) + call swmodel%dyn_proc%update( & + swmodel%mesh, swmodel%vars%PROGVARS_manager, swmodel%vars%AUXVARS_manager, & + swmodel%vars%PHYTENDS_manager, is_update ) + end do + call PROF_rapend('GlobalSW_dynamics', 1) + end if + + !########## Calculate diagnostic variables ########## + !call this%vars%Clac_diagnostics() + call swmodel%vars%AUXVARS_manager%MeshFieldComm_Exchange() + + !#### Check values ################################# + call swmodel%vars%Check() + + call USER_update() + + return + end subroutine update + + subroutine calc_tendency() + use mod_user, only: USER_calc_tendency + implicit none + !------------------------------------------------------------------------ + + call PROF_rapstart( 'GlobalSW_tendency', 1) + + !########## calculate tendency ########## + + !* Exchange halo data ( for physics ) + call PROF_rapstart( 'ATM_exchange_prgv', 2) + call swmodel%vars%PROGVARS_manager%MeshFieldComm_Exchange() + call PROF_rapend( 'ATM_exchange_prgv', 2) + + !- ATMOS + + !- USER + call USER_calc_tendency() + + call PROF_rapend( 'GlobalSW_tendency', 1) + + return + end subroutine calc_tendency + + subroutine init() + use scale_const, only: CONST_setup + use scale_calendar, only: CALENDAR_setup + use scale_random, only: RANDOM_setup + use scale_time_manager, only: TIME_manager_Init + use scale_file_history_meshfield, only: FILE_HISTORY_meshfield_setup + + use scale_time_manager, only: & + TIME_manager_Init, & + TIME_manager_report_timeintervals + use scale_meshfield_statistics, only: & + MeshField_statistics_setup + use scale_file_restart_meshfield, only: & + restart_file, & + FILE_restart_meshfield_setup + use scale_file_monitor_meshfield, only: & + FILE_monitor_meshfield_setup + + + use mod_user, only: USER_setup + implicit none + + integer :: comm, myrank, nprocs + logical :: ismaster + integer :: ierr + + character(len=H_MID) :: conf_name + !------------------------------------------------------------------------ + + call PRC_MPIstart( comm ) + + call PRC_SINGLECOM_setup( comm, & ! [IN] + nprocs, myrank, ismaster ) ! [OUT] + + call PRC_ERRHANDLER_setup( .false., ismaster ) ! [IN] + + ! setup scale_io + call get_command_argument(1, conf_name) + call IO_setup( "global_shallow_water", trim(conf_name) ) + + ! setup log + call IO_LOG_setup( myrank, ismaster ) + + ! setup profiler + call PROF_setup + call PROF_setprefx('INIT') + call PROF_rapstart( "ALL", 0 ) + + ! setup constants + call CONST_setup + + ! setup calendar & initial time + call CALENDAR_setup + + ! setup random number + call RANDOM_setup + + ! setup a module for restart file + call FILE_restart_meshfield_setup + call TIME_manager_Init( & + setup_TimeIntegration = .true., & + restart_in_basename = restart_file%in_basename ) + + ! setup submodels + call swmodel%setup() + + ! Setup user module + call USER_setup( swmodel ) + + !--- + call PROF_rapend( "ALL", 0 ) + return + end subroutine init + + subroutine final() + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_finalize + use scale_file_monitor_meshfield, only: & + FILE_monitor_meshfield_final + use scale_time_manager, only: & + TIME_manager_Final + implicit none + !------------------------------------------------------------------------ + + call PROF_setprefx('FIN') + call PROF_rapstart( "ALL", 0 ) + + call PROF_rapstart('Monit', 2) + call FILE_monitor_meshfield_final + call PROF_rapend ('Monit', 2) + + call PROF_rapstart('File', 2) + call FILE_HISTORY_meshfield_finalize() + call PROF_rapend ('File', 2) + + ! finalization submodels + call swmodel%finalize() + + !- + call TIME_manager_Final + + call PROF_rapend( "ALL", 0 ) + call PROF_rapreport + + call PRC_MPIfinish() + + return + end subroutine final + +end program global_shallow_water diff --git a/model/global_shallow_water/src/global_shallow_water_init.F90 b/model/global_shallow_water/src/global_shallow_water_init.F90 new file mode 100644 index 00000000..1e9973b1 --- /dev/null +++ b/model/global_shallow_water/src/global_shallow_water_init.F90 @@ -0,0 +1,183 @@ +!------------------------------------------------------------------------------- +!> Program global shallow water (a launcher of main routine) +!! +!! @par Description +!! global shallow water model +!! which is discretized by a discontinuous galerkin method. +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +program global_shallow_water_init + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_file_history, only: & + FILE_HISTORY_set_nowdate + + use scale_time_manager, only: & + TIME_manager_checkstate, TIME_manager_advance, & + TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP, TIME_NSTEP, & + TIME_DOresume, TIME_DOend + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_write + + use mod_globalsw_component, only: & + GlobalSWComponent + + use mod_user, only: & + USER_mkinit + + implicit none + + integer :: nowstep + character(len=H_MID) :: timelabel + + type(GlobalSWComponent) :: swmodel + !------------------------------------------------------- + + call init() + + LOG_NEWLINE + LOG_PROGRESS(*) 'START TIMESTEP' + call PROF_setprefx('MAIN') + + !- Execute mkinit + call PROF_rapstart('mkInit',1) + call USER_mkinit( swmodel ) + call PROF_rapend ('mkInit',1) + + !- Output + call PROF_rapstart('restart',1) + call restart_write() + call PROF_rapend ('restart',1) + + LOG_NEWLINE + + !########## Finalize ########## + call final() + +contains + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + subroutine restart_write + implicit none + !---------------------------------------- + + if ( swmodel%isActivated() ) call swmodel%vars%Write_restart_file() + + return + end subroutine restart_write + + subroutine init() + use scale_const, only: CONST_setup + use scale_calendar, only: CALENDAR_setup + use scale_random, only: RANDOM_setup + use scale_time_manager, only: TIME_manager_Init + use scale_file_history_meshfield, only: FILE_HISTORY_meshfield_setup + + use scale_time_manager, only: & + TIME_manager_Init, & + TIME_manager_report_timeintervals + use scale_meshfield_statistics, only: & + MeshField_statistics_setup + use scale_file_restart_meshfield, only: & + restart_file, & + FILE_restart_meshfield_setup + use scale_file_monitor_meshfield, only: & + FILE_monitor_meshfield_setup + + + use mod_user, only: USER_setup + implicit none + + integer :: comm, myrank, nprocs + logical :: ismaster + integer :: ierr + + character(len=H_MID) :: conf_name + !------------------------------------------------------------------------ + + call PRC_MPIstart( comm ) + + call PRC_SINGLECOM_setup( comm, & ! [IN] + nprocs, myrank, ismaster ) ! [OUT] + + call PRC_ERRHANDLER_setup( .false., ismaster ) ! [IN] + + ! setup scale_io + call get_command_argument(1, conf_name) + call IO_setup( "global_shallow_water_init", trim(conf_name) ) + + ! setup log + call IO_LOG_setup( myrank, ismaster ) + + ! setup profiler + call PROF_setup + call PROF_setprefx('INIT') + call PROF_rapstart( "All", 0 ) + + ! setup constants + call CONST_setup + + ! setup calendar & initial time + call CALENDAR_setup + call TIME_manager_Init( .false. ) + + ! setup random number + call RANDOM_setup + + ! setup a module for restart file + call FILE_restart_meshfield_setup + + ! setup submodels + call swmodel%setup() + + ! Setup user module + call USER_setup( swmodel ) + + !--- + call PROF_rapend( "All", 0 ) + return + end subroutine init + + subroutine final() + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_finalize + use scale_file_monitor_meshfield, only: & + FILE_monitor_meshfield_final + use scale_time_manager, only: & + TIME_manager_Final + implicit none + !------------------------------------------------------------------------ + + call PROF_setprefx('FIN') + call PROF_rapstart('All', 1) + + call PROF_rapstart('File', 2) + call FILE_HISTORY_meshfield_finalize() + call PROF_rapend ('File', 2) + + ! finalization submodels + call swmodel%finalize() + + !- + call TIME_manager_Final + + call PROF_rapend( "All", 1 ) + call PROF_rapreport + + call PRC_MPIfinish() + + return + end subroutine final + +end program global_shallow_water_init diff --git a/model/global_shallow_water/src/mod_exp.F90 b/model/global_shallow_water/src/mod_exp.F90 new file mode 100644 index 00000000..0a394776 --- /dev/null +++ b/model/global_shallow_water/src/mod_exp.F90 @@ -0,0 +1,143 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_exp + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV + + use scale_meshfield_base, only: MeshField2D + use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_element_base, only: ElementBase2D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_localmesh_2d, only: LocalMesh2D + + use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D + + use scale_localmeshfield_base, only: LocalMeshFieldBase + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + type, abstract, public :: experiment + character(len=H_SHORT) :: label + contains + procedure, public :: Init => exp_Init + procedure, public :: Final => exp_Final + procedure, public :: SetInitCond => exp_SetInitCond + procedure(exp_SetInitCond_lc), deferred :: setInitCond_lc + end type + + abstract interface + subroutine exp_SetInitCond_lc( & + this, h, U, V, hs, u1, u2, & + x, y, lcmesh, elem ) + + import experiment + import LocalMesh2D + import ElementBase2D + import RP + + class(experiment), intent(inout) :: this + type(LocalMesh2D), intent(in) :: lcmesh + class(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: h(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: hs(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u2(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + end subroutine exp_SetInitCond_lc + end interface + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + subroutine exp_Init( this, exp_name ) + implicit none + class(experiment), intent(inout) :: this + character(len=*), intent(in) :: exp_name + !---------------------------------------------------------------------- + + this%label = exp_name + return + end subroutine exp_Init + + subroutine exp_Final( this ) + implicit none + class(experiment), intent(inout) :: this + !---------------------------------------------------------------------- + + return + end subroutine exp_Final + + subroutine exp_SetInitCond( this, & + model_mesh, sw_prgvars_manager, sw_auxvars_manager ) + + use scale_meshfield_base, only: MeshFieldBase + use scale_model_var_manager, only: ModelVarManager + use scale_meshfieldcomm_base, only: MeshFieldContainer + use mod_sw_vars, only: & + SWVars_GetLocalMeshPrgVars + use mod_sw_mesh, only: SWMesh + + implicit none + + class(experiment), intent(inout) :: this + class(SWMesh), target, intent(in) :: model_mesh + class(ModelVarManager), intent(inout) :: sw_prgvars_manager + class(ModelVarManager), intent(inout) :: sw_auxvars_manager + + class(LocalMeshFieldBase), pointer :: h, U, V + class(LocalMeshFieldBase), pointer :: hs, u1, u2 + + integer :: n + class(LocalMesh2D), pointer :: lcmesh + class(MeshCubedSphereDom2D), pointer :: mesh + !---------------------------------------------------------------------- + + mesh => model_mesh%mesh + + do n=1, mesh%LOCAL_MESH_NUM + call SWVars_GetLocalMeshPrgVars( & + n, mesh, sw_prgvars_manager, sw_auxvars_manager, & + h, U, V, hs, u1, u2, lcmesh ) + + call this%setInitCond_lc( & + h%val, U%val, V%val, hs%val, u1%val, u2%val, & ! (out) + lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), & ! (in) + lcmesh, lcmesh%refElem2D ) ! (in) + end do + + return + end subroutine exp_SetInitCond + +end module mod_exp \ No newline at end of file diff --git a/model/global_shallow_water/src/mod_globalsw_component.F90 b/model/global_shallow_water/src/mod_globalsw_component.F90 new file mode 100644 index 00000000..4893a874 --- /dev/null +++ b/model/global_shallow_water/src/mod_globalsw_component.F90 @@ -0,0 +1,219 @@ +!------------------------------------------------------------------------------- +!> module global shallow water component +!! +!! @par Description +!! global shallow water component module +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_globalsw_component + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc + + use scale_mesh_base, only: MeshBase + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmeshfield_base, only: LocalMeshFieldBase + use scale_model_component, only: ModelComponent + + use mod_sw_vars, only: SWVars + use mod_sw_mesh, only: SWMesh + use mod_sw_dyn, only: SWDyn + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedure + ! + type, extends(ModelComponent), public :: GlobalSWComponent + type(SWMesh) :: mesh + type(SWVars) :: vars + type(SWDyn) :: dyn_proc + contains + procedure, public :: setup => SW_setup + procedure, public :: calc_tendency => SW_calc_tendency + procedure, public :: update => SW_update + procedure, public :: finalize => SW_finalize + end type GlobalSWComponent + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + !----------------------------------------------------------------------------- +contains +subroutine SW_setup( this ) + use scale_const, only: & + UNDEF8 => CONST_UNDEF8 + use scale_atmos_hydrometeor, only: & + ATMOS_HYDROMETEOR_setup + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_setup + use scale_time_manager, only: & + TIME_manager_Regist_component + + implicit none + + class(GlobalSWComponent), intent(inout) :: this + + logical :: ACTIVATE_FLAG = .true. + + real(DP) :: TIME_DT = UNDEF8 + character(len=H_SHORT) :: TIME_DT_UNIT = 'SEC' + real(DP) :: TIME_DT_RESTART = UNDEF8 + character(len=H_SHORT) :: TIME_DT_RESTART_UNIT = 'SEC' + + logical :: GlobalSW_DYN_DO = .true. + + namelist / PARAM_GLOBALSW / & + ACTIVATE_FLAG, & + TIME_DT, & + TIME_DT_UNIT, & + TIME_DT_RESTART, & + TIME_DT_RESTART_UNIT, & + GlobalSW_DYN_DO + + integer :: ierr + !-------------------------------------------------- + call PROF_rapstart( 'GlobalSW_setup', 1) + LOG_INFO('GlobalShallowWater_setup',*) 'Global shallow water model components ' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_GLOBALSW,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("GlobalShallowWater_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("GlobalShallowWater_setup",*) 'Not appropriate names in namelist PARAM_GLOBALSW. Check!' + call PRC_abort + endif + LOG_NML(PARAM_GLOBALSW) + + !************************************************ + call this%ModelComponent_Init('GlobalSW', ACTIVATE_FLAG ) + if ( .not. ACTIVATE_FLAG ) return + + !- Setup time manager + + call this%time_manager%Init( this%GetComponentName(), & + TIME_DT, TIME_DT_UNIT, & + TIME_DT_RESTART, TIME_DT_RESTART_UNIT ) + + call TIME_manager_Regist_component( this%time_manager ) + + !- Setup mesh + + call this%mesh%Init() + + !- Setup file I/O for atmospheric component + + call FILE_HISTORY_meshfield_setup( meshcubedsphere2D_=this%mesh%mesh ) + + !- Setup variables + + call this%vars%Init( this%mesh ) + + !- Setup each processes in atmospheric model ------------------------------------ + + !- Setup index for atmospheric tracers + call ATMOS_HYDROMETEOR_setup() + + !- Setup the module for atmosphere / dynamics + call this%dyn_proc%ModelComponentProc_Init( 'SWDyn', GlobalSW_DYN_DO ) + call this%dyn_proc%setup( this%mesh, this%time_manager ) + + call PROF_rapend( 'GlobalSW_setup', 1) + return +end subroutine SW_setup + +subroutine SW_update( this ) + implicit none + class(GlobalSWComponent), intent(inout) :: this + + integer :: tm_process_id + logical :: is_update + integer :: inner_itr + !------------------------------------------------------------------------ + + !- ATMOS + if ( this%dyn_proc%IsActivated() ) then + call PROF_rapstart('GlobalSW_dynamics', 1) + tm_process_id = this%dyn_proc%tm_process_id + is_update = this%time_manager%Do_process( tm_process_id ) + + LOG_PROGRESS(*) 'shallow water / dynamics' + do inner_itr=1, this%time_manager%Get_process_inner_itr_num( tm_process_id ) + call this%dyn_proc%update( & + this%mesh, this%vars%PROGVARS_manager, this%vars%AUXVARS_manager, & + this%vars%PHYTENDS_manager, is_update ) + end do + call PROF_rapend('GlobalSW_dynamics', 1) + end if + + !########## Calculate diagnostic variables ########## + !call this%vars%Clac_diagnostics() + call this%vars%AUXVARS_manager%MeshFieldComm_Exchange() + + !#### Check values ################################# + call this%vars%Check() + + return +end subroutine SW_update + +subroutine SW_calc_tendency( this ) + implicit none + class(GlobalSWComponent), intent(inout) :: this + !------------------------------------------------------------------------ + + call PROF_rapstart( 'GlobalSW_tendency', 1) + + !########## calculate tendency ########## + + !* Exchange halo data ( for physics ) + call PROF_rapstart( 'ATM_exchange_prgv', 2) + call this%vars%PROGVARS_manager%MeshFieldComm_Exchange() + call PROF_rapend( 'ATM_exchange_prgv', 2) + + call PROF_rapend( 'GlobalSW_tendency', 1) + + return +end subroutine SW_calc_tendency + +subroutine SW_finalize( this ) + implicit none + class(GlobalSWComponent), intent(inout) :: this + !-------------------------------------------------- + + LOG_INFO('GlobalSWComponent_finalize',*) + + if ( .not. this%IsActivated() ) return + + call this%dyn_proc%finalize() + + call this%vars%Final() + call this%mesh%Final() + call this%time_manager%Final() + + return +end subroutine SW_finalize + +end module mod_globalsw_component \ No newline at end of file diff --git a/model/global_shallow_water/src/mod_sw_bnd.F90 b/model/global_shallow_water/src/mod_sw_bnd.F90 new file mode 100644 index 00000000..5d7280f6 --- /dev/null +++ b/model/global_shallow_water/src/mod_sw_bnd.F90 @@ -0,0 +1,79 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_sw_bnd + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base + use scale_element_quadrilateral + use scale_localmesh_2d + use scale_mesh_rectdom2d + + use scale_localmeshfield_base, only: LocalMeshField2D + use scale_meshfield_base, only: MeshField2D + + use scale_mesh_bndinfo, only: & + MeshBndInfo + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + type, public :: SWBnd + contains + procedure :: Init => SW_bnd_setup + procedure :: Final => SW_bnd_finalize + end type + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + logical, save :: is_initialized = .false. + +contains + subroutine SW_bnd_setup( this ) + implicit none + class(SWBnd), intent(inout) :: this + !----------------------------------------------- + + is_initialized = .false. + return + end subroutine SW_bnd_setup + + subroutine SW_bnd_finalize( this ) + implicit none + class(SWBnd), intent(inout) :: this + !-------------------------------------- + + if (is_initialized) then + end if + + is_initialized = .false. + return + end subroutine SW_bnd_finalize +end module mod_sw_bnd \ No newline at end of file diff --git a/model/global_shallow_water/src/mod_sw_dyn.F90 b/model/global_shallow_water/src/mod_sw_dyn.F90 new file mode 100644 index 00000000..206a4626 --- /dev/null +++ b/model/global_shallow_water/src/mod_sw_dyn.F90 @@ -0,0 +1,932 @@ +!------------------------------------------------------------------------------- +!> module dynamical process +!! +!! @par Description +!! Module for shallow water equation +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_sw_dyn + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_prc + use scale_io + use scale_prof + use scale_const, only: & + UNDEF8 => CONST_UNDEF8 + + use scale_sparsemat, only: SparseMat + use scale_timeint_rk, only: TimeInt_RK + + use scale_mesh_base, only: MeshBase + use scale_mesh_base2d, only: MeshBase2D + + use scale_localmesh_base, only: LocalMeshBase + use scale_localmesh_2d, only: LocalMesh2D + use scale_element_base, only: & + ElementBase, ElementBase2D + + use scale_meshfield_base, only: MeshFieldBase + use scale_localmeshfield_base, only: LocalMeshFieldBase + + use scale_model_mesh_manager, only: ModelMeshBase + use scale_model_var_manager, only: ModelVarManager + use scale_model_component_proc, only: ModelComponentProc + + use scale_atm_dyn_dgm_globalsw, only: & + atm_dyn_dgm_globalsw_Init, & + atm_dyn_dgm_globalsw_Final, & + atm_dyn_dgm_globalsw_cal_tend + + use scale_element_modalfilter, only: ModalFilter + + use mod_sw_mesh, only: SWMesh + use mod_sw_vars, only: & + SWVars_GetLocalMeshPrgVar, & + SWVars_GetLocalMeshPrgVars, & + SW_PROGVARS_NUM, & + h_ID => SW_PROGVARS_h_ID, & + U_ID => SW_PROGVARS_U_ID, & + V_ID => SW_PROGVARS_V_ID, & + hs_ID => SW_AUXVARS_hs_ID, & + u1_ID => SW_AUXVARS_u1_ID, & + u2_ID => SW_AUXVARS_u2_ID + + use mod_sw_bnd, only:SWBnd + + use mod_sw_dyn_vars, only: & + SWDynVars, & + SWDynAuxVars_GetLocalMeshFields + + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedure + ! + + abstract interface + subroutine atm_dyn_globalsw_cal_tend_ex( & + h_dt, U_dt, V_dt, & ! (out) + h_, U_, V_, hs_, u1_, u2_, CORIOLIS, & ! (in) + Dx, Dy, Sx, Sy, Lift, lmesh, elem ) + + import RP + import LocalMesh2D + import elementbase2D + import SparseMat + implicit none + + class(LocalMesh2D), intent(in) :: lmesh + class(elementbase2D), intent(in) :: elem + type(SparseMat), intent(in) :: Dx, Dy, Sx, Sy, Lift + real(RP), intent(out) :: h_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: U_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: V_dt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: h_ (elem%Np,lmesh%NeA) + real(RP), intent(in) :: U_ (elem%Np,lmesh%NeA) + real(RP), intent(in) :: V_ (elem%Np,lmesh%NeA) + real(RP), intent(in) :: hs_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: u1_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: u2_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: CORIOLIS(elem%Np,lmesh%NeA) + end subroutine atm_dyn_globalsw_cal_tend_ex + end interface + + type, extends(ModelComponentProc), public :: SWDyn + integer :: EQS_TYPEID + type(TimeInt_RK), allocatable :: tint(:) + type(SWBnd) :: boundary_cond + type(SWDynVars) :: dyn_vars + + procedure (atm_dyn_globalsw_cal_tend_ex), pointer, nopass :: cal_tend_ex => null() + + ! explicit numerical diffusion + logical :: CALC_NUMDIFF_FLAG + integer :: ND_LAPLACIAN_NUM + real(RP) :: ND_COEF_H + + ! element-wise modal filter + logical :: MODALFILTER_FLAG + type(ModalFilter) :: modal_filter + + contains + procedure, public :: setup => SWDyn_setup + procedure, public :: calc_tendency => SWDyn_calc_tendency + procedure, public :: update => SWDyn_update + procedure, public :: finalize => SWDyn_finalize + end type SWDyn + + !----------------------------------------------------------------------------- + !++ Public parameters & variables + !----------------------------------------------------------------------------- + + integer, public, parameter :: EQS_TYPEID_GLOBAL_SHALLOW_WATER = 1 + + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + ! private :: cal_numfilter_tend + ! private :: add_phy_tend + + private :: setup_modalfilter + private :: setup_numdiff + private :: setup_coriolis_parameter + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + !----------------------------------------------------------------------------- + +contains + + subroutine SWDyn_setup( this, model_mesh, tm_parent_comp ) + use mod_sw_mesh, only: SWMesh + use mod_sw_vars, only: SW_PROGVARS_NUM + use scale_time_manager, only: TIME_manager_component + + implicit none + + class(SWDyn), intent(inout) :: this + class(ModelMeshBase), target, intent(in) :: model_mesh + class(TIME_manager_component), intent(inout) :: tm_parent_comp + + character(len=H_MID) :: EQS_TYPE = "GLOBAL_SHALLOW_WATER" + character(len=H_SHORT) :: TINTEG_TYPE = 'RK_TVD_3' + real(DP) :: TIME_DT = UNDEF8 + character(len=H_SHORT) :: TIME_DT_UNIT = 'SEC' + + logical :: MODALFILTER_FLAG = .false. + logical :: NUMDIFF_FLAG = .false. + + namelist / PARAM_SW_DYN / & + EQS_TYPE, & + TINTEG_TYPE, & + TIME_DT, & + TIME_DT_UNIT, & + MODALFILTER_FLAG, & + NUMDIFF_FLAG + + class(SWMesh), pointer :: sw_mesh + class(MeshBase), pointer :: ptr_mesh + class(LocalMeshBase), pointer :: ptr_lcmesh + class(ElementBase2D), pointer :: elem2D + integer :: n + real(DP) :: dtsec + + integer :: ierr + !-------------------------------------------------- + + if (.not. this%IsActivated()) return + LOG_INFO('SWDyn_setup',*) + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_SW_DYN,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("SW_DYN_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("SW_DYN_setup",*) 'Not appropriate names in namelist PARAM_SW_DYN. Check!' + call PRC_abort + endif + LOG_NML(PARAM_SW_DYN) + + !- get mesh -------------------------------------------------- + + call model_mesh%GetModelMesh( ptr_mesh ) + select type(model_mesh) + type is (SWMesh) + sw_mesh => model_mesh + end select + + !- Setup the temporal integrator + + call tm_parent_comp%Regist_process( 'SW_DYN', TIME_DT, TIME_DT_UNIT, & ! (in) + this%tm_process_id ) ! (out) + + dtsec = tm_parent_comp%process_list(this%tm_process_id)%dtsec + + allocate( this%tint(ptr_mesh%LOCAL_MESH_NUM) ) + do n = 1, ptr_mesh%LOCAL_MESH_NUM + call ptr_mesh%GetLocalMesh( n, ptr_lcmesh ) + call this%tint(n)%Init( TINTEG_TYPE, dtsec, SW_PROGVARS_NUM, 2, & + (/ ptr_mesh%refElem%Np, ptr_lcmesh%NeA /) ) + end do + + !- initialize an object to manage boundary conditions + call this%boundary_cond%Init() + + !- initialize the variables + call this%dyn_vars%Init( model_mesh ) + call setup_coriolis_parameter( this%dyn_vars, sw_mesh ) + + !- Initialize a module for 3D dynamical core + + select case(EQS_TYPE) + case("GLOBAL_SHALLOW_WATER") + this%EQS_TYPEID = EQS_TYPEID_GLOBAL_SHALLOW_WATER + call atm_dyn_dgm_globalsw_Init( sw_mesh%mesh ) + this%cal_tend_ex => atm_dyn_dgm_globalsw_cal_tend + case default + LOG_ERROR("SW_DYN_setup",*) 'Not appropriate names in namelist PARAM_SW_DYN. Check!' + call PRC_abort + end select + + !- Setup the numerical diffusion + this%CALC_NUMDIFF_FLAG = NUMDIFF_FLAG + if( NUMDIFF_FLAG ) call setup_numdiff( this, sw_mesh ) + + !- Setup the modal filter + this%MODALFILTER_FLAG = MODALFILTER_FLAG + if ( MODALFILTER_FLAG ) call setup_modalfilter( this, sw_mesh ) + + return + end subroutine SWDyn_setup + + subroutine SWDyn_calc_tendency( this, model_mesh, prgvars_list, auxvars_list, forcing_list, is_update ) + implicit none + + class(SWDyn), intent(inout) :: this + class(ModelMeshBase), intent(in) :: model_mesh + class(ModelVarManager), intent(inout) :: prgvars_list + class(ModelVarManager), intent(inout) :: auxvars_list + class(ModelVarManager), intent(inout) :: forcing_list + logical, intent(in) :: is_update + !-------------------------------------------------- + if (.not. this%IsActivated()) return + !LOG_INFO('AtmosDyn_tendency',*) + + return + end subroutine SWDyn_calc_tendency + +!OCL SERIAL + subroutine SWDyn_update( this, model_mesh, prgvars_list, auxvars_list, forcing_list, is_update ) + + use scale_atm_dyn_dgm_modalfilter, only: & + atm_dyn_dgm_modalfilter_apply + + implicit none + + class(SWDyn), intent(inout) :: this + class(ModelMeshBase), intent(in) :: model_mesh + class(ModelVarManager), intent(inout) :: prgvars_list + class(ModelVarManager), intent(inout) :: auxvars_list + class(ModelVarManager), intent(inout) :: forcing_list + logical, intent(in) :: is_update + + integer :: rkstage + integer :: tintbuf_ind + + class(MeshBase), pointer :: mesh + class(MeshBase2D), pointer :: mesh2D + class(LocalMesh2D), pointer :: lcmesh + integer :: n + integer :: ke + + class(LocalMeshFieldBase), pointer :: h, U, V + class(LocalMeshFieldBase), pointer :: hs, u1, u2 + class(LocalMeshFieldBase), pointer :: Coriolis + + integer :: vid + real(RP) :: implicit_fac + real(RP) :: dt + character(len=H_SHORT) :: labl + !-------------------------------------------------- + + call PROF_rapstart( 'SW_DYN_update', 1) + + call model_mesh%GetModelMesh( mesh ) + + !- + do rkstage=1, this%tint(1)%nstage + + !* Exchange halo data + call PROF_rapstart( 'SW_DYN_exchange_prgv', 2) + call prgvars_list%MeshFieldComm_Exchange() + call PROF_rapend( 'SW_DYN_exchange_prgv', 2) + + do n=1, mesh%LOCAL_MESH_NUM + call PROF_rapstart( 'SW_DYN_get_localmesh_ptr', 2) + call SWVars_GetLocalMeshPrgVars( n, & + mesh, prgvars_list, auxvars_list, & + h, U, V, hs, u1, u2, lcmesh ) + call PROF_rapend( 'SW_DYN_get_localmesh_ptr', 2) + + !* Apply boundary conditions + call PROF_rapstart( 'SW_DYN_applyBC_prgv', 2) + call PROF_rapend( 'SW_DYN_applyBC_prgv', 2) + end do + + do n=1, mesh%LOCAL_MESH_NUM + tintbuf_ind = this%tint(n)%tend_buf_indmap(rkstage) + + call PROF_rapstart( 'SW_DYN_get_localmesh_ptr', 2) + call SWVars_GetLocalMeshPrgVars( n, & + mesh, prgvars_list, auxvars_list, & + h, U, V, hs, u1, u2, lcmesh ) + + call SWDynAuxVars_GetLocalMeshFields( n, & + mesh, this%dyn_vars%AUXVARS2D_manager, & + Coriolis ) + call PROF_rapend( 'SW_DYN_get_localmesh_ptr', 2) + + call PROF_rapstart( 'SW_DYN_update_caltend_ex', 2) + call this%cal_tend_ex( & + this%tint(n)%tend_buf2D_ex(:,:,h_ID,tintbuf_ind), & + this%tint(n)%tend_buf2D_ex(:,:,U_ID ,tintbuf_ind), & + this%tint(n)%tend_buf2D_ex(:,:,V_ID ,tintbuf_ind), & + h%val, U%val, V%val, & + hs%val, u1%val, u2%val, & + Coriolis%val, & + model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), & + model_mesh%SOptrMat(1), model_mesh%SOptrMat(2), & + model_mesh%LiftOptrMat, & + lcmesh, lcmesh%refElem2D ) + call PROF_rapend( 'SW_DYN_update_caltend_ex', 2) + + call PROF_rapstart( 'SW_DYN_update_add_tp', 2) + ! call add_phy_tend( & + ! this, this%tint(n)%tend_buf2D_ex(:,:,:,tintbuf_ind), & ! (inout) + ! forcing_list, & ! (in) + ! mesh, n, lcmesh, lcmesh%refElem2D ) ! (in) + call PROF_rapend( 'SW_DYN_update_add_tp', 2) + + call PROF_rapstart( 'SW_DYN_update_advance', 2) + call this%tint(n)%Advance( rkstage, h%val, h_ID, & + 1, lcmesh%refElem%Np, lcmesh%NeS, lcmesh%NeE ) + + call this%tint(n)%Advance( rkstage, U%val, U_ID, & + 1, lcmesh%refElem%Np, lcmesh%NeS, lcmesh%NeE ) + + call this%tint(n)%Advance( rkstage, V%val, V_ID, & + 1, lcmesh%refElem%Np, lcmesh%NeS, lcmesh%NeE ) + + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + u1%val(:,ke) = lcmesh%G_ij(:,ke,1,1) * U%val(:,ke) + lcmesh%G_ij(:,ke,1,2) * V%val(:,ke) + u2%val(:,ke) = lcmesh%G_ij(:,ke,2,1) * U%val(:,ke) + lcmesh%G_ij(:,ke,2,2) * V%val(:,ke) + end do + call PROF_rapend( 'SW_DYN_update_advance', 2) + + !------------------------------------------------------------------------------ + end do + end do + + !-- modal filter + if ( this%MODALFILTER_FLAG ) then + do n=1, mesh%LOCAL_MESH_NUM + call PROF_rapstart( 'SW_DYN_get_localmesh_ptr', 2) + call SWVars_GetLocalMeshPrgVars( n, & + mesh, prgvars_list, auxvars_list, & + h, U, V, hs, u1, u2, lcmesh ) + call PROF_rapend( 'SW_DYN_get_localmesh_ptr', 2) + + call PROF_rapstart( 'SW_DYN_update_expfilter', 2) + call atm_dyn_dgm_modalfilter_apply( & ! (inout) + h%val, U%val, V%val, u1%val, u2%val, & ! (in) + lcmesh, lcmesh%refElem2D, this%modal_filter ) ! (in) + call PROF_rapend( 'SW_DYN_update_expfilter', 2) + end do + end if + + !-- numerical diffusion + if ( this%CALC_NUMDIFF_FLAG ) then + + call PROF_rapstart( 'ATM_DYN_numfilter', 1) + call prgvars_list%MeshFieldComm_Exchange() + + do vid = 1, SW_PROGVARS_NUM + ! call cal_numfilter_tend( this, model_mesh, prgvars_list, auxvars_list, vid ) + end do + + do n=1, mesh%LOCAL_MESH_NUM + dt = this%tint(n)%Get_deltime() + + call SWVars_GetLocalMeshPrgVars( n, & + mesh, prgvars_list, auxvars_list, & + h, U, V, hs, u1, u2, lcmesh ) + + !$omp parallel do + do ke=1, lcmesh%Ne + h%val(:,ke) = h%val(:,ke) + dt * this%tint(n)%tend_buf2D_ex(:,ke,h_ID,1) + U%val(:,ke) = U%val(:,ke) + dt * this%tint(n)%tend_buf2D_ex(:,ke,U_ID,1) + V%val(:,ke) = V%val(:,ke) + dt * this%tint(n)%tend_buf2D_ex(:,ke,V_ID,1) + end do + end do + + call PROF_rapend( 'SW_DYN_numfilter', 2) + end if + + call PROF_rapend( 'SW_DYN_update', 1) + + return + end subroutine SWDyn_update + + subroutine SWDyn_finalize( this ) + implicit none + class(SWDyn), intent(inout) :: this + + integer :: n + !-------------------------------------------------- + if (.not. this%IsActivated()) return + LOG_INFO('SWDyn_finalize',*) + + select case(this%EQS_TYPEID) + case(EQS_TYPEID_GLOBAL_SHALLOW_WATER) + call atm_dyn_dgm_globalsw_Final() + end select + + ! if (this%CALC_NUMDIFF_FLAG) then + ! call atm_dyn_dgm_nonhydro3d_numdiff_Final() + ! end if + + if (this%MODALFILTER_FLAG) then + call this%modal_filter%Final() + end if + + do n = 1, size(this%tint) + call this%tint(n)%Final() + end do + deallocate( this%tint ) + + call this%boundary_cond%Final() + call this%dyn_vars%Final() + + return + end subroutine SWDyn_finalize + + !--- private --------------- + +!OCL SERIAL + ! subroutine add_phy_tend( this, & ! (in) + ! dyn_tends, & ! (inout) + ! phytends_list, & ! (in) + ! mesh, domID, lcmesh, elem2D ) ! (in) + + ! use scale_const, only: & + ! Rdry => CONST_Rdry, & + ! CPdry => CONST_CPdry, & + ! CVdry => CONST_CVdry, & + ! PRES00 => CONST_PRE00 + + ! use mod_sw_vars, only: & + ! SWVars_GetLocalMeshPhyTends + + ! implicit none + + ! class(SWDyn), intent(inout) :: this + ! class(LocalMesh2D), intent(in) :: lcmesh + ! class(elementbase2D), intent(in) :: elem2D + ! real(RP), intent(inout) :: dyn_tends(elem2D%Np,lcmesh%NeA,SW_PROGVARS_NUM) + ! class(ModelVarManager), intent(inout) :: phytends_list + ! class(MeshBase), intent(in) :: mesh + ! integer, intent(in) :: domID + + ! class(LocalMeshFieldBase), pointer :: h_tp, U_tp, V_tp + ! integer :: ke + ! !--------------------------------------------------------------------------------- + + ! call SWVars_GetLocalMeshPhyTends( domID, mesh, phytends_list, & ! (in) + ! DENS_tp, MOMX_tp, MOMY_tp, MOMZ_tp, RHOT_tp, RHOH_p ) ! (out) + + ! !$omp parallel do & + ! !$Omp private( RHOT, EXNER ) + ! do ke=lcmesh%NeS, lcmesh%NeE + ! RHOT(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT(:,ke) + ! EXNER(:) = (RovP0 * RHOT(:))**RovCv + + ! dyn_tends(:,ke,DDENS_ID) = dyn_tends(:,ke,DDENS_ID) + DENS_tp%val(:,ke) + ! dyn_tends(:,ke,MOMX_ID ) = dyn_tends(:,ke,MOMX_ID ) + MOMX_tp%val(:,ke) + ! dyn_tends(:,ke,MOMY_ID ) = dyn_tends(:,ke,MOMY_ID ) + MOMY_tp%val(:,ke) + ! dyn_tends(:,ke,MOMZ_ID ) = dyn_tends(:,ke,MOMZ_ID ) + MOMZ_tp%val(:,ke) + ! dyn_tends(:,ke,DRHOT_ID) = dyn_tends(:,ke,DRHOT_ID) + RHOT_tp%val(:,ke) & + ! + RHOH_p %val(:,ke) / ( CpDry * EXNER(:) ) + ! end do + + ! return + ! end subroutine add_phy_tend + +!OCL SERIAL + ! subroutine cal_numfilter_tend( this, model_mesh, prgvars_list, auxvars_list, varid ) + + ! use mod_atmos_dyn_vars, only: & + ! AtmosDynAuxVars_GetLocalMeshFields, & + ! AtmosDynNumDiffFlux_GetLocalMeshFields, & + ! AtmosDynNumDiffTend_GetLocalMeshFields + + ! use scale_atm_dyn_dgm_nonhydro3d_numdiff, only: & + ! atm_dyn_dgm_nonhydro3d_numdiff_tend, & + ! atm_dyn_dgm_nonhydro3d_numdiff_cal_laplacian, & + ! atm_dyn_dgm_nonhydro3d_numdiff_cal_flx + + ! implicit none + + ! class(AtmosDyn), intent(inout) :: this + ! class(ModelMeshBase), intent(in) :: model_mesh + ! class(ModelVarManager), intent(inout) :: prgvars_list + ! class(ModelVarManager), intent(inout) :: auxvars_list + ! integer, intent(in) :: varid + + ! class(LocalMeshFieldBase), pointer :: var + ! class(LocalMeshFieldBase), pointer :: ND_flx_x, ND_flx_y, ND_flx_z + ! class(LocalMeshFieldBase), pointer :: ND_lapla_h, ND_lapla_v + ! class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT + ! class(LocalMeshFieldBase), pointer :: DENS_hyd, PRES_hyd + + ! class(MeshBase), pointer :: mesh + ! class(LocalMesh3D), pointer :: lcmesh + ! integer :: n + ! integer :: ke + ! integer :: nd_itr + ! real(RP) :: nd_sign + ! logical :: dens_weight_flag + ! logical, allocatable :: is_bound(:,:) + + ! !----------------------------------------- + + ! nd_sign = (-1)**(mod(this%ND_LAPLACIAN_NUM+1,2)) + ! dens_weight_flag = (varid /= DDENS_ID) + + ! call model_mesh%GetModelMesh( mesh ) + + ! do n=1, mesh%LOCAL_MESH_NUM + ! call AtmosVars_GetLocalMeshPrgVar( n, mesh, prgvars_list, auxvars_list, & + ! varid, var, & + ! DENS_hyd, PRES_hyd, lcmesh ) + ! call AtmosVars_GetLocalMeshPrgVars( n, mesh, prgvars_list, auxvars_list, & + ! DDENS, MOMX, MOMY, MOMZ, DRHOT, & + ! DENS_hyd, PRES_hyd ) + ! call AtmosDynNumDiffFlux_GetLocalMeshFields( n, mesh, this%dyn_vars%NUMDIFF_FLUX_manager, & + ! ND_flx_x, ND_flx_y, ND_flx_z ) + + ! allocate( is_bound(lcmesh%refElem%NfpTot,lcmesh%Ne) ) + ! call this%boundary_cond%ApplyBC_numdiff_even_lc( var%val, is_bound, varid, n, & + ! MOMX%val, MOMY%val, MOMZ%val, DENS_hyd%val, PRES_hyd%val, & + ! lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%normal_fn(:,:,3), & + ! lcmesh%vmapM, lcmesh%vmapP, lcmesh%vmapB, lcmesh, lcmesh%refElem3D ) + + ! call atm_dyn_dgm_nonhydro3d_numdiff_cal_flx( ND_flx_x%val, ND_flx_y%val, ND_flx_z%val, & + ! var%val, var%val, DDENS%val, DENS_hyd%val, & + ! model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), model_mesh%DOptrMat(3), & + ! model_mesh%LiftOptrMat, & + ! lcmesh, lcmesh%refElem3D, is_bound, dens_weight_flag ) + + ! deallocate( is_bound ) + ! end do + + ! !* Exchange halo data + ! call this%dyn_vars%NUMDIFF_FLUX_manager%MeshFieldComm_Exchange() + + ! do nd_itr=1, this%ND_LAPLACIAN_NUM-1 + ! do n = 1, mesh%LOCAL_MESH_NUM + ! call AtmosDynNumDiffFlux_GetLocalMeshFields( n, mesh, this%dyn_vars%NUMDIFF_FLUX_manager, & + ! ND_flx_x, ND_flx_y, ND_flx_z, lcmesh) + ! call AtmosDynNumDiffTend_GetLocalMeshFields( n, mesh, this%dyn_vars%NUMDIFF_TEND_manager, & + ! ND_lapla_h, ND_lapla_v ) + + ! allocate( is_bound(lcmesh%refElem%NfpTot,lcmesh%Ne) ) + ! call this%boundary_cond%ApplyBC_numdiff_odd_lc( & + ! ND_flx_x%val, ND_flx_y%val, ND_flx_z%val, is_bound, varid, n, & + ! lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%normal_fn(:,:,3), & + ! lcmesh%vmapM, lcmesh%vmapP, lcmesh%vmapB, lcmesh, lcmesh%refElem3D ) + + ! call atm_dyn_dgm_nonhydro3d_numdiff_cal_laplacian( ND_lapla_h%val, ND_lapla_v%val, & + ! ND_flx_x%val, ND_flx_y%val, ND_flx_z%val, & + ! model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), model_mesh%DOptrMat(3), & + ! model_mesh%LiftOptrMat, & + ! lcmesh, lcmesh%refElem3D, is_bound ) + + ! deallocate( is_bound ) + ! end do + ! !* Exchange halo data + ! call this%dyn_vars%NUMDIFF_TEND_manager%MeshFieldComm_Exchange() + + ! do n = 1, mesh%LOCAL_MESH_NUM + ! call AtmosDynNumDiffFlux_GetLocalMeshFields( n, mesh, this%dyn_vars%NUMDIFF_FLUX_manager, & + ! ND_flx_x, ND_flx_y, ND_flx_z, lcmesh) + ! call AtmosDynNumDiffTend_GetLocalMeshFields( n, mesh, this%dyn_vars%NUMDIFF_TEND_manager, & + ! ND_lapla_h, ND_lapla_v ) + ! call AtmosVars_GetLocalMeshPrgVars( n, mesh, prgvars_list, auxvars_list, & + ! DDENS, MOMX, MOMY, MOMZ, DRHOT, & + ! DENS_hyd, PRES_hyd ) + + ! allocate( is_bound(lcmesh%refElem%NfpTot,lcmesh%Ne) ) + ! call this%boundary_cond%ApplyBC_numdiff_even_lc( & + ! ND_lapla_h%val, is_bound, varid, n, & + ! MOMX%val, MOMY%val, MOMZ%val, DENS_hyd%val, PRES_hyd%val, & + ! lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%normal_fn(:,:,3), & + ! lcmesh%vmapM, lcmesh%vmapP, lcmesh%vmapB, lcmesh, lcmesh%refElem3D ) + + ! call atm_dyn_dgm_nonhydro3d_numdiff_cal_flx( ND_flx_x%val, ND_flx_y%val, ND_flx_z%val, & + ! ND_lapla_h%val, ND_lapla_v%val, DDENS%val, DENS_hyd%val, & + ! model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), model_mesh%DOptrMat(3), & + ! model_mesh%LiftOptrMat, & + ! lcmesh, lcmesh%refElem3D, is_bound, .false. ) + + ! deallocate( is_bound ) + ! end do + ! !* Exchange halo data + ! call this%dyn_vars%NUMDIFF_FLUX_manager%MeshFieldComm_Exchange() + ! end do + + ! do n = 1, mesh%LOCAL_MESH_NUM + + ! call AtmosDynNumDiffFlux_GetLocalMeshFields( n, mesh, this%dyn_vars%NUMDIFF_FLUX_manager, & + ! ND_flx_x, ND_flx_y, ND_flx_z, lcmesh) + ! call AtmosVars_GetLocalMeshPrgVar( n, mesh, prgvars_list, auxvars_list, & + ! varid, var, & + ! DENS_hyd, PRES_hyd, lcmesh ) + ! call AtmosVars_GetLocalMeshPrgVar( n, mesh, prgvars_list, auxvars_list, & + ! DDENS_ID, DDENS ) + + ! allocate( is_bound(lcmesh%refElem%NfpTot,lcmesh%Ne) ) + ! call this%boundary_cond%ApplyBC_numdiff_odd_lc( & + ! ND_flx_x%val, ND_flx_y%val, ND_flx_z%val, is_bound, varid, n, & + ! lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%normal_fn(:,:,3), & + ! lcmesh%vmapM, lcmesh%vmapP, lcmesh%vmapB, lcmesh, lcmesh%refElem3D ) + + ! call atm_dyn_dgm_nonhydro3d_numdiff_tend( this%tint(n)%tend_buf2D_ex(:,:,varid,1), & + ! ND_flx_x%val, ND_flx_y%val, ND_flx_z%val, & + ! DDENS%val, DENS_hyd%val, nd_sign * this%ND_COEF_H, nd_sign * this%ND_COEF_V, & + ! model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), model_mesh%DOptrMat(3), & + ! model_mesh%LiftOptrMat, & + ! lcmesh, lcmesh%refElem3D, is_bound, dens_weight_flag ) + + ! deallocate( is_bound ) + ! end do + + ! return + ! end subroutine cal_numfilter_tend + + !-- Setup modal filter +!OCL SERIAL + subroutine setup_modalfilter( this, sw_mesh ) + implicit none + + class(SWDyn), target, intent(inout) :: this + class(SWMesh), target, intent(in) :: sw_mesh + + real(RP) :: MF_ETAC = 2.0_RP/3.0_RP + real(RP) :: MF_ALPHA = 36.0_RP + integer :: MF_ORDER = 16 + + namelist /PARAM_SW_DYN_MODALFILTER/ & + MF_ETAC, MF_ALPHA, MF_ORDER + + integer :: ierr + !--------------------------------------------------------------- + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_SW_DYN_MODALFILTER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("SW_DYN_setup_modalfilter",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("SW_DYN_setup_modalfilter",*) 'Not appropriate names in namelist PARAM_ATMOS_DYN_MODALFILTER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_SW_DYN_MODALFILTER) + + call sw_mesh%Construct_ModalFilter2D( & + this%modal_filter, & ! (inout) + MF_ETAC, MF_ALPHA, MF_ORDER ) ! (in) + + return + end subroutine setup_modalfilter + + !-- Setup explicit numerical diffusion +!OCL SERIAL + subroutine setup_numdiff( this, sw_mesh ) + implicit none + + class(SWDyn), target, intent(inout) :: this + class(SWMesh), target, intent(in) :: sw_mesh + + integer :: ND_LAPLACIAN_NUM = 1 + real(RP) :: ND_COEF_h = 0.0_RP + + namelist /PARAM_SW_DYN_NUMDIFF/ & + ND_LAPLACIAN_NUM, & + ND_COEF_h + + integer :: ierr + !--------------------------------------------------------------- + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_SW_DYN_NUMDIFF,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("ATMOS_SW_setup_numdiff",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("ATMOS_SW_setup_numdiff",*) 'Not appropriate names in namelist PARAM_SW_DYN_NUMDIFF. Check!' + call PRC_abort + endif + LOG_NML(PARAM_SW_DYN_NUMDIFF) + + this%ND_LAPLACIAN_NUM = ND_LAPLACIAN_NUM + this%ND_COEF_H = ND_COEF_h +! call atm_dyn_dgm_nonhydro3d_numdiff_Init( sw_mesh%mesh ) + + return + end subroutine setup_numdiff + + !-- Setup Coriolis parameter + +!OCL SERIAL + subroutine setup_coriolis_parameter( this, sw_mesh ) + + use scale_coriolis_param, only: & + get_coriolis_parameter + implicit none + + class(SWDynVars), target, intent(inout) :: this + class(SWMesh), target, intent(in) :: sw_mesh + + class(LocalMeshFieldBase), pointer :: coriolis + class(LocalMesh2D), pointer :: lcmesh2D + integer :: n + !--------------------------------------------------------------- + + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + call SWDynAuxVars_GetLocalMeshFields( n, sw_mesh%mesh, this%AUXVARS2D_manager, & + coriolis, lcmesh2D ) + + call get_coriolis_parameter( & + coriolis%val(:,lcmesh2D%NeS:lcmesh2D%NeE), & ! (out) + "SPHERE", lcmesh2D%refElem2D%Np * lcmesh2D%Ne, & ! (in) + lat=lcmesh2D%lat(:,:) ) ! (in) + end do + + return + end subroutine setup_coriolis_parameter + +!-------- + +! subroutine cal_MOMZ_tend( & +! MOMZ_t, MOMZ_t_advx, MOMZ_t_advY, MOMZ_t_advZ, MOMZ_t_lift, MOMZ_t_buoy, & ! (out) +! DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) +! Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + +! use scale_element_base +! use scale_sparsemat +! use scale_const, only: & +! GRAV => CONST_GRAV, & +! Rdry => CONST_Rdry, & +! CPdry => CONST_CPdry, & +! CVdry => CONST_CVdry, & +! PRES00 => CONST_PRE00 +! use scale_atm_dyn_nonhydro3d, only: IntrpMat_VPOrdM1 +! implicit none + +! class(LocalMesh3D), intent(in) :: lmesh +! class(elementbase3D), intent(in) :: elem +! class(LocalMesh2D), intent(in) :: lmesh2D +! class(elementbase2D), intent(in) :: elem2D +! type(SparseMat), intent(in) :: Dx, Dy, Dz, Sx, Sy, Sz, Lift +! real(RP), intent(out) :: MOMZ_t(elem%Np,lmesh%NeA) +! real(RP), intent(out) :: MOMZ_t_advx(elem%Np,lmesh%NeA) +! real(RP), intent(out) :: MOMZ_t_advy(elem%Np,lmesh%NeA) +! real(RP), intent(out) :: MOMZ_t_advz(elem%Np,lmesh%NeA) +! real(RP), intent(out) :: MOMZ_t_lift(elem%Np,lmesh%NeA) +! real(RP), intent(out) :: MOMZ_t_buoy(elem%Np,lmesh%NeA) + +! real(RP), intent(in) :: DDENS_(elem%Np,lmesh%NeA) +! real(RP), intent(in) :: MOMX_(elem%Np,lmesh%NeA) +! real(RP), intent(in) :: MOMY_(elem%Np,lmesh%NeA) +! real(RP), intent(in) :: MOMZ_(elem%Np,lmesh%NeA) +! real(RP), intent(in) :: DRHOT_(elem%Np,lmesh%NeA) +! real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeA) +! real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeA) + +! real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) +! real(RP) :: del_flux(elem%NfpTot,lmesh%Ne) +! real(RP) :: dens_(elem%Np), RHOT_(elem%Np), dpres_(elem%Np) +! real(RP) :: pres_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) + +! integer :: ke +! !------------------------------------------------------------------------ + +! call cal_del_flux_dyn( del_flux, & ! (out) +! DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) +! lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) +! lmesh%vmapM, lmesh%vmapP, & ! (in) +! lmesh, elem ) ! (in) + +! !----- +! !$omp parallel do private(RHOT_,pres_,dpres_,dens_,u_,v_,w_,Fx,Fy,Fz,LiftDelFlx) +! do ke = lmesh%NeS, lmesh%NeE +! !-- + +! RHOT_(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) + DRHOT_(:,ke) +! pres_(:) = PRES00 * (Rdry*RHOT_(:)/PRES00)**(CPdry/Cvdry) +! dpres_(:) = pres_(:) - PRES_hyd(:,ke) +! dens_(:) = DDENS_(:,ke) + DENS_hyd(:,ke) + +! u_(:) = MOMX_(:,ke)/dens_(:) +! v_(:) = MOMY_(:,ke)/dens_(:) +! w_(:) = MOMZ_(:,ke)/dens_(:) + +! !-- MOMZ +! call sparsemat_matmul(Dx, u_(:)*MOMZ_(:,ke), Fx) +! call sparsemat_matmul(Dy, v_(:)*MOMZ_(:,ke), Fy) +! call sparsemat_matmul(Dz, w_(:)*MOMZ_(:,ke), Fz) +! MOMZ_t_advx(:,ke) = - lmesh%Escale(:,ke,1,1) * Fx(:) +! MOMZ_t_advy(:,ke) = - lmesh%Escale(:,ke,2,2) * Fy(:) +! MOMZ_t_advz(:,ke) = - lmesh%Escale(:,ke,3,3) * Fz(:) + +! call sparsemat_matmul(Dz, dpres_(:), Fz) +! MOMZ_t_buoy(:,ke) = - lmesh%Escale(:,ke,3,3) * Fz(:) & +! - matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) * Grav + +! call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke), LiftDelFlx) +! MOMZ_t_lift(:,ke) = - LiftDelFlx(:) + +! MOMZ_t(:,ke) = MOMZ_t_advx(:,ke) + MOMZ_t_advy(:,ke) + MOMZ_t_advz(:,ke) & +! + MOMZ_t_lift(:,ke) + MOMZ_t_buoy(:,ke) +! end do + +! return +! end subroutine cal_MOMZ_tend + + +! subroutine cal_del_flux_dyn( del_flux, & +! DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & +! nx, ny, nz, vmapM, vmapP, lmesh, elem ) + +! use scale_const, only: & +! GRAV => CONST_GRAV, & +! Rdry => CONST_Rdry, & +! CPdry => CONST_CPdry, & +! CVdry => CONST_CVdry, & +! PRES00 => CONST_PRE00 + +! implicit none + +! class(LocalMesh3D), intent(in) :: lmesh +! class(elementbase3D), intent(in) :: elem +! real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%Ne) +! real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) +! real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) +! real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) +! real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) +! integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) +! integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) + +! integer :: i, iP, iM +! real(RP) :: VelP, VelM, alpha +! real(RP) :: uM, uP, vM, vP, wM, wP, presM, presP, dpresM, dpresP, densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P +! real(RP) :: gamm, rgamm +! !------------------------------------------------------------------------ + +! gamm = CpDry/CvDry +! rgamm = CvDry/CpDry + +! !$omp parallel do private( & +! !$omp iM, iP, uM, VelP, VelM, alpha, & +! !$omp uP, vM, vP, wM, wP, presM, presP, dpresM, dpresP, densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P) +! do i=1, elem%NfpTot*lmesh%Ne +! iM = vmapM(i); iP = vmapP(i) + +! rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm +! rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm + +! rhotM = rhot_hyd_M + DRHOT_(iM) +! presM = PRES00 * (Rdry*rhotM/PRES00)**gamm +! dpresM = presM - PRES_hyd(iM)*abs(nz(i)) + +! rhotP = rhot_hyd_P + DRHOT_(iP) +! presP = PRES00 * (Rdry*rhotP/PRES00)**gamm +! dpresP = presP - PRES_hyd(iP)*abs(nz(i)) + +! densM = DDENS_(iM) + DENS_hyd(iM) +! densP = DDENS_(iP) + DENS_hyd(iP) + +! VelM = (MOMX_(iM)*nx(i) + MOMY_(iM)*ny(i) + MOMZ_(iM)*nz(i))/densM +! VelP = (MOMX_(iP)*nx(i) + MOMY_(iP)*ny(i) + MOMZ_(iP)*nz(i))/densP + +! alpha = max( sqrt(gamm*presM/densM) + abs(VelM), sqrt(gamm*presP/densP) + abs(VelP) ) + + +! del_flux(i) = 0.5_RP*( & +! ( MOMZ_(iP)*VelP - MOMZ_(iM)*VelM) & +! + ( dpresP - dpresM )*nz(i) & +! - alpha*(MOMZ_(iP) - MOMZ_(iM)) ) +! end do + +! return +! end subroutine cal_del_flux_dyn +end module mod_sw_dyn \ No newline at end of file diff --git a/model/global_shallow_water/src/mod_sw_dyn_vars.F90 b/model/global_shallow_water/src/mod_sw_dyn_vars.F90 new file mode 100644 index 00000000..d41ef731 --- /dev/null +++ b/model/global_shallow_water/src/mod_sw_dyn_vars.F90 @@ -0,0 +1,311 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_sw_dyn_vars + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + + use scale_element_base, only: ElementBase2D + use scale_localmesh_base, only: LocalMeshBase + use scale_localmesh_2d, only: LocalMesh2D + use scale_mesh_base2d, only: MeshBase2D + + use scale_meshfield_base, only: MeshField2D + use scale_localmeshfield_base, only: LocalMeshFieldBase + + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + use scale_meshfieldcomm_base, only: MeshFieldContainer + + use scale_model_var_manager, only: & + ModelVarManager, VariableInfo + use scale_model_mesh_manager, only: ModelMeshBase + + use mod_sw_mesh, only: SWMesh + + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + type, public :: SWDynVars + type(MeshField2D), allocatable :: AUX_VARS2D(:) + type(ModelVarManager) :: AUXVARS2D_manager + + type(MeshField2D), allocatable :: NUMDIFF_FLUX_VARS2D(:) + type(ModelVarManager) :: NUMDIFF_FLUX_manager + type(MeshFieldCommCubedSphereDom2D) :: NUMDIFF_FLUX_comm + + type(MeshField2D), allocatable :: NUMDIFF_TEND_VARS2D(:) + type(ModelVarManager) :: NUMDIFF_TEND_manager + type(MeshFieldCommCubedSphereDom2D) :: NUMDIFF_TEND_comm + contains + procedure :: Init => SWDynVars_Init + procedure :: Final => SWDynVars_Final + end type SWDynVars + + public :: SWDynAuxVars_GetLocalMeshFields + public :: SWDynNumDiffFlux_GetLocalMeshFields + public :: SWDynNumDiffTend_GetLocalMeshFields + !public :: AtmosDynVars_GetLocalMeshFields_analysis + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + integer, public, parameter :: ATMOS_DYN_AUXVARS2D_NUM = 1 + integer, public, parameter :: ATMOS_DYN_AUXVARS2D_CORIOLIS_ID = 1 + + type(VariableInfo), public :: ATMOS_DYN_AUXVARS2D_VINFO(ATMOS_DYN_AUXVARS2D_NUM) + DATA ATMOS_DYN_AUXVARS2D_VINFO / & + VariableInfo( ATMOS_DYN_AUXVARS2D_CORIOLIS_ID, 'CORIOLIS', 'coriolis parameter', & + 's-1', 2, 'XY', '' ) / + + integer, public, parameter :: SW_DYN_NUMDIFF_FLUX_NUM = 2 + integer, public, parameter :: SW_DYN_NUMDIFFFLX_X_ID = 1 + integer, public, parameter :: SW_DYN_NUMDIFFFLX_Y_ID = 2 + + integer, public, parameter :: SW_DYN_NUMDIFF_TEND_NUM = 1 + integer, public, parameter :: SW_DYN_NUMDIFF_LAPLAH_ID = 1 + + type(VariableInfo), public :: SW_DYN_NUMDIFF_FLUX_VINFO(SW_DYN_NUMDIFF_FLUX_NUM) + DATA SW_DYN_NUMDIFF_FLUX_VINFO / & + VariableInfo( SW_DYN_NUMDIFFFLX_X_ID, 'DIFFFLX_X', 'flux in x-direction', & + '?.m/s', 2, 'XY', '' ), & + VariableInfo( SW_DYN_NUMDIFFFLX_Y_ID, 'DIFFFLX_Y', 'flux in y-direction', & + '?.m/s', 2, 'XY', '' ) / + + type(VariableInfo), public :: SW_DYN_NUMDIFF_TEND_VINFO(SW_DYN_NUMDIFF_TEND_NUM) + DATA SW_DYN_NUMDIFF_TEND_VINFO / & + VariableInfo( SW_DYN_NUMDIFF_LAPLAH_ID, 'NUMDIFF_LAPLAH', 'tendency due to nundiff', & + '?/s', 2, 'XY', '' ) / + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + +contains + subroutine SWDynVars_Init( this, model_mesh ) + implicit none + class(SWDynVars), target, intent(inout) :: this + class(ModelMeshBase), target, intent(in) :: model_mesh + + integer :: v + integer :: n + logical :: reg_file_hist + + class(SWMesh), pointer :: sw_mesh + class(MeshBase2D), pointer :: mesh2D + + !-------------------------------------------------- + + LOG_INFO('SWDynVars_Init',*) + + !- Initialize auxiliary and diagnostic variables + + nullify( sw_mesh ) + select type(model_mesh) + type is (SWMesh) + sw_mesh => model_mesh + end select + + mesh2D => sw_mesh%mesh + + !- + call this%AUXVARS2D_manager%Init() + allocate( this%AUX_VARS2D(ATMOS_DYN_AUXVARS2D_NUM) ) + + reg_file_hist = .false. + do v = 1, ATMOS_DYN_AUXVARS2D_NUM + call this%AUXVARS2D_manager%Regist( & + ATMOS_DYN_AUXVARS2D_VINFO(v), mesh2D, & ! (in) + this%AUX_VARS2D(v), reg_file_hist ) ! (out) + + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + this%AUX_VARS2D(v)%local(n)%val(:,:) = 0.0_RP + end do + end do + + !- + call this%NUMDIFF_FLUX_manager%Init() + allocate( this%NUMDIFF_FLUX_VARS2D(SW_DYN_NUMDIFF_FLUX_NUM) ) + + reg_file_hist = .false. + do v = 1, SW_DYN_NUMDIFF_FLUX_NUM + call this%NUMDIFF_FLUX_manager%Regist( & + SW_DYN_NUMDIFF_FLUX_VINFO(v), mesh2D, & ! (in) + this%NUMDIFF_FLUX_VARS2D(v), reg_file_hist ) ! (out) + + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + this%NUMDIFF_FLUX_VARS2D(v)%local(n)%val(:,:) = 0.0_RP + end do + end do + call this%NUMDIFF_FLUX_comm%Init( SW_DYN_NUMDIFF_FLUX_NUM, 0, sw_mesh%mesh ) + call this%NUMDIFF_FLUX_manager%MeshFieldComm_Prepair( this%NUMDIFF_FLUX_comm, this%NUMDIFF_FLUX_VARS2D(:) ) + + !- + call this%NUMDIFF_TEND_manager%Init() + allocate( this%NUMDIFF_TEND_VARS2D(SW_DYN_NUMDIFF_TEND_NUM) ) + + reg_file_hist = .false. + do v = 1, SW_DYN_NUMDIFF_TEND_NUM + call this%NUMDIFF_TEND_manager%Regist( & + SW_DYN_NUMDIFF_TEND_VINFO(v), mesh2D, & ! (in) + this%NUMDIFF_TEND_VARS2D(v), reg_file_hist ) ! (out) + + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + this%NUMDIFF_TEND_VARS2D(v)%local(n)%val(:,:) = 0.0_RP + end do + end do + call this%NUMDIFF_TEND_comm%Init( SW_DYN_NUMDIFF_TEND_NUM, 0, sw_mesh%mesh ) + call this%NUMDIFF_TEND_manager%MeshFieldComm_Prepair( this%NUMDIFF_TEND_comm, this%NUMDIFF_TEND_VARS2D(:) ) + + return + end subroutine SWDynVars_Init + + subroutine SWDynVars_Final( this ) + implicit none + class(SWDynVars), target, intent(inout) :: this + !--------------------------------------------------- + + LOG_INFO('SWDynVars_Final',*) + + call this%AUXVARS2D_manager%Final() + + call this%NUMDIFF_FLUX_comm%Final() + call this%NUMDIFF_FLUX_manager%Final() + + call this%NUMDIFF_TEND_comm%Final() + call this%NUMDIFF_TEND_manager%Final() + + + return + end subroutine SWDynVars_Final + + subroutine SWDynAuxVars_GetLocalMeshFields( domID, mesh, auxvars_list, & + Coriolis, & + lcmesh2D & + ) + + use scale_mesh_base, only: MeshBase + use scale_meshfield_base, only: MeshFieldBase + implicit none + + integer, intent(in) :: domID + class(MeshBase), intent(in) :: mesh + class(ModelVarManager), intent(inout) :: auxvars_list + class(LocalMeshFieldBase), pointer, intent(out) :: Coriolis + class(LocalMesh2D), pointer, intent(out), optional :: lcmesh2D + + class(MeshFieldBase), pointer :: field + class(LocalMeshBase), pointer :: lcmesh + !------------------------------------------------------- + + !-- + call auxvars_list%Get(ATMOS_DYN_AUXVARS2D_CORIOLIS_ID, field) + call field%GetLocalMeshField(domID, Coriolis) + !--- + + if (present(lcmesh2D)) then + call mesh%GetLocalMesh( domID, lcmesh ) + nullify( lcmesh2D ) + + select type(lcmesh) + type is (LocalMesh2D) + if (present(lcmesh2D)) lcmesh2D => lcmesh + end select + end if + + return + end subroutine SWDynAuxVars_GetLocalMeshFields + + subroutine SWDynNumDiffFlux_GetLocalMeshFields( domID, mesh, auxvars_list, & + NUMDIFF_FLUX_X, NUMDIFF_FLUX_Y, & + lcmesh2D & + ) + + use scale_mesh_base, only: MeshBase + use scale_meshfield_base, only: MeshFieldBase + implicit none + + integer, intent(in) :: domID + class(MeshBase), intent(in) :: mesh + class(ModelVarManager), intent(inout) :: auxvars_list + class(LocalMeshFieldBase), pointer, intent(out) :: NUMDIFF_FLUX_X + class(LocalMeshFieldBase), pointer, intent(out) :: NUMDIFF_FLUX_Y + class(LocalMesh2D), pointer, intent(out), optional :: lcmesh2D + + class(MeshFieldBase), pointer :: field + class(LocalMeshBase), pointer :: lcmesh + !------------------------------------------------------- + + !-- + call auxvars_list%Get(SW_DYN_NUMDIFFFLX_X_ID, field) + call field%GetLocalMeshField(domID, NUMDIFF_FLUX_X) + + call auxvars_list%Get(SW_DYN_NUMDIFFFLX_Y_ID, field) + call field%GetLocalMeshField(domID, NUMDIFF_FLUX_Y) + + !--- + + if (present(lcmesh2D)) then + call mesh%GetLocalMesh( domID, lcmesh ) + nullify( lcmesh2D ) + + select type(lcmesh) + type is (LocalMesh2D) + if (present(lcmesh2D)) lcmesh2D => lcmesh + end select + end if + + return + end subroutine SWDynNumDiffFlux_GetLocalMeshFields + + subroutine SWDynNumDiffTend_GetLocalMeshFields( domID, mesh, auxvars_list, & + NUMDIFF_LAPLAH, & + lcmesh2D & + ) + + use scale_mesh_base, only: MeshBase + use scale_meshfield_base, only: MeshFieldBase + implicit none + + integer, intent(in) :: domID + class(MeshBase), intent(in) :: mesh + class(ModelVarManager), intent(inout) :: auxvars_list + class(LocalMeshFieldBase), pointer, intent(out) :: NUMDIFF_LAPLAH + class(LocalMesh2D), pointer, intent(out), optional :: lcmesh2D + + class(MeshFieldBase), pointer :: field + class(LocalMeshBase), pointer :: lcmesh + !------------------------------------------------------- + + !-- + call auxvars_list%Get(SW_DYN_NUMDIFF_LAPLAH_ID, field) + call field%GetLocalMeshField(domID, NUMDIFF_LAPLAH) + + !--- + + if (present(lcmesh2D)) then + call mesh%GetLocalMesh( domID, lcmesh ) + nullify( lcmesh2D ) + + select type(lcmesh) + type is (LocalMesh2D) + if (present(lcmesh2D)) lcmesh2D => lcmesh + end select + end if + + return + end subroutine SWDynNumDiffTend_GetLocalMeshFields + +end module mod_sw_dyn_vars \ No newline at end of file diff --git a/model/global_shallow_water/src/mod_sw_mesh.F90 b/model/global_shallow_water/src/mod_sw_mesh.F90 new file mode 100644 index 00000000..25960813 --- /dev/null +++ b/model/global_shallow_water/src/mod_sw_mesh.F90 @@ -0,0 +1,159 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_sw_mesh + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + + use scale_meshfield_base, only: MeshField3D + use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_element_base, only: ElementBase2D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + use scale_sparsemat, only: sparsemat + use scale_model_mesh_manager, only: & + ModelMesh2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + type, extends(ModelMesh2D), public :: SWMesh + type(MeshCubedSphereDom2D) :: mesh + type(QuadrilateralElement) :: element + contains + procedure :: Init => SWMesh_Init + procedure :: Final => SWMesh_Final + procedure :: Construct_ModalFilter2D => SWMesh_construct_ModalFilter2D + end type SWMesh + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + subroutine SWMesh_Init( this ) + use scale_const, only: & + RPlanet => CONST_RADIUS + use scale_FILE_monitor_meshfield, only: & + FILE_monitor_meshfield_set_dim + + implicit none + class(SWMesh), target, intent(inout) :: this + + integer :: NeGX = 2 + integer :: NeGY = 2 + integer :: Nprc = 1 + integer :: NLocalMeshPerPrc = 6 + logical :: LumpedMassMatFlag = .false. + integer :: PolyOrder = 1 + + namelist / PARAM_SW_MESH / & + NeGX, NeGY, NLocalMeshPerPrc, & + Nprc, & + PolyOrder, LumpedMassMatFlag + + integer :: n + character(len=H_SHORT) :: dim_type + class(LocalMesh2D), pointer :: lcmesh + + character(len=H_SHORT) :: SpMV_storage_format = 'ELL' ! CSR or ELL + + integer :: ierr + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("SW_MESH_setup",*) 'Setup' + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_SW_MESH,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("SW_MESH_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("SW_MESH_setup",*) 'Not appropriate names in namelist PARAM_SW_MESH. Check!' + call PRC_abort + endif + LOG_NML(PARAM_SW_MESH) + + !---- + + ! Setup the element + + call this%element%Init( PolyOrder, LumpedMassMatFlag ) + + ! Setup the mesh + call this%mesh%Init( & + NeGX, NeGY, RPlanet, & + this%element, NLocalMeshPerPrc, Nprc ) + + call this%mesh%Generate() + + !- + call this%ModelMesh2D_Init( this%mesh ) + + call this%DOptrMat(1)%Init( this%element%Dx1, storage_format=SpMV_storage_format ) + call this%DOptrMat(2)%Init( this%element%Dx2, storage_format=SpMV_storage_format ) + + call this%SOptrMat(1)%Init( this%element%Sx1, storage_format=SpMV_storage_format ) + call this%SOptrMat(2)%Init( this%element%Sx2, storage_format=SpMV_storage_format ) + + call this%LiftOptrMat%Init( this%element%Lift, storage_format=SpMV_storage_format ) + + !- +! call FILE_monitor_meshfield_set_dim( this%mesh, 'SW2D' ) + + return + end subroutine SWMesh_Init + + subroutine SWMesh_Final(this) + implicit none + + class(SWMesh), intent(inout) :: this + !------------------------------------------- + + call this%mesh%Final() + call this%ModelMesh2D_Final() + + return + end subroutine SWMesh_Final + + subroutine SWMesh_construct_ModalFilter2D( this, & + filter, & + etac, alpha, ord ) + + use scale_element_modalfilter, only: ModalFilter + implicit none + class(SWMesh), intent(in) :: this + class(ModalFilter), intent(inout) :: filter + real(RP), intent(in) :: etac + real(RP), intent(in) :: alpha + integer, intent(in) :: ord + !------------------------------------------- + + call filter%Init( this%element, & + etac, alpha, ord ) + + return + end subroutine SWMesh_construct_ModalFilter2D + +end module mod_sw_mesh \ No newline at end of file diff --git a/model/global_shallow_water/src/mod_sw_vars.F90 b/model/global_shallow_water/src/mod_sw_vars.F90 new file mode 100644 index 00000000..4a6acc34 --- /dev/null +++ b/model/global_shallow_water/src/mod_sw_vars.F90 @@ -0,0 +1,873 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_sw_vars + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_debug + use scale_const, only: & + Grav => CONST_GRAV, & + RPlanet => CONST_RADIUS + + use scale_element_base, only: & + ElementBase, ElementBase2D + use scale_mesh_base, only: MeshBase + use scale_mesh_base2d, only: & + MeshBase2D, & + DIMTYPE_XY => MeshBase2D_DIMTYPEID_XYT + + use scale_localmesh_base, only: LocalMeshBase + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmeshfield_base, only: LocalMeshFieldBase + use scale_meshfield_base, only: & + MeshFieldBase, MeshField2D + use scale_file_restart_meshfield, only: & + FILE_restart_meshfield_component + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + use scale_meshfieldcomm_base, only: MeshFieldContainer + + use scale_model_var_manager, only: & + ModelVarManager, VariableInfo + + use mod_sw_mesh, only: SWMesh + + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + type, public :: SWVars + type(MeshField2D), allocatable :: PROG_VARS(:) + type(ModelVarManager) :: PROGVARS_manager + type(MeshFieldCommCubedSphereDom2D) :: PROGVARS_comm + + type(MeshField2D), allocatable :: AUX_VARS(:) + type(ModelVarManager) :: AUXVARS_manager + type(MeshFieldCommCubedSphereDom2D) :: AUXVARS_comm + + type(MeshField2D), allocatable :: PHY_TEND(:) + type(ModelVarManager) :: PHYTENDS_manager + + type(ModelVarManager) :: DIAGVARS_manager + integer, allocatable :: DIAGVARS_HISTID(:) + + type(FILE_restart_meshfield_component) :: restart_file + + logical :: check_range + logical :: check_total + contains + procedure :: Init => SWVars_Init + procedure :: Final => SWVars_Final + procedure :: Clac_diagnostics => SWVars_CalculateDiagnostics + procedure :: History => SWVars_History + procedure :: Check => SWVars_Check + procedure :: Monitor => SWVars_Monitor + procedure :: Read_restart_file => SWVar_Read_restart_file + procedure :: Write_restart_file => SWVar_Write_restart_file + end type SWVars + + public :: SWVars_GetLocalMeshPrgVar + public :: SWVars_GetLocalMeshPrgVars + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + ! Prognostic variables in dynamical process + + integer, public, parameter :: SW_PROGVARS_h_ID = 1 + integer, public, parameter :: SW_PROGVARS_U_ID = 2 + integer, public, parameter :: SW_PROGVARS_V_ID = 3 + integer, public, parameter :: SW_PROGVARS_NUM = 3 + + type(VariableInfo), public :: SW_PROGVARS_VINFO(SW_PROGVARS_NUM) + + DATA SW_PROGVARS_VINFO / & + VariableInfo( SW_PROGVARS_h_ID, 'h', 'fluid thickness', & + 'm', 2, 'XY', 'depth of fluid' ), & + VariableInfo( SW_PROGVARS_U_ID , 'U', 'velocity x1 (contravariant vector)', & + 's-1', 2, 'XY', 'x1_component_contravariant_velocity_vector' ), & + VariableInfo( SW_PROGVARS_V_ID , 'V', 'velocity x2 (contravariant vector)', & + 's-1', 2, 'XY', 'x1_component_contravariant_velocity_vector' ) / + + real(RP) :: PROGVARS_check_min(SW_PROGVARS_NUM) + real(RP) :: PROGVARS_check_max(SW_PROGVARS_NUM) + + ! Reference state + + integer, public, parameter :: SW_AUXVARS_u1_ID = 1 + integer, public, parameter :: SW_AUXVARS_u2_ID = 2 + integer, public, parameter :: SW_AUXVARS_hs_ID = 3 + integer, public, parameter :: SW_AUXVARS_VOR_ID = 4 + integer, public, parameter :: SW_AUXVARS_NUM = 4 + + type(VariableInfo), public :: SW_AUXVARS_VINFO(SW_AUXVARS_NUM) + DATA SW_AUXVARS_VINFO / & + VariableInfo( SW_AUXVARS_u1_ID, 'u1', 'velocity x1 (covariant vector)', & + 'm2/s', 2, 'XY', 'x1_component_covariant_velocity_vector' ), & + VariableInfo( SW_AUXVARS_u2_ID, 'u2', 'velocity x2 (covariant vector)', & + 'm2/s', 2, 'XY', 'x1_component_covariant_velocity_vector' ), & + VariableInfo( SW_AUXVARS_hs_ID, 'hs', 'topography', & + 'm', 2, 'XY', 'topography' ), & + VariableInfo( SW_AUXVARS_VOR_ID, 'VOR', 'relative vorticity', & + 's-1', 2, 'XY', 'relative_vorticity' ) / + + ! Tendency by physical processes + + integer, public, parameter :: SW_PHYTEND_h_ID = 1 + integer, public, parameter :: SW_PHYTEND_U_ID = 2 + integer, public, parameter :: SW_PHYTEND_V_ID = 3 + integer, public, parameter :: SW_PHYTEND_NUM = 3 + + type(VariableInfo), public :: SW_PHYTEND_VINFO(SW_PHYTEND_NUM) + DATA SW_PHYTEND_VINFO / & + VariableInfo( SW_PHYTEND_h_ID, 'h_tp', 'h_tp', & + 'm/s', 2, 'XY', 'tendency of physical process for h' ), & + VariableInfo( SW_PHYTEND_U_ID, 'V_tp', 'U_tp', & + 's-2', 2, 'XY', 'tendency of physical process for U' ), & + VariableInfo( SW_PHYTEND_V_ID, 'U_tp', 'V_tp', & + 's-2', 2, 'XY', 'tendency of physical process for V' ) / + + ! Diagnostic variables + + integer, public, parameter :: SW_DIAGVARS_Vellon_ID = 1 + integer, public, parameter :: SW_DIAGVARS_Vellat_ID = 2 + integer, public, parameter :: SW_DIAGVARS_Height_ID = 3 + integer, public, parameter :: SW_DIAGVARS_ENGT = 4 + integer, public, parameter :: SW_DIAGVARS_ENGP = 5 + integer, public, parameter :: SW_DIAGVARS_ENGK = 6 + integer, public, parameter :: SW_DIAGVARS_NUM = 6 + + type(VariableInfo), public :: SW_DIAGVARS_VINFO(SW_DIAGVARS_NUM) + DATA SW_DIAGVARS_VINFO / & + VariableInfo( SW_DIAGVARS_Vellon_ID, 'Vel_lon', 'velocity u' , 'm/s' , 2, 'XY', 'lon_wind' ), & + VariableInfo( SW_DIAGVARS_Vellat_ID, 'Vel_lat', 'velocity v' , 'm/s' , 2, 'XY', 'lat_wind' ), & + VariableInfo( SW_DIAGVARS_Vellat_ID, 'Height', 'Height' , 'm' , 2, 'XY', 'height' ), & + Variableinfo( SW_DIAGVARS_ENGT , 'ENGT', 'total energy' , 'J/m3' , 2, 'XY', '' ), & + Variableinfo( SW_DIAGVARS_ENGP , 'ENGP', 'potential energy' , 'J/m3' , 2, 'XY', '' ), & + Variableinfo( SW_DIAGVARS_ENGK , 'ENGK', 'kinetic energy' , 'J/m3' , 2, 'XY', '' ) / + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + ! for monitor + + integer, private, parameter :: IM_QDRY = 1 + integer, private, parameter :: IM_ENGT = 2 + integer, private, parameter :: IM_ENGP = 3 + integer, private, parameter :: IM_ENGK = 4 + integer, private, parameter :: DVM_nmax = 4 + integer, private :: DV_MONIT_id(DVM_nmax) + +contains + subroutine SWVars_Init( this, sw_mesh ) + + use scale_file_monitor_meshfield, only: & + MONITOR_reg => FILE_monitor_meshfield_reg + implicit none + + class(SWVars), target, intent(inout) :: this + class(SWMesh), intent(in) :: sw_mesh + + integer :: iv + integer :: n + logical :: reg_file_hist + + type(MeshField2D) :: diag_vars(SW_DIAGVARS_NUM) + + logical :: CHECK_RANGE = .false. + logical :: CHECK_TOTAL = .false. + + namelist / PARAM_SW_VARS / & + CHECK_RANGE, & + CHECK_TOTAL + + character(len=H_LONG) :: IN_BASENAME = '' !< Basename of the input file + logical :: IN_POSTFIX_TIMELABEL = .false. !< Add timelabel to the basename of input file? + character(len=H_LONG) :: OUT_BASENAME = '' !< Basename of the output file + logical :: OUT_POSTFIX_TIMELABEL = .true. !< Add timelabel to the basename of output file? + character(len=H_MID) :: OUT_TITLE = '' !< Title of the output file + character(len=H_SHORT) :: OUT_DTYPE = 'DEFAULT' !< REAL4 or REAL8 + + namelist / PARAM_SW_VARS_RESTART / & + IN_BASENAME, & + IN_POSTFIX_TIMELABEL, & + OUT_BASENAME, & + OUT_POSTFIX_TIMELABEL, & + OUT_TITLE, & + OUT_DTYPE + + integer :: ierr + logical :: is_specified + + integer :: DV_id + !-------------------------------------------------- + + LOG_INFO('SWVars_Init',*) + + !- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_SW_VARS,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("SW_vars_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("SW_vars_setup",*) 'Not appropriate names in namelist PARAM_SW_VARS. Check!' + call PRC_abort + endif + LOG_NML(PARAM_SW_VARS) + + !- Initialize prognostic variables + + call this%PROGVARS_manager%Init() + allocate( this%PROG_VARS(SW_PROGVARS_NUM) ) + + reg_file_hist = .true. + do iv = 1, SW_PROGVARS_NUM + + call this%PROGVARS_manager%Regist( & + SW_PROGVARS_VINFO(iv), sw_mesh%mesh, & ! (in) + this%PROG_VARS(iv), & ! (inout) + reg_file_hist, monitor_flag=.true. ) ! (out) + + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + this%PROG_VARS(iv)%local(n)%val(:,:) = 0.0_RP + end do + end do + + call this%PROGVARS_comm%Init( 1, 1, sw_mesh%mesh ) + call this%PROGVARS_manager%MeshFieldComm_Prepair( this%PROGVARS_comm, this%PROG_VARS(:) ) + + LOG_NEWLINE + LOG_INFO("SW_vars_setup",*) 'List of prognostic variables (SW) ' + LOG_INFO_CONT('(1x,A,A24,A,A48,A,A12,A)') & + ' |', 'VARNAME ','|', & + 'DESCRIPTION ', '[', 'UNIT ', ']' + do iv = 1, SW_PROGVARS_NUM + LOG_INFO_CONT('(1x,A,I3,A,A24,A,A48,A,A12,A)') & + 'NO.',iv,'|',SW_PROGVARS_VINFO(iv)%NAME,'|', SW_PROGVARS_VINFO(iv)%DESC,'[', SW_PROGVARS_VINFO(iv)%UNIT,']' + end do + + !- Initialize auxiliary variables + + call this%AUXVARS_manager%Init() + allocate( this%AUX_VARS(SW_AUXVARS_NUM) ) + + reg_file_hist = .true. + do iv = 1, SW_AUXVARS_NUM + call this%AUXVARS_manager%Regist( & + SW_AUXVARS_VINFO(iv), sw_mesh%mesh, & ! (in) + this%AUX_VARS(iv), reg_file_hist ) ! (out) + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + this%AUX_VARS(iv)%local(n)%val(:,:) = 1.0_RP + end do + end do + + call this%AUXVARS_comm%Init(SW_AUXVARS_NUM, 0, sw_mesh%mesh) + call this%AUXVARS_manager%MeshFieldComm_Prepair( this%AUXVARS_comm, this%AUX_VARS(:) ) + + call this%PROGVARS_comm%SetCovariantVec( 1, & + this%AUX_VARS(SW_AUXVARS_u1_ID), & + this%AUX_VARS(SW_AUXVARS_u2_ID) ) + + !- Initialize the tendency of physical processes + + call this%PHYTENDS_manager%Init() + allocate( this%PHY_TEND(SW_PHYTEND_NUM) ) + + reg_file_hist = .true. + do iv = 1, SW_PHYTEND_NUM + call this%PHYTENDS_manager%Regist( & + SW_PHYTEND_VINFO(iv), sw_mesh%mesh, & ! (in) + this%PHY_TEND(iv), reg_file_hist ) ! (out) + do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM + this%PHY_TEND(iv)%local(n)%val(:,:) = 0.0_RP + end do + end do + + !- Initialize diagnostic variables for output + call this%DIAGVARS_manager%Init() + allocate( this%DIAGVARS_HISTID(SW_DIAGVARS_NUM) ) + + reg_file_hist = .true. + do iv = 1, SW_DIAGVARS_NUM + call this%DIAGVARS_manager%Regist( & + SW_DIAGVARS_VINFO(iv), sw_mesh%mesh, & ! (in) + diag_vars(iv), reg_file_hist ) ! (out) + + this%DIAGVARS_HISTID(iv) = diag_vars(iv)%hist_id + end do + call this%DIAGVARS_manager%Final() + + !-- Setup information for input/output restart files. + + is_specified = .true. + !- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_SW_VARS_RESTART,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("SWVars_Init",*) 'Not found namelist PARAM_SW_VARS_RESTART. Default used.' + is_specified = .false. + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("SWVars_Init",*) 'Not appropriate names in namelist PARAM_SW_VARS_RESTART. Check!' + call PRC_abort + endif + LOG_NML(PARAM_SW_VARS_RESTART) + + if (is_specified) then + call this%restart_file%Init('SW', & + IN_BASENAME, IN_POSTFIX_TIMELABEL, & + OUT_BASENAME, OUT_POSTFIX_TIMELABEL, OUT_DTYPE, OUT_TITLE, & + SW_PROGVARS_NUM + SW_AUXVARS_NUM, & + meshCubedSphere2D=sw_mesh%mesh ) + else + call this%restart_file%Init('SW', & + SW_PROGVARS_NUM + SW_AUXVARS_NUM, & + meshCubedSphere2D=sw_mesh%mesh ) + end if + + !-----< monitor output setup >----- + + ! call MONITOR_reg( 'QDRY', 'fluid mass', 'kg', & ! (in) + ! DV_MONIT_id(IM_QDRY), & ! (out) + ! dim_type='ATM2D', is_tendency=.false. ) ! (in) + + ! call MONITOR_reg( 'ENGT', 'total energy', 'J', & ! (in) + ! DV_MONIT_id(IM_ENGT), & ! (out) + ! dim_type='ATM2D', is_tendency=.false. ) ! (in) + ! call MONITOR_reg( 'ENGP', 'potential energy', 'J', & ! (in) + ! DV_MONIT_id(IM_ENGP), & ! (out) + ! dim_type='ATM2D', is_tendency=.false. ) ! (in) + ! call MONITOR_reg( 'ENGK', 'kinetic energy', 'J', & ! (in) + ! DV_MONIT_id(IM_ENGK), & ! (out) + ! dim_type='ATM2D', is_tendency=.false. ) ! (in) + + + !-----< check the range of values >----- + + this%check_range = CHECK_RANGE + this%check_total = CHECK_TOTAL + LOG_INFO("SW_vars_setup",*) 'Check value range of variables? : ', CHECK_RANGE + LOG_INFO("SW_vars_setup",*) 'Check total value of variables? : ', CHECK_TOTAL + + PROGVARS_check_min(:) = (/ -10000.0_RP, -1.0_RP, -1.0_RP /) + PROGVARS_check_max(:) = (/ 10000.0_RP, 1.0_RP, 1.0_RP /) + + return + end subroutine SWVars_Init + + subroutine SWVars_Final( this ) + implicit none + class(SWVars), intent(inout) :: this + + !-------------------------------------------------- + + LOG_INFO('SWVars_Final',*) + + call this%restart_file%Final() + + call this%PROGVARS_comm%Final() + call this%AUXVARS_comm%Final() + + call this%PROGVARS_manager%Final() + call this%AUXVARS_manager%Final() + call this%PHYTENDS_manager%Final() + + deallocate( this%DIAGVARS_HISTID ) + + return + end subroutine SWVars_Final + + subroutine SWVars_history( this ) + use scale_file_history_meshfield, only: FILE_HISTORY_meshfield_put + implicit none + class(SWVars), intent(inout) :: this + + integer :: n + integer :: v + class(MeshBase2D), pointer :: mesh2D + class(LocalMesh2D), pointer :: lcmesh + integer :: hst_id + + type(MeshField2D) :: tmp_field + !------------------------------------------------------------------------- + + mesh2D => this%PROG_VARS(1)%mesh + do v = 1, SW_PROGVARS_NUM + hst_id = this%PROG_VARS(v)%hist_id + if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%PROG_VARS(v) ) + end do + + call this%Clac_diagnostics() + do v = 1, SW_AUXVARS_NUM + hst_id = this%AUX_VARS(v)%hist_id + if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%AUX_VARS(v) ) + end do + + do v = 1, SW_PHYTEND_NUM + hst_id = this%PHY_TEND(v)%hist_id + if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%PHY_TEND(v) ) + end do + + call tmp_field%Init( "tmp_field", "", mesh2D) + do v = 1, SW_DIAGVARS_NUM + hst_id = this%DIAGVARS_HISTID(v) + if ( hst_id > 0 ) then + call vars_calc_diagvar( this, SW_DIAGVARS_VINFO(v)%NAME, tmp_field ) + call FILE_HISTORY_meshfield_put( hst_id, tmp_field ) + end if + end do + call tmp_field%Final() + + return + end subroutine SWVars_history + + subroutine SWVar_Read_restart_file( this, sw_mesh ) + + use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D + use scale_meshfieldcomm_base, only: MeshFieldContainer + implicit none + + class(SWVars), intent(inout), target :: this + class(SWMesh), intent(in) :: sw_mesh + + integer :: v + !--------------------------------------- + + LOG_NEWLINE + LOG_INFO("SWVar_read_restart_file",*) 'Open restart file (SW) ' + + !- Open restart file + call this%restart_file%Open() + + !- Read restart file + do v=1, SW_PROGVARS_NUM + call this%restart_file%Read_var( DIMTYPE_XY, this%PROG_VARS(v)%varname, & + this%PROG_VARS(v) ) + end do + do v=1, SW_AUXVARS_hs_ID + call this%restart_file%Read_var( DIMTYPE_XY, this%AUX_VARS(v)%varname, & + this%AUX_VARS(v) ) + end do + + !- Close restart file + LOG_INFO("SWVar_read_restart_file",*) 'Close restart file (SW) ' + call this%restart_file%Close() + + !-- Check read data + call this%Check( force = .true. ) + + !-- Calculate diagnostic variables + call this%Clac_diagnostics() + + !-- Communicate halo data of hydrostatic & diagnostic variables + call this%AUXVARS_manager%MeshFieldComm_Exchange() + + return + end subroutine SWVar_Read_restart_file + + subroutine SWVar_write_restart_file( this ) + + implicit none + class(SWVars), intent(inout) :: this + + integer :: v, rf_vid + !--------------------------------------- + + LOG_NEWLINE + LOG_INFO("SWVar_write_restart_file",*) 'Create restart file (SW) ' + + !- Check data which will be written to restart file + call this%Check( force = .true. ) + + !- Create restart file + call this%restart_file%Create() + + !- Define variables + do v=1, SW_PROGVARS_NUM + rf_vid = v + call this%restart_file%Def_var( this%PROG_VARS(v), & + SW_PROGVARS_VINFO(v)%DESC, rf_vid, DIMTYPE_XY ) + end do + do v=1, SW_AUXVARS_hs_ID + rf_vid = SW_PROGVARS_NUM + v + call this%restart_file%Def_var( this%AUX_VARS(v), & + SW_AUXVARS_VINFO(v)%DESC, rf_vid, DIMTYPE_XY ) + end do + call this%restart_file%End_def() + + !- Write restart file + do v=1, SW_PROGVARS_NUM + rf_vid = v + call this%restart_file%Write_var( rf_vid, this%PROG_VARS(v) ) + end do + do v=1, SW_AUXVARS_hs_ID + rf_vid = SW_PROGVARS_NUM + v + call this%restart_file%Write_var( rf_vid, this%AUX_VARS(v) ) + end do + + !- Close restart file + LOG_INFO("SWVar_write_restart_file",*) 'Close restart file (SW) ' + call this%restart_file%Close() + + return + end subroutine SWVar_write_restart_file + + subroutine SWVars_Check( this, force ) + + use scale_meshfield_statistics, only: & + MeshField_statistics_total, & + MeshField_statistics_detail + + implicit none + class(SWVars), intent(in) :: this + logical, intent(in), optional :: force + + integer :: iv + integer :: iv_diag + integer :: n + logical :: check + + class(MeshBase2D), pointer :: mesh2D + class(LocalMeshBase), pointer :: lcmesh + class(LocalMeshFieldBase), pointer :: lcfield + type(ElementBase), pointer :: elem + character(len=H_MID) :: varname + + type(MeshField2D) :: vel_fields(2) + type(MeshField2D) :: work + !-------------------------------------------------------------------------- + + if ( present(force) ) then + check = force + else + check = this%check_range + end if + + if (check) then + do iv=1, SW_PROGVARS_NUM + mesh2D => this%PROG_VARS(iv)%mesh + do n=1, mesh2D%LOCAL_MESH_NUM + lcmesh => mesh2D%lcmesh_list(n) + elem => lcmesh%refElem + call this%PROG_VARS(iv)%GetLocalMeshField(n, lcfield) + write(varname,'(a,i3.3,a)') this%PROG_VARS(iv)%varname//'(domID=', n, ')' + call VALCHECK( elem%Np, 1, elem%Np, lcmesh%NeA, lcmesh%NeS, lcmesh%NeE, lcfield%val(:,:), & + PROGVARS_check_min(iv), PROGVARS_check_max(iv), trim(varname), __FILE__, __LINE__ ) + end do + end do + + mesh2D => this%PROG_VARS(1)%mesh + do iv=1, 2 + iv_diag = SW_DIAGVARS_Vellon_ID + iv - 1 + call vel_fields(iv)%Init( SW_DIAGVARS_VINFO(iv_diag)%NAME, "", mesh2D ) + call vars_calc_diagvar( this, vel_fields(iv)%varname, vel_fields(iv) ) + end do + call MeshField_statistics_detail( vel_fields(:) ) + do iv=1, 2 + call vel_fields(iv)%Final() + end do + end if + + if ( present(force) ) then + check = force + else + check = this%check_total + end if + if (check) then + mesh2D => this%PROG_VARS(1)%mesh + call work%Init("tmp", "", mesh2D) + call work%Final() + end if + + return + end subroutine SWVars_Check + + subroutine SWVars_Monitor( this ) + use scale_file_monitor_meshfield, only: & + FILE_monitor_meshfield_put + + implicit none + class(SWVars), intent(in) :: this + + integer :: iv + class(MeshBase2D), pointer :: mesh2D + type(MeshField2D) :: work + !-------------------------------------------------------------------------- + + ! do iv=1, SW_PROGVARS_NUM + ! call FILE_monitor_meshfield_put( this%PROG_VARS(iv)%monitor_id, this%PROG_VARS(iv) ) + ! end do + + !##### Energy Budget ##### + ! mesh2D => this%PROG_VARS(1)%mesh + ! call work%Init("tmp", "", mesh2D) + + ! if ( DV_MONIT_id(IM_ENGT) > 0 ) then + ! call vars_calc_diagvar( this, 'ENGT', work ) + ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGT), work ) + ! end if + ! if ( DV_MONIT_id(IM_ENGP) > 0 ) then + ! call vars_calc_diagvar( this, 'ENGP', work ) + ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGP), work ) + ! end if + ! if ( DV_MONIT_id(IM_ENGK) > 0 ) then + ! call vars_calc_diagvar( this, 'ENGK', work ) + ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGK), work ) + ! end if + ! if ( DV_MONIT_id(IM_ENGI) > 0 ) then + ! call vars_calc_diagvar( this, 'ENGI', work ) + ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGI), work ) + ! end if + + ! call work%Final() + + return + end subroutine SWVars_Monitor + + !---- Getter --------------------------------------------------------------------------- + + subroutine SWVars_GetLocalMeshPrgVar( domID, mesh, prgvars_list, auxvars_list, & + varid, & + var, hs, lcmesh2D ) + + implicit none + integer, intent(in) :: domID + class(MeshBase), intent(in) :: mesh + class(ModelVarManager), intent(inout) :: prgvars_list + class(ModelVarManager), intent(inout) :: auxvars_list + integer, intent(in) :: varid + class(LocalMeshFieldBase), pointer, intent(out) :: var + class(LocalMeshFieldBase), pointer, intent(out), optional :: hs + class(LocalMesh2D), pointer, intent(out), optional :: lcmesh2D + + class(MeshFieldBase), pointer :: field + class(LocalMeshBase), pointer :: lcmesh + !------------------------------------------------------- + + !-- + call prgvars_list%Get(varid, field) + call field%GetLocalMeshField(domID, var) + + if (present(hs)) then + call auxvars_list%Get(SW_AUXVARS_hs_ID, field) + call field%GetLocalMeshField(domID, hs) + end if + + if (present(lcmesh2D)) then + call mesh%GetLocalMesh( domID, lcmesh ) + nullify( lcmesh2D ) + + select type(lcmesh) + type is (LocalMesh2D) + if (present(lcmesh2D)) lcmesh2D => lcmesh + end select + end if + + return + end subroutine SWVars_GetLocalMeshPrgVar + + subroutine SWVars_GetLocalMeshPrgVars( domID, mesh, prgvars_list, auxvars_list, & + h, U, V, & + hs, u1, u2, lcmesh2D & + ) + + use scale_mesh_base, only: MeshBase + use scale_meshfield_base, only: MeshFieldBase + use scale_localmesh_base, only: LocalMeshBase + use scale_localmesh_2d, only: LocalMesh2D + + implicit none + integer, intent(in) :: domID + class(MeshBase), intent(in) :: mesh + class(ModelVarManager), intent(inout) :: prgvars_list + class(ModelVarManager), intent(inout) :: auxvars_list + class(LocalMeshFieldBase), pointer, intent(out) :: h, U, V + class(LocalMeshFieldBase), pointer, intent(out) :: hs, u1, u2 + class(LocalMesh2D), pointer, intent(out), optional :: lcmesh2D + + class(MeshFieldBase), pointer :: field + class(LocalMeshBase), pointer :: lcmesh + !------------------------------------------------------- + + !-- + call prgvars_list%Get(SW_PROGVARS_h_ID, field) + call field%GetLocalMeshField(domID, h) + + call prgvars_list%Get(SW_PROGVARS_U_ID, field) + call field%GetLocalMeshField(domID, U) + + call prgvars_list%Get(SW_PROGVARS_V_ID, field) + call field%GetLocalMeshField(domID, V) + + !-- + call auxvars_list%Get(SW_AUXVARS_hs_ID, field) + call field%GetLocalMeshField(domID, hs) + + call auxvars_list%Get(SW_AUXVARS_u1_ID, field) + call field%GetLocalMeshField(domID, u1) + + call auxvars_list%Get(SW_AUXVARS_u2_ID, field) + call field%GetLocalMeshField(domID, u2) + + !--- + + if (present(lcmesh2D)) then + call mesh%GetLocalMesh( domID, lcmesh ) + nullify( lcmesh2D ) + + select type(lcmesh) + type is (LocalMesh2D) + if (present(lcmesh2D)) lcmesh2D => lcmesh + end select + end if + + return + end subroutine SWVars_GetLocalMeshPrgVars + + !----------------------------------------------------------------------------- + !> Calculate diagnostic variables + subroutine SWVars_CalculateDiagnostics( this ) + implicit none + class(SWVars), intent(inout), target :: this + + type(LocalMesh2D), pointer :: lcmesh2D + integer :: n + integer :: varid + + class(MeshField2D), pointer :: field + !------------------------------------------------------- + + do varid=SW_AUXVARS_VOR_ID+1, SW_AUXVARS_NUM + field => this%AUX_VARS(varid) + do n=1, field%mesh%LOCAL_MESH_NUM + lcmesh2D => field%mesh%lcmesh_list(n) + call vars_calc_diagnoseVar( & + field%varname, field%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_h_ID )%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_U_ID)%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_V_ID)%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_hs_ID)%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_u1_ID )%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_u2_ID )%local(n)%val, & + lcmesh2D, lcmesh2D%refElem2D ) + end do + end do + + return + end subroutine SWVars_CalculateDiagnostics + +!-- private ----------------------------------------------------------------------- + + subroutine vars_calc_diagvar( this, field_name, field_work ) + use scale_const, only: & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + implicit none + class(SWVars), intent(in) :: this + character(*), intent(in) :: field_name + type(MeshField2D), intent(inout) :: field_work + + type(LocalMesh2D), pointer :: lcmesh2D + integer :: n + !-------------------------------------------------- + + field_work%varname = field_name + + do n=1, field_work%mesh%LOCAL_MESH_NUM + lcmesh2D => field_work%mesh%lcmesh_list(n) + call vars_calc_diagnoseVar( & + field_name, field_work%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_h_ID )%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_U_ID)%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_V_ID)%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_hs_ID)%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_u1_ID )%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_u2_ID )%local(n)%val, & + lcmesh2D, lcmesh2D%refElem2D ) + end do + + return + end subroutine vars_calc_diagvar + + subroutine vars_calc_diagnoseVar( field_name, var_out, & + h_, U_, V_, hs_, u1_, u2_, & + lcmesh, elem ) + + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatVec + implicit none + + type(LocalMesh2D), intent(in) :: lcmesh + type(ElementBase2D), intent(in) :: elem + character(*), intent(in) :: field_name + real(RP), intent(out) :: var_out(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: h_(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: U_(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: V_(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: hs_(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: u1_(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: u2_(elem%Np,lcmesh%NeA) + + integer :: ke + real(RP) :: dummy(elem%Np,lcmesh%NeA) + !------------------------------------------------------------------------- + + select case(trim(field_name)) + case('Vel_lon') + call CubedSphereCnv_CS2LonLatVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & ! (in) + U_(:,lcmesh%NeS:lcmesh%NeE), V_(:,lcmesh%NeS:lcmesh%NeE), & ! (in) + var_out(:,lcmesh%NeS:lcmesh%NeE), dummy(:,lcmesh%NeS:lcmesh%NeE) ) ! (out) + case('Vel_lat') + call CubedSphereCnv_CS2LonLatVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & ! (in) + U_(:,lcmesh%NeS:lcmesh%NeE), V_(:,lcmesh%NeS:lcmesh%NeE), & ! (in) + dummy(:,lcmesh%NeS:lcmesh%NeE), var_out(:,lcmesh%NeS:lcmesh%NeE) ) ! (out) + case('Height') + !$omp parallel do + do ke=1, lcmesh%Ne + var_out(:,ke) = h_(:,ke) + hs_(:,ke) + end do + case('ENGK') + !$omp parallel do + do ke=1, lcmesh%Ne + var_out(:,ke) = 0.5_RP * h_(:,ke) * ( u1_(:,ke) * U_(:,ke) + u2_(:,ke) * V_(:,ke) ) + end do + case('ENGP') + !$omp parallel do + do ke=1, lcmesh%Ne + var_out(:,ke) = Grav * ( h_(:,ke) + hs_(:,ke) ) + end do + case('ENGT') + !$omp parallel do + do ke=1, lcmesh%Ne + var_out(:,ke) = & + 0.5_RP * h_(:,ke) * ( u1_(:,ke) * U_(:,ke) + u2_(:,ke) * V_(:,ke) ) & ! ENGK + + Grav * ( h_(:,ke) + hs_(:,ke) ) ! ENGP + end do + end select + + return + end subroutine vars_calc_diagnoseVar + +end module mod_sw_vars \ No newline at end of file diff --git a/model/global_shallow_water/src/util/mod_user.F90 b/model/global_shallow_water/src/util/mod_user.F90 new file mode 100644 index 00000000..eca162f3 --- /dev/null +++ b/model/global_shallow_water/src/util/mod_user.F90 @@ -0,0 +1,110 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + + use mod_globalsw_component, only: & + GlobalSWComponent + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit( swmodel ) + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + !------------------------------------------ + + return + end subroutine USER_mkinit + + subroutine USER_setup( swmodel ) + use scale_prc, only: & + PRC_abort + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'This module is dummy.' + + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + +end module mod_user From ce2734e3c56c6250f9ad300e2aa2f7e94a76f89f Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 15:28:54 +0900 Subject: [PATCH 03/98] Modify source codes. --- model/atm_nonhydro2d/src/mod_atmos_bnd.F90 | 27 +++++++++---------- .../atm_nonhydro3d/src/admin/mod_dg_prep.F90 | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/model/atm_nonhydro2d/src/mod_atmos_bnd.F90 b/model/atm_nonhydro2d/src/mod_atmos_bnd.F90 index c4eba61f..92fe3cad 100644 --- a/model/atm_nonhydro2d/src/mod_atmos_bnd.F90 +++ b/model/atm_nonhydro2d/src/mod_atmos_bnd.F90 @@ -45,7 +45,6 @@ module mod_atmos_bnd ! !++ Public parameters & variables ! - !----------------------------------------------------------------------------- ! @@ -54,7 +53,7 @@ module mod_atmos_bnd !------------------- type(MeshBndInfo), allocatable :: VelBC_list(:) - type(MeshBndInfo), allocatable :: ThermalBC_list(:) + type(MeshBndInfo), allocatable :: MassBC_list(:) integer, parameter :: domBnd_Btm_ID = 1 integer, parameter :: domBnd_Right_ID = 2 @@ -63,7 +62,7 @@ module mod_atmos_bnd integer, parameter :: DOM_BND_NUM = 4 integer :: velBC_ids(DOM_BND_NUM) - integer :: thermalBC_ids(DOM_BND_NUM) + integer :: massBC_ids(DOM_BND_NUM) logical, save :: is_initialized = .false. @@ -109,10 +108,10 @@ subroutine ATMOS_bnd_setup() velBC_ids(domBnd_Left_ID) = BndType_NameToID(left_vel_bc) velBC_ids(domBnd_Right_ID) = BndType_NameToID(right_vel_bc) - thermalBC_ids(domBnd_Btm_ID) = BndType_NameToID(btm_thermal_bc) - thermalBC_ids(domBnd_Top_ID) = BndType_NameToID(top_thermal_bc) - thermalBC_ids(domBnd_Left_ID) = BndType_NameToID(left_thermal_bc) - thermalBC_ids(domBnd_Right_ID) = BndType_NameToID(right_thermal_bc) + massBC_ids(domBnd_Btm_ID) = BndType_NameToID(btm_thermal_bc) + massBC_ids(domBnd_Top_ID) = BndType_NameToID(top_thermal_bc) + massBC_ids(domBnd_Left_ID) = BndType_NameToID(left_thermal_bc) + massBC_ids(domBnd_Right_ID) = BndType_NameToID(right_thermal_bc) !------ is_initialized = .false. @@ -128,9 +127,9 @@ subroutine ATMOS_bnd_finalize() if (is_initialized) then do n=1, size(VelBC_list) call VelBC_list(n)%Final() - call ThermalBC_list(n)%Final() + call MassBC_list(n)%Final() end do - deallocate( VelBC_list, ThermalBC_list ) + deallocate( VelBC_list, MassBC_list ) end if is_initialized = .false. @@ -148,12 +147,12 @@ subroutine ATMOS_bnd_setBCInfo() allocate( VelBC_list(mesh%LOCAL_MESH_NUM) ) - allocate( ThermalBC_list(mesh%LOCAL_MESH_NUM) ) + allocate( MassBC_list(mesh%LOCAL_MESH_NUM) ) do n=1, mesh%LOCAL_MESH_NUM lcmesh => mesh%lcmesh_list(n) call bnd_Init_lc( & - VelBC_list(n), ThermalBC_list(n), & ! (inout) + VelBC_list(n), MassBC_list(n), & ! (inout) lcmesh%VMapB, mesh, lcmesh, lcmesh%refElem2D ) ! (in) end do @@ -184,7 +183,7 @@ subroutine ATMOS_bnd_applyBC_prgvars( & call applyBC_prgvars_lc( & DDENS%local(n)%val, MOMX%local(n)%val, MOMZ%local(n)%val, DRHOT%local(n)%val, & ! (inout) DENS_hydro%local(n)%val, PRES_hydro%local(n)%val, & ! (in) - VelBC_list(n), ThermalBC_list(n), & ! (in) + VelBC_list(n), MassBC_list(n), & ! (in) lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%VMapM, lcmesh%VMapP, lcmesh%VMapB, & ! (in) lcmesh, lcmesh%refElem2D ) ! (in) end do @@ -222,7 +221,7 @@ subroutine ATMOS_bnd_applyBC_auxvars( & GxPT%local(n)%val, GzPT%local(n)%val, & ! (inout) DENS_hydro%local(n)%val, PRES_hydro%local(n)%val, & ! (in) viscCoef_h, viscCoef_v, diffCoef_h, diffCoef_v, & ! (in) - VelBC_list(n), ThermalBC_list(n), & ! (in) + VelBC_list(n), MassBC_list(n), & ! (in) lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%VMapM, lcmesh%VMapP, lcmesh%VMapB, & ! (in) lcmesh, lcmesh%refElem2D ) ! (in) end do @@ -269,7 +268,7 @@ subroutine bnd_Init_lc( & if ( mesh%tileID_globalMap(b,tileID) == tileID & .and. mesh%tileFaceID_globalMap(b,tileID) == b ) then call velBCInfo%Set(is_, ie_, velbc_ids(b)) - call thermalBCInfo%Set(is_, ie_, thermalbc_ids(b)) + call thermalBCInfo%Set(is_, ie_, massBC_ids(b)) end if is_ = ie_ + 1 end do diff --git a/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 b/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 index 623dd472..21fb8aa3 100644 --- a/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 +++ b/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 @@ -234,6 +234,6 @@ subroutine restart_write if ( atmos%isActivated() ) call atmos%vars%Write_restart_file() return - end subroutine + end subroutine restart_write end module mod_dg_prep \ No newline at end of file From 3da2f3534414bf232db9acba5e9862d52e5c7a54 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 15:30:35 +0900 Subject: [PATCH 04/98] Modify use statements because we changed the management of axis information. --- model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 | 6 +++--- model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 | 6 +++--- model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 | 7 ++++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 index 041e1c82..6a879777 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 @@ -12,7 +12,9 @@ module mod_atmos_phy_sfc_vars use scale_element_base, only: ElementBase3D use scale_mesh_base, only: MeshBase use scale_mesh_base2d, only: MeshBase2D - use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_base3d, only: & + MeshBase3D, & + DIMTYPE_XYZ => MeshBase3D_DIMTYPEID_XYZ use scale_localmesh_base, only: LocalMeshBase use scale_localmesh_3d, only: LocalMesh3D use scale_localmeshfield_base, only: LocalMeshFieldBase @@ -21,8 +23,6 @@ module mod_atmos_phy_sfc_vars use scale_file_restart_meshfield, only: & FILE_restart_meshfield_component - use scale_file_common_meshfield, only: & - DIMTYPE_XYZ => FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZ use scale_model_var_manager, only: & ModelVarManager, VariableInfo diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 index 74e36be6..a4625b72 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 @@ -12,7 +12,9 @@ module mod_atmos_phy_tb_vars use scale_element_base, only: ElementBase3D use scale_mesh_base, only: MeshBase use scale_mesh_base2d, only: MeshBase2D - use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_base3d, only: & + MeshBase3D, & + DIMTYPE_XYZ => MeshBase3D_DIMTYPEID_XYZ use scale_localmesh_base, only: LocalMeshBase use scale_localmesh_3d, only: LocalMesh3D use scale_localmeshfield_base, only: LocalMeshFieldBase @@ -21,8 +23,6 @@ module mod_atmos_phy_tb_vars use scale_file_restart_meshfield, only: & FILE_restart_meshfield_component - use scale_file_common_meshfield, only: & - DIMTYPE_XYZ => FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZ use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D use scale_meshfieldcomm_base, only: MeshFieldContainer diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 index 90749d10..d82741c8 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 @@ -13,7 +13,10 @@ module mod_atmos_vars use scale_element_base, only: & ElementBase, ElementBase3D use scale_mesh_base, only: MeshBase - use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_base3d, only: & + MeshBase3D, & + DIMTYPE_XYZ => MeshBase3D_DIMTYPEID_XYZ + use scale_localmesh_base, only: LocalMeshBase use scale_localmesh_3d, only: LocalMesh3D use scale_localmeshfield_base, only: LocalMeshFieldBase @@ -21,8 +24,6 @@ module mod_atmos_vars use scale_file_restart_meshfield, only: & FILE_restart_meshfield_component - use scale_file_common_meshfield, only: & - DIMTYPE_XYZ => FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZ use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D use scale_meshfieldcomm_base, only: MeshFieldContainer From 8a08c4b825c7a71ed742cd026c905362d92040b0 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 15:34:07 +0900 Subject: [PATCH 05/98] Output correct information of axes in lon-lat coordinate. --- .../mod_cs2lonlat_interp_field.F90 | 11 ++++------ .../mod_cs2lonlat_interp_file.F90 | 5 ++--- .../mod_cs2lonlat_interp_mesh.F90 | 22 +++++++++++++------ .../util/interp/mod_interp_field.F90 | 4 ++-- .../util/interp/mod_interp_file.F90 | 4 ++-- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 index 31026ca7..d0f036bb 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 @@ -244,8 +244,8 @@ subroutine interpolate_local( out_val, & PI => CONST_PI use scale_file_base_meshfield, only: & FILE_base_meshfield - use scale_file_common_meshfield, only: & - MF2D_XYT => FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT + use scale_mesh_base2d, only: & + MF2D_XYT => MeshBase2D_DIMTYPEID_XYT use scale_polynominal, only: & polynominal_genLegendrePoly use mod_cs2lonlat_interp_mesh, only: & @@ -294,17 +294,14 @@ subroutine interpolate_local( out_val, & allocate( in_val_list(in_prc)%spectral_coef(in_lcmesh%refElem2D%Np,in_lcmesh%NeX,in_lcmesh%NeY,in_csmesh%LOCAL_MESH_NUM) ) call tmp_field2D%Init( varname, "", in_csmesh ) - call in_file_list(out_domID)%in_files(in_prc)%Read_Var_cubedsphere( & - MF2D_XYT, varname, tmp_field2D, step=istep ) + call in_file_list(out_domID)%in_files(in_prc)%Read_Var( & + MF2D_XYT, varname, tmp_field2D, step=istep ) !$omp parallel do collapse(2) private(in_ke2D,ii,jj) do in_domID=1, in_csmesh%LOCAL_MESH_NUM do jj=1, in_lcmesh%NeY do ii=1, in_lcmesh%NeX in_ke2D = ii + (jj-1)*in_lcmesh%NeX - !tmp_field2D%local(in_domID)%val(:,in_ke2D) = in_csmesh%lcmesh_list(in_domID)%panelID! lon(:,in_ke2D) - ! write(*,*) in_prc, in_domID, ii, jj, ":::", & - ! tmp_field2D%local(in_domID)%val(1:1,in_ke2D), in_csmesh%lcmesh_list(in_domID)%PRC_myrank in_val_list(in_prc)%spectral_coef(:,ii,jj,in_domID) = & matmul( in_elem2D%invV, tmp_field2D%local(in_domID)%val(:,in_ke2D) ) end do diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 index 01050c43..16246990 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 @@ -52,9 +52,8 @@ module mod_cs2lonlat_interp_file contains subroutine interp_file_Init( in_basename, out_vinfo, mesh2D ) use scale_file_h - use scale_file_common_meshfield, only: & - DIMTYPE2D_XYT => FILE_COMMON_MESHFILED2D_DIMTYPEID_XYT, & - DIMTYPE3D_XYZT => FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZT + use scale_mesh_base2d, only: & + DIMTYPE2D_XYT => MeshBase2D_DIMTYPEID_XYT use mod_cs2lonlat_interp_field, only: OutVarInfo implicit none diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 index a5938339..b7ce6770 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 @@ -83,6 +83,9 @@ module mod_cs2lonlat_interp_mesh contains subroutine interp_mesh_Init() + use scale_mesh_base2d, only: & + MeshBase2D_DIMTYPEID_X, MeshBase2D_DIMTYPEID_Y, & + MeshBase2D_DIMTYPEID_XY, MeshBase2D_DIMTYPEID_XYT implicit none @@ -125,10 +128,14 @@ subroutine interp_mesh_Init() call out_elem2D%Init( out_PolyOrder_h, .false. ) call out_mesh2D%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, & - 0.0_RP, 2.0_RP*PI, -0.5_RP*PI, 0.5_RP*PI, & + 0.0_RP, 360.0_RP, -90.0_RP, 90.0_RP, & .true., .false., out_elem2D, 1, & out_NprcX, out_NprcY ) - + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XY, 'lonlat', 'degree', 'longitude,latitude' ) + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, 'lonlatt', 'degree', 'longitude,latitude' ) + call out_mesh2D%Generate() !- @@ -301,7 +308,8 @@ subroutine NodeMappingInfo_Init( this, & in_prc2lcprc_tmp(:) = -1 call get_panelID( this%inCSPanelID(:,:), & - lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), & + lcmesh%pos_en(:,:,1) * PI / 180.0_RP, & + lcmesh%pos_en(:,:,2) * PI / 180.0_RP, & elem2D%Nfp**2 * lcmesh%NeX*lcmesh%NeY ) in_tile_num = 0 @@ -315,8 +323,8 @@ subroutine NodeMappingInfo_Init( this, & this%lcprc(p_h,ke_h) = -1 out_cspanel = this%inCSPanelID(p_h,ke_h) - out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) - out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) + out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) * PI / 180.0_RP + out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) * PI / 180.0_RP call CubedSphereCnv_LonLat2CSPos( & out_cspanel, out_lon, out_lat, 1, & out_x, out_y ) @@ -373,8 +381,8 @@ subroutine NodeMappingInfo_Init( this, & prcID = in_lcprc2prc_tmp( this%lcprc(p_h,ke_h) ) out_cspanel = this%inCSPanelID(p_h,ke_h) - out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) - out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) + out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) * PI / 180.0_RP + out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) * PI / 180.0_RP call CubedSphereCnv_LonLat2CSPos( & out_cspanel, out_lon, out_lat, 1, & out_x, out_y ) diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 index d37c832c..36955fee 100644 --- a/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 +++ b/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 @@ -250,8 +250,8 @@ subroutine interpolate_local( out_val, & UNDEF8 => CONST_UNDEF8 use scale_file_base_meshfield, only: & FILE_base_meshfield - use scale_file_common_meshfield, only: & - MF3D_XYZT => FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZT + use scale_mesh_base3d, only: & + MF3D_XYZT => MeshBase3D_DIMTYPEID_XYZT use scale_polynominal, only: & polynominal_genLegendrePoly use mod_interp_mesh, only: & diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_file.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_file.F90 index 140ed41c..e0ceb5c6 100644 --- a/model/atm_nonhydro3d/util/interp/mod_interp_file.F90 +++ b/model/atm_nonhydro3d/util/interp/mod_interp_file.F90 @@ -53,8 +53,8 @@ module mod_interp_file !OCL SERIAL subroutine interp_file_Init( in_basename, out_vinfo, mesh3D ) use scale_file_h - use scale_file_common_meshfield, only: & - DIMTYPE_XYZT => FILE_COMMON_MESHFILED3D_DIMTYPEID_XYZT + use scale_mesh_base3d, only: & + DIMTYPE_XYZT => MeshBase3D_DIMTYPEID_XYZT use mod_interp_field, only: OutVarInfo implicit none From b5dc6f906bbcee74212ca918044c8ebdd45208ac Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 18:04:18 +0900 Subject: [PATCH 06/98] Enable to monitor the statistics in 2D model. --- FElib/src/depend | 2 +- .../src/file/scale_file_monitor_meshfield.F90 | 139 +++++++++++++----- .../src/global_shallow_water.F90 | 31 +++- .../global_shallow_water/src/mod_sw_mesh.F90 | 2 +- .../global_shallow_water/src/mod_sw_vars.F90 | 92 ++++++------ 5 files changed, 169 insertions(+), 97 deletions(-) diff --git a/FElib/src/depend b/FElib/src/depend index cc7dd1e1..31635024 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -20,7 +20,7 @@ $(OBJ_DIR)/scale_element_quadrilateral.o: element/scale_element_quadrilateral.F9 $(OBJ_DIR)/scale_file_base_meshfield.o: file/scale_file_base_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o $(OBJ_DIR)/scale_file_common_meshfield.o: file/scale_file_common_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_polynominal.o $(OBJ_DIR)/scale_file_history_meshfield.o: file/scale_file_history_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o -$(OBJ_DIR)/scale_file_monitor_meshfield.o: file/scale_file_monitor_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o +$(OBJ_DIR)/scale_file_monitor_meshfield.o: file/scale_file_monitor_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_file_restart_meshfield.o: file/scale_file_restart_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_base_meshfield.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o $(OBJ_DIR)/scale_gmres.o: common/scale_gmres.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_linalgebra.o: common/scale_linalgebra.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_sparsemat.o diff --git a/FElib/src/file/scale_file_monitor_meshfield.F90 b/FElib/src/file/scale_file_monitor_meshfield.F90 index e39f9ec9..dbd2a3f8 100644 --- a/FElib/src/file/scale_file_monitor_meshfield.F90 +++ b/FElib/src/file/scale_file_monitor_meshfield.F90 @@ -17,11 +17,13 @@ module scale_file_monitor_meshfield use scale_precision use scale_io use scale_prof + use scale_monitor, only: MONITOR_set_dim + use scale_monitor, only: MONITOR_put - use scale_meshfield_base, only: MeshField3D + use scale_mesh_base2d, only: MeshBase2D use scale_mesh_base3d, only: MeshBase3D - use scale_localmesh_3d, only: LocalMesh3D - use scale_element_base, only: ElementBase3D + use scale_meshfield_base, only: MeshField2D + use scale_meshfield_base, only: MeshField3D use scale_monitor, only: & FILE_monitor_meshfield_setup => MONITOR_setup, & @@ -38,10 +40,23 @@ module scale_file_monitor_meshfield !++ Public type & procedures ! !----------------------------------------------------------------------------- + public :: FILE_monitor_meshfield_setup + + interface FILE_monitor_meshfield_set_dim + module procedure FILE_monitor_meshfield_set_dim2D + module procedure FILE_monitor_meshfield_set_dim3D + end interface public :: FILE_monitor_meshfield_set_dim + public :: FILE_monitor_meshfield_reg + + interface FILE_monitor_meshfield_put + module procedure FILE_monitor_meshfield_put2D + module procedure FILE_monitor_meshfield_put3D + end interface public :: FILE_monitor_meshfield_put + public :: FILE_monitor_meshfield_write public :: FILE_monitor_meshfield_final @@ -56,8 +71,32 @@ module scale_file_monitor_meshfield ! contains - subroutine FILE_monitor_meshfield_set_dim( mesh3D, dim_type ) - use scale_monitor, only: MONITOR_set_dim + subroutine FILE_monitor_meshfield_set_dim2D( mesh2D, dim_type ) + implicit none + + class(MeshBase2D), intent(in) :: mesh2D + character(*), intent(in) :: dim_type + + real(RP) :: area(1,1) + real(RP) :: total_area, total_area_lc + + integer :: n + integer :: ke + !--------------------------------------------------------------------------- + + total_area = 0.0_RP + do n=1, mesh2D%LOCAL_MESH_NUM + total_area = total_area + cal_total_lc( mesh2D%lcmesh_list(n) ) + end do + area(1,1) = 1.0_RP + + call MONITOR_set_dim( 1, 1, 1, 1, 1, 1, 1, 1, 1, & + dim_type, 2, area=area(:,:), total_area=total_area ) + + return + end subroutine FILE_monitor_meshfield_set_dim2D + + subroutine FILE_monitor_meshfield_set_dim3D( mesh3D, dim_type ) implicit none class(MeshBase3D), intent(in) :: mesh3D @@ -68,74 +107,94 @@ subroutine FILE_monitor_meshfield_set_dim( mesh3D, dim_type ) integer :: n integer :: ke - type(LocalMesh3D), pointer :: lcmesh - type(ElementBase3D), pointer :: elem3D !--------------------------------------------------------------------------- - total_area = cal_total_lc( mesh3D ) + total_area = 0.0_RP + do n=1, mesh3D%LOCAL_MESH_NUM + total_area = total_area + cal_total_lc( mesh3D%lcmesh_list(n) ) + end do area(1,1) = 1.0_RP call MONITOR_set_dim( 1, 1, 1, 1, 1, 1, 1, 1, 1, & dim_type, 2, area=area(:,:), total_area=total_area ) return - end subroutine FILE_monitor_meshfield_set_dim + end subroutine FILE_monitor_meshfield_set_dim3D + + subroutine FILE_monitor_meshfield_put2D( itemid, field ) + implicit none + + class(MeshField2D), intent(in) :: field + integer, intent(in) :: itemid + + real(RP) :: total_lc(1,1) + integer :: n + !--------------------------------------------------------------------------- + + if ( itemid <= 0 ) return + + total_lc(1,1) = 0.0_RP + do n=1, field%mesh%LOCAL_MESH_NUM + total_lc(1,1) = total_lc(1,1) & + + cal_total_lc( field%mesh%lcmesh_list(n), field%local(n)%val ) + end do + call MONITOR_put( itemid, total_lc(:,:) ) + + return + end subroutine FILE_monitor_meshfield_put2D - subroutine FILE_monitor_meshfield_put( itemid, field ) - use scale_monitor, only: MONITOR_put + subroutine FILE_monitor_meshfield_put3D( itemid, field ) implicit none class(MeshField3D), intent(in) :: field integer, intent(in) :: itemid real(RP) :: total_lc(1,1) + integer :: n !--------------------------------------------------------------------------- if ( itemid <= 0 ) return - total_lc(1,1) = cal_total_lc( field%mesh, field ) + total_lc(1,1) = 0.0_RP + do n=1, field%mesh%LOCAL_MESH_NUM + total_lc(1,1) = total_lc(1,1) & + + cal_total_lc( field%mesh%lcmesh_list(n), field%local(n)%val ) + end do call MONITOR_put( itemid, total_lc(:,:) ) return - end subroutine FILE_monitor_meshfield_put + end subroutine FILE_monitor_meshfield_put3D !-- private---------------------- - function cal_total_lc( mesh3D, field ) result(total) + function cal_total_lc( lcmesh, field_val ) result(total) + use scale_localmesh_base, only: LocalMeshBase + use scale_element_base, only: ElementBase implicit none - class(MeshBase3D), intent(in), target :: mesh3D - class(MeshField3D), intent(in), optional :: field + class(LocalMeshBase), intent(in) :: lcmesh + real(RP), intent(in), optional :: field_val(lcmesh%refElem%Np,lcmesh%NeA) real(RP) :: total - integer :: n + class(ElementBase), pointer :: elem integer :: ke - class(LocalMesh3D), pointer :: lcmesh - class(ElementBase3D), pointer :: elem3D - - real(RP) :: total_lc !--------------------------------------------------------------------------- total = 0.0_RP - do n=1, mesh3D%LOCAL_MESH_NUM - lcmesh => mesh3D%lcmesh_list(n) - elem3D => lcmesh%refElem3D - - total_lc = 0.0_RP - if ( present(field) ) then - !$omp parallel do reduction(+:total_lc) - do ke=lcmesh%NeS, lcmesh%NeE - total_lc = total_lc & - + sum( elem3D%IntWeight_lgl(:) * lcmesh%J(:,ke) * field%local(n)%val(:,ke) ) - end do - else - !$omp parallel do reduction(+:total_lc) - do ke=lcmesh%NeS, lcmesh%NeE - total_lc = total_lc + sum( elem3D%IntWeight_lgl(:) * lcmesh%J(:,ke) ) - end do - end if - total = total + total_lc - end do + elem => lcmesh%refElem + + if ( present(field_val) ) then + !$omp parallel do reduction(+:total) + do ke=lcmesh%NeS, lcmesh%NeE + total = total & + + sum( elem%IntWeight_lgl(:) * lcmesh%J(:,ke) * lcmesh%Gsqrt(:,ke) * field_val(:,ke) ) + end do + else + !$omp parallel do reduction(+:total) + do ke=lcmesh%NeS, lcmesh%NeE + total = total + sum( elem%IntWeight_lgl(:) * lcmesh%J(:,ke) * lcmesh%Gsqrt(:,ke) ) + end do + end if return end function cal_total_lc diff --git a/model/global_shallow_water/src/global_shallow_water.F90 b/model/global_shallow_water/src/global_shallow_water.F90 index 0e0d0bd0..cb6f2f55 100644 --- a/model/global_shallow_water/src/global_shallow_water.F90 +++ b/model/global_shallow_water/src/global_shallow_water.F90 @@ -21,11 +21,13 @@ program global_shallow_water use scale_prof use scale_file_history, only: & FILE_HISTORY_set_nowdate + use scale_file_monitor_meshfield, only: & + FILE_monitor_meshfield_write use scale_time_manager, only: & TIME_manager_checkstate, TIME_manager_advance, & TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP, TIME_NSTEP, & - TIME_DOresume, TIME_DOend + TIME_DOresume, TIME_DOend, TIME_DTSEC use scale_file_history_meshfield, only: & FILE_HISTORY_meshfield_write @@ -75,9 +77,9 @@ program global_shallow_water call USER_update !* restart and monitor output ******************* - ! if ( swmodel%IsActivated() ) call swmodel%vars%Monitor() - ! call restart_write - ! call FILE_MONITOR_meshfield_write('MAIN', TIME_NOWSTEP) + if ( swmodel%IsActivated() ) call swmodel%vars%Monitor() + call restart_write + call FILE_MONITOR_meshfield_write('MAIN', TIME_NOWSTEP) !* calc tendencies and diagnostices ************* if ( swmodel%IsActivated() .and. swmodel%time_manager%do_step ) then @@ -118,11 +120,22 @@ subroutine restart_read() !- History & Monitor call swmodel%vars%History() - !call swmodel%vars%Monitor() + call swmodel%vars%Monitor() return end subroutine restart_read + subroutine restart_write + implicit none + !---------------------------------------- + + if ( swmodel%isActivated() .and. swmodel%time_manager%do_restart) then + call swmodel%vars%Write_restart_file() + end if + + return + end subroutine restart_write + subroutine update() use mod_user, only: USER_update implicit none @@ -148,7 +161,7 @@ subroutine update() end if !########## Calculate diagnostic variables ########## - !call this%vars%Clac_diagnostics() + call swmodel%vars%Clac_diagnostics() call swmodel%vars%AUXVARS_manager%MeshFieldComm_Exchange() !#### Check values ################################# @@ -246,6 +259,12 @@ subroutine init() setup_TimeIntegration = .true., & restart_in_basename = restart_file%in_basename ) + ! setup statistics + call MeshField_statistics_setup + + ! setup monitor + call FILE_monitor_meshfield_setup( TIME_DTSEC ) + ! setup submodels call swmodel%setup() diff --git a/model/global_shallow_water/src/mod_sw_mesh.F90 b/model/global_shallow_water/src/mod_sw_mesh.F90 index 25960813..e76945f2 100644 --- a/model/global_shallow_water/src/mod_sw_mesh.F90 +++ b/model/global_shallow_water/src/mod_sw_mesh.F90 @@ -120,7 +120,7 @@ subroutine SWMesh_Init( this ) call this%LiftOptrMat%Init( this%element%Lift, storage_format=SpMV_storage_format ) !- -! call FILE_monitor_meshfield_set_dim( this%mesh, 'SW2D' ) + call FILE_monitor_meshfield_set_dim( this%mesh, 'ATM2D' ) return end subroutine SWMesh_Init diff --git a/model/global_shallow_water/src/mod_sw_vars.F90 b/model/global_shallow_water/src/mod_sw_vars.F90 index 4a6acc34..30072f71 100644 --- a/model/global_shallow_water/src/mod_sw_vars.F90 +++ b/model/global_shallow_water/src/mod_sw_vars.F90 @@ -163,11 +163,10 @@ module mod_sw_vars ! for monitor - integer, private, parameter :: IM_QDRY = 1 - integer, private, parameter :: IM_ENGT = 2 - integer, private, parameter :: IM_ENGP = 3 - integer, private, parameter :: IM_ENGK = 4 - integer, private, parameter :: DVM_nmax = 4 + integer, private, parameter :: IM_ENGT = 1 + integer, private, parameter :: IM_ENGP = 2 + integer, private, parameter :: IM_ENGK = 3 + integer, private, parameter :: DVM_nmax = 3 integer, private :: DV_MONIT_id(DVM_nmax) contains @@ -211,6 +210,7 @@ subroutine SWVars_Init( this, sw_mesh ) integer :: ierr logical :: is_specified + logical :: monitor_flag(SW_PROGVARS_NUM) integer :: DV_id !-------------------------------------------------- @@ -232,13 +232,16 @@ subroutine SWVars_Init( this, sw_mesh ) call this%PROGVARS_manager%Init() allocate( this%PROG_VARS(SW_PROGVARS_NUM) ) - reg_file_hist = .true. + reg_file_hist = .true. + monitor_flag(:) = .false. + monitor_flag(SW_PROGVARS_h_ID) = .true. + do iv = 1, SW_PROGVARS_NUM - call this%PROGVARS_manager%Regist( & - SW_PROGVARS_VINFO(iv), sw_mesh%mesh, & ! (in) - this%PROG_VARS(iv), & ! (inout) - reg_file_hist, monitor_flag=.true. ) ! (out) + call this%PROGVARS_manager%Regist( & + SW_PROGVARS_VINFO(iv), sw_mesh%mesh, & ! (in) + this%PROG_VARS(iv), & ! (inout) + reg_file_hist, monitor_flag(iv) ) ! (in) do n = 1, sw_mesh%mesh%LOCAL_MESH_NUM this%PROG_VARS(iv)%local(n)%val(:,:) = 0.0_RP @@ -338,20 +341,15 @@ subroutine SWVars_Init( this, sw_mesh ) !-----< monitor output setup >----- - ! call MONITOR_reg( 'QDRY', 'fluid mass', 'kg', & ! (in) - ! DV_MONIT_id(IM_QDRY), & ! (out) - ! dim_type='ATM2D', is_tendency=.false. ) ! (in) - - ! call MONITOR_reg( 'ENGT', 'total energy', 'J', & ! (in) - ! DV_MONIT_id(IM_ENGT), & ! (out) - ! dim_type='ATM2D', is_tendency=.false. ) ! (in) - ! call MONITOR_reg( 'ENGP', 'potential energy', 'J', & ! (in) - ! DV_MONIT_id(IM_ENGP), & ! (out) - ! dim_type='ATM2D', is_tendency=.false. ) ! (in) - ! call MONITOR_reg( 'ENGK', 'kinetic energy', 'J', & ! (in) - ! DV_MONIT_id(IM_ENGK), & ! (out) - ! dim_type='ATM2D', is_tendency=.false. ) ! (in) - + call MONITOR_reg( 'ENGT', 'total energy', 'J', & ! (in) + DV_MONIT_id(IM_ENGT), & ! (out) + dim_type='ATM2D', is_tendency=.false. ) ! (in) + call MONITOR_reg( 'ENGP', 'potential energy', 'J', & ! (in) + DV_MONIT_id(IM_ENGP), & ! (out) + dim_type='ATM2D', is_tendency=.false. ) ! (in) + call MONITOR_reg( 'ENGK', 'kinetic energy', 'J', & ! (in) + DV_MONIT_id(IM_ENGK), & ! (out) + dim_type='ATM2D', is_tendency=.false. ) ! (in) !-----< check the range of values >----- @@ -361,7 +359,7 @@ subroutine SWVars_Init( this, sw_mesh ) LOG_INFO("SW_vars_setup",*) 'Check total value of variables? : ', CHECK_TOTAL PROGVARS_check_min(:) = (/ -10000.0_RP, -1.0_RP, -1.0_RP /) - PROGVARS_check_max(:) = (/ 10000.0_RP, 1.0_RP, 1.0_RP /) + PROGVARS_check_max(:) = (/ 15000.0_RP, 1.0_RP, 1.0_RP /) return end subroutine SWVars_Init @@ -605,32 +603,28 @@ subroutine SWVars_Monitor( this ) type(MeshField2D) :: work !-------------------------------------------------------------------------- - ! do iv=1, SW_PROGVARS_NUM - ! call FILE_monitor_meshfield_put( this%PROG_VARS(iv)%monitor_id, this%PROG_VARS(iv) ) - ! end do + do iv=1, SW_PROGVARS_h_ID + call FILE_monitor_meshfield_put( this%PROG_VARS(iv)%monitor_id, this%PROG_VARS(iv) ) + end do !##### Energy Budget ##### - ! mesh2D => this%PROG_VARS(1)%mesh - ! call work%Init("tmp", "", mesh2D) - - ! if ( DV_MONIT_id(IM_ENGT) > 0 ) then - ! call vars_calc_diagvar( this, 'ENGT', work ) - ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGT), work ) - ! end if - ! if ( DV_MONIT_id(IM_ENGP) > 0 ) then - ! call vars_calc_diagvar( this, 'ENGP', work ) - ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGP), work ) - ! end if - ! if ( DV_MONIT_id(IM_ENGK) > 0 ) then - ! call vars_calc_diagvar( this, 'ENGK', work ) - ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGK), work ) - ! end if - ! if ( DV_MONIT_id(IM_ENGI) > 0 ) then - ! call vars_calc_diagvar( this, 'ENGI', work ) - ! call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGI), work ) - ! end if - - ! call work%Final() + mesh2D => this%PROG_VARS(1)%mesh + call work%Init("tmp", "", mesh2D) + + if ( DV_MONIT_id(IM_ENGT) > 0 ) then + call vars_calc_diagvar( this, 'ENGT', work ) + call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGT), work ) + end if + if ( DV_MONIT_id(IM_ENGP) > 0 ) then + call vars_calc_diagvar( this, 'ENGP', work ) + call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGP), work ) + end if + if ( DV_MONIT_id(IM_ENGK) > 0 ) then + call vars_calc_diagvar( this, 'ENGK', work ) + call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGK), work ) + end if + + call work%Final() return end subroutine SWVars_Monitor From b47db2bfb55bebb81cf16be7b06445fe68f2c285 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 18:04:46 +0900 Subject: [PATCH 07/98] Modify a statement. --- model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 b/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 index 2be2288c..27184fcf 100644 --- a/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 +++ b/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 @@ -319,12 +319,11 @@ subroutine restart_write implicit none !---------------------------------------- - if ( atmos%isActivated() .and. atmos%time_manager%do_restart) then call atmos%vars%Write_restart_file() end if return - end subroutine + end subroutine restart_write end module mod_dg_driver \ No newline at end of file From efcec378414eb512aeb494a897370149ea041c7b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 18:11:59 +0900 Subject: [PATCH 08/98] Add standard test cases of global shallow water model which are proposed by Williamson et al. (1992). --- .../scale_atm_dyn_dgm_globalsw.F90 | 260 ++++++++++++++++++ .../global_shallow_water/test/Makefile.common | 144 ++++++++++ .../test/case/W92_case2/Makefile | 28 ++ .../test/case/W92_case2/init.conf | 39 +++ .../test/case/W92_case2/mod_user.F90 | 203 ++++++++++++++ .../test/case/W92_case2/run.conf | 72 +++++ .../test/case/W92_case5/Makefile | 28 ++ .../test/case/W92_case5/init.conf | 38 +++ .../test/case/W92_case5/mod_user.F90 | 209 ++++++++++++++ .../test/case/W92_case5/run.conf | 77 ++++++ .../test/case/W92_case6/Makefile | 28 ++ .../test/case/W92_case6/init.conf | 38 +++ .../test/case/W92_case6/mod_user.F90 | 226 +++++++++++++++ .../test/case/W92_case6/run.conf | 77 ++++++ 14 files changed, 1467 insertions(+) create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 create mode 100644 model/global_shallow_water/test/Makefile.common create mode 100644 model/global_shallow_water/test/case/W92_case2/Makefile create mode 100644 model/global_shallow_water/test/case/W92_case2/init.conf create mode 100644 model/global_shallow_water/test/case/W92_case2/mod_user.F90 create mode 100644 model/global_shallow_water/test/case/W92_case2/run.conf create mode 100644 model/global_shallow_water/test/case/W92_case5/Makefile create mode 100644 model/global_shallow_water/test/case/W92_case5/init.conf create mode 100644 model/global_shallow_water/test/case/W92_case5/mod_user.F90 create mode 100644 model/global_shallow_water/test/case/W92_case5/run.conf create mode 100644 model/global_shallow_water/test/case/W92_case6/Makefile create mode 100644 model/global_shallow_water/test/case/W92_case6/init.conf create mode 100644 model/global_shallow_water/test/case/W92_case6/mod_user.F90 create mode 100644 model/global_shallow_water/test/case/W92_case6/run.conf diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 new file mode 100644 index 00000000..f4dc9109 --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 @@ -0,0 +1,260 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / global shallow water +!! +!! @par Description +!! DGM scheme for Atmospheric dynamical process. +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_globalsw + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + + use scale_const, only: & + GRAV => CONST_GRAV + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_mesh_base2d, only: MeshBase2D + use scale_localmeshfield_base, only: LocalMeshField2D + use scale_meshfield_base, only: MeshField2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_globalsw_Init + public :: atm_dyn_dgm_globalsw_Final + public :: atm_dyn_dgm_globalsw_cal_tend + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + integer, private, parameter :: VARS_H_ID = 1 + integer, private, parameter :: VARS_U1_ID = 2 + integer, private, parameter :: VARS_u2_ID = 3 + integer, private, parameter :: PROG_VARS_NUM = 3 + + private :: cal_del_flux_dyn + +contains + subroutine atm_dyn_dgm_globalsw_Init( mesh ) + implicit none + class(MeshBase2D), intent(in) :: mesh + !-------------------------------------------- + return + end subroutine atm_dyn_dgm_globalsw_Init + + + subroutine atm_dyn_dgm_globalsw_Final() + implicit none + !-------------------------------------------- + return + end subroutine atm_dyn_dgm_globalsw_Final + + !------------------------------- + +!OCL SERIAL + subroutine atm_dyn_dgm_globalsw_cal_tend( & + h_dt, U_dt, V_dt, & ! (out) + h_, U_, V_, hs_, u1_, u2_, CORIOLIS, & ! (in) + Dx, Dy, Sx, Sy, Lift, lmesh, elem ) + + use scale_atm_dyn_dgm_spongelayer, only: & + atm_dyn_dgm_spongelayer_add_tend + + implicit none + + class(LocalMesh2D), intent(in) :: lmesh + class(elementbase2D), intent(in) :: elem + type(SparseMat), intent(in) :: Dx, Dy, Sx, Sy, Lift + real(RP), intent(out) :: h_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: U_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: V_dt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: h_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: U_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: V_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: hs_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: u1_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: u2_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: CORIOLIS(elem%Np,lmesh%NeA) + + real(RP) :: Fx(elem%Np), Fy(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP) :: del_flux_aux(elem%NfpTot,lmesh%Ne,1) + real(RP) :: u1_dt(elem%Np), u2_dt(elem%Np) + real(RP) :: VOR(elem%Np), E(elem%Np) + integer :: ke + !------------------------------------------------------------------------ + + call PROF_rapstart('cal_dyn_tend_bndflux', 3) + call cal_del_flux_dyn( del_flux, del_flux_aux, & ! (out) + h_, U_, V_, hs_, u1_, u2_, & ! (in) + lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,2,2), & ! (in) + lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), & ! (in) + lmesh%vmapM, lmesh%vmapP, & ! (in) + lmesh, elem ) ! (in) + call PROF_rapend('cal_dyn_tend_bndflux', 3) + + !----- + call PROF_rapstart('cal_dyn_tend_interior', 3) + + !$omp parallel do private( & + !$omp E, VOR, & + !$omp u1_dt, u2_dt, Fx, Fy, LiftDelFlx ) + do ke = lmesh%NeS, lmesh%NeE + !-- + call sparsemat_matmul(Dx, u2_(:,ke), Fx) + call sparsemat_matmul(Dy, u1_(:,ke), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_aux(:,ke,1), LiftDelFlx) + + VOR(:) = ( & + lmesh%Escale(:,ke,1,1) * Fx(:) & + - lmesh%Escale(:,ke,2,2) * Fy(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + + E(:) = Grav * ( hs_(:,ke) + h_(:,ke) ) & + + 0.5_RP * ( u1_(:,ke) * U_(:,ke) + u2_(:,ke) * V_(:,ke) ) + + !-- h + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * h_(:,ke) * U_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * h_(:,ke) * V_(:,ke), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_H_ID), LiftDelFlx) + + h_dt(:,ke) = - ( & + lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + ! if (lmesh%panelID==1 .and. ke==1 )then + ! write(*,*) "Gsqrt:", lmesh%Gsqrt(:,ke) + ! write(*,*) "Fx:", Fx(:) + ! write(*,*) "Fy:", Fy(:) + ! write(*,*) "Lift:", LiftDelFlx(:) + ! write(*,*) "ht:", h_dt(:,ke) + ! end if + !-- u1 + call sparsemat_matmul(Dx, E(:), Fx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_u1_ID), LiftDelFlx) + + u1_dt(:) = - ( & + lmesh%Escale(:,ke,1,1) * Fx(:) & + + LiftDelFlx(:) & + - lmesh%Gsqrt(:,ke) * ( CORIOLIS(:,ke) + VOR(:) ) * V_(:,ke) ) + + !-- u2 + call sparsemat_matmul(Dy, E(:), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_u2_ID), LiftDelFlx) + + u2_dt(:) = - ( & + lmesh%Escale(:,ke,2,2) * Fy(:) & + + LiftDelFlx(:) & + + lmesh%Gsqrt(:,ke) * ( CORIOLIS(:,ke) + VOR(:) ) * U_(:,ke) ) + + !-- + U_dt(:,ke) = lmesh%GIJ(:,ke,1,1) * u1_dt(:) + lmesh%GIJ(:,ke,1,2) * u2_dt(:) + V_dt(:,ke) = lmesh%GIJ(:,ke,2,1) * u1_dt(:) + lmesh%GIJ(:,ke,2,2) * u2_dt(:) + end do + + call PROF_rapend('cal_dyn_tend_interior', 3) + + return + end subroutine atm_dyn_dgm_globalsw_cal_tend + + !------ + +!OCL SERIAL + subroutine cal_del_flux_dyn( del_flux, del_flux_aux, & + h_, U_, V_, hs_, u1_, u2_, & + Gsqrt_, G11_, G22_, nx, ny, vmapM, vmapP, lmesh, elem ) + + implicit none + + class(LocalMesh2D), intent(in) :: lmesh + class(elementbase2D), intent(in) :: elem + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_aux(elem%NfpTot,lmesh%Ne,1) + real(RP), intent(in) :: h_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: U_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: V_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: hs_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: u1_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: u2_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt_(elem%Np*lmesh%Ne) + real(RP), intent(in) :: G11_(elem%Np*lmesh%Ne) + real(RP), intent(in) :: G22_(elem%Np*lmesh%Ne) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + + integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: h_P(elem%NfpTot), h_M(elem%NfpTot) + real(RP) :: E_P(elem%NfpTot), E_M(elem%NfpTot) + real(RP) :: Gii(elem%NfpTot) + !------------------------------------------------------------------------ + + + !$omp parallel do private( iM, iP, & + !$omp alpha, VelM, VelP, & + !$omp h_P, h_M, E_P, E_M, Gii ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + + h_M(:) = h_(iM) + h_P(:) = h_(iP) + VelM(:) = U_(iM) * nx(:,ke) + V_(iM) * ny(:,ke) + VelP(:) = U_(iP) * nx(:,ke) + V_(iP) * ny(:,ke) + Gii(:) = G11_(iM) * abs(nx(:,ke)) + G22_(iM) * abs(ny(:,ke)) + + E_M(:) = 0.5_RP * ( U_(iM) * u1_(iM) + V_(iM) * u2_(iM) ) & + + Grav * ( h_M(:) + hs_(iM) ) + E_P(:) = 0.5_RP * ( U_(iP) * u1_(iP) + V_(iP) * u2_(iP) ) & + + Grav * ( h_P(:) + hs_(iP) ) + + alpha(:) = max( sqrt( Gii(:) * Grav * (h_M(:) + hs_(iM)) ) + abs(VelM(:)), & + sqrt( Gii(:) * Grav * (h_P(:) + hs_(iP)) ) + abs(VelP(:)) ) + alpha(:) = 0.0_RP + del_flux(:,ke,VARS_h_ID) = 0.5_RP * Gsqrt_(iM) * ( & + (h_P(:) * VelP(:) - h_M(:) * VelM(:) ) & + - alpha(:) * ( h_P(:) - h_M(:) ) ) + + del_flux(:,ke,VARS_u1_ID) = 0.5_RP * ( & + ( E_P(:) - E_M(:) ) * nx(:,ke) & + - alpha(:) * ( u1_(iP) - u1_(iM) ) ) + + del_flux(:,ke,VARS_u2_ID) = 0.5_RP * ( & + ( E_P(:) - E_M(:) ) * ny(:,ke) & + - alpha(:) * ( u2_(iP) - u2_(iM) ) ) + + del_flux_aux(:,ke,1) = 0.5_RP * ( & + ( u2_(iP) - u2_(iM) ) * nx(:,ke) & + - ( u1_(iP) - u1_(iM) ) * ny(:,ke) ) + end do + + return + end subroutine cal_del_flux_dyn + +end module scale_atm_dyn_dgm_globalsw diff --git a/model/global_shallow_water/test/Makefile.common b/model/global_shallow_water/test/Makefile.common new file mode 100644 index 00000000..9c97eddb --- /dev/null +++ b/model/global_shallow_water/test/Makefile.common @@ -0,0 +1,144 @@ +################################################################################ +# +# Common Makefile for each test (Please include this file) +# +################################################################################ + +ifeq ($(origin SYSDEP_DIR), undefined) + SYSDEP_DIR = $(TOPDIR)/sysdep +endif + +msg1 = "\n" + +ifeq ($(SCALE_DEBUG),T) + msg1 += "SCALE_DEBUG is set.\n" + USELOCALBIN = T +endif + +ifeq ($(SCALE_USE_SINGLEFP),T) + msg1 += "SCALE_USE_SINGLEFP is set.\n" + USELOCALBIN = T +endif + +ifeq ($(SCALE_USE_FIXEDINDEX),T) + msg1 += "SCALE_USE_FIXEDINDEX is set.\n" + USELOCALBIN = T +endif + +ifneq ($(ORG_SRCS),) + msg1 += "User-defined file is used.\n" + USELOCALBIN = T +endif + +ifeq ($(SCALE_DISABLE_LOCALBIN),T) + USELOCALBIN = F +endif + +ifeq ($(USELOCALBIN),T) + BUILD_DIR := $(PWD)/.libs + BINDIR = $(PWD) + msg1 += "The location of executable files is changed to $(BINDIR)\n" +else + BUILD_DIR := $(TOPDIR)/.libs + BINDIR = $(TOPDIR)/bin +endif + +ifeq ($(origin PPNAME), undefined) + PPNAME = +endif + +ifeq ($(origin INITNAME), undefined) + INITNAME = global_shallow_water_init +endif + +ifeq ($(origin BINNAME), undefined) + BINNAME = global_shallow_water +endif + +ifeq ($(origin N2GNAME), undefined) + N2GNAME = net2g +endif + +ifeq ($(origin PPCONF), undefined) + PPCONF = NONE +endif + +ifeq ($(origin INITCONF), undefined) + INITCONF = NONE +endif + +ifeq ($(origin RUNCONF), undefined) + RUNCONF = NONE +endif + +ifeq ($(origin N2GCONF), undefined) + N2GCONF = NONE +endif + +#UTILDIR = ${TOPDIR}/scale-rm/util/netcdf2grads_h + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + + +all: build + + +$(BUILD_DIR)/%.F90: $(CODE_DIR)/%.F90 + mkdir -p $(BUILD_DIR) + cp -f $< $@ + +build: $(patsubst %,$(BUILD_DIR)/%,$(ORG_SRCS)) + @echo -e "$(msg1)" + mkdir -p $(BUILD_DIR) + $(MAKE) -C $(GLOBALSWDIR)/src SYSDEP_DIR=$(SYSDEP_DIR) \ + BUILD_DIR=$(BUILD_DIR) \ + BINDIR=$(BINDIR) + +util: + $(MAKE) -C $(UTILDIR) + +run: jobshell + $(JOBSUB) run.sh + +jobshell: + @if [ -f ../Mkjobshell.$(SCALE_FE_SYS).sh ]; then \ + bash ../Mkjobshell.$(SCALE_FE_SYS).sh $(BINDIR) \ + $(PPNAME) $(INITNAME) $(BINNAME) $(N2GNAME) \ + $(PPCONF) $(INITCONF) $(RUNCONF) $(N2GCONF) \ + $(TPROC) \ + $(DATPARAM) $(DATDISTS); \ + else \ + bash $(SYSDEP_DIR)/Mkjobshell.$(SCALE_FE_SYS).sh $(BINDIR) \ + $(PPNAME) $(INITNAME) $(BINNAME) $(N2GNAME) \ + $(PPCONF) $(INITCONF) $(RUNCONF) $(N2GCONF) \ + $(TPROC) \ + $(DATPARAM) $(DATDISTS); \ + fi + +vis: + bash ./visualize/visualize.sh + +eval: + bash ./evaluate/evaluate.sh + + + +.PHONY: allclean distclean clean + +allclean: distclean clean + $(MAKE) -C $(GLOBALSWDIR)/src allclean BINDIR=$(BINDIR) \ + BUILD_DIR=$(BUILD_DIR) \ + SYSDEP_DIR=$(SYSDEP_DIR) + +distclean: clean + $(MAKE) -C $(GLOBALSWDIR)/src distclean BINDIR=$(BINDIR) \ + BUILD_DIR=$(BUILD_DIR) \ + SYSDEP_DIR=$(SYSDEP_DIR) + rm -f *.nc *LOG.pe* monitor.pe* latlon* run.sh + +clean: + $(MAKE) -C $(GLOBALSWDIR)/src clean BINDIR=$(BINDIR) \ + BUILD_DIR=$(BUILD_DIR) \ + SYSDEP_DIR=$(SYSDEP_DIR) + diff --git a/model/global_shallow_water/test/case/W92_case2/Makefile b/model/global_shallow_water/test/case/W92_case2/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case2/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/global_shallow_water/test/case/W92_case2/init.conf b/model/global_shallow_water/test/case/W92_case2/init.conf new file mode 100644 index 00000000..9f645e72 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case2/init.conf @@ -0,0 +1,39 @@ +#--- Configuration file for a test case of W92 case2 ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +! &PARAM_MKINIT +! initname = 'W92_case2', +!/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP + alpha = 0.0D0, +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 1.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/global_shallow_water/test/case/W92_case2/mod_user.F90 b/model/global_shallow_water/test/case/W92_case2/mod_user.F90 new file mode 100644 index 00000000..3ed8a893 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case2/mod_user.F90 @@ -0,0 +1,203 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! Test case 2 of Williamson et al. (1992) +!! Steady-state geostrophic flow +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_globalsw_component, only: & + GlobalSWComponent + + use scale_element_base, only: ElementBase2D + use scale_localmesh_2d, only: LocalMesh2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_W92_case2 + contains + procedure :: setInitCond_lc => exp_SetInitCond_W92_case2 + end type + type(Exp_W92_case2), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( swmodel ) + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + !------------------------------------------ + + call exp_manager%Init('W92_case2') + call exp_manager%SetInitCond( & + swmodel%mesh, swmodel%vars%PROGVARS_manager, swmodel%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(GlobalSWComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_W92_case2( this, & + h, U, V, hs, u1, u2, & + x, y, lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + RPlanet => CONST_RADIUS, & + OMG => CONST_OHM + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + implicit none + + class(Exp_W92_case2), intent(inout) :: this + type(LocalMesh2D), intent(in) :: lcmesh + class(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: h(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: hs(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u2(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + + real(RP), parameter :: PHI0 = 2.94E4_RP + real(RP) :: U0 + real(RP) :: alpha + namelist /PARAM_EXP/ & + alpha + + integer, parameter :: IntrpPolyOrder_h = 6 + integer, parameter :: IntrpPolyOrder_v = 6 + real(RP), allocatable :: PRES_purtub(:,:) + + real(RP) :: VelLon(elem%Np,lcmesh%Ne) + real(RP) :: VelLat(elem%Np,lcmesh%Ne) + integer :: ke + integer :: ierr + !----------------------------------------------------------------------------- + + U0 = 2.0_RP * PI * RPlanet / ( 12.0_RP * 2.0_RP * PI / OMG ) + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("W92Case2_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("W92Case2_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + h(:,ke) = ( PHI0 & + - 0.5_RP * U0 * ( 2.0_RP * RPlanet * OMG + U0 ) & + * ( sin(lcmesh%lat(:,ke)) * cos(alpha) - cos(lcmesh%lon(:,ke)) * cos(lcmesh%lat(:,ke)) * sin(alpha) )**2 & + ) / Grav + hs(:,ke) = 0.0_RP + VelLon(:,ke) = U0 * ( cos(alpha) * cos(lcmesh%lat(:,ke)) + sin(alpha) * cos(lcmesh%lon(:,ke)) * sin(lcmesh%lat(:,ke)) ) + VelLon(:,ke) = VelLon(:,ke) / cos(lcmesh%lat(:,ke)) + VelLat(:,ke) = - U0 * sin(alpha) * sin(lcmesh%lon(:,ke)) + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + VelLon(:,:), VelLat(:,:), U(:,lcmesh%NeS:lcmesh%NeE), V(:,lcmesh%NeS:lcmesh%NeE) ) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + u1(:,ke) = lcmesh%G_ij(:,ke,1,1) * U(:,ke) + lcmesh%G_ij(:,ke,1,2) * V(:,ke) + u2(:,ke) = lcmesh%G_ij(:,ke,2,1) * U(:,ke) + lcmesh%G_ij(:,ke,2,2) * V(:,ke) + end do + + return + end subroutine exp_SetInitCond_W92_case2 +end module mod_user diff --git a/model/global_shallow_water/test/case/W92_case2/run.conf b/model/global_shallow_water/test/case/W92_case2/run.conf new file mode 100644 index 00000000..6d816649 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case2/run.conf @@ -0,0 +1,72 @@ +#--- Configuration file for a test case of W92 case2 ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 864000D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 300.0D0, + TIME_DT_UNIT = 'SEC', +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 300.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +&PARAM_SW_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 150.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .false., + NUMDIFF_FLAG = .false., +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 14400.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='h' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='Vel_lon' / +&HISTORY_ITEM name='Vel_lat' / + +#*** Statistics ******************************************* +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 18 +/ +&MONITOR_ITEM name='h' / +&MONITOR_ITEM name='ENGT' / +&MONITOR_ITEM name='ENGK' / +&MONITOR_ITEM name='ENGI' / +&MONITOR_ITEM name='ENGP' / diff --git a/model/global_shallow_water/test/case/W92_case5/Makefile b/model/global_shallow_water/test/case/W92_case5/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case5/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/global_shallow_water/test/case/W92_case5/init.conf b/model/global_shallow_water/test/case/W92_case5/init.conf new file mode 100644 index 00000000..550e8cc5 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case5/init.conf @@ -0,0 +1,38 @@ +#--- Configuration file for a test case of W92 case5 ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +! &PARAM_MKINIT +! initname = 'W92_case5', +!/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 1.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/global_shallow_water/test/case/W92_case5/mod_user.F90 b/model/global_shallow_water/test/case/W92_case5/mod_user.F90 new file mode 100644 index 00000000..d20fa3e4 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case5/mod_user.F90 @@ -0,0 +1,209 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! Test case 5 of Williamson et al. (1992) +!! Zonal flow over an isolated mountain +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_globalsw_component, only: & + GlobalSWComponent + + use scale_element_base, only: ElementBase2D + use scale_localmesh_2d, only: LocalMesh2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_W92_case5 + contains + procedure :: setInitCond_lc => exp_SetInitCond_W92_case5 + end type + type(Exp_W92_case5), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( swmodel ) + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + !------------------------------------------ + + call exp_manager%Init('W92_case5') + call exp_manager%SetInitCond( & + swmodel%mesh, swmodel%vars%PROGVARS_manager, swmodel%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(GlobalSWComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_W92_case5( this, & + h, U, V, hs, u1, u2, & + x, y, lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + RPlanet => CONST_RADIUS, & + OMG => CONST_OHM + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + implicit none + + class(Exp_W92_case5), intent(inout) :: this + type(LocalMesh2D), intent(in) :: lcmesh + class(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: h(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: hs(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u2(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + + real(RP), parameter :: h0 = 5.96E3_RP + real(RP) :: R_mt + real(RP) :: LonC_mt + real(RP) :: LatC_mt + real(RP) :: U0 + namelist /PARAM_EXP/ & + U0 + + integer, parameter :: IntrpPolyOrder_h = 6 + integer, parameter :: IntrpPolyOrder_v = 6 + + real(RP) :: VelLon(elem%Np,lcmesh%Ne) + real(RP) :: VelLat(elem%Np,lcmesh%Ne) + integer :: ke + integer :: ierr + + real(RP) :: r(elem%Np) + !----------------------------------------------------------------------------- + + U0 = 20.0_RP + R_mt = PI / 9.0_RP + LonC_mt = 0.5_RP * PI + LatC_mt = PI / 6.0_RP + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("W92Case5_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("W92Case5_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + !$omp parallel do private(r) + do ke=lcmesh%NeS, lcmesh%NeE + r(:) = sqrt( min(R_mt**2, (lcmesh%lon(:,ke) - LonC_mt)**2 + (lcmesh%lat(:,ke) - LatC_mt)**2) ) + hs(:,ke) = 2000.0_RP * ( 1.0_RP - r(:) / R_mt ) + + h(:,ke) = h0 - hs(:,ke) & + - 0.5_RP * U0 * ( 2.0_RP * RPlanet * OMG + U0 ) * sin(lcmesh%lat(:,ke))**2 / Grav + VelLon(:,ke) = U0 + VelLat(:,ke) = 0.0_RP + + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + VelLon(:,:), VelLat(:,:), U(:,lcmesh%NeS:lcmesh%NeE), V(:,lcmesh%NeS:lcmesh%NeE) ) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + u1(:,ke) = lcmesh%G_ij(:,ke,1,1) * U(:,ke) + lcmesh%G_ij(:,ke,1,2) * V(:,ke) + u2(:,ke) = lcmesh%G_ij(:,ke,2,1) * U(:,ke) + lcmesh%G_ij(:,ke,2,2) * V(:,ke) + end do + + return + end subroutine exp_SetInitCond_W92_case5 +end module mod_user diff --git a/model/global_shallow_water/test/case/W92_case5/run.conf b/model/global_shallow_water/test/case/W92_case5/run.conf new file mode 100644 index 00000000..a53279e5 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case5/run.conf @@ -0,0 +1,77 @@ +#--- Configuration file for a test case of W92 case2 ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 1296000D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 300.0D0, + TIME_DT_UNIT = 'SEC', +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 300.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +&PARAM_SW_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 150.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_SW_DYN_MODALFILTER + MF_ETAC = 0.6666666666D0, + MF_ALPHA = 1.0D-2, + MF_ORDER = 16, +/ +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 28800.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='h' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='Height' / +&HISTORY_ITEM name='Vel_lon' / +&HISTORY_ITEM name='Vel_lat' / + +#*** Statistics ******************************************* +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 18 +/ +&MONITOR_ITEM name='h' / +&MONITOR_ITEM name='ENGT' / +&MONITOR_ITEM name='ENGK' / +&MONITOR_ITEM name='ENGI' / +&MONITOR_ITEM name='ENGP' / diff --git a/model/global_shallow_water/test/case/W92_case6/Makefile b/model/global_shallow_water/test/case/W92_case6/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case6/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/global_shallow_water/test/case/W92_case6/init.conf b/model/global_shallow_water/test/case/W92_case6/init.conf new file mode 100644 index 00000000..d70faa22 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case6/init.conf @@ -0,0 +1,38 @@ +#--- Configuration file for a test case of W92 case5 ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +! &PARAM_MKINIT +! initname = 'W92_case6', +!/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 1.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/global_shallow_water/test/case/W92_case6/mod_user.F90 b/model/global_shallow_water/test/case/W92_case6/mod_user.F90 new file mode 100644 index 00000000..7c303353 --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case6/mod_user.F90 @@ -0,0 +1,226 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! Test case 5 of Williamson et al. (1992) +!! Rossby–Haurwitz wave +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_globalsw_component, only: & + GlobalSWComponent + + use scale_element_base, only: ElementBase2D + use scale_localmesh_2d, only: LocalMesh2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_W92_case6 + contains + procedure :: setInitCond_lc => exp_SetInitCond_W92_case6 + end type + type(Exp_W92_case6), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( swmodel ) + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + !------------------------------------------ + + call exp_manager%Init('W92_case6') + call exp_manager%SetInitCond( & + swmodel%mesh, swmodel%vars%PROGVARS_manager, swmodel%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(GlobalSWComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_W92_case6( this, & + h, U, V, hs, u1, u2, & + x, y, lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + RPlanet => CONST_RADIUS, & + OMG => CONST_OHM + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + implicit none + + class(Exp_W92_case6), intent(inout) :: this + type(LocalMesh2D), intent(in) :: lcmesh + class(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: h(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: hs(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u2(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + + real(RP) :: H00 + real(RP) :: K_ + real(DP), parameter :: OM = 7.848d-6 + + namelist /PARAM_EXP/ & + H00, K_ + + + real(RP) :: VelLon(elem%Np,lcmesh%Ne) + real(RP) :: VelLat(elem%Np,lcmesh%Ne) + real(RP) :: lon(elem%Np) + real(RP) :: lat(elem%Np) + real(RP) :: A(elem%Np) + real(RP) :: B(elem%Np) + real(RP) :: C(elem%Np) + integer :: ke + integer :: ierr + + real(RP) :: r(elem%Np) + !----------------------------------------------------------------------------- + + H00 = 8000.0_RP + K_ = OM + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("W92Case6_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("W92Case6_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + !$omp parallel do private(lon, lat, A, B, C) + do ke=lcmesh%NeS, lcmesh%NeE + lon(:) = lcmesh%lon(:,ke) + lat(:) = lcmesh%lat(:,ke) + + VelLon(:,ke) = RPlanet * ( OM & + - K_ * cos(lat(:))**2 * ( -4.0_RP * sin(lat(:))**2 + cos(lat(:))**2 ) * cos(4.0_RP*lon(:)) & ! * cos(lat(:)) + ) + VelLat(:,ke) = - RPlanet * K_ * 4.0_RP * cos(lat(:))**3 * sin(lat(:)) * sin(4.0_RP*lon(:)) + + + A(:) = 0.5_RP * OM * ( 2.0_RP * OMG + OM ) * cos(lat(:))**2 & + + 0.25_RP * K_**2 * cos(lat(:))**(2*4) & + * ( dble(4+1) * cos(lat(:))**2 + dble(2 * 4**2 - 4 - 2) - 2.0_RP * dble(4**2) / cos(lat(:))**2 ) + + B(:) = 2.0_RP * ( OMG + OM ) * K_ / dble((4 + 1)*(4 + 2)) * cos(lat(:))**4 & + * ( dble(4**2 + 2*4 +2) - dble((4 + 1)**2)*cos(lat(:))**2 ) + + C(:) = 0.25_RP * K_**2 * cos(lat(:))**(2*4) & + * ( dble(4 + 1) * cos(lat(:))**2 - dble(4 + 2) ) + + h(:,ke) = H00 + ( & + RPlanet**2 * ( A(:) + B(:) * cos(4.0_RP * lon(:)) + C(:) * cos(2.0_RP * 4.0_RP * lon(:)) ) & + ) / Grav + hs(:,ke) = 0.0_RP + + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + VelLon(:,:), VelLat(:,:), U(:,lcmesh%NeS:lcmesh%NeE), V(:,lcmesh%NeS:lcmesh%NeE) ) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + u1(:,ke) = lcmesh%G_ij(:,ke,1,1) * U(:,ke) + lcmesh%G_ij(:,ke,1,2) * V(:,ke) + u2(:,ke) = lcmesh%G_ij(:,ke,2,1) * U(:,ke) + lcmesh%G_ij(:,ke,2,2) * V(:,ke) + end do + + return + end subroutine exp_SetInitCond_W92_case6 +end module mod_user diff --git a/model/global_shallow_water/test/case/W92_case6/run.conf b/model/global_shallow_water/test/case/W92_case6/run.conf new file mode 100644 index 00000000..586f923d --- /dev/null +++ b/model/global_shallow_water/test/case/W92_case6/run.conf @@ -0,0 +1,77 @@ +#--- Configuration file for a test case of W92 case2 ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 1296000D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +&PARAM_SW_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 100.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_SW_DYN_MODALFILTER + MF_ETAC = 0.333333333333D0, + MF_ALPHA = 2.0D-2, + MF_ORDER = 16, +/ +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 28800.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='h' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='Height' / +&HISTORY_ITEM name='Vel_lon' / +&HISTORY_ITEM name='Vel_lat' / + +#*** Statistics ******************************************* +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 18 +/ +&MONITOR_ITEM name='h' / +&MONITOR_ITEM name='ENGT' / +&MONITOR_ITEM name='ENGK' / +&MONITOR_ITEM name='ENGI' / +&MONITOR_ITEM name='ENGP' / From 9a89ea513066ea5f5cf48ede932f0df40c2c4721 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 18:12:45 +0900 Subject: [PATCH 09/98] Update README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cb93db4b..8716c0f7 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,13 @@ Futhermore, some dynamical cores of atmospheric and oceanic model with DGM will ## Models with FE library +### Shallow water model +- Global shallow water model using cubed-sphere mesh + ### Nonhydrostatic atmospheric model - Simple 2D model with only dynamical process - 3D model with dynamical process and some physical processes - ## Simple samples for intrduction to DGM. ### 1D problems - linear advection equation From e64bc5828f6a225d9877f70bc8fe34b73e7be8cb Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 11 May 2021 18:14:44 +0900 Subject: [PATCH 10/98] Build source codes of global shallow water model in github CI. --- .github/workflows/FEProject_build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index 169098d5..7de37a01 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -125,6 +125,9 @@ jobs: export SCALE_FE_SYS=Linux64-gnu-ompi export SCALE=${GITHUB_WORKSPACE}/../scale + echo "Build global shallow water model" + make -C global_shallow_water/src + echo "Build 2D nonhydrostatic atmospheric model" make -C atm_nonhydro2d/src From 866bc4be1cb713cccd796173d8a7e140b8a8bfd5 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 13 May 2021 10:18:15 +0900 Subject: [PATCH 11/98] Fix a bug in calculating the statistics of variables. --- FElib/src/data/scale_meshfield_statistics.F90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/FElib/src/data/scale_meshfield_statistics.F90 b/FElib/src/data/scale_meshfield_statistics.F90 index 23da6672..11bb37e4 100644 --- a/FElib/src/data/scale_meshfield_statistics.F90 +++ b/FElib/src/data/scale_meshfield_statistics.F90 @@ -329,10 +329,12 @@ subroutine search_maxmin_local( VA, field_list, lcmesh_list, & refElem => lcmesh%refElem do v=1, VA call field_list(v)%GetLocalMeshField(n, lcfield) - statval_l( v,:) = lcfield%val(1,lcmesh%NeS) - statidx_l(1,v,:) = 1 - statidx_l(2,v,:) = lcmesh%NeS - statidx_l(3,v,:) = n + if (n==1) then + statval_l( v,:) = lcfield%val(1,lcmesh%NeS) + statidx_l(1,v,:) = 1 + statidx_l(2,v,:) = lcmesh%NeS + statidx_l(3,v,:) = n + end if do ke=lcmesh%NeS, lcmesh%NeE do p =1, refElem%Np if ( lcfield%val(p,ke) > statval_l(v,1) ) then From dd39d28828001a7b45ef943497066577ede52a13 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 13 May 2021 10:19:45 +0900 Subject: [PATCH 12/98] Enable to calculate the diagnostics in a global shallow water model. --- .../src/global_shallow_water.F90 | 2 +- .../src/mod_globalsw_component.F90 | 4 +- .../global_shallow_water/src/mod_sw_vars.F90 | 112 ++++++++++++++++-- 3 files changed, 105 insertions(+), 13 deletions(-) diff --git a/model/global_shallow_water/src/global_shallow_water.F90 b/model/global_shallow_water/src/global_shallow_water.F90 index cb6f2f55..eddc29ad 100644 --- a/model/global_shallow_water/src/global_shallow_water.F90 +++ b/model/global_shallow_water/src/global_shallow_water.F90 @@ -161,7 +161,7 @@ subroutine update() end if !########## Calculate diagnostic variables ########## - call swmodel%vars%Clac_diagnostics() + call swmodel%vars%Clac_diagnostics( swmodel%mesh ) call swmodel%vars%AUXVARS_manager%MeshFieldComm_Exchange() !#### Check values ################################# diff --git a/model/global_shallow_water/src/mod_globalsw_component.F90 b/model/global_shallow_water/src/mod_globalsw_component.F90 index 4893a874..02931d1b 100644 --- a/model/global_shallow_water/src/mod_globalsw_component.F90 +++ b/model/global_shallow_water/src/mod_globalsw_component.F90 @@ -164,13 +164,13 @@ subroutine SW_update( this ) do inner_itr=1, this%time_manager%Get_process_inner_itr_num( tm_process_id ) call this%dyn_proc%update( & this%mesh, this%vars%PROGVARS_manager, this%vars%AUXVARS_manager, & - this%vars%PHYTENDS_manager, is_update ) + this%vars%PHYTENDS_manager, is_update ) end do call PROF_rapend('GlobalSW_dynamics', 1) end if !########## Calculate diagnostic variables ########## - !call this%vars%Clac_diagnostics() + call this%vars%Clac_diagnostics( this%mesh ) call this%vars%AUXVARS_manager%MeshFieldComm_Exchange() !#### Check values ################################# diff --git a/model/global_shallow_water/src/mod_sw_vars.F90 b/model/global_shallow_water/src/mod_sw_vars.F90 index 30072f71..9af5303c 100644 --- a/model/global_shallow_water/src/mod_sw_vars.F90 +++ b/model/global_shallow_water/src/mod_sw_vars.F90 @@ -150,7 +150,7 @@ module mod_sw_vars DATA SW_DIAGVARS_VINFO / & VariableInfo( SW_DIAGVARS_Vellon_ID, 'Vel_lon', 'velocity u' , 'm/s' , 2, 'XY', 'lon_wind' ), & VariableInfo( SW_DIAGVARS_Vellat_ID, 'Vel_lat', 'velocity v' , 'm/s' , 2, 'XY', 'lat_wind' ), & - VariableInfo( SW_DIAGVARS_Vellat_ID, 'Height', 'Height' , 'm' , 2, 'XY', 'height' ), & + VariableInfo( SW_DIAGVARS_Height_ID, 'Height', 'Height' , 'm' , 2, 'XY', 'height' ), & Variableinfo( SW_DIAGVARS_ENGT , 'ENGT', 'total energy' , 'J/m3' , 2, 'XY', '' ), & Variableinfo( SW_DIAGVARS_ENGP , 'ENGP', 'potential energy' , 'J/m3' , 2, 'XY', '' ), & Variableinfo( SW_DIAGVARS_ENGK , 'ENGK', 'kinetic energy' , 'J/m3' , 2, 'XY', '' ) / @@ -406,7 +406,6 @@ subroutine SWVars_history( this ) if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%PROG_VARS(v) ) end do - call this%Clac_diagnostics() do v = 1, SW_AUXVARS_NUM hst_id = this%AUX_VARS(v)%hist_id if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%AUX_VARS(v) ) @@ -466,7 +465,7 @@ subroutine SWVar_Read_restart_file( this, sw_mesh ) call this%Check( force = .true. ) !-- Calculate diagnostic variables - call this%Clac_diagnostics() + call this%Clac_diagnostics( sw_mesh ) !-- Communicate halo data of hydrostatic & diagnostic variables call this%AUXVARS_manager%MeshFieldComm_Exchange() @@ -731,9 +730,10 @@ end subroutine SWVars_GetLocalMeshPrgVars !----------------------------------------------------------------------------- !> Calculate diagnostic variables - subroutine SWVars_CalculateDiagnostics( this ) + subroutine SWVars_CalculateDiagnostics( this, model_mesh ) implicit none class(SWVars), intent(inout), target :: this + class(SWMesh), intent(in) :: model_mesh type(LocalMesh2D), pointer :: lcmesh2D integer :: n @@ -742,6 +742,8 @@ subroutine SWVars_CalculateDiagnostics( this ) class(MeshField2D), pointer :: field !------------------------------------------------------- + call this%PROGVARS_manager%MeshFieldComm_Exchange() + do varid=SW_AUXVARS_VOR_ID+1, SW_AUXVARS_NUM field => this%AUX_VARS(varid) do n=1, field%mesh%LOCAL_MESH_NUM @@ -758,19 +760,27 @@ subroutine SWVars_CalculateDiagnostics( this ) end do end do + ! VOR + field => this%AUX_VARS(SW_AUXVARS_VOR_ID) + do n=1, field%mesh%LOCAL_MESH_NUM + lcmesh2D => field%mesh%lcmesh_list(n) + + call vars_eval_vor_lc( field%local(n)%val, & + this%PROG_VARS(SW_PROGVARS_U_ID)%local(n)%val, this%PROG_VARS(SW_PROGVARS_V_ID)%local(n)%val, & + this%AUX_VARS(SW_AUXVARS_u1_ID )%local(n)%val, this%AUX_VARS(SW_AUXVARS_u2_ID )%local(n)%val, & + model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), model_mesh%LiftOptrMat, & + lcmesh2D, lcmesh2D%refElem2D ) + end do + return end subroutine SWVars_CalculateDiagnostics !-- private ----------------------------------------------------------------------- +!OCL SERIAL subroutine vars_calc_diagvar( this, field_name, field_work ) - use scale_const, only: & - Rdry => CONST_Rdry, & - CPdry => CONST_CPdry, & - CVdry => CONST_CVdry, & - PRES00 => CONST_PRE00 - implicit none + class(SWVars), intent(in) :: this character(*), intent(in) :: field_name type(MeshField2D), intent(inout) :: field_work @@ -797,6 +807,84 @@ subroutine vars_calc_diagvar( this, field_name, field_work ) return end subroutine vars_calc_diagvar +!OCL SERIAL + subroutine vars_eval_vor_lc( vor, & + U, V, u1, u2, Dx, Dy, Lift, lcmesh, elem ) + + use scale_sparsemat, only: sparsemat, & + sparsemat_matmul + implicit none + + type(LocalMesh2D), intent(in) :: lcmesh + type(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: vor(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: u2(elem%Np,lcmesh%NeA) + type(SparseMat), intent(in) :: Dx, Dy + type(SparseMat), intent(in) :: Lift + + integer :: ke + real(RP) :: del_flux(elem%NfpTot,lcmesh%Ne,1) + real(RP) :: Fx(elem%Np), Fy(elem%Np), LiftDelFlx(elem%Np) + !---------------------------------------------------- + + call eval_vor_del_flux( del_flux, & + U, V, u1, u2, lcmesh%Gsqrt, lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), & + lcmesh%VMapM, lcmesh%VMapP, lcmesh, lcmesh%refElem2D ) + + !$omp parallel do private(Fx, Fy, LiftDelFlx) + do ke=lcmesh%NeS, lcmesh%NeE + call sparsemat_matmul(Dx, u2(:,ke), Fx) + call sparsemat_matmul(Dy, u1(:,ke), Fy) + call sparsemat_matmul(Lift, lcmesh%Fscale(:,ke) * del_flux(:,ke,1), LiftDelFlx) + + vor(:,ke) = ( lcmesh%Escale(:,ke,1,1) * Fx(:) & + - lcmesh%Escale(:,ke,2,2) * Fy(:) & + + LiftDelFlx(:) ) / lcmesh%Gsqrt(:,ke) + end do + + return + end subroutine vars_eval_vor_lc + +!OCL SERIAL + subroutine eval_vor_del_flux( del_flux_aux, & + U_, V_, u1_, u2_, & + Gsqrt_, nx, ny, vmapM, vmapP, lmesh, elem ) + + implicit none + + class(LocalMesh2D), intent(in) :: lmesh + class(elementbase2D), intent(in) :: elem + real(RP), intent(out) :: del_flux_aux(elem%NfpTot,lmesh%Ne,1) + real(RP), intent(in) :: U_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: V_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: u1_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: u2_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt_(elem%Np*lmesh%Ne) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + + integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) + !------------------------------------------------------------------------ + + + !$omp parallel do private( iM, iP ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + + del_flux_aux(:,ke,1) = 0.5_RP * ( & + ( u2_(iP) - u2_(iM) ) * nx(:,ke) & + - ( u1_(iP) - u1_(iM) ) * ny(:,ke) ) + end do + + return + end subroutine eval_vor_del_flux + +!OCL SERIAL subroutine vars_calc_diagnoseVar( field_name, var_out, & h_, U_, V_, hs_, u1_, u2_, & lcmesh, elem ) @@ -832,6 +920,10 @@ subroutine vars_calc_diagnoseVar( field_name, var_out, & lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & ! (in) U_(:,lcmesh%NeS:lcmesh%NeE), V_(:,lcmesh%NeS:lcmesh%NeE), & ! (in) var_out(:,lcmesh%NeS:lcmesh%NeE), dummy(:,lcmesh%NeS:lcmesh%NeE) ) ! (out) + !$omp parallel do + do ke=1, lcmesh%Ne + var_out(:,ke) = var_out(:,ke) * cos(lcmesh%lat(:,ke)) + end do case('Vel_lat') call CubedSphereCnv_CS2LonLatVec( & lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & ! (in) From 6e794f7e5cbaffe6892ea123899257059d1d2124 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 13 May 2021 10:20:59 +0900 Subject: [PATCH 13/98] Add two test cases for a global shallow water model. --- .../test/case/BarotropicInstability/Makefile | 28 ++ .../test/case/BarotropicInstability/init.conf | 38 +++ .../case/BarotropicInstability/mod_user.F90 | 307 ++++++++++++++++++ .../test/case/BarotropicInstability/run.conf | 78 +++++ .../test/case/CrossPolarFlow/Makefile | 28 ++ .../test/case/CrossPolarFlow/init.conf | 38 +++ .../test/case/CrossPolarFlow/mod_user.F90 | 205 ++++++++++++ .../test/case/CrossPolarFlow/run.conf | 77 +++++ 8 files changed, 799 insertions(+) create mode 100644 model/global_shallow_water/test/case/BarotropicInstability/Makefile create mode 100644 model/global_shallow_water/test/case/BarotropicInstability/init.conf create mode 100644 model/global_shallow_water/test/case/BarotropicInstability/mod_user.F90 create mode 100644 model/global_shallow_water/test/case/BarotropicInstability/run.conf create mode 100644 model/global_shallow_water/test/case/CrossPolarFlow/Makefile create mode 100644 model/global_shallow_water/test/case/CrossPolarFlow/init.conf create mode 100644 model/global_shallow_water/test/case/CrossPolarFlow/mod_user.F90 create mode 100644 model/global_shallow_water/test/case/CrossPolarFlow/run.conf diff --git a/model/global_shallow_water/test/case/BarotropicInstability/Makefile b/model/global_shallow_water/test/case/BarotropicInstability/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/global_shallow_water/test/case/BarotropicInstability/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/global_shallow_water/test/case/BarotropicInstability/init.conf b/model/global_shallow_water/test/case/BarotropicInstability/init.conf new file mode 100644 index 00000000..ad9e7117 --- /dev/null +++ b/model/global_shallow_water/test/case/BarotropicInstability/init.conf @@ -0,0 +1,38 @@ +#--- Configuration file for a test case of W92 case5 ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +! &PARAM_MKINIT +! initname = 'G04_BarotropicInstability', +!/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 1.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 17, + NeGY = 17, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/global_shallow_water/test/case/BarotropicInstability/mod_user.F90 b/model/global_shallow_water/test/case/BarotropicInstability/mod_user.F90 new file mode 100644 index 00000000..d3539c9d --- /dev/null +++ b/model/global_shallow_water/test/case/BarotropicInstability/mod_user.F90 @@ -0,0 +1,307 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! a test case proposed by Galewsky et al. (2004) +!! barotropic instability test +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + RPlanet => CONST_RADIUS, & + OMG => CONST_OHM + + use mod_exp, only: experiment + use mod_globalsw_component, only: & + GlobalSWComponent + + use scale_element_line, only: LineElement + use scale_element_base, only: ElementBase2D + use scale_localmesh_2d, only: LocalMesh2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_G04_BarotropicInstability + contains + procedure :: setInitCond_lc => exp_SetInitCond_G04_BarotropicInstability + end type + type(Exp_G04_BarotropicInstability), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( swmodel ) + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + !------------------------------------------ + + call exp_manager%Init('DB89_CrossPolarFlow') + call exp_manager%SetInitCond( & + swmodel%mesh, swmodel%vars%PROGVARS_manager, swmodel%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(GlobalSWComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_G04_BarotropicInstability( this, & + h, U, V, hs, u1, u2, & + x, y, lcmesh, elem ) + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + implicit none + + class(Exp_G04_BarotropicInstability), intent(inout) :: this + type(LocalMesh2D), intent(in) :: lcmesh + class(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: h(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: hs(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u2(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + + real(RP) :: lat0, lat1 + real(RP) :: umax + real(RP) :: H0 + + real(RP) :: hhat + real(RP) :: phi2 + real(RP) :: alph + real(RP) :: beta + + namelist /PARAM_EXP/ & + lat0, lat1, umax, & + hhat, phi2, alph, beta + + + real(RP) :: VelLon(elem%Np,lcmesh%Ne) + real(RP) :: VelLat(elem%Np,lcmesh%Ne) + integer :: ke + integer :: ierr + + type(LineElement) :: elem1D + integer :: p + + real(RP) :: lon_(elem%Np) + !----------------------------------------------------------------------------- + + lat0 = PI / 7.0_RP + lat1 = 0.5_RP * PI - lat0 + umax = 80.0_RP + H0 = 10.E3_RP + + hhat = 120.0_RP + phi2 = 0.25_RP * PI + alph = 1.0_RP / 3.0_RP + beta = 1.0_RP / 15.0_RP + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("DB89_CrossPolarFlow_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("DB89_CrossPolarFlow_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + call elem1D%Init( 12, .false. ) + + !$omp parallel do private (p, lon_) + do ke=lcmesh%NeS, lcmesh%NeE + + call cal_zonal_vel( VelLon(:,ke), & + lcmesh%lat(:,ke), elem%Np, lat0, lat1, umax ) + VelLon(:,ke) = VelLon(:,ke) / cos(lcmesh%lat(:,ke)) + + VelLat(:,ke) = 0.0_RP + + do p=1, elem%Np + call cal_height_variation( h(p,ke), lcmesh%lat(p,ke), elem1D, lat0, lat1, umax ) + h(p,ke) = H0 + h(p,ke) + end do + + lon_(:) = lcmesh%lon(:,ke) + where ( lon_(:) > PI ) + lon_(:) = lon_(:) - 2.0_RP * PI + end where + where ( abs(lon_(:)) < PI ) + h(:,ke) = h(:,ke) & + + hhat * cos(lcmesh%lat(:,ke)) * exp(- (lon_(:)/alph)**2) & + * exp(- ((phi2 - lcmesh%lat(:,ke))/beta)**2 ) + end where + hs(:,ke) = 0.0_RP + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + VelLon(:,:), VelLat(:,:), U(:,lcmesh%NeS:lcmesh%NeE), V(:,lcmesh%NeS:lcmesh%NeE) ) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + u1(:,ke) = lcmesh%G_ij(:,ke,1,1) * U(:,ke) + lcmesh%G_ij(:,ke,1,2) * V(:,ke) + u2(:,ke) = lcmesh%G_ij(:,ke,2,1) * U(:,ke) + lcmesh%G_ij(:,ke,2,2) * V(:,ke) + end do + + !-- + call elem1D%Final() + + return + end subroutine exp_SetInitCond_G04_BarotropicInstability + + subroutine cal_height_variation( height, & + lat, elem1D, lat0, lat1, umax ) + implicit none + real(RP), intent(out) :: height + real(RP), intent(in) :: lat + type(LineElement), intent(in) :: elem1D + real(RP), intent(in) :: lat0, lat1 + real(RP), intent(in) :: umax + + integer :: ke + integer :: ke_max + real(RP) :: dlat_e_default + real(RP), allocatable :: lat_e(:) + real(RP) :: lat_lc(elem1D%Np) + real(RP) :: u_lc(elem1D%Np) + !-------------------------------------- + + dlat_e_default = 2.5_RP / 180.0_RP * PI + ke_max = int( abs(lat) / dlat_e_default ) + if ( ke_max * dlat_e_default < abs(lat) ) ke_max = ke_max + 1 + + allocate( lat_e(ke_max+1) ) + lat_e(1) = 0.0_RP + do ke=2, ke_max + lat_e(ke) = lat_e(ke-1) + sign(dlat_e_default, lat) + end do + lat_e(ke_max+1) = lat + + ! + height = 0.0_RP + do ke=1, ke_max + lat_lc(:) = lat_e(ke) + 0.5_RP * ( lat_e(ke+1) - lat_e(ke) ) * ( 1.0_RP + elem1D%x1(:) ) + call cal_zonal_vel( u_lc(:), lat_lc(:), elem1D%Np, lat0, lat1, umax ) + + height = height & + - 0.5_RP * ( lat_e(ke+1) - lat_e(ke) ) * RPlanet / Grav & + * sum( elem1D%IntWeight_lgl(:) * u_lc(:) * ( & + 2.0_RP * OMG * sin(lat_lc(:)) + u_lc(:) * tan(lat_lc(:)) / RPlanet ) ) + end do + + return + end subroutine cal_height_variation + + subroutine cal_zonal_vel( u, lat, Np, lat0, lat1, umax ) + integer, intent(in) :: Np + real(RP), intent(out) :: u(Np) + real(RP), intent(in) :: lat(Np) + real(RP), intent(in) :: lat0, lat1 + real(RP), intent(in) :: umax + + real(RP) :: en + !--------------------------------------------------- + + en = exp( - 4.0_RP / (lat1 - lat0)**2 ) + + where( lat0 < lat(:) .and. lat(:) < lat1 ) + u(:) = umax / en * exp( 1.0_RP / ( ( lat(:) - lat0 ) * ( lat(:) - lat1 ) ) ) + elsewhere + u(:) = 0.0_RP + end where + + return + end subroutine cal_zonal_vel + +end module mod_user diff --git a/model/global_shallow_water/test/case/BarotropicInstability/run.conf b/model/global_shallow_water/test/case/BarotropicInstability/run.conf new file mode 100644 index 00000000..8d75400f --- /dev/null +++ b/model/global_shallow_water/test/case/BarotropicInstability/run.conf @@ -0,0 +1,78 @@ +#--- Configuration file for a test case of W92 case2 ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 518400D0, !864000D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 180.0D0, + TIME_DT_UNIT = 'SEC', +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 180.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 17, + NeGY = 17, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +&PARAM_SW_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 30.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_SW_DYN_MODALFILTER + MF_ETAC = 0D0, + MF_ALPHA = 1.0D-1, + MF_ORDER = 16, +/ +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 28800.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='h' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='Height' / +&HISTORY_ITEM name='Vel_lon' / +&HISTORY_ITEM name='Vel_lat' / +&HISTORY_ITEM name='VOR' / + +#*** Statistics ******************************************* +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 18 +/ +&MONITOR_ITEM name='h' / +&MONITOR_ITEM name='ENGT' / +&MONITOR_ITEM name='ENGK' / +&MONITOR_ITEM name='ENGI' / +&MONITOR_ITEM name='ENGP' / diff --git a/model/global_shallow_water/test/case/CrossPolarFlow/Makefile b/model/global_shallow_water/test/case/CrossPolarFlow/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/global_shallow_water/test/case/CrossPolarFlow/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/global_shallow_water/test/case/CrossPolarFlow/init.conf b/model/global_shallow_water/test/case/CrossPolarFlow/init.conf new file mode 100644 index 00000000..c49a60e1 --- /dev/null +++ b/model/global_shallow_water/test/case/CrossPolarFlow/init.conf @@ -0,0 +1,38 @@ +#--- Configuration file for a test case of W92 case5 ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +! &PARAM_MKINIT +! initname = 'DB89_CrossPolarFlow', +!/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 1.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/global_shallow_water/test/case/CrossPolarFlow/mod_user.F90 b/model/global_shallow_water/test/case/CrossPolarFlow/mod_user.F90 new file mode 100644 index 00000000..e68a3149 --- /dev/null +++ b/model/global_shallow_water/test/case/CrossPolarFlow/mod_user.F90 @@ -0,0 +1,205 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! a test case proposed by Donald and Bates (1989) +!! cross-polar flow with a geostrophically balanced initial state +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_globalsw_component, only: & + GlobalSWComponent + + use scale_element_base, only: ElementBase2D + use scale_localmesh_2d, only: LocalMesh2D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_DB89_CrossPolarFlow + contains + procedure :: setInitCond_lc => exp_SetInitCond_DB89_CrossPolarFlow + end type + type(Exp_DB89_CrossPolarFlow), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( swmodel ) + implicit none + + class(GlobalSWComponent), intent(inout) :: swmodel + !------------------------------------------ + + call exp_manager%Init('DB89_CrossPolarFlow') + call exp_manager%SetInitCond( & + swmodel%mesh, swmodel%vars%PROGVARS_manager, swmodel%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(GlobalSWComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_DB89_CrossPolarFlow( this, & + h, U, V, hs, u1, u2, & + x, y, lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + RPlanet => CONST_RADIUS, & + OMG => CONST_OHM + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + implicit none + + class(Exp_DB89_CrossPolarFlow), intent(inout) :: this + type(LocalMesh2D), intent(in) :: lcmesh + class(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: h(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: U(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: V(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: hs(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u1(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: u2(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + + real(RP) :: PHI0 + real(RP) :: V0 + namelist /PARAM_EXP/ & + PHI0, V0 + + + real(RP) :: VelLon(elem%Np,lcmesh%Ne) + real(RP) :: VelLat(elem%Np,lcmesh%Ne) + real(RP) :: lon(elem%Np) + real(RP) :: lat(elem%Np) + integer :: ke + integer :: ierr + + real(RP) :: r(elem%Np) + !----------------------------------------------------------------------------- + + PHI0 = 5.768E4_RP + V0 = 20.0_RP + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("DB89_CrossPolarFlow_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("DB89_CrossPolarFlow_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + !$omp parallel do private(lon, lat) + do ke=lcmesh%NeS, lcmesh%NeE + lon(:) = lcmesh%lon(:,ke) + lat(:) = lcmesh%lat(:,ke) + + VelLon(:,ke) = - V0 * sin(lon(:)) * sin(lat(:)) * ( 4.0_RP * cos(lat(:))**2 - 1.0_RP ) / cos(lat(:)) + VelLat(:,ke) = V0 * sin(lat(:))**2 * cos(lon(:)) + + h(:,ke) = ( PHI0 + 2.0_RP * OMG * RPlanet * V0 * sin(lat(:))**3 * cos(lat(:)) * sin(lon(:)) ) / Grav + hs(:,ke) = 0.0_RP + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + VelLon(:,:), VelLat(:,:), U(:,lcmesh%NeS:lcmesh%NeE), V(:,lcmesh%NeS:lcmesh%NeE) ) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + u1(:,ke) = lcmesh%G_ij(:,ke,1,1) * U(:,ke) + lcmesh%G_ij(:,ke,1,2) * V(:,ke) + u2(:,ke) = lcmesh%G_ij(:,ke,2,1) * U(:,ke) + lcmesh%G_ij(:,ke,2,2) * V(:,ke) + end do + + return + end subroutine exp_SetInitCond_DB89_CrossPolarFlow +end module mod_user diff --git a/model/global_shallow_water/test/case/CrossPolarFlow/run.conf b/model/global_shallow_water/test/case/CrossPolarFlow/run.conf new file mode 100644 index 00000000..67c8ef22 --- /dev/null +++ b/model/global_shallow_water/test/case/CrossPolarFlow/run.conf @@ -0,0 +1,77 @@ +#--- Configuration file for a test case of W92 case2 ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 864000D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', +/ +#** SW ****************************************************** +&PARAM_GLOBALSW + ACTIVATE_FLAG = .true., + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', + GLOBALSW_DYN_DO = .true. +/ +&PARAM_SW_MESH + NeGX = 5, + NeGY = 5, + NLocalMeshPerPrc = 6, + Nprc = 1, + PolyOrder = 7, +! LumpedMassMatFlag = .true., +/ +&PARAM_SW_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** SW / DYN ****************************************************** +&PARAM_SW_DYN + EQS_TYPE = "GLOBAL_SHALLOW_WATER", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 150.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_SW_DYN_MODALFILTER + MF_ETAC = 0.333333333333D0, + MF_ALPHA = 2.0D-2, + MF_ORDER = 16, +/ +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 28800.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='h' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='Height' / +&HISTORY_ITEM name='Vel_lon' / +&HISTORY_ITEM name='Vel_lat' / + +#*** Statistics ******************************************* +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 18 +/ +&MONITOR_ITEM name='h' / +&MONITOR_ITEM name='ENGT' / +&MONITOR_ITEM name='ENGK' / +&MONITOR_ITEM name='ENGI' / +&MONITOR_ITEM name='ENGP' / From 8fd01ec42f37bba180a139ce6a0ad2a1d159813d Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 15 May 2021 16:22:45 +0900 Subject: [PATCH 14/98] Add a subroutine to generate the Legendre polynomial. --- FElib/src/common/scale_polynominal.F90 | 30 ++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/FElib/src/common/scale_polynominal.F90 b/FElib/src/common/scale_polynominal.F90 index 4a40e57e..34ff9462 100644 --- a/FElib/src/common/scale_polynominal.F90 +++ b/FElib/src/common/scale_polynominal.F90 @@ -18,6 +18,7 @@ module scale_polynominal ! public :: Polynominal_GenLegendrePoly + public :: Polynominal_GenLegendrePoly_sub public :: Polynominal_GenDLegendrePoly public :: Polynominal_GenGaussLobattoPt @@ -49,6 +50,7 @@ module scale_polynominal contains !> A function to obtain the values of Lagrange basis functions which are evaluated over aribitary points !! +!OCL SERIAL function Polynominal_GenLagrangePoly(Nord, x_lgl, x) result(l) implicit none @@ -85,6 +87,7 @@ end function Polynominal_GenLagrangePoly !> A function to obtain the differential values of Lagrange basis functions which are evaluated over aribitary points !! +!OCL SERIAL function Polynominal_GenDLagrangePoly_lglpt(Nord, x_lgl) result(lr) implicit none @@ -118,12 +121,13 @@ end function Polynominal_GenDLagrangePoly_lglpt !> A function to obtain the values of Legendre polynominals which are evaluated at aribitary points. !! - function Polynominal_GenLegendrePoly(Nord, x) result(P) +!OCL SERIAL + subroutine Polynominal_GenLegendrePoly_sub(Nord, x, P) implicit none integer, intent(in) :: Nord real(RP), intent(in) :: x(:) - real(RP) :: P(size(x), Nord+1) + real(RP), intent(out) :: P(size(x), Nord+1) integer :: n @@ -142,10 +146,27 @@ function Polynominal_GenLegendrePoly(Nord, x) result(P) end do return + end subroutine Polynominal_GenLegendrePoly_sub + + !> A function to obtain the values of Legendre polynominals which are evaluated at aribitary points. + !! +!OCL SERIAL + function Polynominal_GenLegendrePoly(Nord, x) result(P) + implicit none + + integer, intent(in) :: Nord + real(RP), intent(in) :: x(:) + real(RP) :: P(size(x), Nord+1) + !--------------------------------------------------------------------------- + + call Polynominal_GenLegendrePoly_sub( Nord, x(:), & ! (in) + P(:,:) ) ! (out) + return end function Polynominal_GenLegendrePoly !> A function to obtain differential values of Legendre polynominals which are evaluated at aribitary points. !! +!OCL SERIAL function Polynominal_GenDLegendrePoly(Nord, x, P) result(GradP) implicit none @@ -175,6 +196,7 @@ end function Polynominal_GenDLegendrePoly !> A function to calcuate the Legendre-Gauss-Lobtatto (LGL) points. !! +!OCL SERIAL function Polynominal_GenGaussLobattoPt(Nord) result(pts) implicit none @@ -193,6 +215,7 @@ end function Polynominal_GenGaussLobattoPt !> A function to calcuate the Gauss-Lobbato weights. !! +!OCL SERIAL function Polynominal_GenGaussLobattoPtIntWeight(Nord) result(int_weight_lgl) implicit none @@ -213,6 +236,7 @@ end function Polynominal_GenGaussLobattoPtIntWeight !> A function to calcuate the Gauss-Legendre points. !! +!OCL SERIAL function Polynominal_GenGaussLegendrePt(Nord) result(pts) implicit none @@ -226,6 +250,7 @@ end function Polynominal_GenGaussLegendrePt !> A function to calcuate the Gauss-Legendre weights. !! +!OCL SERIAL function Polynominal_GenGaussLegendrePtIntWeight(Nord) result(int_weight_gl) implicit none @@ -249,6 +274,7 @@ end function Polynominal_GenGaussLegendrePtIntWeight !- private ------------------------------- !> Calculate the N'th-order Gauss quadrature points and weights associated the Jacobi polynomial of type (alpja,beta). +!OCL SERIAL subroutine gen_JacobiGaussQuadraturePts( alpha, beta, N, & x ) From b432459690e3b81e1a93a9c794bf2cbb10c02d90 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 15 May 2021 16:29:06 +0900 Subject: [PATCH 15/98] Use a subroutine to generate the Legendre polynomial. --- .../src/file/scale_file_common_meshfield.F90 | 49 ++++++++++--------- .../mod_cs2lonlat_interp_field.F90 | 16 +++--- .../util/interp/mod_interp_field.F90 | 36 +++++++++----- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/FElib/src/file/scale_file_common_meshfield.F90 b/FElib/src/file/scale_file_common_meshfield.F90 index 5751f111..f2ce908a 100644 --- a/FElib/src/file/scale_file_common_meshfield.F90 +++ b/FElib/src/file/scale_file_common_meshfield.F90 @@ -174,7 +174,7 @@ end subroutine File_common_meshfield_get_axis1D subroutine File_common_meshfield_put_field1D_cartesbuf( mesh1D, field1D, & buf, force_uniform_grid ) use scale_polynominal, only: & - polynominal_genLegendrePoly + Polynominal_GenLegendrePoly_sub implicit none class(MeshBase1D), target, intent(in) :: mesh1D class(MeshField1D), intent(in) :: field1d @@ -191,7 +191,7 @@ subroutine File_common_meshfield_put_field1D_cartesbuf( mesh1D, field1D, & integer :: Np real(RP), allocatable :: x_local(:) real(RP) :: x_local0, delx - real(RP) :: ox + real(RP) :: ox(1) real(RP), allocatable :: spectral_coef(:) real(RP), allocatable :: P1D_ori_x(:,:) !------------------------------------------------ @@ -219,7 +219,7 @@ subroutine File_common_meshfield_put_field1D_cartesbuf( mesh1D, field1D, & spectral_coef(:) = matmul(refElem%invV(:,:), field1d%local(n)%val(:,kelem1)) do i2=1, Np ox = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx - P1D_ori_x(:,:) = polynominal_genLegendrePoly( refElem%PolyOrder, (/ ox /) ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, ox, P1D_ori_x(:,:) ) i = i0_s + i2 + (kelem1-1)*Np buf(i) = 0.0_RP @@ -550,7 +550,7 @@ end subroutine File_common_meshfield_get_axis2D_cubedsphere subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & buf, force_uniform_grid ) use scale_polynominal, only: & - polynominal_genLegendrePoly + Polynominal_GenLegendrePoly_sub implicit none class(MeshRectDom2D), target, intent(in) :: mesh2D class(MeshField2D), intent(in) :: field2d @@ -569,7 +569,7 @@ subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & real(RP) :: x_local0, delx real(RP), allocatable :: y_local(:) real(RP) :: y_local0, dely - real(RP) :: ox, oy + real(RP) :: ox(1), oy(1) real(RP), allocatable :: spectral_coef(:) real(RP), allocatable :: P1D_ori_x(:,:) real(RP), allocatable :: P1D_ori_y(:,:) @@ -609,11 +609,11 @@ subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & spectral_coef(:) = matmul(refElem%invV(:,:), field2d%local(n)%val(:,kelem1)) do j2=1, Nfp do i2=1, Nfp - ox = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx - oy = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely + ox(1) = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx + oy(1) = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely - P1D_ori_x(:,:) = polynominal_genLegendrePoly( refElem%PolyOrder, (/ ox /) ) - P1D_ori_y(:,:) = polynominal_genLegendrePoly( refElem%PolyOrder, (/ oy /) ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, ox, P1D_ori_x(:,:) ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, oy, P1D_ori_y(:,:) ) i = i0_s + i2 + (i1-1)*Nfp j = j0_s + j2 + (j1-1)*Nfp @@ -966,10 +966,11 @@ subroutine File_common_meshfield_get_axis3D( mesh3D, dimsinfo, x, y, z, & return end subroutine File_common_meshfield_get_axis3D +!OCL_SERIAL subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & buf, force_uniform_grid ) use scale_polynominal, only: & - polynominal_genLegendrePoly + Polynominal_GenLegendrePoly_sub implicit none class(MeshCubeDom3D), target, intent(in) :: mesh3D class(MeshField3D), intent(in) :: field3d @@ -990,7 +991,7 @@ subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & real(RP) :: y_local0, dely real(RP), allocatable :: z_local(:) real(RP) :: z_local0, delz - real(RP) :: ox, oy, oz + real(RP) :: ox(1), oy(1), oz(1) real(RP), allocatable :: spectral_coef(:) real(RP), allocatable :: P1D_ori_x(:,:) real(RP), allocatable :: P1D_ori_y(:,:) @@ -1020,12 +1021,12 @@ subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & allocate( P1D_ori_z(1,Nnode_v) ) end if - !$omp parallel do collapse(2) private( kelem1, & - !$omp i, i1, i2, j, j2, k, k2, indx, & - !$omp x_local, x_local0, y_local, y_local0, z_local, z_local0, & - !$omp delx, dely, delz, ox, oy, oz, & - !$omp spectral_coef, P1D_ori_x, P1D_ori_y, P1D_ori_z, & - !$omp p1, p2, p3, l ) + !$omp parallel do collapse(2) private( kelem1, & + !$omp i, i1, i2, j, j2, k, k2, indx, & + !$omp x_local, x_local0, y_local, y_local0, z_local, z_local0, & + !$omp delx, dely, delz, ox, oy, oz, & + !$omp spectral_coef, P1D_ori_x, P1D_ori_y, P1D_ori_z, & + !$omp p1, p2, p3, l ) do k1=1, lcmesh%NeZ do j1=1, lcmesh%NeY do i1=1, lcmesh%NeX @@ -1046,14 +1047,14 @@ subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & do k2=1, Nnode_v do j2=1, Nnode_h1D do i2=1, Nnode_h1D - ox = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx - oy = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely - oz = - 1.0_RP + 2.0_RP * (z_local(k2) - z_local0) / delz - - P1D_ori_x(:,:) = polynominal_genLegendrePoly( refElem%PolyOrder_h, (/ ox /) ) - P1D_ori_y(:,:) = polynominal_genLegendrePoly( refElem%PolyOrder_h, (/ oy /) ) - P1D_ori_z(:,:) = polynominal_genLegendrePoly( refElem%PolyOrder_v, (/ oz /) ) + ox(1) = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx + oy(1) = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely + oz(1) = - 1.0_RP + 2.0_RP * (z_local(k2) - z_local0) / delz + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_h, ox, P1D_ori_x ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_h, oy, P1D_ori_y ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_v, oz, P1D_ori_z ) + i = i0_s + i2 + (i1-1)*Nnode_h1D j = j0_s + j2 + (j1-1)*Nnode_h1D k = k0_s + k2 + (k1-1)*Nnode_v diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 index d0f036bb..e537817d 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 @@ -247,7 +247,7 @@ subroutine interpolate_local( out_val, & use scale_mesh_base2d, only: & MF2D_XYT => MeshBase2D_DIMTYPEID_XYT use scale_polynominal, only: & - polynominal_genLegendrePoly + Polynominal_GenLegendrePoly_sub use mod_cs2lonlat_interp_mesh, only: & nodeMap_list, & in_Nprc, in_elem2D, in_NLocalMeshPerPrc @@ -276,7 +276,7 @@ subroutine interpolate_local( out_val, & type(MeshCubedSphereDom2D), pointer :: in_csmesh real(RP) :: P1D_ori_x(1,in_elem2D%Nfp) real(RP) :: P1D_ori_y(1,in_elem2D%Nfp) - real(RP) :: ox, oy + real(RP) :: ox(1), oy(1) real(RP) :: vx(in_elem2D%Nv), vy(in_elem2D%Nv) integer :: node_ids(in_elem2D%Nv) type(MeshField2D) :: tmp_field2D @@ -344,15 +344,11 @@ subroutine interpolate_local( out_val, & vx(:) = in_lcmesh%pos_ev(node_ids(:),1) vy(:) = in_lcmesh%pos_ev(node_ids(:),2) - ox = - 1.0_RP + 2.0_RP * (mappingInfo%elem_x(p,ke2D) - vx(1)) / (vx(2) - vx(1)) - oy = - 1.0_RP + 2.0_RP * (mappingInfo%elem_y(p,ke2D) - vy(1)) / (vy(3) - vy(1)) + ox(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_x(p,ke2D) - vx(1)) / (vx(2) - vx(1)) + oy(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_y(p,ke2D) - vy(1)) / (vy(3) - vy(1)) - if ( abs(ox) > 1.001_RP .or. abs(oy) > 1.001_RP ) then - write(*,*) ii,jj,px,py,":",ox,oy - stop - end if - P1D_ori_x(:,:) = polynominal_genLegendrePoly( in_elem2D%PolyOrder, (/ ox /) ) - P1D_ori_y(:,:) = polynominal_genLegendrePoly( in_elem2D%PolyOrder, (/ oy /) ) + call Polynominal_GenLegendrePoly_sub( in_elem2D%PolyOrder, ox, P1D_ori_x(:,:) ) + call Polynominal_GenLegendrePoly_sub( in_elem2D%PolyOrder, oy, P1D_ori_y(:,:) ) out_val(p,ke2D) = 0.0_RP do p2=1, in_elem2D%Nfp diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 index 36955fee..f159d083 100644 --- a/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 +++ b/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 @@ -253,7 +253,7 @@ subroutine interpolate_local( out_val, & use scale_mesh_base3d, only: & MF3D_XYZT => MeshBase3D_DIMTYPEID_XYZT use scale_polynominal, only: & - polynominal_genLegendrePoly + Polynominal_GenLegendrePoly_sub use mod_interp_mesh, only: & in_NprcX, in_NprcY, in_NeX, in_NeY, in_NeZ, & in_elem3D, & @@ -287,11 +287,12 @@ subroutine interpolate_local( out_val, & real(RP) :: P1D_ori_x(1,in_elem3D%Nnode_h1D) real(RP) :: P1D_ori_y(1,in_elem3D%Nnode_h1D) real(RP) :: P1D_ori_z(1,in_elem3D%Nnode_v) - real(RP) :: ox, oy, oz + real(RP) :: ox(1), oy(1), oz(1) real(RP) :: vx(in_elem3D%Nv), vy(in_elem3D%Nv), vz(in_elem3D%Nv) integer :: node_ids(in_elem3D%Nv) - !--------------------------------------------- + real(RP) :: normalization_coef(in_elem3D%PolyOrder_h+1,in_elem3D%PolyOrder_h+1,in_elem3D%PolyOrder_v+1) + !----------------------------------------------------------------------------- in_tile_num = size(mappingInfo%in_tileID_list) do i=1, in_tile_num @@ -308,9 +309,11 @@ subroutine interpolate_local( out_val, & do jj = 1, size(in_mesh%rcdomIJK2LCMeshID,2) do ii = 1, size(in_mesh%rcdomIJK2LCMeshID,1) if ( in_mesh%rcdomIJK2LCMeshID(ii,jj,kk) == n ) then + call PROF_rapstart('INTERP_field_interpolate_readvar', 0) call in_file_list(out_domID)%in_files(i)%Read_Var( & MF3D_XYZT, varname, in_lcmesh, & i0_s, j0_s, k0_s, in_val_list(i)%val(:,:), step=istep ) + call PROF_rapend('INTERP_field_interpolate_readvar', 0) end if i0_s = i0_s + in_lcmesh%NeX * in_lcmesh%refElem3D%Nnode_h1D j0_s = j0_s + in_lcmesh%NeY * in_lcmesh%refElem3D%Nnode_h1D @@ -328,8 +331,19 @@ subroutine interpolate_local( out_val, & end do end do end do + end do + !$omp parallel do collapse(2) + do p3=1, in_elem3D%Nnode_v + do p2=1, in_elem3D%Nnode_h1D + do p1=1, in_elem3D%Nnode_h1D + normalization_coef(p1,p2,p3) = sqrt( ( dble(p1-1) + 0.5_RP ) & + * ( dble(p2-1) + 0.5_RP ) & + * ( dble(p3-1) + 0.5_RP ) ) + end do + end do + end do !$omp parallel do collapse(3) private( ke_h, ke3D, & !$omp pX, pY, pZ, p_h, p, in_px, in_py, & @@ -352,7 +366,7 @@ subroutine interpolate_local( out_val, & in_px = mappingInfo%prc_x(p_h,ke_h) in_py = mappingInfo%prc_y(p_h,ke_h) - if (in_px > 0 .and. in_py > 0) then + if (in_px > 0 .and. in_py > 0 ) then in_ex = mappingInfo%elem_i(p_h,ke_h) in_ey = mappingInfo%elem_j(p_h,ke_h) in_ez = mappingInfo%elem_k(p,ke3D) @@ -367,13 +381,13 @@ subroutine interpolate_local( out_val, & vy(:) = in_lcmesh%pos_ev(node_ids(:),2) vz(:) = in_lcmesh%pos_ev(node_ids(:),3) - ox = - 1.0_RP + 2.0_RP * (out_lcmesh%pos_en(p,ke3D,1) - vx(1)) / (vx(2) - vx(1)) - oy = - 1.0_RP + 2.0_RP * (out_lcmesh%pos_en(p,ke3D,2) - vy(1)) / (vy(3) - vy(1)) - oz = - 1.0_RP + 2.0_RP * (out_lcmesh%pos_en(p,ke3D,3) - vz(1)) / (vz(5) - vz(1)) + ox(1) = - 1.0_RP + 2.0_RP * (out_lcmesh%pos_en(p,ke3D,1) - vx(1)) / (vx(2) - vx(1)) + oy(1) = - 1.0_RP + 2.0_RP * (out_lcmesh%pos_en(p,ke3D,2) - vy(1)) / (vy(3) - vy(1)) + oz(1) = - 1.0_RP + 2.0_RP * (out_lcmesh%pos_en(p,ke3D,3) - vz(1)) / (vz(5) - vz(1)) - P1D_ori_x(:,:) = polynominal_genLegendrePoly( in_elem3D%PolyOrder_h, (/ ox /) ) - P1D_ori_y(:,:) = polynominal_genLegendrePoly( in_elem3D%PolyOrder_h, (/ oy /) ) - P1D_ori_z(:,:) = polynominal_genLegendrePoly( in_elem3D%PolyOrder_v, (/ oz /) ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_h, ox, P1D_ori_x ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_h, oy, P1D_ori_y ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_v, oz, P1D_ori_z ) out_val(p,ke3D) = 0.0_RP do p3=1, in_elem3D%Nnode_v @@ -382,7 +396,7 @@ subroutine interpolate_local( out_val, & l = p1 + (p2-1)*in_elem3D%Nnode_h1D + (p3-1)*in_elem3D%Nnode_h1D**2 out_val(p,ke3D) = out_val(p,ke3D) + & ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) * P1D_ori_z(1,p3) ) & - * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)*(dble(p3-1) + 0.5_RP)) & + * normalization_coef(p1,p2,p3) & * in_val_list(in_listID)%spectral_coef(l,in_ex,in_ey,in_ez) end do end do From 55a326aa47e63106ad0d05dd209cd48c443d577d Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 15 May 2021 16:31:33 +0900 Subject: [PATCH 16/98] Add OpenMP directives. --- FElib/src/file/scale_file_base_meshfield.F90 | 17 +++++++- FElib/src/mesh/scale_mesh_base3d.F90 | 3 ++ FElib/src/mesh/scale_mesh_cubedom3d.F90 | 9 ++++- FElib/src/mesh/scale_meshutil_3d.F90 | 37 ++++++++++++++++- .../util/interp/mod_interp_mesh.F90 | 40 +++++++++++++++---- 5 files changed, 94 insertions(+), 12 deletions(-) diff --git a/FElib/src/file/scale_file_base_meshfield.F90 b/FElib/src/file/scale_file_base_meshfield.F90 index e985e5fe..616d4fb8 100644 --- a/FElib/src/file/scale_file_base_meshfield.F90 +++ b/FElib/src/file/scale_file_base_meshfield.F90 @@ -334,6 +334,7 @@ subroutine FILE_base_meshfield_enddef( this ) ! (inout) return end subroutine FILE_base_meshfield_enddef +!OCL_SERIAL subroutine FILE_base_meshfield_write_var1d( this, & ! (inout) vid, field1d, sec_str, sec_end ) ! (in) @@ -369,6 +370,7 @@ subroutine FILE_base_meshfield_write_var1d( this, & ! (inout) return end subroutine FILE_base_meshfield_write_var1d +!OCL_SERIAL subroutine FILE_base_meshfield_write_var2d( this, & ! (inout) vid, field2d, sec_str, sec_end ) ! (in) @@ -411,6 +413,7 @@ subroutine FILE_base_meshfield_write_var2d( this, & ! (inout) return end subroutine FILE_base_meshfield_write_var2d +!OCL_SERIAL subroutine FILE_base_meshfield_write_var3d( this, & ! (inout) vid, field3d, sec_str, sec_end ) ! (in) @@ -419,6 +422,7 @@ subroutine FILE_base_meshfield_write_var3d( this, & ! (inout) FILE_Write use scale_file_common_meshfield, only: & File_common_meshfield_put_field3D_cartesbuf + use scale_prof implicit none class(FILE_base_meshfield), intent(inout) :: this @@ -438,11 +442,16 @@ subroutine FILE_base_meshfield_write_var3d( this, & ! (inout) dims(2) = this%dimsinfo(MF3D_DIMTYPE_Y)%size dims(3) = this%dimsinfo(MF3D_DIMTYPE_Z)%size allocate( buf(dims(1),dims(2),dims(3)) ) + + call PROF_rapstart('FILE_base_meshfield_write_putbuf', 0) + call File_common_meshfield_put_field3D_cartesbuf( this%mesh3D, field3d, buf(:,:,:), & this%force_uniform_grid ) - + call PROF_rapend('FILE_base_meshfield_write_putbuf', 0) + call PROF_rapstart('FILE_base_meshfield_FILE_write', 0) call FILE_Write( this%vars_ncid(vid), buf(:,:,:), & ! (in) sec_str, sec_end, start ) ! (in) + call PROF_rapend('FILE_base_meshfield_FILE_write', 0) end if return @@ -510,6 +519,7 @@ subroutine FILE_base_meshfield_get_dataInfo( this, varname, istep, & ! (in) return end subroutine FILE_base_meshfield_get_dataInfo +!OCL_SERIAL subroutine FILE_base_meshfield_read_var1d( this, & ! (inout) dim_typeid, varname, & ! (in) field1d, & ! (inout) @@ -550,6 +560,7 @@ subroutine FILE_base_meshfield_read_var1d( this, & ! (inout) return end subroutine FILE_base_meshfield_read_var1d +!OCL_SERIAL subroutine FILE_base_meshfield_read_var1d_local( this, & ! (inout) dim_typeid, varname, lcmesh, i0_s, & ! (in) val, & ! (out) @@ -593,6 +604,7 @@ subroutine FILE_base_meshfield_read_var1d_local( this, & ! (inout) return end subroutine FILE_base_meshfield_read_var1d_local +!OCL_SERIAL subroutine FILE_base_meshfield_read_var2d( this, & ! (inout) dim_typeid, varname, & ! (in) field2d, & ! (inout) @@ -641,6 +653,7 @@ subroutine FILE_base_meshfield_read_var2d( this, & ! (inout) return end subroutine FILE_base_meshfield_read_var2d +!OCL_SERIAL subroutine FILE_base_meshfield_read_var2d_local( this, & ! (inout) dim_typeid, varname, lcmesh, i0_s, j0_s, & ! (in) val, & ! (out) @@ -685,6 +698,7 @@ subroutine FILE_base_meshfield_read_var2d_local( this, & ! (inout) return end subroutine FILE_base_meshfield_read_var2d_local +!OCL_SERIAL subroutine FILE_base_meshfield_read_var3d( this, & ! (inout) dim_typeid, varname, & ! (in) field3d, & ! (inout) @@ -727,6 +741,7 @@ subroutine FILE_base_meshfield_read_var3d( this, & ! (inout) return end subroutine FILE_base_meshfield_read_var3d +!OCL_SERIAL subroutine FILE_base_meshfield_read_var3d_local( this, & ! (inout) dim_typeid, varname, lcmesh, i0_s, j0_s, k0_s, & ! (in) val, & ! (out) diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index 3012dc94..e86598bf 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -218,6 +218,9 @@ end subroutine calc_normal end do end do + !$omp parallel do private( ke, node_ids, vx, vy, vz, & + !$omp xX, xY, xZ, yX, yY, yZ, zX, zY, zZ, & + !$omp i, j, Escale_f, d ) do ke=1, lcmesh%Ne node_ids(:) = lcmesh%EToV(ke,:) vx(:) = lcmesh%pos_ev(node_ids(:),1) diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 668cf332..88d6e8e9 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -267,6 +267,7 @@ end subroutine MeshCubeDom3D_generate !- private ------------------------------------------------------ +!OCL SERIAL subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & tileID, panelID, & i, j, k, NprcX, NprcY, NprcZ, & @@ -274,6 +275,7 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & NeX, NeY, NeZ, & FZ ) + use scale_prof use scale_meshutil_3d, only: & MeshUtil3D_genConnectivity, & MeshUtil3D_genCubeDomain, & @@ -350,9 +352,8 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & & lcmesh%NeX, lcmesh%xmin, lcmesh%xmax, & ! (in) & lcmesh%NeY, lcmesh%ymin, lcmesh%ymax, & ! (in) & lcmesh%NeZ, lcmesh%zmin, lcmesh%zmax, FZ=FZ_lc ) ! (in) - - !--- + !--- call MeshBase3D_setGeometricInfo( lcmesh, MeshCubeDom3D_coord_conv, MeshCubeDom3D_calc_normal ) !--- @@ -371,6 +372,7 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & elem%Nfaces_h, elem%Nfaces_v, elem%Nfaces ) ! (in) !--- + !$omp parallel do collapse(2) private(ii,ke) do kk=1, lcmesh%NeZ do jj=1, lcmesh%NeY do ii=1, lcmesh%NeX @@ -383,6 +385,7 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & return end subroutine MeshCubeDom3D_setupLocalDom +!OCL SERIAL subroutine MesshCubeDom3D_assignDomID( this, & tileID_table, panelID_table, & pi_table, pj_table, pk_table ) @@ -453,6 +456,7 @@ subroutine MesshCubeDom3D_assignDomID( this, & return end subroutine MesshCubeDom3D_assignDomID +!OCL SERIAL subroutine MeshCubeDom3D_coord_conv( x, y, z, xX, xY, xZ, yX, yY, yZ, zX, zY, zZ, & vx, vy, vz, elem ) @@ -484,6 +488,7 @@ subroutine MeshCubeDom3D_coord_conv( x, y, z, xX, xY, xZ, yX, yY, yZ, zX, zY, zZ return end subroutine MeshCubeDom3D_coord_conv +!OCL SERIAL subroutine MeshCubeDom3D_calc_normal( normal_fn, & Escale_f, fid_h, fid_v, elem ) diff --git a/FElib/src/mesh/scale_meshutil_3d.F90 b/FElib/src/mesh/scale_meshutil_3d.F90 index ccbf0356..4ecb8edf 100644 --- a/FElib/src/mesh/scale_meshutil_3d.F90 +++ b/FElib/src/mesh/scale_meshutil_3d.F90 @@ -22,6 +22,7 @@ module scale_meshutil_3d contains +!OCL SERIAL subroutine MeshUtil3D_genCubeDomain( pos_v, EToV, & Ke_x, xmin, xmax, Ke_y, ymin, ymax, Ke_z, zmin, zmax, & Fz ) @@ -49,6 +50,9 @@ subroutine MeshUtil3D_genCubeDomain( pos_v, EToV, & NvY = Ke_Y + 1 NvZ = Ke_Z + 1 + !$omp parallel private(i,j,k,n) + + !$omp do collapse(2) do k=1, NvZ do j=1, NvY do i=1, NvX @@ -64,6 +68,7 @@ subroutine MeshUtil3D_genCubeDomain( pos_v, EToV, & end do end do + !$omp do collapse(2) do k=1, Ke_z do j=1, Ke_y do i=1, Ke_x @@ -78,6 +83,8 @@ subroutine MeshUtil3D_genCubeDomain( pos_v, EToV, & end do end do + !$omp end parallel + !--- !!$ !!$ write(*,*) "-- vx, vy --" @@ -99,7 +106,7 @@ subroutine MeshUtil3D_genCubeDomain( pos_v, EToV, & return end subroutine MeshUtil3D_genCubeDomain - +!OCL SERIAL subroutine MeshUtil3D_genConnectivity( EToE, EToF, & EToV, Ne, Nfaces ) @@ -221,6 +228,7 @@ subroutine MeshUtil3D_genConnectivity( EToE, EToF, & return end subroutine MeshUtil3D_genConnectivity +!OCL SERIAL subroutine bubbleSort( array ) implicit none real(RP), intent(inout) :: array(:) @@ -243,6 +251,7 @@ subroutine bubbleSort( array ) return end subroutine bubbleSort +!OCL SERIAL subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & pos_en, pos_ev, EtoE, EtoF, EtoV, Fmask_h, Fmask_v, & Ne, Nv, Np, Nfp_h, Nfp_v, NfpTot, Nfaces_h, Nfaces_v, Nfaces) @@ -297,6 +306,9 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & integer :: MapP_v(Nfp_v,Nfaces_v,Ne) !----------------------------------------------------------------------------- + !$omp parallel private(k,f,p,n) + + !$omp do do k=1, Ne do p=1, Np n = p + (k-1)*Np @@ -306,7 +318,9 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & z(n) = pos_en(p,k,3) end do end do + !$omp end do + !$omp do do k=1, Ne do f=1, Nfaces_h do p=1, Nfp_h @@ -325,8 +339,19 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & end do end do end do + !$omp end do + !$omp workshare VMapP_h(:,:,:) = -1 + VMapP_v(:,:,:) = -1 + !$omp end workshare + !$omp end parallel + + !$omp parallel private( & + !$omp k1, f1, k2, f2, v1, v2, refd2, & + !$omp r_h, r_v, dist_h, dist_v, idP, idM ) + + !$omp do do k1=1, Ne do f1=1, Nfaces_h k2 = EToE(k1,f1); f2 = EToF(k1,f1) @@ -357,8 +382,9 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & end do end do end do + !omp end do - VMapP_v(:,:,:) = -1 + !$omp do do k1=1, Ne do f1=1, Nfaces_v k2 = EToE(k1,Nfaces_h+f1); f2 = EToF(k1,Nfaces_h+f1) - Nfaces_h @@ -386,7 +412,10 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & end do end do end do + !omp end do + !$omp end parallel + !$omp parallel do private(k,f,n,i) do k=1, Ne do f=1, Nfaces_h do n=1, Nfp_h @@ -407,6 +436,7 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & end do end do end do + !----- ! mapB_counter = 0 ! do k=1,mesh%Ne @@ -443,6 +473,7 @@ subroutine MeshUtil3D_BuildInteriorMap( VMapM, VMapP, MapM, MapP, & return end subroutine MeshUtil3D_BuildInteriorMap +!OCL SERIAL subroutine MeshUtil3D_genPatchBoundaryMap( VMapB, MapB, VMapP, & pos_en, xmin, xmax, ymin, ymax, zmin, zmax, & Fmask_h, Fmask_v, Ne, Nv, Np, Nfp_h, Nfp_v, NfpTot, Nfaces_h, Nfaces_v, Nfaces ) @@ -579,6 +610,7 @@ subroutine MeshUtil3D_genPatchBoundaryMap( VMapB, MapB, VMapP, return contains +!OCL SERIAL subroutine eval_domain_boundary( & elemIDs, ordInfo, faceIDs, counterB, & domb_id, r, rbc, ord_info, k_, f_, normalized_fac ) @@ -607,6 +639,7 @@ subroutine eval_domain_boundary( & end subroutine eval_domain_boundary end subroutine MeshUtil3D_genPatchBoundaryMap +!OCL SERIAL subroutine MeshUtil3D_buildGlobalMap( & panelID_table, pi_table, pj_table, pk_table, & tileID_map, tileFaceID_map, tilePanelID_map, & diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 index b66d61c0..8a7b725d 100644 --- a/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 @@ -77,9 +77,14 @@ module mod_interp_mesh integer, private :: out_NprcY = 1 ! y length of 2D processor topology (output) type(HexahedralElement), private :: out_elem3D + real(RP), private :: dom_zmin = 0.0_RP + real(RP), private :: dom_zmax = 0.0_RP + contains !OCL SERIAL subroutine interp_mesh_Init() + use scale_const, only: & + UNDEF => CONST_UNDEF implicit none integer :: out_NeX = 1 @@ -95,8 +100,8 @@ subroutine interp_mesh_Init() real(RP) :: dom_ymin = 0.0_RP real(RP) :: dom_ymax = 0.0_RP logical :: isPeriodicY = .false. - real(RP) :: dom_zmin = 0.0_RP - real(RP) :: dom_zmax = 0.0_RP + real(RP) :: out_dom_zmin + real(RP) :: out_dom_zmax logical :: isPeriodicZ = .false. integer, parameter :: FZ_nmax = 1000 @@ -123,6 +128,8 @@ subroutine interp_mesh_Init() dom_ymin, dom_ymax, & isPeriodicY, & dom_zmin, dom_zmax, & + out_dom_zmin, & + out_dom_zmax, & isPeriodicZ, & in_Fz, out_Fz @@ -132,6 +139,9 @@ subroutine interp_mesh_Init() LOG_NEWLINE LOG_INFO("interp_mesh",*) 'Setup' + out_dom_zmin = UNDEF + out_dom_zmax = UNDEF + !--- read namelist rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_INTERP_MESH,iostat=ierr) @@ -143,23 +153,26 @@ subroutine interp_mesh_Init() endif LOG_NML(PARAM_INTERP_MESH) - + if ( out_dom_zmin == UNDEF ) out_dom_zmin = dom_zmin + if ( out_dom_zmax == UNDEF ) out_dom_zmax = dom_zmax + !- + call in_elem3D%Init( in_PolyOrder_h, in_PolyOrder_v, .true. ) call out_elem3D%Init( out_PolyOrder_h, out_PolyOrder_v, .true. ) call out_mesh%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, out_NeZ, & - dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + dom_xmin, dom_xmax, dom_ymin, dom_ymax, out_dom_zmin, out_dom_zmax, & isPeriodicX, isPeriodicY, isPeriodicZ, out_elem3D, ATMOS_MESH_NLocalMeshPerPrc, & out_NprcX, out_NprcY, & FZ=out_FZ(1:out_NeZ+1) ) call out_mesh%Generate() + !- call construct_map( in_FZ(1:in_NeZ+1) ) - return end subroutine interp_mesh_Init @@ -199,6 +212,7 @@ subroutine construct_map( in_Fz ) delx = ( out_mesh%xmax_gl - out_mesh%xmin_gl ) / dble(in_NprcX) dely = ( out_mesh%ymax_gl - out_mesh%ymin_gl ) / dble(in_NprcY) + !$omp parallel do private(i) do j=1, in_NprcY do i=1, in_NprcX in_tiles_x(:,i,j) = out_mesh%xmin_gl + delx * dble( (/ i-1, i, i, i-1 /) ) @@ -263,6 +277,7 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) this%prcXY2inListID(:,:) = -1 in_tile_num = 0 + do ke_h=1, lcmesh%NeX * lcmesh%NeY do p_h_y=1, elem%Nnode_h1D do p_h_x=1, elem%Nnode_h1D @@ -298,6 +313,9 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) allocate( this%in_tileID_list(in_tile_num) ) this%in_tileID_list(:) = in_tileID_tmp(1:in_tile_num) + !$omp parallel do collapse(3) private( & + !$omp p_h, out_x, out_y, prc_i, prc_j, & + !$omp delx, dely, i, j, in_elem_x, in_elem_y, is_inside_elem ) do ke_h=1, lcmesh%NeX * lcmesh%NeY do p_h_y=1, elem%Nnode_h1D do p_h_x=1, elem%Nnode_h1D @@ -338,7 +356,7 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) in_rank = this%in_tileID_list(i) - 1 call this%in_mesh_list(i)%Init( in_NprcX*in_NeX, in_NprcY*in_NeY, in_NeZ, & out_mesh%xmin_gl, out_mesh%xmax_gl, out_mesh%ymin_gl, out_mesh%ymax_gl, & - out_mesh%zmin_gl, out_mesh%zmax_gl, & + dom_zmin, dom_zmax, & out_mesh%isPeriodicX, out_mesh%isPeriodicY, out_mesh%isPeriodicZ, & in_elem3D, 1, in_NprcX, in_NprcY, & nproc=in_NprcX*in_NprcY, myrank=in_rank, & @@ -348,8 +366,15 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) end do !-- + !$omp parallel private( & + !$omp ke_h, p_h, prc_i, prc_j, in_lcmesh, & + !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) + + !$omp workshare this%elem_k(:,:) = -1 + !$omp end workshare + !$omp do collapse(2) do ke_h=1, lcmesh%NeX * lcmesh%NeY do p_h=1, elem%Nnode_h1D**2 prc_i = this%prc_x(p_h,ke_h) @@ -379,7 +404,8 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) end do end do - + !$omp end do + !$omp end parallel return end subroutine NodeMappingInfo_Init From e4a4031e5730657d9efdef1f390b4eae75bb7f87 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 16 May 2021 21:26:05 +0900 Subject: [PATCH 17/98] Add some modules for providing 3D cubed sphere mesh. --- FElib/src/Makefile | 5 +- FElib/src/depend | 14 +- FElib/src/file/scale_file_base_meshfield.F90 | 62 +- .../src/file/scale_file_common_meshfield.F90 | 301 +++++++++- .../src/file/scale_file_history_meshfield.F90 | 79 ++- .../src/file/scale_file_restart_meshfield.F90 | 9 +- FElib/src/mesh/scale_mesh_base3d.F90 | 8 +- FElib/src/mesh/scale_mesh_cubedom3d.F90 | 20 +- .../src/mesh/scale_mesh_cubedspheredom3d.F90 | 538 ++++++++++++++++++ FElib/src/mesh/scale_meshutil_3d.F90 | 3 +- .../src/mesh/scale_meshutil_cubedsphere3d.F90 | 169 ++++++ 11 files changed, 1143 insertions(+), 65 deletions(-) create mode 100644 FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 create mode 100644 FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 diff --git a/FElib/src/Makefile b/FElib/src/Makefile index 3b4da62c..f51bedb1 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -53,6 +53,7 @@ OBJS_NAME_MESH = \ scale_meshutil_2d.o \ scale_meshutil_3d.o \ scale_meshutil_cubedsphere2d.o \ + scale_meshutil_cubedsphere3d.o \ scale_mesh_bndinfo.o \ scale_localmesh_base.o \ scale_localmesh_1d.o \ @@ -65,7 +66,8 @@ OBJS_NAME_MESH = \ scale_mesh_linedom1d.o \ scale_mesh_rectdom2d.o \ scale_mesh_cubedom3d.o \ - scale_mesh_cubedspheredom2d.o + scale_mesh_cubedspheredom2d.o \ + scale_mesh_cubedspheredom3d.o OBJS_NAME_DATA = \ scale_variableinfo.o \ @@ -76,6 +78,7 @@ OBJS_NAME_DATA = \ scale_meshfieldcomm_rectdom2d.o \ scale_meshfieldcomm_cubedspheredom2d.o \ scale_meshfieldcomm_cubedom3d.o \ + scale_meshfieldcomm_cubedspheredom3d.o \ scale_meshfield_statistics.o OBJS_NAME_FILE = \ diff --git a/FElib/src/depend b/FElib/src/depend index 31635024..cac3672a 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -17,11 +17,11 @@ $(OBJ_DIR)/scale_element_hexahedral.o: element/scale_element_hexahedral.F90 $(DE $(OBJ_DIR)/scale_element_line.o: element/scale_element_line.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o $(OBJ_DIR)/scale_element_modalfilter.o: element/scale_element_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_element_quadrilateral.o: element/scale_element_quadrilateral.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o -$(OBJ_DIR)/scale_file_base_meshfield.o: file/scale_file_base_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o -$(OBJ_DIR)/scale_file_common_meshfield.o: file/scale_file_common_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_polynominal.o -$(OBJ_DIR)/scale_file_history_meshfield.o: file/scale_file_history_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o +$(OBJ_DIR)/scale_file_base_meshfield.o: file/scale_file_base_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_cubedspheredom3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o +$(OBJ_DIR)/scale_file_common_meshfield.o: file/scale_file_common_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_cubedspheredom3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_polynominal.o +$(OBJ_DIR)/scale_file_history_meshfield.o: file/scale_file_history_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_cubedspheredom3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_file_monitor_meshfield.o: file/scale_file_monitor_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o -$(OBJ_DIR)/scale_file_restart_meshfield.o: file/scale_file_restart_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_base_meshfield.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o +$(OBJ_DIR)/scale_file_restart_meshfield.o: file/scale_file_restart_meshfield.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_file_base_meshfield.o $(OBJ_DIR)/scale_file_common_meshfield.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_cubedspheredom3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_variableinfo.o $(OBJ_DIR)/scale_gmres.o: common/scale_gmres.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_linalgebra.o: common/scale_linalgebra.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_linkedlist.o: common/scale_linkedlist.F90 $(DEPENDLIB) @@ -37,6 +37,7 @@ $(OBJ_DIR)/scale_mesh_base3d.o: mesh/scale_mesh_base3d.F90 $(DEPENDLIB) $(OBJ_DI $(OBJ_DIR)/scale_mesh_bndinfo.o: mesh/scale_mesh_bndinfo.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_mesh_cubedom3d.o: mesh/scale_mesh_cubedom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshutil_3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o: mesh/scale_mesh_cubedspheredom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o +$(OBJ_DIR)/scale_mesh_cubedspheredom3d.o: mesh/scale_mesh_cubedspheredom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere3d.o $(OBJ_DIR)/scale_mesh_linedom1d.o: mesh/scale_mesh_linedom1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o: mesh/scale_mesh_rectdom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_2d.o $(OBJ_DIR)/scale_meshfield_base.o: data/scale_meshfield_base.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o @@ -45,11 +46,13 @@ $(OBJ_DIR)/scale_meshfieldcomm_1d.o: data/scale_meshfieldcomm_1d.F90 $(DEPENDLIB $(OBJ_DIR)/scale_meshfieldcomm_base.o: data/scale_meshfieldcomm_base.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_cubedom3d.o: data/scale_meshfieldcomm_cubedom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_cubedom3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o $(OBJ_DIR)/scale_meshfieldcomm_cubedspheredom2d.o: data/scale_meshfieldcomm_cubedspheredom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o +$(OBJ_DIR)/scale_meshfieldcomm_cubedspheredom3d.o: data/scale_meshfieldcomm_cubedspheredom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o $(OBJ_DIR)/scale_meshfieldcomm_rectdom2d.o: data/scale_meshfieldcomm_rectdom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o $(OBJ_DIR)/scale_meshutil_1d.o: mesh/scale_meshutil_1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_2d.o: mesh/scale_meshutil_2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_quicksort.o $(OBJ_DIR)/scale_meshutil_3d.o: mesh/scale_meshutil_3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_quicksort.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o: mesh/scale_meshutil_cubedsphere2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_2d.o +$(OBJ_DIR)/scale_meshutil_cubedsphere3d.o: mesh/scale_meshutil_cubedsphere3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_3d.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o $(OBJ_DIR)/scale_model_component.o: model_framework/scale_model_component.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_time_manager.o $(OBJ_DIR)/scale_model_component_proc.o: model_framework/scale_model_component_proc.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_model_mesh_manager.o $(OBJ_DIR)/scale_model_var_manager.o $(OBJ_DIR)/scale_time_manager.o $(OBJ_DIR)/scale_model_mesh_manager.o: model_framework/scale_model_mesh_manager.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_sparsemat.o @@ -102,6 +105,7 @@ MODS = \ $(OBJ_DIR)/scale_mesh_bndinfo.mod \ $(OBJ_DIR)/scale_mesh_cubedom3d.mod \ $(OBJ_DIR)/scale_mesh_cubedspheredom2d.mod \ + $(OBJ_DIR)/scale_mesh_cubedspheredom3d.mod \ $(OBJ_DIR)/scale_mesh_linedom1d.mod \ $(OBJ_DIR)/scale_mesh_rectdom2d.mod \ $(OBJ_DIR)/scale_meshfield_base.mod \ @@ -110,11 +114,13 @@ MODS = \ $(OBJ_DIR)/scale_meshfieldcomm_base.mod \ $(OBJ_DIR)/scale_meshfieldcomm_cubedom3d.mod \ $(OBJ_DIR)/scale_meshfieldcomm_cubedspheredom2d.mod \ + $(OBJ_DIR)/scale_meshfieldcomm_cubedspheredom3d.mod \ $(OBJ_DIR)/scale_meshfieldcomm_rectdom2d.mod \ $(OBJ_DIR)/scale_meshutil_1d.mod \ $(OBJ_DIR)/scale_meshutil_2d.mod \ $(OBJ_DIR)/scale_meshutil_3d.mod \ $(OBJ_DIR)/scale_meshutil_cubedsphere2d.mod \ + $(OBJ_DIR)/scale_meshutil_cubedsphere3d.mod \ $(OBJ_DIR)/scale_model_component.mod \ $(OBJ_DIR)/scale_model_component_proc.mod \ $(OBJ_DIR)/scale_model_mesh_manager.mod \ diff --git a/FElib/src/file/scale_file_base_meshfield.F90 b/FElib/src/file/scale_file_base_meshfield.F90 index 616d4fb8..f104a23b 100644 --- a/FElib/src/file/scale_file_base_meshfield.F90 +++ b/FElib/src/file/scale_file_base_meshfield.F90 @@ -36,6 +36,7 @@ module scale_file_base_meshfield use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D use scale_localmesh_1d, only: LocalMesh1D use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D @@ -62,6 +63,7 @@ module scale_file_base_meshfield class(MeshRectDom2D), pointer :: mesh2D class(MeshCubedSphereDom2D), pointer :: meshCS2D class(MeshCubeDom3D), pointer :: mesh3D + class(MeshCubedSphereDom3D), pointer :: meshCS3D type(FILE_common_meshfield_diminfo), allocatable :: dimsinfo(:) logical :: force_uniform_grid @@ -105,9 +107,12 @@ module scale_file_base_meshfield contains - subroutine FILE_base_meshfield_Init( this, & ! (inout) - var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D, & ! (in) - force_uniform_grid ) ! (in) + subroutine FILE_base_meshfield_Init( this, & ! (inout) + var_num, & ! (in) + mesh1D, & ! (in) + mesh2D, meshCubedSphere2D, & ! (in) + mesh3D, meshCubedSphere3D, & ! (in) + force_uniform_grid ) ! (in) use scale_file_common_meshfield, only: & File_common_meshfield_get_dims @@ -120,6 +125,7 @@ subroutine FILE_base_meshfield_Init( this, & ! (inout) class(MeshRectDom2D), target, optional, intent(in) :: mesh2D class(MeshCubedSphereDom2D), target, optional, intent(in) :: meshCubedSphere2D class(MeshCubeDom3D), target, optional, intent(in) :: mesh3D + class(MeshCubedSphereDom3D), target, optional, intent(in) :: meshCubedSphere3D logical, intent(in), optional :: force_uniform_grid logical :: check_specify_mesh @@ -133,6 +139,7 @@ subroutine FILE_base_meshfield_Init( this, & ! (inout) !- check_specify_mesh = .false. nullify( this%mesh1D, this%mesh2D, this%mesh3D ) + nullify( this%meshCS2D, this%meshCS3D ) if (present(mesh1D)) then this%mesh1D => mesh1D @@ -162,7 +169,14 @@ subroutine FILE_base_meshfield_Init( this, & ! (inout) allocate( this%dimsinfo(MF3D_DTYPE_NUM) ) call File_common_meshfield_get_dims( mesh3D, this%dimsinfo(:) ) end if + if (present(meshCubedSphere3D)) then + this%meshCS3D => meshCubedSphere3D + check_specify_mesh = .true. + allocate( this%dimsinfo(MF3D_DTYPE_NUM) ) + call File_common_meshfield_get_dims( meshCubedSphere3D, this%dimsinfo(:) ) + end if + if ( present(force_uniform_grid) ) then this%force_uniform_grid = force_uniform_grid else @@ -421,7 +435,8 @@ subroutine FILE_base_meshfield_write_var3d( this, & ! (inout) FILE_opened, & FILE_Write use scale_file_common_meshfield, only: & - File_common_meshfield_put_field3D_cartesbuf + File_common_meshfield_put_field3D_cartesbuf, & + File_common_meshfield_put_field3D_cubedsphere_cartesbuf use scale_prof implicit none @@ -443,15 +458,16 @@ subroutine FILE_base_meshfield_write_var3d( this, & ! (inout) dims(3) = this%dimsinfo(MF3D_DIMTYPE_Z)%size allocate( buf(dims(1),dims(2),dims(3)) ) - call PROF_rapstart('FILE_base_meshfield_write_putbuf', 0) + if ( associated(this%mesh3D) ) then + call File_common_meshfield_put_field3D_cartesbuf( this%mesh3D, field3d, buf(:,:,:), & + this%force_uniform_grid ) + else if ( associated(this%meshCS3D) ) then + call File_common_meshfield_put_field3D_cubedsphere_cartesbuf( & + this%meshCS3D, field3d, buf(:,:,:) ) + end if - call File_common_meshfield_put_field3D_cartesbuf( this%mesh3D, field3d, buf(:,:,:), & - this%force_uniform_grid ) - call PROF_rapend('FILE_base_meshfield_write_putbuf', 0) - call PROF_rapstart('FILE_base_meshfield_FILE_write', 0) call FILE_Write( this%vars_ncid(vid), buf(:,:,:), & ! (in) sec_str, sec_end, start ) ! (in) - call PROF_rapend('FILE_base_meshfield_FILE_write', 0) end if return @@ -707,7 +723,9 @@ subroutine FILE_base_meshfield_read_var3d( this, & ! (inout) use scale_file, only: & FILE_Read use scale_file_common_meshfield, only: & - File_common_meshfield_set_cartesbuf_field3D + File_common_meshfield_set_cartesbuf_field3D, & + File_common_meshfield_set_cartesbuf_field3D_cubedsphere + implicit none @@ -734,8 +752,14 @@ subroutine FILE_base_meshfield_read_var3d( this, & ! (inout) buf(:,:,:), & ! (out) step=step, allow_missing=allow_missing ) ! (in) - call File_common_meshfield_set_cartesbuf_field3D( this%mesh3D, buf(:,:,:), & - field3d ) + if ( associated(this%meshCS3D) ) then + call File_common_meshfield_set_cartesbuf_field3D_cubedsphere( & + this%meshCS3D, buf(:,:,:), & + field3d ) + else if ( associated(this%mesh3D) ) then + call File_common_meshfield_set_cartesbuf_field3D( this%mesh3D, buf(:,:,:), & + field3d ) + end if end if return @@ -854,7 +878,8 @@ subroutine def_axes( this, & ! (in) end do end if - if ( associated(this%mesh3D) ) then + if ( associated(this%mesh3D) & + .or. associated(this%meshCS3D) ) then do d=1, 3 call FILE_Def_Axis( this%fid, & this%dimsinfo(d)%name, this%dimsinfo(d)%desc, this%dimsinfo(d)%unit, & @@ -915,6 +940,15 @@ subroutine write_axes( this, & ! (in) call FILE_Write_Axis( this%fid, this%dimsinfo(3)%name, z(:), start(3:3) ) end if + if ( associated(this%meshCS3D) ) then + allocate( x(this%dimsinfo(1)%size), y(this%dimsinfo(2)%size), z(this%dimsinfo(3)%size) ) + call File_common_meshfield_get_axis( this%meshCS3D, this%dimsinfo, x(:), y(:), z(:) ) + + call FILE_Write_Axis( this%fid, this%dimsinfo(1)%name, x(:), start(1:1) ) + call FILE_Write_Axis( this%fid, this%dimsinfo(2)%name, y(:), start(2:2) ) + call FILE_Write_Axis( this%fid, this%dimsinfo(3)%name, z(:), start(3:3) ) + end if + return end subroutine write_axes diff --git a/FElib/src/file/scale_file_common_meshfield.F90 b/FElib/src/file/scale_file_common_meshfield.F90 index f2ce908a..869b1c38 100644 --- a/FElib/src/file/scale_file_common_meshfield.F90 +++ b/FElib/src/file/scale_file_common_meshfield.F90 @@ -25,6 +25,7 @@ module scale_file_common_meshfield use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D use scale_localmesh_1d, only: LocalMesh1D use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D @@ -47,6 +48,7 @@ module scale_file_common_meshfield module procedure File_common_meshfield_get_dims2D module procedure File_common_meshfield_get_dims2D_cubedsphere module procedure File_common_meshfield_get_dims3D + module procedure File_common_meshfield_get_dims3D_cubedsphere end interface public :: FILE_common_meshfield_get_dims @@ -59,6 +61,7 @@ module scale_file_common_meshfield module procedure File_common_meshfield_get_axis2D module procedure File_common_meshfield_get_axis2D_cubedsphere module procedure File_common_meshfield_get_axis3D + module procedure File_common_meshfield_get_axis3D_cubedsphere end interface public :: FILE_common_meshfield_get_axis @@ -66,11 +69,13 @@ module scale_file_common_meshfield public :: File_common_meshfield_put_field2D_cartesbuf public :: File_common_meshfield_put_field2D_cubedsphere_cartesbuf public :: File_common_meshfield_put_field3D_cartesbuf + public :: File_common_meshfield_put_field3D_cubedsphere_cartesbuf public :: File_common_meshfield_set_cartesbuf_field1D public :: File_common_meshfield_set_cartesbuf_field2D public :: File_common_meshfield_set_cartesbuf_field2D_cubedsphere public :: File_common_meshfield_set_cartesbuf_field3D + public :: File_common_meshfield_set_cartesbuf_field3D_cubedsphere public :: File_common_meshfield_set_cartesbuf_field1D_local public :: File_common_meshfield_set_cartesbuf_field2D_local @@ -106,6 +111,7 @@ module scale_file_common_meshfield !- 1D --------------- +!OCL SERIAL subroutine File_common_meshfield_get_dims1D( mesh1D, dimsinfo ) implicit none @@ -129,6 +135,7 @@ subroutine File_common_meshfield_get_dims1D( mesh1D, dimsinfo ) return end subroutine File_common_meshfield_get_dims1D +!OCL SERIAL subroutine File_common_meshfield_get_axis1D( mesh1D, dimsinfo, x, & force_uniform_grid ) implicit none @@ -171,6 +178,7 @@ subroutine File_common_meshfield_get_axis1D( mesh1D, dimsinfo, x, & return end subroutine File_common_meshfield_get_axis1D +!OCL SERIAL subroutine File_common_meshfield_put_field1D_cartesbuf( mesh1D, field1D, & buf, force_uniform_grid ) use scale_polynominal, only: & @@ -182,7 +190,7 @@ subroutine File_common_meshfield_put_field1D_cartesbuf( mesh1D, field1D, & logical, intent(in), optional :: force_uniform_grid integer :: n, kelem1, p - integer :: i0, i1, i2, i + integer :: i, i2 type(LocalMesh1D), pointer :: lcmesh type(elementbase1D), pointer :: refElem integer :: i0_s @@ -247,6 +255,7 @@ subroutine File_common_meshfield_put_field1D_cartesbuf( mesh1D, field1D, & return end subroutine File_common_meshfield_put_field1D_cartesbuf +!OCL SERIAL subroutine File_common_meshfield_set_cartesbuf_field1D( mesh1D, buf, & field1D ) implicit none @@ -278,6 +287,7 @@ subroutine File_common_meshfield_set_cartesbuf_field1D( mesh1D, buf, & return end subroutine File_common_meshfield_set_cartesbuf_field1D +!OCL SERIAL subroutine File_common_meshfield_set_cartesbuf_field1D_local( & lcmesh, buf, i0_s, & val ) @@ -287,7 +297,7 @@ subroutine File_common_meshfield_set_cartesbuf_field1D_local( & integer, intent(in) :: i0_s real(RP), intent(inout) :: val(lcmesh%refElem1D%Np,lcmesh%NeA) - integer :: n, kelem1, p + integer :: kelem1 integer :: i, i1, i2 type(elementbase1D), pointer :: refElem integer :: indx @@ -309,13 +319,13 @@ end subroutine File_common_meshfield_set_cartesbuf_field1D_local !- 2D --------------- +!OCL SERIAL subroutine File_common_meshfield_get_dims2D( mesh2D, dimsinfo ) implicit none class(MeshRectDom2D), target, intent(in) :: mesh2D type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase2D_DIMTYPE_NUM) - type(ElementBase2D), pointer :: refElem type(LocalMesh2D), pointer :: lcmesh integer :: i, j, n @@ -360,13 +370,13 @@ subroutine File_common_meshfield_get_dims2D( mesh2D, dimsinfo ) return end subroutine File_common_meshfield_get_dims2D +!OCL SERIAL subroutine File_common_meshfield_get_dims2D_cubedsphere( mesh2D, dimsinfo ) implicit none class(MeshCubedSphereDom2D), target, intent(in) :: mesh2D type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase2D_DIMTYPE_NUM) - type(ElementBase2D), pointer :: refElem type(LocalMesh2D), pointer :: lcmesh integer :: i, j, n @@ -414,6 +424,7 @@ subroutine File_common_meshfield_get_dims2D_cubedsphere( mesh2D, dimsinfo ) return end subroutine File_common_meshfield_get_dims2D_cubedsphere +!OCL SERIAL subroutine File_common_meshfield_get_axis2D( mesh2D, dimsinfo, x, y, & force_uniform_grid ) implicit none @@ -428,7 +439,6 @@ subroutine File_common_meshfield_get_axis2D( mesh2D, dimsinfo, x, y, & integer :: ni, nj integer :: k integer :: i, j - integer :: i2, j2 type(ElementBase2D), pointer :: refElem type(LocalMesh2D), pointer :: lcmesh @@ -480,6 +490,7 @@ subroutine File_common_meshfield_get_axis2D( mesh2D, dimsinfo, x, y, & return end subroutine File_common_meshfield_get_axis2D +!OCL SERIAL subroutine File_common_meshfield_get_axis2D_cubedsphere( mesh2D, dimsinfo, x, y ) use scale_const, only: & @@ -494,8 +505,7 @@ subroutine File_common_meshfield_get_axis2D_cubedsphere( mesh2D, dimsinfo, x, y integer :: ni, nj, np, n integer :: k - integer :: i, j, p - integer :: i2, j2, p2 + integer :: i, j type(ElementBase2D), pointer :: refElem type(LocalMesh2D), pointer :: lcmesh @@ -547,6 +557,7 @@ subroutine File_common_meshfield_get_axis2D_cubedsphere( mesh2D, dimsinfo, x, y return end subroutine File_common_meshfield_get_axis2D_cubedsphere +!OCL SERIAL subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & buf, force_uniform_grid ) use scale_polynominal, only: & @@ -557,7 +568,7 @@ subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & real(RP), intent(inout) :: buf(:,:) logical, intent(in), optional :: force_uniform_grid - integer :: n, kelem1, p + integer :: n, kelem1 integer :: i0, j0, i1, j1, i2, j2, i, j type(LocalMesh2D), pointer :: lcmesh type(elementbase2D), pointer :: refElem @@ -657,6 +668,7 @@ subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & return end subroutine File_common_meshfield_put_field2D_cartesbuf +!OCL SERIAL subroutine File_common_meshfield_put_field2D_cubedsphere_cartesbuf( mesh2D, field2D, & buf ) use scale_prc, only: PRC_abort @@ -667,7 +679,7 @@ subroutine File_common_meshfield_put_field2D_cubedsphere_cartesbuf( mesh2D, fiel class(MeshField2D), intent(in) :: field2d real(RP), intent(inout) :: buf(:,:) - integer :: n, kelem1, p + integer :: n, kelem1 integer :: i0, j0, p0, i1, j1, i2, j2, i, j type(LocalMesh2D), pointer :: lcmesh type(elementbase2D), pointer :: refElem @@ -711,7 +723,7 @@ subroutine File_common_meshfield_put_field2D_cubedsphere_cartesbuf( mesh2D, fiel return end subroutine File_common_meshfield_put_field2D_cubedsphere_cartesbuf - +!OCL SERIAL subroutine File_common_meshfield_set_cartesbuf_field2D( mesh2D, buf, & field2D ) implicit none @@ -746,6 +758,7 @@ subroutine File_common_meshfield_set_cartesbuf_field2D( mesh2D, buf, & return end subroutine File_common_meshfield_set_cartesbuf_field2D +!OCL SERIAL subroutine File_common_meshfield_set_cartesbuf_field2D_local( & lcmesh, buf, i0_s, j0_s, & val ) @@ -755,7 +768,7 @@ subroutine File_common_meshfield_set_cartesbuf_field2D_local( & integer, intent(in) :: i0_s, j0_s real(RP), intent(inout) :: val(lcmesh%refElem2D%Np,lcmesh%NeA) - integer :: n, kelem1, p + integer :: kelem1 integer :: i1, j1, i2, j2, i, j type(elementbase2D), pointer :: refElem integer :: indx @@ -780,6 +793,7 @@ subroutine File_common_meshfield_set_cartesbuf_field2D_local( & return end subroutine File_common_meshfield_set_cartesbuf_field2D_local +!OCL SERIAL subroutine File_common_meshfield_set_cartesbuf_field2D_cubedsphere( mesh2D, buf, & field2D ) implicit none @@ -819,6 +833,7 @@ end subroutine File_common_meshfield_set_cartesbuf_field2D_cubedsphere !- 3D ------------ +!OCL SERIAL subroutine File_common_meshfield_get_dims3D( mesh3D, dimsinfo ) implicit none @@ -827,8 +842,6 @@ subroutine File_common_meshfield_get_dims3D( mesh3D, dimsinfo ) type(LocalMesh3D), pointer :: lcmesh integer :: i, j, k, n - integer :: icount, jcount, kcount - integer :: i_size, j_size, k_size type(MeshDimInfo), pointer :: dimInfo @@ -887,6 +900,77 @@ subroutine File_common_meshfield_get_dims3D( mesh3D, dimsinfo ) return end subroutine File_common_meshfield_get_dims3D +!OCL SERIAL + subroutine File_common_meshfield_get_dims3D_cubedsphere( mesh3D, dimsinfo ) + implicit none + + class(MeshCubedSphereDom3D), target, intent(in) :: mesh3D + type(FILE_common_meshfield_diminfo), intent(out) :: dimsinfo(MeshBase3D_DIMTYPE_NUM) + + type(LocalMesh3D), pointer :: lcmesh + integer :: i, j, k, n + + integer :: i_size, j_size, k_size + + type(MeshDimInfo), pointer :: diminfo + type(MeshDimInfo), pointer :: diminfo_x + type(MeshDimInfo), pointer :: diminfo_y + type(MeshDimInfo), pointer :: diminfo_z + !------------------------------------------------- + + i_size = 0 + do i=1, size(mesh3D%rcdomIJKP2LCMeshID,1) + n = mesh3D%rcdomIJKP2LCMeshID(i,1,1,1) + lcmesh => mesh3D%lcmesh_list(n) + i_size =i_size + lcmesh%NeX * lcmesh%refElem3D%Nnode_h1D + end do + + j_size = 0 + do j=1, size(mesh3D%rcdomIJKP2LCMeshID,2) + n = mesh3D%rcdomIJKP2LCMeshID(1,j,1,1) + lcmesh => mesh3D%lcmesh_list(n) + j_size = j_size + lcmesh%NeY * lcmesh%refElem3D%Nnode_h1D + end do + + k_size = 0 + do k=1, size(mesh3D%rcdomIJKP2LCMeshID,3) + n = mesh3D%rcdomIJKP2LCMeshID(1,1,k,1) + lcmesh => mesh3D%lcmesh_list(n) + k_size = k_size + lcmesh%NeZ * lcmesh%refElem3D%Nnode_v + end do + + k_size = k_size * size(mesh3D%rcdomIJKP2LCMeshID,4) + + diminfo_x => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_X) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_X), & + dimInfo_x, "X", 1, (/ diminfo_x%name /), (/ i_size /) ) + + diminfo_y => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_Y) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Y), & + diminfo_y, "Y", 1, (/ diminfo_y%name /), (/ j_size /) ) + + diminfo_z => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_Z) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Z), & + diminfo_z, "Z", 1, (/ diminfo_z%name /), (/ k_size /) ) + + diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_ZT) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_ZT), & + diminfo, "ZT", 1, (/ diminfo_z%name /), (/ k_size /) ) + + diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_XYZ) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_XYZ), & + diminfo, "XYZ", 3, (/ diminfo_x%name, diminfo_y%name, diminfo_z%name /), & + (/ i_size, j_size, k_size /) ) + + diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_XYZT) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_XYZT), & + diminfo, "XYZT", 3, (/ diminfo_x%name, diminfo_y%name, diminfo_z%name /), & + (/ i_size, j_size, k_size /) ) + + return + end subroutine File_common_meshfield_get_dims3D_cubedsphere + +!OCL SERIAL subroutine File_common_meshfield_get_axis3D( mesh3D, dimsinfo, x, y, z, & force_uniform_grid ) implicit none @@ -900,7 +984,6 @@ subroutine File_common_meshfield_get_axis3D( mesh3D, dimsinfo, x, y, z, & integer :: n, kelem integer :: i, j, k - integer :: i2, j2, k2 type(ElementBase3D), pointer :: refElem type(LocalMesh3D), pointer :: lcmesh @@ -966,6 +1049,86 @@ subroutine File_common_meshfield_get_axis3D( mesh3D, dimsinfo, x, y, z, & return end subroutine File_common_meshfield_get_axis3D +!OCL SERIAL + subroutine File_common_meshfield_get_axis3D_cubedsphere( mesh3D, dimsinfo, x, y, z ) + + use scale_const, only: & + PI => CONST_PI + use scale_prc + implicit none + + class(MeshCubedSphereDom3D), target, intent(in) :: mesh3D + type(FILE_common_meshfield_diminfo), intent(in) :: dimsinfo(MeshBase3D_DIMTYPE_NUM) + real(DP), intent(out) :: x(dimsinfo(MeshBase3D_DIMTYPEID_X)%size) + real(DP), intent(out) :: y(dimsinfo(MeshBase3D_DIMTYPEID_Y)%size) + real(DP), intent(out) :: z(dimsinfo(MeshBase3D_DIMTYPEID_Z)%size) + + integer :: n, ni, nj, nk, np + integer :: kelem + integer :: i, j, k + type(ElementBase3D), pointer :: refElem + type(LocalMesh3D), pointer :: lcmesh + + integer :: is, js, ks, ie, je, ke, igs, jgs, kgs + + logical :: uniform_grid = .false. + real(RP), allocatable :: x_local(:) + real(RP), allocatable :: y_local(:) + real(RP), allocatable :: z_local(:) + !------------------------------------------------- + + igs = 0; jgs = 0; kgs = 0 + + do np=1, size(mesh3D%rcdomIJKP2LCMeshID,4) + do nk=1, size(mesh3D%rcdomIJKP2LCMeshID,3) + do nj=1, size(mesh3D%rcdomIJKP2LCMeshID,2) + do ni=1, size(mesh3D%rcdomIJKP2LCMeshID,1) + n = mesh3D%rcdomIJKP2LCMeshID(ni,nj,nk,np) + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D + + allocate( x_local(refElem%Nnode_h1D), y_local(refElem%Nnode_h1D), z_local(refElem%Nnode_v) ) + + do k=1, lcmesh%NeZ + do j=1, lcmesh%NeY + do i=1, lcmesh%NeX + kelem = i + (j-1) * lcmesh%NeX + (k-1) * lcmesh%NeX * lcmesh%NeY + if ( j==1 .and. nj == 1 .and. k==1 .and. nk == 1 .and. np == 1) then + x_local(:) = lcmesh%pos_en(refElem%Fmask_h(1:refElem%Nnode_h1D,1),kelem,1) + + is = igs + 1 + (i-1)*refElem%Nnode_h1D + ie = is + refElem%Nnode_h1D - 1 + x(is:ie) = x_local(:) + end if + if ( i==1 .and. ni == 1 .and. k==1 .and. nk == 1 .and. np == 1 ) then + y_local(:) = lcmesh%pos_en(refElem%Fmask_h(1:refElem%Nnode_h1D,4),kelem,2) + + js = jgs + 1 + (j-1)*refElem%Nnode_h1D + je = js + refElem%Nnode_h1D - 1 + y(js:je) = y_local(:) + end if + if ( i==1 .and. ni == 1 .and. j == 1 .and. nj == 1 ) then + z_local(:) = lcmesh%pos_en(refElem%Colmask(:,1),kelem,3) & + + ( lcmesh%panelID - 1.0_RP ) * ( mesh3D%zmin_gl - mesh3D%zmin_gl ) + + ks = kgs + 1 + (j-1)*refElem%Nnode_v + ke = ks + refElem%Nnode_v - 1 + z(ks:ke) = z_local(:) + end if + end do + end do + end do + + igs = ie; jgs = je; kgs = ke + deallocate( x_local, y_local, z_local ) + end do + end do + end do + end do + + return + end subroutine File_common_meshfield_get_axis3D_cubedsphere + !OCL_SERIAL subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & buf, force_uniform_grid ) @@ -977,7 +1140,7 @@ subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & real(RP), intent(inout) :: buf(:,:,:) logical, intent(in), optional :: force_uniform_grid - integer :: n, kelem1, p + integer :: n, kelem1 integer :: i0, j0, k0, i1, j1, k1, i2, j2, k2, i, j, k type(LocalMesh3D), pointer :: lcmesh type(elementbase3D), pointer :: refElem @@ -1105,6 +1268,71 @@ subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & return end subroutine File_common_meshfield_put_field3D_cartesbuf +!OCL SERIAL + subroutine File_common_meshfield_put_field3D_cubedsphere_cartesbuf( mesh3D, field3D, & + buf ) + use scale_prc, only: PRC_abort + use scale_polynominal, only: & + polynominal_genLegendrePoly + implicit none + class(MeshCubedSphereDom3D), target, intent(in) :: mesh3D + class(MeshField3D), intent(in) :: field3d + real(RP), intent(inout) :: buf(:,:,:) + + integer :: kelem1 + integer :: n, i0, j0, k0, p0 + integer :: i1, j1, k1, i2, j2, k2, i, j, k + type(LocalMesh3D), pointer :: lcmesh + type(elementbase3D), pointer :: refElem + integer :: i0_s, j0_s, k0_s + integer :: Nnode_h1D + integer :: Nnode_v + !------------------------------------------------ + + i0_s = 0; j0_s = 0; k0_s = 0 + + do p0=1, size(mesh3D%rcdomIJKP2LCMeshID,4) + do k0=1, size(mesh3D%rcdomIJKP2LCMeshID,3) + do j0=1, size(mesh3D%rcdomIJKP2LCMeshID,2) + do i0=1, size(mesh3D%rcdomIJKP2LCMeshID,1) + n = mesh3D%rcdomIJKP2LCMeshID(i0,j0,k0,p0) + + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D + Nnode_h1D = refElem%Nnode_h1D + Nnode_v = refElem%Nnode_v + + do k1=1, lcmesh%NeZ + do j1=1, lcmesh%NeY + do i1=1, lcmesh%NeX + kelem1 = i1 + (j1-1)*lcmesh%NeX + (k1-1)*lcmesh%NeX*lcmesh%NeY + + do k2=1, Nnode_v + do j2=1, Nnode_h1D + do i2=1, Nnode_h1D + i = i0_s + i2 + (i1-1)*Nnode_h1D + j = j0_s + j2 + (j1-1)*Nnode_h1D + k = k0_s + k2 + (k1-1)*Nnode_v + buf(i,j,k) = field3d%local(n)%val(i2+(j2-1)*Nnode_h1D+(k2-1)*Nnode_h1D**2,kelem1) + end do + end do + end do + end do + end do + end do + + i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D + j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + k0_s = k0_s + lcmesh%NeZ * refElem%Nnode_v + end do + end do + end do + i0_s = 0; j0_s = 0 + end do + + return + end subroutine File_common_meshfield_put_field3D_cubedsphere_cartesbuf + subroutine File_common_meshfield_set_cartesbuf_field3D( mesh3D, buf, & field3D ) implicit none @@ -1142,6 +1370,47 @@ subroutine File_common_meshfield_set_cartesbuf_field3D( mesh3D, buf, & return end subroutine File_common_meshfield_set_cartesbuf_field3D +!OCL SERIAL + subroutine File_common_meshfield_set_cartesbuf_field3D_cubedsphere( mesh3D, buf, & + field3D ) + implicit none + class(MeshCubedSphereDom3D), target, intent(in) :: mesh3D + real(RP), intent(in) :: buf(:,:,:) + class(MeshField3D), intent(inout) :: field3d + + integer :: n + integer :: i0, j0, k0, p0 + type(LocalMesh3D), pointer :: lcmesh + type(elementbase3D), pointer :: refElem + integer :: i0_s, j0_s, k0_s, p0_s + !---------------------------------------------------- + + i0_s = 0; j0_s = 0; k0_s = 0; p0_s = 0 + + do p0=1, size(mesh3D%rcdomIJKP2LCMeshID,4) + do k0=1, size(mesh3D%rcdomIJKP2LCMeshID,3) + do j0=1, size(mesh3D%rcdomIJKP2LCMeshID,2) + do i0=1, size(mesh3D%rcdomIJKP2LCMeshID,1) + n = mesh3D%rcdomIJKP2LCMeshID(i0,j0,k0,p0) + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D + + call File_common_meshfield_set_cartesbuf_field3D_local( & + lcmesh, buf(:,:,:), i0_s, j0_s, k0_s, & + field3d%local(n)%val(:,:) ) + + i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D + j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + k0_s = k0_s + lcmesh%NeZ * refElem%Nnode_v + end do + end do + end do + i0_s = 0; j0_s = 0 + end do + + return + end subroutine File_common_meshfield_set_cartesbuf_field3D_cubedsphere + subroutine File_common_meshfield_set_cartesbuf_field3D_local( & lcmesh, buf, i0_s, j0_s, k0_s, & val ) @@ -1151,7 +1420,7 @@ subroutine File_common_meshfield_set_cartesbuf_field3D_local( & integer, intent(in) :: i0_s, j0_s, k0_s real(RP), intent(inout) :: val(lcmesh%refElem3D%Np,lcmesh%NeA) - integer :: n, kelem1, p + integer :: kelem1 integer :: i1, j1, k1, i2, j2, k2, i, j, k type(elementbase3D), pointer :: refElem integer :: indx diff --git a/FElib/src/file/scale_file_history_meshfield.F90 b/FElib/src/file/scale_file_history_meshfield.F90 index 79fb4e7d..ea954052 100644 --- a/FElib/src/file/scale_file_history_meshfield.F90 +++ b/FElib/src/file/scale_file_history_meshfield.F90 @@ -27,6 +27,7 @@ module scale_file_history_meshfield use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D use scale_localmesh_1d, only: LocalMesh1D use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D @@ -71,6 +72,7 @@ module scale_file_history_meshfield class(MeshRectDom2D), pointer :: mesh2D class(MeshCubeDom3D), pointer :: mesh3D class(MeshCubedSphereDom2D), pointer :: meshCubedSphere2D + class(MeshCubedSphereDom3D), pointer :: meshCubedSphere3D integer :: dims1D_size(1) integer :: dims2D_size(2) @@ -81,8 +83,8 @@ module scale_file_history_meshfield !---------------- subroutine FILE_HISTORY_meshfield_setup( & - mesh1D_, mesh2D_, mesh3D_, & - meshcubedsphere2D_ ) + mesh1D_, mesh2D_, mesh3D_, & + meshcubedsphere2D_, meshcubedsphere3D_ ) use scale_file_h, only: & FILE_HSHORT @@ -104,6 +106,7 @@ subroutine FILE_HISTORY_meshfield_setup( & class(MeshRectDom2d), intent(in), target, optional :: mesh2D_ class(MeshCubeDom3D), intent(in), target, optional :: mesh3D_ class(MeshCubedSphereDom2D), intent(in), target, optional :: meshCubedsphere2D_ + class(MeshCubedSphereDom3D), intent(in), target, optional :: meshCubedsphere3D_ character(len=H_MID) :: FILE_HISTORY_MESHFILED_H_TITLE = 'SCALE-FEM FILE_HISTORY_MESHFIELD' !< title of the output file character(len=H_MID) :: FILE_HISTORY_MESHFIELD_T_SINCE @@ -111,9 +114,6 @@ subroutine FILE_HISTORY_meshfield_setup( & character(len=FILE_HSHORT) :: calendar real(DP) :: start_daysec - integer :: ierr - integer :: k - !--------------------------------------------------------------------------- FILE_HISTORY_MESHFIELD_STARTDATE(:) = TIME_NOWDATE @@ -148,7 +148,7 @@ subroutine FILE_HISTORY_meshfield_setup( & !- Set a pointer to the variable of mesh nullify( mesh1D, mesh2D, mesh3D ) - nullify( meshCubedSphere2D ) + nullify( meshCubedSphere2D, meshCubedsphere3D ) if ( present(mesh1D_) ) then mesh1D => mesh1D_ @@ -162,6 +162,9 @@ subroutine FILE_HISTORY_meshfield_setup( & else if ( present(meshCubedsphere2D_) ) then meshCubedSphere2D => meshCubedsphere2D_ call set_dim_axis2D_cubedsphere() + else if ( present(meshCubedsphere3D_) ) then + meshCubedSphere3D => meshCubedsphere3D_ + call set_dim_axis3D_cubedsphere() else LOG_ERROR("FILE_HISTORY_meshfield_setup",*) "Any mesh (mesh1d/2d/3d) are not specified." call PRC_abort @@ -231,7 +234,8 @@ end subroutine FILE_HISTORY_meshfield_put2D subroutine FILE_HISTORY_meshfield_put3D(hstid, field3d) use scale_file_common_meshfield, only: & - File_common_meshfield_put_field3D_cartesbuf + File_common_meshfield_put_field3D_cartesbuf, & + File_common_meshfield_put_field3D_cubedsphere_cartesbuf implicit none integer, intent(in) :: hstid @@ -242,7 +246,12 @@ subroutine FILE_HISTORY_meshfield_put3D(hstid, field3d) !------------------------------------------------- allocate( buf(dims3D_size(1,1),dims3D_size(2,1),dims3D_size(3,1)) ) - call File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3d, buf(:,:,:) ) + if ( associated(mesh3D) ) then + call File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3d, buf(:,:,:) ) + else if ( associated(meshCubedSphere3D) ) then + call File_common_meshfield_put_field3D_cubedsphere_cartesbuf( & + meshCubedSphere3D, field3d, buf(:,:,:) ) + end if call FILE_HISTORY_put(hstid, buf) return @@ -265,7 +274,7 @@ subroutine set_dim_axis1D() real(RP), allocatable :: x(:) integer :: start(1,1), count(1,1) character(len=H_SHORT) :: dims(1,1) - integer :: d, n, ndim + integer :: n, ndim !------------------------------------------------- call File_common_meshfield_get_dims1D( mesh1D, & ! (in) @@ -306,7 +315,7 @@ subroutine set_dim_axis2D() real(RP), allocatable :: x(:), y(:) integer :: start(2,1), count(2,1) character(len=H_SHORT) :: dims(2,1) - integer :: d, n, ndim + integer :: n, ndim !------------------------------------------------- call File_common_meshfield_get_dims2D( mesh2D, & ! (in) @@ -350,7 +359,7 @@ subroutine set_dim_axis3D() real(RP), allocatable :: x(:), y(:), z(:) integer :: start(3,1), count(3,1) character(len=H_SHORT) :: dims(3,1) - integer :: d, n, ndim + integer :: n, ndim !------------------------------------------------- call File_common_meshfield_get_dims3D( mesh3D, & ! (in) @@ -394,7 +403,7 @@ subroutine set_dim_axis2D_cubedsphere() real(RP), allocatable :: x(:), y(:) integer :: start(2,1), count(2,1) character(len=H_SHORT) :: dims(2,1) - integer :: d, n, ndim + integer :: n, ndim !------------------------------------------------- call File_common_meshfield_get_dims( meshCubedSphere2D, & ! (in) @@ -422,6 +431,52 @@ subroutine set_dim_axis2D_cubedsphere() return end subroutine set_dim_axis2D_cubedsphere + + subroutine set_dim_axis3D_cubedsphere() + use scale_file_common_meshfield, only: & + FILE_common_meshfield_diminfo, & + File_common_meshfield_get_dims, & + File_common_meshfield_get_axis + use scale_mesh_base3d, only: & + DIMTYPE_NUM => MeshBase3D_DIMTYPE_NUM, & + DIMTYPE_X => MeshBase3D_DIMTYPEID_X, & + DIMTYPE_Y => MeshBase3D_DIMTYPEID_Y, & + DIMTYPE_Z => MeshBase3D_DIMTYPEID_Z + + implicit none + + type(FILE_common_meshfield_diminfo) :: dimsinfo(DIMTYPE_NUM) + real(RP), allocatable :: x(:), y(:), z(:) + integer :: start(3,1), count(3,1) + character(len=H_SHORT) :: dims(3,1) + integer :: n, ndim + !------------------------------------------------- + + call File_common_meshfield_get_dims( meshCubedSphere3D, & ! (in) + dimsinfo(:) ) ! (out) + + dims3D_size(1,1) = dimsinfo(DIMTYPE_X)%size + dims3D_size(2,1) = dimsinfo(DIMTYPE_Y)%size + dims3D_size(3,1) = dimsinfo(DIMTYPE_Z)%size + allocate( x(dims3D_size(1,1)), y(dims3D_size(2,1)), z(dims3D_size(3,1)) ) + call File_common_meshfield_get_axis( meshCubedSphere3D, dimsinfo, & ! (in) + x, y, z ) ! (out) + + start(:,:) = 1 + do n=1, DIMTYPE_NUM + ndim = dimsinfo(n)%ndim + dims(1:ndim,1) = dimsinfo(n)%dims(1:ndim) + count(1:ndim,1) = dimsinfo(n)%count(1:ndim) + call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) + end do + + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%desc, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:)) + + return + end subroutine set_dim_axis3D_cubedsphere + !---------------- end module scale_file_history_meshfield diff --git a/FElib/src/file/scale_file_restart_meshfield.F90 b/FElib/src/file/scale_file_restart_meshfield.F90 index 2a26d1e3..101e8a80 100644 --- a/FElib/src/file/scale_file_restart_meshfield.F90 +++ b/FElib/src/file/scale_file_restart_meshfield.F90 @@ -22,6 +22,7 @@ module scale_file_restart_meshfield use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D use scale_localmesh_1d, only: LocalMesh1D use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D @@ -194,7 +195,10 @@ subroutine FILE_restart_meshfield_component_Init2( this, & in_basename, in_postfix_timelabel, & out_basename, out_postfix_timelabel, & out_dtype, out_title, & - var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D ) + var_num, & + mesh1D, & + mesh2D, meshCubedSphere2D, & + mesh3D, meshCubedSphere3D ) implicit none @@ -211,6 +215,7 @@ subroutine FILE_restart_meshfield_component_Init2( this, & class(MeshRectDom2D), target, optional, intent(in) :: mesh2D class(MeshCubedSphereDom2D), target, optional, intent(in) :: meshCubedSphere2D class(MeshCubeDom3D), target, optional, intent(in) :: mesh3D + class(MeshCubedSphereDom3D), target, optional, intent(in) :: meshCubedSphere3D !-------------------------------------------------- this%comp_name = comp_name @@ -223,7 +228,7 @@ subroutine FILE_restart_meshfield_component_Init2( this, & this%out_dtype = out_dtype !- - call this%base%Init( var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D ) + call this%base%Init( var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D, meshCubedSphere3D ) return end subroutine FILE_restart_meshfield_component_Init2 diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index e86598bf..94977e28 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -200,10 +200,10 @@ end subroutine calc_normal allocate( lcmesh%zS(refElem%Np,lcmesh%Ne) ) allocate( lcmesh%Sz(refElem%Np,lcmesh%Ne) ) allocate( lcmesh%Gsqrt(refElem%Np,lcmesh%Ne) ) - allocate( lcmesh%G_ij(refElem%Np,lcmesh%Ne2D,2,2) ) - allocate( lcmesh%GIJ (refElem%Np,lcmesh%Ne2D,2,2) ) - allocate( lcmesh%lon2D(refElem%Np,lcmesh%Ne2D) ) - allocate( lcmesh%lat2D(refElem%Np,lcmesh%Ne2D) ) + allocate( lcmesh%G_ij(refElem%Nfp_v,lcmesh%Ne2D,2,2) ) + allocate( lcmesh%GIJ (refElem%Nfp_v,lcmesh%Ne2D,2,2) ) + allocate( lcmesh%lon2D(refElem%Nfp_v,lcmesh%Ne2D) ) + allocate( lcmesh%lat2D(refElem%Nfp_v,lcmesh%Ne2D) ) do f=1, refElem%Nfaces_h do i=1, refElem%Nfp_h diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 88d6e8e9..5b3d0a4b 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -232,16 +232,16 @@ subroutine MeshCubeDom3D_generate( this ) tileID = tileID_table(n, mesh%PRC_myrank+1) call MeshCubeDom3D_setupLocalDom( mesh, & - & tileID, panelID_table(tileID), & - & pi_table(tileID), pj_table(tileID), pk_table(tileID), this%NprcX, this%NprcY, this%NprcZ, & - & this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, this%zmin_gl, this%zmax_gl, & - & this%NeGX/this%NprcX, this%NeGY/this%NprcY, this%NeGZ/this%NprcZ, this%FZ(:) ) - - call MeshRectDom2D_setupLocalDom( this%mesh2D%lcmesh_list(n), & - & tileID, panelID_table(tileID), & - & pi_table(tileID), pj_table(tileID), this%NprcX, this%NprcY, & - & this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & - & this%NeGX/this%NprcX, this%NeGY/this%NprcY ) + tileID, panelID_table(tileID), & + pi_table(tileID), pj_table(tileID), pk_table(tileID), this%NprcX, this%NprcY, this%NprcZ, & + this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, this%zmin_gl, this%zmax_gl, & + this%NeGX/this%NprcX, this%NeGY/this%NprcY, this%NeGZ/this%NprcZ, this%FZ(:) ) + + call MeshRectDom2D_setupLocalDom( this%mesh2D%lcmesh_list(n), & + tileID, panelID_table(tileID), & + pi_table(tileID), pj_table(tileID), this%NprcX, this%NprcY, & + this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & + this%NeGX/this%NprcX, this%NeGY/this%NprcY ) call mesh%SetLocalMesh2D( this%mesh2D%lcmesh_list(n) ) !--- diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 new file mode 100644 index 00000000..77c3fcac --- /dev/null +++ b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 @@ -0,0 +1,538 @@ +#include "scaleFElib.h" +module scale_mesh_cubedspheredom3d + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_io + use scale_precision + + use scale_mesh_base3d, only: & + MeshBase3D, MeshBase3D_Init, MeshBase3D_Final, & + MeshBase3D_setGeometricInfo, & + MeshBase3D_DIMTYPE_NUM, & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_ZT, MeshBase3D_DIMTYPEID_XYZT + use scale_localmesh_3d, only: LocalMesh3D + use scale_element_hexahedral, only: HexahedralElement + + use scale_mesh_base2d, only: & + MeshBase2D, MeshBase2D_Init, MeshBase2D_Final, & + MeshBase2D_setGeometricInfo + use scale_mesh_rectdom2d, only: & + MeshRectDom2D, MeshRectDom2D_setupLocalDom + use scale_localmesh_2d, only: LocalMesh2D + use scale_element_quadrilateral, only: QuadrilateralElement + + use scale_element_base, only: ElementBase2D, ElementBase3D + + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public type & procedure + ! + type, extends(MeshBase3D), public :: MeshCubedSphereDom3D + integer :: NeGX + integer :: NeGY + integer :: NeGZ + + real(RP), public :: xmin_gl, xmax_gl + real(RP), public :: ymin_gl, ymax_gl + real(RP), public :: zmin_gl, zmax_gl + + real(RP), allocatable :: FZ(:) + + integer, allocatable :: rcdomIJKP2LCMeshID(:,:,:,:) + + real(RP) :: RPlanet + + type(MeshRectDom2D) :: mesh2D + type(QuadrilateralElement) :: refElem2D + contains + procedure :: Init => MeshCubedSphereDom3D_Init + procedure :: Final => MeshCubedSphereDom3D_Final + procedure :: Generate => MeshCubedSphereDom3D_generate + procedure :: AssignDomID => MesshCubedSphereDom3D_assignDomID + procedure :: GetMesh2D => MeshCubedSphereDom3D_getMesh2D + end type MeshCubedSphereDom3D + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + subroutine MeshCubedSphereDom3D_Init( this, & + NeGX, NeGY, NeGZ, RPlanet, & + dom_zmin, dom_zmax, & + refElem, NLocalMeshPerPrc, & + nproc, myrank, & + FZ ) + + use scale_const, only: & + PI => CONST_PI + implicit none + + class(MeshCubedSphereDom3D), intent(inout) :: this + integer, intent(in) :: NeGX + integer, intent(in) :: NeGY + integer, intent(in) :: NeGZ + real(RP), intent(in) :: RPlanet + real(RP), intent(in) :: dom_Zmin + real(RP), intent(in) :: dom_zmax + type(HexahedralElement), intent(in), target :: refElem + integer, intent(in) :: NLocalMeshPerPrc + integer, intent(in), optional :: nproc + integer, intent(in), optional :: myrank + real(RP), intent(in), optional :: FZ(NeGZ+1) + + integer :: k + real(RP) :: dz + !----------------------------------------------------------------------------- + + this%NeGX = NeGX + this%NeGY = NeGY + this%NeGZ = NeGZ + + this%xmin_gl = - 0.25_RP * PI + this%xmax_gl = + 0.25_RP * PI + this%ymin_gl = - 0.25_RP * PI + this%ymax_gl = + 0.25_RP * PI + this%zmin_gl = dom_zmin + this%zmax_gl = dom_zmax + this%RPlanet = RPlanet + + !- Fz + allocate( this%FZ(this%NeGZ+1) ) + if ( present(FZ) ) then + this%FZ(:) = FZ(:) + else + this%FZ(1 ) = dom_Zmin + this%FZ(this%NeGZ+1) = dom_Zmax + dz = (dom_zmax - dom_zmin) / dble(this%NeGZ) + do k=2, this%NeGZ + this%FZ(k) = this%FZ(k-1) + dz + end do + end if + + !-- + call MeshBase3D_Init( this, refElem, NLocalMeshPerPrc, 6, & + nproc, myrank ) + + !--- + call this%refElem2D%Init( this%refElem3D%PolyOrder_h, refElem%IsLumpedMatrix() ) + call MeshBase2D_Init( this%mesh2D, this%refElem2D, NLocalMeshPerPrc, & + nproc, myrank ) + + !-- Modify the information of dimension for the cubed sphere mesh + call this%SetDimInfo( MeshBase3D_DIMTYPEID_X, "x", "1", "X-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_Y, "y", "1", "Y-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_Z, "z", "m", "Z-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, "xyz", "1", "XYZ-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_ZT, "zt", "1", "XYZ-coordinate" ) + call this%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, "xyzt", "1", "XYZ-coordinate" ) + + return + end subroutine MeshCubedSphereDom3D_Init + + subroutine MeshCubedSphereDom3D_Final( this ) + implicit none + class(MeshCubedSphereDom3D), intent(inout) :: this + !----------------------------------------------------------------------------- + + if (this%isGenerated) then + if ( allocated(this%rcdomIJKP2LCMeshID) ) then + deallocate( this%rcdomIJKP2LCMeshID ) + end if + else + deallocate( this%FZ ) + end if + + call this%mesh2D%Final() + call this%refElem2D%Final() + + call MeshBase3D_Final( this ) + + return + end subroutine MeshCubedSphereDom3D_Final + + subroutine MeshCubedSphereDom3D_getMesh2D( this, ptr_mesh2D ) + implicit none + class(MeshCubedSphereDom3D), intent(in), target :: this + class(MeshBase2D), pointer, intent(out) :: ptr_mesh2D + !------------------------------------------------------- + + ptr_mesh2D => this%mesh2D + return + end subroutine MeshCubedSphereDom3D_getMesh2D + + subroutine MeshCubedSphereDom3D_generate( this ) + use scale_mesh_cubedspheredom2d, only: & + MeshCubedSphereDom2D_check_division_params + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatCoord + implicit none + + class(MeshCubedSphereDom3D), intent(inout), target :: this + + integer :: n + type(LocalMesh3D), pointer :: mesh + type(LocalMesh2D), pointer :: lcmesh2D + + integer :: tileID_table(this%LOCAL_MESH_NUM, this%PRC_NUM) + integer :: panelID_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + integer :: pi_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + integer :: pj_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + integer :: pk_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + + integer :: NprcX_lc, NprcY_lc, NprcZ_lc + integer :: tileID + + !----------------------------------------------------------------------------- + + call MeshCubedSphereDom2D_check_division_params( & + NprcX_lc, NprcY_lc, & + this%PRC_NUM, this%LOCAL_MESH_NUM_global, & + .true. ) + + NprcZ_lc = 1 + + !--- Construct the connectivity of patches (only master node) + + call this%AssignDomID( & + NprcX_lc, NprcY_lc, NprcZ_lc, & ! (in) + tileID_table, panelID_table, & ! (out) + pi_table, pj_table, pk_table ) ! (out) + + do n=1, this%LOCAL_MESH_NUM + mesh => this%lcmesh_list(n) + tileID = tileID_table(n, mesh%PRC_myrank+1) + + call MeshCubedSphereDom3D_setupLocalDom( mesh, & + tileID, panelID_table(tileID), & + pi_table(tileID), pj_table(tileID), pk_table(tileID), & + NprcX_lc, NprcY_lc, NprcZ_lc, & + this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & + this%zmin_gl, this%zmax_gl, this%RPlanet, & + this%NeGX/NprcX_lc, this%NeGY/NprcY_lc, this%NeGZ/NprcZ_lc, & + this%FZ(:) ) + + call MeshRectDom2D_setupLocalDom( this%mesh2D%lcmesh_list(n), & + tileID, panelID_table(tileID), & + pi_table(tileID), pj_table(tileID), NprcX_lc, NprcY_lc, & + this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & + this%NeGX/NprcX_lc, this%NeGY/NprcY_lc ) + + call mesh%SetLocalMesh2D( this%mesh2D%lcmesh_list(n) ) + + lcmesh2D => this%mesh2D%lcmesh_list(n) + call CubedSphereCnv_CS2LonLatCoord( & + lcmesh2D%panelID, lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), & + lcmesh2D%Ne * lcmesh2D%refElem2D%Np, this%RPlanet, & + mesh%lon2D(:,:), mesh%lat2D(:,:) ) + + !--- + ! write(*,*) "** my_rank=", mesh%PRC_myrank + ! write(*,*) " tileID:", mesh%tileID + ! write(*,*) " pnlID:", mesh%panelID, "-- i,j (within a panel)=", pi_table(tileID), pj_table(tileID) + ! write(*,*) " local mesh:", n, "( total", this%LOCAL_MESH_NUM, ")" + ! write(*,*) " panel_connect:", this%tilePanelID_globalMap(:,mesh%tileID) + ! write(*,*) " tile_connect:", this%tileID_globalMap(:,mesh%tileID) + ! write(*,*) " face_connect:", this%tileFaceID_globalMap(:,mesh%tileID) + ! write(*,*) " domain size" + ! write(*,*) " NeX, NeY:", mesh%NeX, mesh%NeY + ! write(*,*) " [X], [Y]:", mesh%xmin, mesh%xmax, ":", mesh%ymin, mesh%ymax + end do + + this%isGenerated = .true. + this%mesh2D%isGenerated = .true. + + deallocate( this%FZ ) + + return + end subroutine MeshCubedSphereDom3D_generate + + !- private ------------------------------ + + subroutine MeshCubedSphereDom3D_setupLocalDom( lcmesh, & + tileID, panelID, & + i, j, k, NprcX, NprcY, NprcZ, & + dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + planet_radius, NeX, NeY, NeZ, & + FZ ) + + use scale_meshutil_cubedsphere3d, only: & + MeshUtilCubedSphere3D_genConnectivity, & + MeshUtilCubedSphere3D_genCubeDomain, & + MeshUtilCubedSphere3D_BuildInteriorMap, & + MeshUtilCubedSphere3D_genPatchBoundaryMap + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_GetMetric + + use scale_localmesh_base, only: BCTYPE_INTERIOR + + implicit none + + type(LocalMesh3D), intent(inout) :: lcmesh + integer, intent(in) :: tileID + integer, intent(in) :: panelID + integer, intent(in) :: i, j, k + integer, intent(in) :: NprcX, NprcY, NprcZ + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + real(RP), intent(in) :: planet_radius + integer, intent(in) :: NeX, NeY, NeZ + real(RP), intent(in) :: FZ(NeZ*NprcZ+1) + + class(ElementBase3D), pointer :: elem + real(RP) :: delx, dely + real(RP) :: FZ_lc(NeZ+1) + + integer :: ii, jj, kk + integer :: ke + !----------------------------------------------------------------------------- + + elem => lcmesh%refElem3D + lcmesh%tileID = tileID + lcmesh%panelID = panelID + + !-- + lcmesh%Ne = NeX * NeY * NeZ + lcmesh%Ne2D = NeX * NeY + lcmesh%Nv = (NeX + 1)*(NeY + 1)*(NeZ + 1) + lcmesh%NeS = 1 + lcmesh%NeE = lcmesh%Ne + lcmesh%NeA = lcmesh%Ne + 2*(NeX + NeY)*NeZ + 2*NeX*NeY + + lcmesh%NeX = NeX + lcmesh%NeY = NeY + lcmesh%NeZ = NeZ + + !-- + delx = ( dom_xmax - dom_xmin ) / dble(NprcX) + dely = ( dom_ymax - dom_ymin ) / dble(NprcY) + FZ_lc(:) = Fz((k-1)*NeZ+1:k*NeZ+1) + lcmesh%xmin = dom_xmin + (i-1)*delx + lcmesh%xmax = dom_xmin + i *delx + lcmesh%ymin = dom_ymin + (j-1)*dely + lcmesh%ymax = dom_ymin + j *dely + lcmesh%zmin = FZ_lc(1) + lcmesh%zmax = FZ_lc(NeZ+1) + + !-- + allocate( lcmesh%pos_ev(lcmesh%Nv,3) ) + allocate( lcmesh%EToV(lcmesh%Ne,elem%Nv) ) + allocate( lcmesh%EToE(lcmesh%Ne,elem%Nfaces) ) + allocate( lcmesh%EToF(lcmesh%Ne,elem%Nfaces) ) + allocate( lcmesh%BCType(lcmesh%refElem%Nfaces,lcmesh%Ne) ) + allocate( lcmesh%VMapM(elem%NfpTot, lcmesh%Ne) ) + allocate( lcmesh%VMapP(elem%NfpTot, lcmesh%Ne) ) + allocate( lcmesh%MapM(elem%NfpTot, lcmesh%Ne) ) + allocate( lcmesh%MapP(elem%NfpTot, lcmesh%Ne) ) + + allocate( lcmesh%EMap3Dto2D(lcmesh%Ne) ) + + lcmesh%BCType(:,:) = BCTYPE_INTERIOR + + !---- + + call MeshUtilCubedSphere3D_genCubeDomain( lcmesh%pos_ev, lcmesh%EToV, & ! (out) + lcmesh%NeX, lcmesh%xmin, lcmesh%xmax, & ! (in) + lcmesh%NeY, lcmesh%ymin, lcmesh%ymax, & ! (in) + lcmesh%NeZ, lcmesh%zmin, lcmesh%zmax, FZ=FZ_lc ) ! (in) + + !--- + + call MeshBase3D_setGeometricInfo(lcmesh, MeshCubedSphereDom3D_coord_conv, MeshCubedSphereDom3D_calc_normal ) + + call CubedSphereCnv_GetMetric( & + lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, planet_radius, & ! (in) + lcmesh%G_ij, lcmesh%GIJ, lcmesh%Gsqrt ) ! (out) + return + !--- + + call MeshUtilCubedSphere3D_genConnectivity( lcmesh%EToE, lcmesh%EToF, & ! (out) + lcmesh%EToV, lcmesh%Ne, elem%Nfaces ) ! (in) + + !--- + call MeshUtilCubedSphere3D_BuildInteriorMap( lcmesh%VmapM, lcmesh%VMapP, lcmesh%MapM, lcmesh%MapP, & ! (out) + lcmesh%pos_en, lcmesh%pos_ev, lcmesh%EToE, lcmesh%EtoF, lcmesh%EtoV, & ! (in) + elem%Fmask_h, elem%Fmask_v, lcmesh%Ne, lcmesh%Nv, elem%Np, elem%Nfp_h, elem%Nfp_v, elem%NfpTot, & ! (in) + elem%Nfaces_h, elem%Nfaces_v, elem%Nfaces ) + + + call MeshUtilCubedSphere3D_genPatchBoundaryMap( lcmesh%VMapB, lcmesh%MapB, lcmesh%VMapP, & !(out) + lcmesh%pos_en, lcmesh%xmin, lcmesh%xmax, lcmesh%ymin, lcmesh%ymax, lcmesh%zmin, lcmesh%zmax, & ! (in) + elem%Fmask_h, elem%Fmask_v, lcmesh%Ne, lcmesh%Nv, elem%Np, elem%Nfp_h, elem%Nfp_v, elem%NfpTot, & ! (in) + elem%Nfaces_h, elem%Nfaces_v, elem%Nfaces ) + + !--- + !$omp parallel do collapse(2) private(ii,ke) + do kk=1, lcmesh%NeZ + do jj=1, lcmesh%NeY + do ii=1, lcmesh%NeX + ke = ii + (jj-1) * lcmesh%NeX + (kk-1) * lcmesh%NeX * lcmesh%NeY + lcmesh%EMap3Dto2D(ke) = ii + (jj-1) * lcmesh%NeX + end do + end do + end do + + return + end subroutine MeshCubedSphereDom3D_setupLocalDom + + subroutine MesshCubedSphereDom3D_assignDomID( this, & + NprcX_lc, NprcY_lc, NprcZ_lc, & + tileID_table, panelID_table, & + pi_table, pj_table, pk_table ) + + use scale_meshutil_cubedsphere3d, only: & + MeshUtilCubedSphere3D_buildGlobalMap + + implicit none + + class(MeshCubedSphereDom3D), target, intent(inout) :: this + integer, intent(in) :: NprcX_lc + integer, intent(in) :: NprcY_lc + integer, intent(in) :: NprcZ_lc + integer, intent(out) :: tileID_table(this%LOCAL_MESH_NUM, this%PRC_NUM) + integer, intent(out) :: panelID_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + integer, intent(out) :: pi_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + integer, intent(out) :: pj_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + integer, intent(out) :: pk_table(this%LOCAL_MESH_NUM*this%PRC_NUM) + + integer :: n + integer :: prc + integer :: tileID + integer :: is_lc, js_lc, ks_lc, ps_lc + integer :: ilc_count, jlc_count, klc_count, plc_count + integer :: ilc, jlc, klc, plc + integer :: Npanel_lc + + type(LocalMesh3D), pointer :: lcmesh + !----------------------------------------------------------------------------- + + call MeshUtilCubedSphere3D_buildGlobalMap( & + panelID_table, pi_table, pj_table, pk_table, & ! (out) + this%tileID_globalMap, this%tileFaceID_globalMap, this%tilePanelID_globalMap, & ! (out) + this%LOCAL_MESH_NUM_global, NprcZ_lc ) ! (in) + + !---- + + do prc=1, this%PRC_NUM + do n=1, this%LOCAL_MESH_NUM + tileID = n + (prc-1)*this%LOCAL_MESH_NUM + lcmesh => this%lcmesh_list(n) + + !- + tileID_table(n,prc) = tileID + this%tileID_global2localMap(tileID) = n + this%PRCRank_globalMap(tileID) = prc - 1 + + !- + if ( this%PRCRank_globalMap(tileID) == lcmesh%PRC_myrank ) then + if (n==1) then + is_lc = pi_table(tileID); ilc_count = 1 + js_lc = pj_table(tileID); jlc_count = 1 + ks_lc = pk_table(tileID); klc_count = 1 + ps_lc = panelID_table(tileID); plc_count = 1 + end if + if(is_lc < pi_table(tileID)) ilc_count = ilc_count + 1 + if(js_lc < pj_table(tileID)) jlc_count = jlc_count + 1 + if(ks_lc < pk_table(tileID)) klc_count = klc_count + 1 + if(ps_lc < panelID_table(tileID)) plc_count = plc_count + 1 + end if + end do + end do + + allocate( this%rcdomIJKP2LCMeshID(ilc_count,jlc_count,klc_count,plc_count) ) + do plc=1, plc_count + do klc=1, klc_count + do jlc=1, jlc_count + do ilc=1, ilc_count + this%rcdomIJKP2LCMeshID(ilc,jlc,klc,plc) = ilc + (jlc - 1)*ilc_count + (klc - 1)*ilc_count*jlc_count & + + (plc-1)*ilc_count*jlc_count*klc_count + end do + end do + end do + end do + + return + end subroutine MesshCubedSphereDom3D_assignDomID + +!OCL SERIAL + subroutine MeshCubedSphereDom3D_coord_conv( x, y, z, xX, xY, xZ, yX, yY, yZ, zX, zY, zZ, & + vx, vy, vz, elem ) + + implicit none + + type(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: x(elem%Np), y(elem%Np), z(elem%Np) + real(RP), intent(out) :: xX(elem%Np), xY(elem%Np), xZ(elem%Np) + real(RP), intent(out) :: yX(elem%Np), yY(elem%Np), yZ(elem%Np) + real(RP), intent(out) :: zX(elem%Np), zY(elem%Np), zZ(elem%Np) + real(RP), intent(in) :: vx(elem%Nv), vy(elem%Nv), vz(elem%Nv) + + !------------------------------------------------- + + x(:) = vx(1) + 0.5_RP*(elem%x1(:) + 1.0_RP)*(vx(2) - vx(1)) + y(:) = vy(1) + 0.5_RP*(elem%x2(:) + 1.0_RP)*(vy(3) - vy(1)) + z(:) = vz(1) + 0.5_RP*(elem%x3(:) + 1.0_RP)*(vz(5) - vz(1)) + + xX(:) = 0.5_RP*(vx(2) - vx(1)) !matmul(refElem%Dx1,mesh%x1(:,n)) + xY(:) = 0.0_RP !matmul(refElem%Dx2,mesh%x1(:,n)) + xZ(:) = 0.0_RP !matmul(refElem%Dx3,mesh%x1(:,n)) + yX(:) = 0.0_RP !matmul(refElem%Dx1,mesh%x2(:,n)) + yY(:) = 0.5_RP*(vy(3) - vy(1)) !matmul(refElem%Dx2,mesh%x2(:,n)) + yZ(:) = 0.0_RP !matmul(refElem%Dx3,mesh%x2(:,n)) + zX(:) = 0.0_RP !matmul(refElem%Dx1,mesh%x3(:,n)) + zY(:) = 0.0_RP !matmul(refElem%Dx2,mesh%x3(:,n)) + zZ(:) = 0.5_RP*(vz(5) - vz(1)) !matmul(refElem%Dx3,mesh%x3(:,n)) + + return + end subroutine MeshCubedSphereDom3D_coord_conv + +!OCL SERIAL + subroutine MeshCubedSphereDom3D_calc_normal( normal_fn, & + Escale_f, fid_h, fid_v, elem ) + + implicit none + + type(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: normal_fn(elem%NfpTot,3) + integer, intent(in) :: fid_h(elem%Nfp_h,elem%Nfaces_h) + integer, intent(in) :: fid_v(elem%Nfp_v,elem%Nfaces_v) + real(RP), intent(in) :: Escale_f(elem%NfpTot,3,3) + + integer :: d + !------------------------------------------------- + + do d=1, 3 + normal_fn(fid_h(:,1),d) = - Escale_f(fid_h(:,1),2,d) + normal_fn(fid_h(:,2),d) = + Escale_f(fid_h(:,2),1,d) + normal_fn(fid_h(:,3),d) = + Escale_f(fid_h(:,3),2,d) + normal_fn(fid_h(:,4),d) = - Escale_f(fid_h(:,4),1,d) + + normal_fn(fid_v(:,1),d) = - Escale_f(fid_v(:,1),3,d) + normal_fn(fid_v(:,2),d) = + Escale_f(fid_v(:,2),3,d) + end do + + return + end subroutine MeshCubedSphereDom3D_calc_normal + +end module scale_mesh_cubedspheredom3d \ No newline at end of file diff --git a/FElib/src/mesh/scale_meshutil_3d.F90 b/FElib/src/mesh/scale_meshutil_3d.F90 index 4ecb8edf..7af3a425 100644 --- a/FElib/src/mesh/scale_meshutil_3d.F90 +++ b/FElib/src/mesh/scale_meshutil_3d.F90 @@ -665,16 +665,15 @@ subroutine MeshUtil3D_buildGlobalMap( & logical, intent(in) :: isPeriodicZ integer, intent(in) :: Ne_x integer, intent(in) :: Ne_y + integer, intent(in) :: Ne_z integer :: NtilePerPanel - integer :: Ne_z integer :: Nv_x, Nv_y, Nv_z integer, allocatable :: nodesID_3d(:,:,:) integer, allocatable :: EToV(:,:) integer, allocatable :: EToE(:,:) integer, allocatable :: EToF(:,:) integer :: i, j, k, f - integer :: panelID integer :: tileID, tileID_R integer :: counter diff --git a/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 b/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 new file mode 100644 index 00000000..ea5ced94 --- /dev/null +++ b/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 @@ -0,0 +1,169 @@ +#include "scaleFElib.h" +module scale_meshutil_cubedsphere3d + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_const, only: & + PI => CONST_PI, & + EPS => CONST_EPS + use scale_precision + use scale_prc + use scale_io + use scale_prc + + use scale_meshutil_3d, only: & + MeshUtilCubedSphere3D_genCubeDomain => MeshUtil3D_genCubeDomain, & + MeshUtilCubedSphere3D_genConnectivity => MeshUtil3D_genConnectivity, & + MeshUtilCubedSphere3D_BuildInteriorMap => MeshUtil3D_BuildInteriorMap, & + MeshUtilCubedSphere3D_genPatchBoundaryMap => MeshUtil3D_genPatchBoundaryMap + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: MeshUtilCubedSphere3D_genCubeDomain + public :: MeshUtilCubedSphere3D_genConnectivity + public :: MeshUtilCubedSphere3D_buildInteriorMap + public :: MeshUtilCubedSphere3D_buildGlobalMap + public :: MeshUtilCubedSphere3D_genPatchBoundaryMap + +contains + subroutine MeshUtilCubedSphere3D_buildGlobalMap( & + panelID_table, pi_table, pj_table, pk_table, & + tileID_map, tileFaceID_map, tilePanelID_map, & + Ntile, & + NeZ ) + + ! use scale_prc, only: PRC_isMaster + use scale_meshutil_3d, only: & + MeshUtil3D_genConnectivity + use scale_meshutil_cubedsphere2d, only: & + MeshUtilCubedSphere2D_getPanelConnectivity + implicit none + + integer, intent(in) :: Ntile + integer, intent(out) :: panelID_table(Ntile) + integer, intent(out) :: pi_table(Ntile) + integer, intent(out) :: pj_table(Ntile) + integer, intent(out) :: pk_table(Ntile) + integer, intent(out) :: tileID_map(6,Ntile) + integer, intent(out) :: tileFaceID_map(6,Ntile) + integer, intent(out) :: tilePanelID_map(6,Ntile) + integer, intent(in) :: NeZ + + integer :: NtilePerPanel + integer :: NeX, NeY, NvX, NvY, NvZ + integer, allocatable :: nodesID_3d(:,:,:,:) + integer, allocatable :: EToV(:,:) + integer, allocatable :: EToE(:,:) + integer, allocatable :: EToF(:,:) + integer :: i, j, k, f + integer :: panelID + integer :: tileID, tileID_R + integer :: counter + + integer :: panel_connectivity(4,6) + integer :: face_connectivity (4,6) + + integer :: pi_, pj_ + !----------------------------------------------------------------------------- + + NtilePerPanel = Ntile / 6 + NeY = int( sqrt(dble(NtilePerPanel)) ) + NeX = NtilePerPanel/NeY + NvX = NeX + 1 + NvY = NeY + 1 + NvZ = NeZ + 1 + allocate( nodesID_3d(NvX,NvY,NvZ,6) ) + allocate( EToV(Ntile,8), EToE(Ntile,8), EToF(Ntile,8) ) + + counter = 0 + do panelID = 1, 6 + do k = 1, NvZ + do j = 1, NvY + do i = 1, NvX + counter = counter + 1 + nodesID_3d(i,j,k,panelID) = counter + end do + end do + end do + end do + + !---- + + tileID = 0 + do panelID = 1, 6 + do k = 1, NeZ + do j = 1, NeY + do i = 1, NeX + tileID = tileID + 1 + panelID_table(tileID) = panelID + pi_table(tileID) = i; pj_table(tileID) = j; pk_table(tileID) = k + EToV(tileID,:) = (/ nodesID_3d(i,j ,k ,panelID), nodesID_3d(i+1,j ,k ,panelID), & + nodesID_3d(i,j+1,k ,panelID), nodesID_3d(i+1,j+1,k ,panelID), & + nodesID_3d(i,j ,k+1,panelID), nodesID_3d(i+1,j ,k+1,panelID), & + nodesID_3d(i,j+1,k+1,panelID), nodesID_3d(i+1,j+1,k+1,panelID) /) + end do + end do + end do + end do + + call MeshUtil3D_genConnectivity( EToE, EToF, & + EToV, Ntile, 6 ) + tileID_map(:,:) = transpose(EToE) + tileFaceID_map(:,:) = transpose(EToF) + + call MeshUtilCubedSphere2D_getPanelConnectivity( & + panel_connectivity, face_connectivity ) + + do tileID=1, Ntile + do f=1, 6 + tileID_R = tileID_map(f,tileID) + tilePanelID_map(f,tileID) = panelID_table(tileID_R) + end do + end do + + !- + do tileID=1, Ntile + panelID = panelID_table(tileID) + + do f=1, 4 + if ( tileFaceID_map(f,tileID) /= f ) cycle ! Does the face correspond the boundary of panel of cubed sphere? + + pi_ = pi_table(tileID) + pj_ = pj_table(tileID) + + select case( panelID ) + case ( 1, 2, 3, 4 ) + if ( pi_table(tileID) == 1 ) pi_ = NeX + if ( pi_table(tileID) == NeX ) pi_ = 1 + if ( pj_table(tileID) == 1 ) pj_ = NeY + if ( pj_table(tileID) == NeY ) pj_ = 1 + case ( 5 ) + pj_ = NeY + if ( pi_table(tileID) == 1 ) pi_ = NeY - pj_table(tileID) + 1 ! West + if ( pi_table(tileID) == NeX ) pi_ = pj_table(tileID) ! East + if ( pj_table(tileID) == 1 ) pi_ = pi_table(tileID) ! South + if ( pj_table(tileID) == NeY ) pi_ = NeX - pi_table(tileID) + 1 ! North + case ( 6 ) + pj_ = 1 + if ( pi_table(tileID) == 1 ) pi_ = pj_table(tileID) ! West + if ( pi_table(tileID) == NeX ) pi_ = NeY - pj_table(tileID) + 1 ! East + if ( pj_table(tileID) == 1 ) pi_ = NeX - pi_table(tileID) + 1 ! South + if ( pj_table(tileID) == NeY ) pi_ = pi_table(tileID) ! North + end select + + tilePanelID_map(f,tileID) = panel_connectivity(f,panelID) + tileID_map(f,tileID) = pi_ + (pj_ - 1) * NeX + (tilePanelID_map(f,tileID) - 1) * NeX * NeY + tileFaceID_map(f,tileID) = face_connectivity(f,panelID) + end do ! loop for f + end do ! loop for tile + + return + end subroutine MeshUtilCubedSphere3D_buildGlobalMap + +end module scale_meshutil_cubedsphere3d From 7c9e1cd8790d2cdadead836d8ddcec57b0264d0d Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 16 May 2021 21:28:12 +0900 Subject: [PATCH 18/98] Add a unit test to check modules for 3D cubed sphere mesh. --- .../test_mesh_cubedom3d_hexahedral.f90 | 4 +- FElib/test/FE/mesh_cubedsphere3d/Makefile | 61 +++++ .../test_mesh_cubedsphere3d | Bin 0 -> 1465424 bytes .../test_mesh_cubedsphere3d.f90 | 254 ++++++++++++++++++ 4 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 FElib/test/FE/mesh_cubedsphere3d/Makefile create mode 100755 FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d create mode 100644 FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 diff --git a/FElib/test/FE/mesh_cubedom3d_hexahedral/test_mesh_cubedom3d_hexahedral.f90 b/FElib/test/FE/mesh_cubedom3d_hexahedral/test_mesh_cubedom3d_hexahedral.f90 index 8e34af9f..9c86d44d 100644 --- a/FElib/test/FE/mesh_cubedom3d_hexahedral/test_mesh_cubedom3d_hexahedral.f90 +++ b/FElib/test/FE/mesh_cubedom3d_hexahedral/test_mesh_cubedom3d_hexahedral.f90 @@ -251,7 +251,7 @@ function elemID(lmesh, i, j, k) result(eid) !-------------------------------------- eid = i + (j-1)*lmesh%NeX + (k-1)*lmesh%NeX*lmesh%NeY return - end function + end function elemID function nodeID(elem, i, j, k) result(nid) type(HexahedralElement), intent(in) :: elem @@ -260,7 +260,7 @@ function nodeID(elem, i, j, k) result(nid) !-------------------------------------- nid = i + (j-1)*elem%Nnode_h1D + (k-1)*elem%Nnode_h1D**2 return - end function + end function nodeID !-------------------------- diff --git a/FElib/test/FE/mesh_cubedsphere3d/Makefile b/FElib/test/FE/mesh_cubedsphere3d/Makefile new file mode 100644 index 00000000..83f485e1 --- /dev/null +++ b/FElib/test/FE/mesh_cubedsphere3d/Makefile @@ -0,0 +1,61 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../..) +BUILD_DIR = ./.libs +SYSDEP_DIR = $(TOPDIR)/sysdep + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + +BINNAME = test_mesh_cubedsphere3d + +LIBS = $(LIBDIR)/libScaleFECore.a + +OBJS = + +all: + $(MAKE) envlog + $(MAKE) makedir + $(MAKE) makebin + $(MAKE) run + +makedir: + mkdir -p $(BUILD_DIR) + +makebin: $(BINNAME) + @echo "Complete making." + +run: + mpirun -n 1 ./$(BINNAME) + +vis: + bash ./visualize/visualize.sh + +$(BINNAME): $(BUILD_DIR)/$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) + +$(BUILD_DIR)/$(BINNAME).o: $(BINNAME).f90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) + +distclean: clean + rm -f $(BINNAME) + +clean: + rm -rf $(BUILD_DIR) + +.SUFFIXES: +.SUFFIXES: .o .f90 .mod + +%.mod: %.f90 + $(MAKE) $(patsubst %.f90,%.o,$<) + +$(BUILD_DIR)/%.o: %.f90 + $(FC) $(FFLAGS) $(ADDITIONAL_FFLAGS) -DVERSION_MACRO=\"$(VERSION)\" -I$(BUILD_DIR) -I$(MODDIR) $(CONTRIB_INCLUDE) -I$(SCALEFELIBDIR)/include $(SCALE_NETCDF_INCLUDE) $(MODDIROPT) $(BUILD_DIR) -o $@ -c $< + +.PHONY : clean distclean allclean + +include $(TOPDIR)/utils/make/Make_environments diff --git a/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d b/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d new file mode 100755 index 0000000000000000000000000000000000000000..fbc53794669aa6d392dcedd6efbc9bdc7a0319ec GIT binary patch literal 1465424 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ℜq_qk4lR5BZUSc&JYJW? zxfGnTE+!9nw@?pDRvbukp&P#f=WE!a0bEOgnQG@hLx+}t^HuPTLAGO%%XQ#=lRRP7 zp=CW}7I?3w?WAk~XVQcZgV!svP1=rJ@TP2q*oBEJ_M~+yI|M98Ujzw|(pks%2+_P6-`A$b#Gq8NTFRP8~0!OQ!!Z#aw-v>SGPTZ!M zZ|;S0eX(PYp6p;Rj8n+_RFmGz`?GjomA6)R&*{+3r?9^1o!u6^g3KN46|hSe4r87E zk~Y0)V?0rU4avuTmEE^f*Tvv&WC!;Hu({3+S`?Sw`pWyz0uBL5DJF)?*nRf14-kK)*-EBoj+OpiWmcOg# z{a|FZ3_Qz5{Zo(Uel_U%D)KQt2^y^i~OZvA3z?QYZrO;l+H-k%JJbq{`UQHWTq8#?9LM*oFlJ}TpVnyr3}^i!mNEqxcc_sTu}8kui) z@htslq0gb>Is}cSf{$+=E<1EEj@JpLSU!u3zLT#-7$xwM6sjD^*psMp=ucAEHk)nK9Tx?q8~E zi+)WUcoJ>!R_ycy>ma&;?f#z!Qg zeTnzq6Kd73h7x)zWvAM9=+v01Ybv~LC*R((gtbpV9&4NiS>r?I2AFeyfwnn|w)Q-8 z2p@ywW`$4%V01BMInB@XuEV`!qG{jiGie|B%?|C+>v5 zo%rnS*zS*zXH?owq%C?n*O`11p3kCB`2zAi7d+>HXAU^u1=jh%VQmNFu*|U3%R|g- z+0Y9abC&>L>Y!WMVXGec;=fXLA@wMA_cHYNLWgADHC3mn`jj#B(DU0S8DD^rv(j1j~91I^)ry5&!CiOgndb<-@ z-$`AHEqR?fwy{@B7@3{J`*WyAslU6i!hb1sB=bEt0w-F&N6)1Ec4StFE*Fp|2uxY)kD2DVc-qIW^~wd}QO zwe~u&>>#vHfcAy78QJ3?7v7pxyI#(7A@>E)=z~5VG9QO+j1h0Buphf8eb@FSwpnO2 zuv22A#g0Qmv=sXyF^D|w{m@nz!ERG8DLRhcpTiAaIUh`HUhqL;RM@&EiG|rqXDeVe z1INxKda59;)~hWUSh%Z^x;#n_$^&x@v;}P?DZ~tAg2*icM#J~ zkNAkK`=io^y2>qeFY)JI$vskKzhv1DKD7t5?3-K=_aqEp$sYIP;@-sgxG!M?rX83Q z;{HTxkJPltIPeujrzQ7DO=pk$j33$K{=4GyDH>9^Q#gl%U+_&z?sNZL@p%V)*x_I1 zA`J2?+ED>K`IGT}FT6+hk-7)T&U5?SQ6^;I9S{#F8 zjg6Ct-5TukJS5i8XeX{e&Wi8PsT~J#+Egn3GPeD?+1<%TizJOXG(0Lgf=|^ng(N!rvO9d zVI8qg8qWpCWazvU`g_J!Hg0D;eLC=FlV9l0XP$Qge9a+$E_l;pYZ^!3$EFi^p8*d& z;N@2Ss~U~38cvx@pV{YlmAP#{eCAVzGeqEJU1NSE0Wa;2N$ii^8@xjpTaLi*oQ3@p zT_||QbPVO}ka_e4rorn(WPfJ7IU)Y$S{L;~9mxLo!sp-NN&d?hc}W@hJ_TB(%(dOs z8j(RhJX>duF#jUFOT7xu!h?aF#v>mOaxMhMB;+DKMB>YjkT;y9y8~H7`OjcF@|hZ2 z+gN}+N5lK+@H&Y)oAOMXV+8qy&nE29c=((`KH*h(bHUp^@KZ!z=tb6DR6%!clBZng z7rKO|QqpqLYk$DT3g1Jq^_;C@(R?lYOFNKL8hpqcMJ_zM;92xyJaZ-EptS(qE0S0h z_+>7{1rGYB*7>FZ_SAQDnGX^8qSs=#mwE21oygvcqI)i6<)W`B=bq#OU+k^GnN1wp z>NCG(oo7^8g^dn!UqyTB>?=3r2VawY1JGCCx@2ApSOzd$_#OiomTgV$H~ngIujy9i zIt#wTzCMk8P1#jxEB}pc6&u?fn=~3*l(K6*u}?j)PbvHML$-BVa{uX+ZJms5oyy#2 z%C=7FGWYpi=Z6SRiQQK?nfJm5K8a6B;r%|ldTN)t5&Ba$wTQZ|=%zY;%(hDX$oV0y zoM$L=pJF#V>$cN&&X%)7u$kXyJFU3>dtUQYiR-UOjw?oCJJ(W%J*l#=oiB^+BRFEw0+pRg7KTPiwn<=LFe#rSAdUguat+MWyj&BY##MVE(R zgG4{m(2+deWuVhNBhAsp&owz}o@;SbJ$Kk4`KHI-ZJdGKseW#=L(2R{bQCyJ_Vwpl z9S+*E;{M`TePd0s%uC6<0_z?6eIw{+FXc)n=COi)-{0xmSz~efo-<;fHXb04;IYxS ztLEK4;wHZVXRd|E2rr<&yq|Ix$3ALYM!Qb^6Z=c@|B^9CYCI$3o5j#xL~J0fe6N`NeRu@^iPgQJ-E*o*LxQMOMX53TQmb2aHwXc~xY z8bf>asmSCvu@4*P@qQHjH=$eB!Y+nqiFJ;p|8BujEtbs@-WKxT%A?sIXpx_$EoMM> z27N(UA13~KG_?43s8 z>tbk-II++md`sP|VEu0eunVz^!Z-V-hTFMBHp}>Dbr`ahy=9A;YfH(IvzFF~-ehx@ z)D_4`WK#&NYmw9Q&?xYPAIT@Mr2Ngu?PlaQ3b_=8_FLaXCv3=TduX5jDKZis7a}_; zpW;XK?KF6L4xaLXE$~t@|2uUcumz8-ZIN;t%6C|KZ@ z5K4%A9;ME|K#pIqCQWFm{AK@Ebucv*yL_I|>2+iJNYtbU7 znbcJ~{E3V|U$(yS67*L15`I2jwz^StL-tfzx9r`g2Pt`3u~X{o?dKAX3&10C&Igy&pUCas%f4v54?0JqPYv)}gZy4VP9lHdRqFIN z=;x!%2c%^B1bKTi))G34p`{48*Cg@ESa%Wd7cpj&y`h9Z8H3NF?pE-h(a5As8yfi@=r?@ZfB&g=s7r;buyx{do3Op@=xiRe$@naY zO)h0Em5j^&(=l0^jLFs!A8Vs5W3mWWvrWAu{bzY6u}mvI*37&fcm&5XPg$+VivCHZ z^d)@I@}G{|1{sXcHh21+pQU&57ud?2Gch?yn^<3CW8KJ=_)_teMTR{b*g-6e*j;K& z)iqV|uju`?}EoVb5YI}-fgdw^MQdgE3m^}S9Q~YX@Nst^B<=jepu4? zNWbfh>8FO=cHNSn|M9wK&b;-y=f?iwy0;m>9=zSN_{m9Q9Wncr>*P9k``ex8PM7yR z=G(F|_twp6ywo8|^*Q>eB4J!uH%=;ZqLoSv#mtTHRG+m+u&Suzjuii_N_E-X%L` z^4xEp&CINsy<-l~gC4e->D+Is&I+eJX*2s9GoJ_n&(YE|to*&gqj??&5B3E%=9WWK zT-?{EtJR!$AKpFER=07WVJ1$q)in*X)wQ_|bK_vcY#U~n`%g2>T_X)M{)BO`{T##0 zy2obP?Y+*n-EA`+H8#`y+2Mx|uy4O%uyVz$D8?z68N=whzir_?HYx9bPKeyeM*m*{g2KQkWnB0pcIn&kpc1-8n`zUfzXQ?sgX4IFUF`MXZ( zW2IGIfGzNx5**l7cjey3J9Y2a>wKj0-R4jSUEL^?sSYanMjwr~Fe^v^Y1!gl79Kd7HhH#apiM+> zbsZ3SN&oaNI*m=^u`N71;d>DJ_cPX(3{od|Y$hfn&tmtCBwV7U((FDUR8Y+HLA9<9)Pu!j45rz*Bn*scTg3Nrd2gZ z(}`t&7u~6MJtJR5M`HIp*cmVOrFv6^jBIXlQNb_SoH!S@1u&bWAU!iezyUZf>D zKHhm&n!z~N5lKYtj4h|e6N$<3wnQ3Z$n;2ibW)skNFnzA`C=G&#NyxhhXflzQrjcv=!g&d&N<$(S(Sr#-*(ds{T(X-i~Lr;2kk4D`9h-gikF zXJ;s-mfGfa3&*L4ezdjAZJ{Yfu3Dq)J;JwIGkcxNyHPgNDl_+_u<>(no@q0CXV}a^Mc_P_ z`yB2|Y-Z`9!>e7B&J7Rh37sd}OxsxAUu!d;f-j@|%Dpl0%=DcUwof`PteV)5zBl_b z*iH%;_wbk}{Q=s3XEWpWK1)u%o$@!?%)^{D671(O^$F}fa#$@sjIDj*!G2HJ( z!|e6CVGgP>%-#=kE#Q79*B-9@hFOd}2DRJjR1rM<0XupE|2P#H=71JkUB5G-;ar2W zi&ZCY)SoIz@eoVRR=D3((u=vu z;s3HOy!@PZxxBklzJc>@Npr&e{P1!CbdQ3MAzY_&U(R(8SEXT&fETIDpbh^2B4w`F ztL8yJ^|o>X_5L7!V~nbcH}?q_m30pXY|6CRuiP78O`QWBPUA8T8@!{=sguGT^nF-o z_tU%8e5qUf@M^K?r+ho{?<&w}F~q17H9(35iWl;|vaO8s1{ z%(zn9EuFoRGTX8iThF4eB|^I`-0xb_-*NeEVRaK_51|{PuM>FJ!u-S^+`Eh%%B~A8|m;4mC;(JaylRlKs z9)6U*#mVO?*2wiSXQ)q>v@_Wo0oJPZML zy)At5sh#u-?ZU&i=#K%{)BPCw?V;|S^v8~c-;#nq2>4~T@TVf9+)nxhzDDMPDd)kUMb6RC`18rJL057PY z%p@72s7O>~rV9E0-bqFyYERGiod5s%KhKvu``K&lS?gWzde?f_dN1peD(yfW()-~{ zIw>PWd&SC#!gnWs1Get&hdmhX&KTU`LU-T-OXwbhyKWHfQMk5mf$RSY?sw?~{dz#t zZ$$pjL-sC6=Ow@Yd7%X;nlq5jS8jo9&&dVbPsb9Dl9a4u<9l7=-k)h6PV z$XN2*mI0Z{jZCE>$7`S3Jyv9@Y-Fl9Wp0=C+!pk%Aa`wu{PjL^)m-HMm-!vRwKowx zEQz&9J)8s3FJC3>c+ZryBLVp;9{DN>`6>bVYUF@?6^DFfLcU7*FXXEr@`;VKlY<|I zCIyd$I+0aAK}MM##Qq+{CW3s`i@cH@WRF0wGjs&`>SN@qX~C|LCD0aZ&Jt5c^0CHH~qW`pn1wDP@Yjhm74JWlOzd z<;Kbr+@?~mSb1m4SDoM=1ZOMql|sG>fO{ACijBzud^>P$)FqF)$o)VfUm?Fn?YBbT zfGrrc-#Trp(6D|6B=r>74o(= zbK3+J*=|FBoZ7c3jlLG3j84kfLm6{MyZ4t<25>lwQ~BbcvDpUg&B|BITrGNByqU2? zB^mKf)uAOaMh{hyxD>rXcV~o6D&z75_B6z&p@RbdQ(*r9`O(ch^;2N}N*~`?t|xYE zag1+Vr|TVC`KFlbHkFSISCs1=mlNNlj|z8N+*Re}RPYG`+pAasWd6;=SpSd`Td3!7KdH=Y7q2XXI zFE1Y#t}GuDuFyw@%gR&2>&sJtb#{0p9cAQMM>$(cr-sYH=>hUezL)4jflPOm%<*Nw2-w_J zWzaKVmA54vL>_T=r5fF<)yBY;?y6v(GJYxPzUQubT;9w+*&?UUMHZ;g4B^q!!!yF&!iz1Yjv#!wjy@3R;@%hfZ!vvOgCB})+?7Fp6@D1v zRvkO|uDjF1iAw8;3uql0ydk{vfP7cu!pSzhV+cI*ec}(RVTPH$5$_%sj<3->boTM+ zYC+mt;T7kZ__l+|b?Q!7?g?SdJtmxyA~H@o;Z(}b z2q&{vVu%_W&KTVPx#7V_PTR3%l>FG9}uk%w+7loVm|= zDRLh5E?TXp-?e(phCJ+6RvzZMUMut2THcwTt~pRd*t&XjbuQzuwZ^>}n@6vWx0St5 zR$waLeI?d*Mfe15)mLI^|7_rWa^U^Nz}tB#`(gGEGq6P(CX4EqWo{p3IGcwV!>-ph zGHxy|>KrEa3ts@-g6O=@PU)AMoO~Y#jpbcL`ZVb3EFWeR1FsL6s)X;|rZG`j?Fh16 z5As7_pQ)j*Pv=1nOhyi*-vq!#=0Lc!KAy z>Cm2ZpVI$U-(qgK`-ZrNn`?%A>)I5tas09>*|@~MadENf2VrN$jbZBq_x{7>sf|xI zn~YZ-sf|s|so|~2XNQ~9!kH$$JugxB94=39Ecsyd0sIKT=;M^k7GRV@nM@&Rc|tl2#a0Uc>#45=IPhnzTJ+(#+SA8W=kY^g_?r%RC$kJ9F)c_yP2+p80MYY(#Sa{9u%=b9ScLq0u%47rSc z5=5pf`goWTp#4S1ls+JRNcw>202WPc+?1JUIL~(P?{iFS43tk4yF-+Q0X-v1!xK8+ zGoc%F>?_X*_f4XIO1ZOazP>fs8P;eG?h0s{W$Fk(AE9XgItOUuKG9_}p_#x`qm95M z$}LwN3!rN;^lX8SF7R9i?#`9mM+8lqpzqjmW&4+dZ{E2f}PX~jU7W<$BX@= zMOrn#VPYZmcg%G;Gv6sE&d84}ZOxCYSe+kn{WU*Q@|*lf=^e^ zvvjO2^3t_x<4p-_#LNWjG*{YuX`_(o#h(LTG_lT*zOq>4+Y-jtr9AYn$3lydFOhSX z!KW*DoNs8p627_9;(XnU+*MAidw=taoJJSF?OKr)eRnQ&SJkY@4kH8aU&{Buwa8y9 zGQ-7$Wo~e|lRDO}u!IBGxT_>yOjyPNy(Xzc=78?2`@c^@b}j}^_Y!xN$kUzIyQ^eQ zietPFT<5Ne`*%xN%B@?GeYwDy>`&@gMmfQ&kQs>!%(*L&5uHgLznJ{({;9!w=$C#d z)A(=rp>|w2^VZLpb7J%Py~SoD>WgB$jQOI9Z(!UTKdiwyKacqg8|gK95!X%d_#N=| zE%5){%w5X}-;oz7UYr;C=?!_2pWT!fxvw-Yvidf@70d5=k;`fG;(M`6(N;y$7?*kReu)&YQyN)c?(MB8Eo-_OW znA?Udg^x06 zL+5R_NId?eqGjm&)aR&fJ7qE1PPs-dXecq^$Gd^`sqxAe4-K59w#Yg7$%={@BZ+%? zdU(v2mrhi?n^p0|Wf*v@q$wk>*Q^$`&X4!iuTD#Uupyg^UeTCAJ_goY2 zYspOXSubBParbJKZXs_0zO1+*Y3a>V6Ma7*pW}&w3@6`GSI4KXhwe2hF1cwEc@kX{ zOP;WyLXS&!28r!=7U)1&3hcxKkh0SIT_8TSs1e=NZP}>ntf4z-K%6%H2 zB)%f|XZ=2+1Z0s1^@J~dL~)EEyO0mNv1`cQbbE!Zp_w$hY^v8Gx<6xx*Z|ID9ol>J zU-21Puwi84BeJqz!h-H^#Ria#9U}{S#w7M8pzq5*P#ZoJJ3f?{KgbaX z;veb^i7!ZeLizY-3h>Xwd_i;Y1ueuEB>o}s1&L3n1RZ-3J|XdIRuY~o{%peDbEpIO z?!aat<%mzni#{#oiLYPk7b`DT&SY@v_X~ya3mpk1pRw*NhQ9{>inJv*{6jpl#=$H5 z)G5aTd|BTU!e+6Rwc<-@6Pw4@5X&oXo2}bhiF|CuM})5^>LYUD;|nmhz8tk-yqjZB z?zdss(36y{C*-`_7CFH<+By|};oBJe#xrQ=!d$a2KMNnsTHA)}uQ2<*z}GsbCB>-z zht3x)U=%7?psc?rinMvI*2j4@#)FR@Ci#yl7|N3f^&yjbQ zk)L&zQMkqAD_ZvbhTYA>j68fm2RCaGTgh2Q!2vCD&m0wbi!*T6CAfWup3)+RwrP>3 z-}3xXi@3niaafDU*jnpPH5@HkWXbDVq{v~56uzZJ4(`w*Z~Q@vd%zXt3#wa7AP+|;Q>94}}QY+{cs`4279Y)dl=pX0YV zwn)(|1+!)3-_TwjjScz_Xww*?8la z7I|48Ys|&xB>ijYHJmH?u@;H2sIiPaF@fB}0sZ6Tvf+XX;nDI`Zfj zlfd@^@SUzlSS=ALLI)|lLW|7F1=n+>KMt8$JP}+k1y?_~W`XN0aGg7V>-aNpbqwH& z&Q&D1js;ip=a~|XX2&R_Uiw5=g5fYh*JRx{rzOG2ONBPWq3axQ#m;$fK6qZkb3;F_ z`2QYzYcY7<1fI9hw#m>H{ZjnLONNto6z!faeKcWaG5S_hF?F$xH|(FQ$f0GlL&gBE z=&fI)>um$LqLW@KxT0efk-wlN-e{>EZS0mlP#14p|0m7osE9Z6-cpe#Y3G8ERK$M= zxOT-G2k!>YdwI(BNX5xD2i{r(p6kK$AwA0fMespMJif}crs~37nr}{*iY)0-k)~e= zJ;Ct+^`M;#-{&2+d-6ZQ?gbwms?zDB@iQGKS+BI2`snb#;HcXort`q7BF-qlms$8@ z&8JarbL}J}?@uZ+Coj$@iMK_rU#a>0Pw5d0un*Sik;!3ZuDUqm?QMGGtsQ#g1ZBMa zTX6jYxc*U(wEQQ0v`a+_TNr!yMAt|?R$@yx3fiIJOVsa8bHwo+^G8YC%)F;5=kF@= zUUuK6woXT+b-yF>>O1C${~br9`G_NOu+toAYIa0g_BtZlWX%iDp(Ex_yv_tyMGk z?X18S(}_&97Chdk9KXV6>Tk?J-uT)&JH;Az*~d|WElsh;U9o3LvCk*AzRrm+qmulR zcd%R#3+Dk(;=5f1-1#;j}l%0>%oQ~$7h3c4Zcg(yWzWxi~26ROo=6FqyEY+Zx8Z+9{x%P{>m!6`!ZxiyrANhaxfcy{dM&b4v`Ex{vcZ)Ggp!yUju#zE2ha{2Z&<5-gF9|!T(M#n*0=<1N{ zH?xW_A#_d17P^+l7WL)kFqT>Wi}7zNaAc2_9w-<`)mG^3iFr#60zxj(`WLPeZ{$%`CH^fWW;3?O%2Ym=7y!nA#UC6D|!mLBU?F< z|0lmaB%zd0wO`#vZU@d_jW~-Kun3Uc*Yp-8mEDtFdeB-%b5iP)@Ah#NNLE z#$(|9$Z1>T;a}JykA7^6?2S|DSF2&|zaKKpbJ4NY2hP`rweR(3H16eGglFO7eOgL; z+0UjmKC>v^cw`6niu}H@ zPxQytr2Ahymk_>!XC~qCJgh%l{CCpaM&7G<&gU79?=3u9`L;;h<0M#&3kZWfiA{E}>mVFs7|4`;0Z^nYz)9?pw>4 zZbt9zLdUgV;od(R8Zq|yN|5X7_$GeAIGdcOILgq>DsnG6;~RW0L57=<*zYSB+q#aQ ziFWF(q|dMAT}B(rTJ9obIx9SrVPef^-ImSS)X9uby$D%MW9-mU@b9tKDQ+}ze0Z*S zTg10|e07{tb;PBqNG9@HO#UvvLF?BYkinkG?3cmHz}I~fYvI7*$y-=!SFAbh$!P(BL1Y^r_g!R-Mm!Y3ZAp^fwEAZ}HHy^iI>5 zseSzRA?>|X`XS#d=cT5f2foKmsZ(1=rKQLEp1dFUC3nuPw?|Uq)v8}0BRsm8yDaav zM;=^bk34dVJ+kgL_R8I_s`tK_Q2mHDto>om&s%VQe08F4NcH3k6RN#6@zqBXhk5E( zOlqW!N0hOjLfV@?u&N1Omi~ZEc~u#5%|-MN`p7DFr!V=o`E>9+Dz?_X7S(Ya`R;>U zTjZms^BX??Q$fRrb#oeiuDN|OA9lpC=04>|6LXR6yhB(oKf-qETx39r|9pxgViY(c zyMz99+j$--azs*iH&0t;4o+KcR?}}cXU-~~xb^a)iSEmt6Bl8Vo6a+e=Wnb_UvbK@ zVa17gp2Smm8_tT(ooBWGW|Z2=g7W=$XPy(6F-G-X&wB<>sz03bKIZ^_V4Aq2#{Pjf z)A51#*X&cV6873pd9xj-yji?6-EX+8JQki<8{BCBAmlHXvztE%)pCBq>%3p!DJwtX zdMQg8*`)nX`)O|$@0pI%-pdK+5Z*+ZyLfConLHU=SKUfP+Ju4sZf0s z?kV7&3RM92nLK681cu;xId8#NaGe!}dkVOxLIph8JSTyJ`4zaQfO`tKr$cW>;hqlp zqHs?G_jKq9;J#R*45_2kS?U?9x72qNY3|~=iDxFyN#LaMPIa6H?&%ORSclN`A@;)w zJ*4hZPm$AvE;`8CX{g5?hxYKql)WP$69)ripBeWFS zNxS?`b-R|UPS+&G`7Zo6nJ1nHeq--V|C+lmeH|5X-|Fj#`8mYLvG&NlRqGPnzV$yU z_dR*A+*gmhxs-ACLG;pf%=62bgLgA7*NdMCd%3ueZP>WA{_1@;97! zVy;L0upJ+*J}_My(f$}|hT;q9PW?kp$Q0Lpp*9qsSDdFS^`o4n%p)0$6Wg%U_NcSk z<5=5wiArcUGk&a~j4jL?EA}eiFPJ-40AJw#4S26mW+M85zxQg-`J`9KS561|&x!AQ zh9GlU7%QB`_<0<*NDpfSmS3YHvS*{{8uSrOYcHCwBAuyQbDA{OZd0teVZIBc26Jp~ zd~VoZobqiB@O0jp=sxm2KDogu@5OvC=RHYe8h%FxaZ4PT#;FlU?s1k8M+RDoeb0&Q zL3}^rbC<9!4*#l&IJU%}F`tUPBjy)6W@2pu^}I$?kx6TjIcb{==sk>m>`$?WU1Qv9 z9i@7+k%#=0br19278^1n^OdT*+N;%F<4rZ04ZZGKuer|dHPzX?adi%Fd|jS54cpIP zo*5h-Mc$8VZC=r{HT3Hdz)1myj-G82*$`L>z%p|-NL;`X(txQ0GoG_LMzViB71-vw z0?Nzxj$;4%2syjEZVu(n^`@|Y9X$@4{!k+!a8)SH^!5EEQl{AVD@7g{*uNetH&$K` zxJg+FlqF}JoVotd1pYcWiyl&mjI4pX0^c-fVFJDmTy2oeVDSERp@Yq4kFJ08+wJgv z|NfFYkdJK(7kT}Q7KNPjyIF(U@6jIlR|Mj;B-Oizy^7iRjb5kieVM9b zDfYHB&W;ct;M2)!$+~)X{rdVx>&yACs4uIR{hr6SJzC$p&0X*2Oa=M9j58miX*kcI zf-@&9d;D$IJxy(ydz#y__O!GOZnMGRs%ZZ5`VG;?dd*{b z_iih%x9r&uyaR1xwr>oL-M%R#IP~Xr59EEc{v>NfPDJxRT7TC-{u`qCIXi^>S>zwR z{qc~37X$`6NwkhfkuyFSD0c?w<$DQlNoPeb79Y`i@N>vFXq-#G9=&}-$hv2D+X-+S z!FRzW1fGJ!2+BAzfQQiNq^=o)ziIpWP>6K;_H`jEc{)kcMSg92c}VU|Rog2<@1Nmk zDueD&xn9Z@Ji4HJ=KxG_>n&sdsGGCMh1NpzE@Z(ZqUr7r*Im<#lL%GkCg-$1Z#q*WuH&LEPHxiyt{%`R7|Ly$kcYHg4`xp1~_p}tX zGYwvrc1eYoTWF6;_5e1)%k{L0a}s+`dG}?iUa{%K)1Ol4Pda?8!O!Ba%;sAT-xBEK z(ckHp547%Sd#rU|n@*b!=GQaBBj_s|TASN6^54N3E7`y`T07eAqMyeDFNZRutjXJ} zLet>g6w*J?x|{Un(eyHYO8HWjAN_p~| ze4kDka^B0yB-P;pPFfyo6?N5H4sMgTS5o%6kVe@f;I~oWHHq?LWlLEy{+6{iQRj}f zRh;4TKK8EK1wXN7l*C~xxiGGLX5Ru1r~299y$m-3{1sY~VnJaFliGULcE zu-CP=wF%C}!k^%j1DrT~!@+pgv%{A)w3C@O;>|91X#e+PfM{}ujZ92J|; z|J(doHNc;D{!{+k@D2Wy^f4a!F8-X(JovBhXN)&T(toY+>Y4m0JbNZzR<-VL6TXe{ zXAyaYFNKGNFNIe#;YZ<1;nC^v=$ZVfe+z$F2l1zjHNu}VPQ>_A%E^rKXW7^JbI`mQ z>;Gl{B7c^}`17C6o!`Nq)Bk7rGvN&RIOYFPK28`UAE*5PR6cgvzkU96F6y5@7k-N@ z+=?yc5c6jvW9iaMZIM*oA`3704q15G_DAb4+Wy_LutF}=kk52vVbdA1@R{3+crk! zUx6`L{*`>wDR&y_{}uW7IB>K<^6v(Ci21BuaFFtQ!Se|7sFXd^gujKdySDYqzn$B@ zF8>C%^~=A3ZU43Wn+fc!0hoj3U!kwixf6aC88{~Y3T%NZ@-OpeRQ`Q|_KeN5PGsMh z{44WoO#Th*{-*p}g3KG0e+TARk$pA7O3I_$s2q&^YeD{XUK!PY4b}!nY-Jf?)?OP$ zH>jvSEw+J}-W)-1{(+Ve{@X;g#EH&t8JM3XY(^ifXO6a*OvX>=^p64OGDin$ul5FO zukjw!%|>VKwchSpySEEHGgRyF9;waqp47k6mwQROZ>#M~{kVsGpO7b}rv}I?`g2TQ z4FaPR7^1VLptBwWR(EXy@bkSR(2o<)k3+R{C}%GE@>lxtNcjJx{@>S+_ki0!(~rBr zzZ0Be`f(841K@j-y8kQsvD4Pi|CYS3^ke6IZ0P97PHZa9c{Y}&*+N4GjRRKBFA|-& zl5yaI3T1>Xj020m8V8cUV;tD$eYC#A``;S}*15t!e`|7YsIL3lsF7$E$gJ;47#+Vd>< zR_1VLKC=H@cU1qa9K`=I{nzj9*MFV2*djG@mSZvejII>`hUi*FOUmjqZ$y`hjsrn+ zk&FWe89R0|4(wzcxS@X>5T3sk9&ebScBZ1QIe>8i{j3!j-Q&3X40tjoId8&``vcaL zj8#iUBPYdSaZ$9b=sRijllb~d^tScra1Yd1y<{(GhJ#@JmJ^H}0<@q0S&cwlL~Q+U#VSD<&AdrY0?RjSi`knkG9XOs49epldd8G1_& z-!4Yp8UYTk^4l1Go7H--Z8Z2DF?E|oZ<~zHIGeOrw!YKmC4E#zBCX&w1=s>>h3Yov zkmiB<^`QjHis347=j+|(Nv*H6ZK!`R6sy~Fq>(b(`E3gDH`PBB5?o_-68tZt{Bw{C zH`jYY<0wyPaVO;^QGX}D30_auZwlQAtSg|6&>$Ha{+{11Cf`%_?ob+Z`Zd2vo!=y# zg1$4r^|IF2+t$?^q1lwFK}Vt6207KID0vQ0dKtKyORWwo|Yep#pj zSUKpFz<^3eVVkufMk+vyJ7$KDC&UR(cpW!U+(x!>-SjGa%mi}^q18&QM)zP47O zWmwc#^2}wI-x}NB`J2hJZvBZP!4Q9m>=B9W_55u`>KEcSDfvv++PU{H{g`zNvX;_Z zv$zPmzm9L*$~fc1cY@K;R$%wv_9I(E?NQc%tzjJlzSUph-`#bLeFgY4av7uK z{DMq;7GmREf*(fK7T4V?Yv}YHvQKh0>7QUddC}^$>SFu?#q1Z|6|ebr>6-8P^}rzC zrQ|8(-NfF4rqAr28;ReIZ$ZvW_+vclB=9%PPw(4QqvL;PEt=S-g0&Its}shAuBrLjG|2Da{L)3wMjSo7y;CGO?9dLaF8 zNi&D^&yuE@@OFNays`BAi2t5P;CJx*bY1gY%RSXGUih|mnDj-Qvk-+r`WJ}*9hd?` z@cWGTg~0ed;S+?5gU3P=FJT?kQr1re`Q~D+*0tcAN&b%q<=;=9Pl*e@*YewQgqN|V ztC#q4)^pv?dahepW0lkFZ(GGWE1^j*d4wj-q`81Re$EyZ{aJe~#*&XDeq zHY>%4EOm|1WM?$o-)2H@slU+dM#`-vF8PEm0!#Wpj5b1-1LT!_2WF6wqC^;&?hXmKDAx;_vL-5BT$-4N(ve@u5MnROY1+cDO!>SOrQZgqpg zwFBX6`7V9$Vb)@CR%`E4@Gk-9V%o6?8m{EK7a7ShOhwnD#>&v(i=*KE5p{4dhT5B& z+8)xzdLBmpvXf87&zF#;J83&R^GiAX-QF$daE|62O}Upw{G;(6@oyI$;p`5^CqMiB zYW|>nHHq&1yZ*@g7R8;L?)^3RJ!^`!j+#>5&APE`nTpIF&w3erk1NW}hOF2A6FO80 zdpe`MJ(6^b@lE1ud_7TZ+*W>LczgK|!q4c}M|u1acsvETTi{jUb2sDK-x$+0_*)w| zza?&{20w>#)Vw2R8A~MXt;l1hH3`+`HEGpW_NOAkUIKq#7x?G=9qU&@mv(RxnwJ1i`h?&u{Y!BDG2f*;S!*f$ZKggZ@Ylgx1Lwr= zeavuYajCE;f{mqh00N5-oq z!_MIU_J6|v!uyXfr`O#-q`Ln8v}${*+IbGVe-z%&pzV9${bc5LH@u(0JfT#o=V{LG zyaxI?v}8{cZ84v9(NTUSE^Q;f$v2tX`@a+CH<{ZDXfMeZOB3UL`6j$SpS=CNpX^yk zTzLOB`s^zDXeoW|T7Hl6cc7oY1+MhnNBKPpmvUwPevGt#=eN=DnI1S6I!-yyp& zKaFp30oGdc?I>wR5??57O!!*zk0HL7-+GD5To%tA^C(Z z0!!LCMjN3^jK8k~#zVs2)IV1DD1Xa5&2Lgqp}}bCHi~-L{>Ay*LHW{dLYG)LD(?(@ z7g;FwUCNVlu@Z&9!QTYVI_;>@j-uzw{H?w*e;+Z&@++CY{Y`D1^xGcvN;~<4zcYs> zSGx!JTWBQx+75qf@b|N<*JM9`ueE2;+?}a>0pagS@HhHJbnZs?sNpOq)&@js&`Ec( z7U}9V_#6Jz&_A-#HMYolXd8A;&IZWgyn!y}BPpi%#&2QOHs%o~3 z*H-JJ^t&UTD#8LVJG^@ z{MG5zqFdiJVgSI@Vq4u5Is7efSuHu=q)j+e){+uL_L&#O z9d$j$`Svf@1-)0Qah}wNj=K)lgv5!a&iAG>~X)!VKf z(!^wy?|R+!3&eGx*nYr_YPNfOl>30oS5++$X?&GZTUT_@BbA zL(pgXvu~TP;N1I5DdRbd-0yJ6C2JIaa@BrUDr+L20@vN{PhC@z4!e3^4#)kOyUt#m zwa@(G_!F)_P`BlrvG1kaL$t%94?haIlG$9sJq+H7m+v#5^TZ)n z2lcqJEgW|Q*p?^WaQ(Xa3)kY!CtRzpI_$dT!$9a&+G_GOWjPOU@6eTU?*C=`%(th0 z?z)S!`**$A=}jEscm07pyE)_jO3Lim)nAVnXxHayS8012c`O?bxn^yA1Guldj&JO7 z{S>&>V?TAxOM2P$wm%&AY4SU+=~r^6!o*(JB<>A-k+L!=SL*S@4}+ociEl>h@lr#V z_xY#8Egt$qgno6{HSfdD&@SjE z{bV=y4x9q^@8~cQ%Fyg|KTRbpD*amI94)x!*|o-)r=%yXliv)c-l!?q>Sh7u=hd zJ_8!j))v}&=cW71JID6ZxcQp(IU|7kVnfh-3-AhnH4T3KcuzQPJ@@B1ll`u{e));( z#ONN^V*1^xtKM<_p1b(|48L3H2P2{V$fV=01nw)@P2FDbc6uKt{W{v|x^v+Z+GQ5) zGX0@m*KzpzAbsljB)@B0_CE7AbI7%w{u$stiaV3ubSyiF^p{H7vyHH#zV+Ovq^Q4*_7l3hTP1uf^gceT7{8zSo(<2*Sm>s0|IAqC zV?5kIc%`O8bKQ7&h*}j7?Uup^ZH!I38KWNHUCDdZRc-XIJ<)paq5jf;XS|VOM=k*!2_I>=N4eV%l*Dbx(k2_mO8GW7K}`tg+B$>*xpT zRJY5B-cfbHb-c32H7EXKSDZWG%H|%C`1L)mdcyw1gRaWN11?2fE1{*0_RXhV=7W0< z`xG9EQx~KR^(>*D z`>ukn)NLtsO98KG;O^QQ@XCHXSsPzb)8k5^9yQ=9cN{NOUC}!p&EQw3LaqwlPR4TO z?}@7cH|C7!{e^NCX#;0m+72|g^)NrygIf>ln`J(ec`MG`>Zp^kwg5vxpTKc!1IPl{9#>gg zS^LDRGF@^VXiVr1-z5QrzFOo`ZaIj*9FWWZ#vw?_!5Vrr9rc*i-!0 zmlyx#J~Y{b_8I4-6eYX&i(OZ2x<7N6qUZgHP4{#5U*@u})yjTWvE62|k2RD1txohL z3;S1dmn&ZxG@OCFvPDp5FQL2il^;=t^qUI8(l28DOUjlqq|A?y8>WbU_8s<@bH1UU^_Ztn z#zmANHd1R-Q`>v=Y3!|rRqBU+_AGXnM4?Zczil4BX`w*K%blR`V4GR!BZ{>k=D2VLmx=b3(%j#>tZ<@tmt0*YNqB=7x7Cn{GXNp?>QJmua^i z%T>4bRSfCqN@lEQyf0g5YoM*7XB=Hhd%w;+BK;tcpnMs$VG?({hFi>r#a_9%0v%eJ z@c&uL7h6Vf_XueeFw&txi8|YG^LshrN=fIRV7y6xQ(G^hw%$2XFK6t*e2dlkJa%gcaouV&V=IphY5AcmwqGfKasWsKOw&h z4h|dlD!3;a`f}z&f0B{$Ixs%sNzi-~4v^=^MLdWZaGg^n8iBxCJm+`DjjgPH!6L4PvQpECMpHB6{TZ_H>(ZL1@q|2s!vY6>@2znJLsocw z9ph~U<82_dD@T5-add|Q2{xZ?j+*g-KE@-sUX6d~Ok9(}b*h%!?#5;;GEE{fOC|i2 z!90~fd;u~`nFikTJ~c~R?3C@;j%(B?PdPHT=Eug#{>D7wI`3lQCc^TqgmC}&Q64vb zwxz@iqQ9H5)s6BLlO~>c$w2z$@;hP4Urzep5nmPkX7+3&Z3~Z+--Hfne3yHSY{Ugl zD)BnPQf?g2-NZS^-cv{TRl=Fr9G4N#!tR(I2!xvWmJe6rwV&{$Kxateld&I93v`Fh7yB{aFT!>z_zQkgcY)VNSjx>Kt`m0>7CY%>*jOcg zDR$Pu{@*6P3GF74M(A2VSl}fPm-Zh;0u zTcN>p>NbOV$+?DO$UlnwspK0=K8^He$|tqJb<=-@E7a$`%tEaXI<@*d-qG>n9L}bcd*e9!)8@8k z=)CQT-@HF=8286Ln4@-@;K5&_<0h~_`~>el=D{PTAv=Cg_-U(JVnzPyo2OV;HOw;& zn|P)g<7wxPbk_0im{9wXSK3qhdv47~-UR>a(e|yNugt39-VWj}ewY4wK~2!xNL<=O zc=wKhu(Z?EnojRs#N+slF~>8mHsF1Zcno%SO_%qM=x-*EsttNq5tcGDYr4HDq`PO} zxA@vl@0x+%;%d9RR_+$RpSV`r?G>Ct$OJm;Wd-hOY(jIJUvImQw+S2D0`3$2InN57 z%lSUC<@L7zoqX6O^_s}HgT(K{)+hBUN!;stj(90H;Orr-E`3O|>(^N)T)x`RU7rg) z%L$jwy3g$A{by`aQ+URK=Q+?|A<0R062A)#?;-sx=wjy)yiKI5<38Sm%zk(y`F$GnsV2RR_e=24{iKs}x7GH! z9!zd??SP-=^ShKkn)E_1{!hZcW=AMYFT znrk=t1c#d1cU`P?Flv+c0smO&l>zuYX{=SEAN_?jB{QMHzJa>`9)6ok{C4t6J&UO4 z{p1l^+`@AoI4j~p50gI1BXEQc{CqxM>%gu`f{|N>1NN9z&Hn5 ziZ(Jv5n!{pk7VTLh9tC?v;FV@OZ(g z4m^US6?pXnWo43%^Qw*6q!}`hU-B+MZWuhDpBWZD)M?Wq=8uyUlYE= z=Bdipiq9|uAH2pooh`^&<;aG!NMpyY6-1Y?V;efWCUMGZtP2pmA*5<%q29>Exb>AZOQgVMF@;7s%rLCOVv7pAhzQ zFHC@QcHibq`vaU?|5kZ=_)X5K_j50RzgX*N;>`FrIWPVocLp5fUI2WW&u-QG^|h^f zzrI#8vR_}5H3|Xlr+^;cyzAsnTf^YHPWtlnj!EEg>OOS1>k^`RoCeJ_Xm;Y}c-knA zHZs#jCfZ1+jkH@oNKmKxT84IXqJN3L)`eb^H->Zg(aFkxXlrPM#{W6g7Ku>*Lg@4^ zw6oCe))L)khh}o#_aB*qbC>JBZe-gm&iTw;tNSK#ZfEX&x({2zh)U9IA#XY9?W@OD zccZ_}0SZa-=3s0%u2 zZr|vJ+`cgl))&ylNIUyZ&6oRAp6$Tgr6O6ct4K}@{p8W8ZniHAy^*r_Wxd63=!>&G znlC$jT*K@-et$IlLKASx`6bYrJ8x67P$-BTAL~tL#KV&@RSw3*JQIA zLFg&EWG*_eg?6_tK);W|onTn$A3~$t>!3$pQbR6!t@SD*a5PV;~VY< z-Y&+7I>rcji~i`OPm2EN95~-l^hf0EZ|IM5_6fd-{~7%eIHEtg2kDRNqVjMkN6K&y z=#TD;)QmQLv`27#gmbsP4cBGhYT>+~n68`6d{U#pbwJmZ`Q*&!e@y?ieWm}dkK%u% zU;nlB>%R%e+Wm2yG!ox zx9KZ2zJ2Jtlje!@!e)_ITNq=69;J*gKjQ4PVaV{wlhjT#{rEQI^26v*$GIc#W7E(b z2;fT!kjW3*Rqub`x2jV^&`CynlG#&Z04sox_=@JgwsA?Zr77AbY|@K$-BVK2>AkG^9bosT|9ESc zH+SIoU-RvI{I-a60$XhFAL0AFiEq>S7R$5T^p@*SEq`r0pugt2bP()|Oox!Wzk;2w z{lz7?#me5OA9P(Z=y$<0_FF=r(#iQtVb_;+F#T^=tRGDofL8>58;U=6of9of^ZXmQ{|?!6y8fo?Q|Ku46dE3fc3Yrn zJ@$QBU*1lAjyOZERnYL)exbuCPd#$Wa`lF*-lTi_+eCSCsHX)JysWe8m-?Gz?XE}1NaxH(?#I;t7!Ww&kXGq*YBOj zU5`i8NIU4B8f3?5>SdR-htNaXLg*tji_uZqOlVW#>~sm;u%#P9Goh8pxRU2-09G9(`Di_q>;@=5=3 zK{M$;@_VfR2oFemOM6H^5xwCL&|doX3ff~i^m`FH2Wb~+1EGC3v`&ZC4rnJdJ_N0< zC$HqYG5Xd$UC`V)K<@_!`j61b3vCVh&30&aJ9H5mY&5;?+D`q2hOz!N6FJ|kz2*{p z@&d@3)K%&xv=AJmPZUv~nt?Xn3fv~}kTwyRR`S1(JzwZ6?IE#olJX!~Q6JwIVE@3RM#eNZ|Cwgjt6Q>XHY~@`*+0y=X{uX{44SvY& zlq>Kps-+(`>+kZ$C41>(Itwiyh?OKAk1^X`0X}bo>vZ7ibNU1n&54(K|lNV$2?kjE_8?hOFv$ zD5H6#^0gq7A6^qTMPnaT%#U5hTz)Zg_F$R*HFSf^m`|=ei+dK3>(%L#`!&uUvzU;5 zPxpu)VwL4S)&XF%!r!ncD@z%H;Za|~KFw*3p7q^%u`=3OBWz(_5jkH$*Qi|IsX7iJ z;~zk_e|?Z_ukgjx#H(jjqW^m}NyzkRtQ7!{s7&9YL$5sQ>VQ^u>dD=OoH5y#r$y-_ zzW?I%=z7NeQNMpn!ndA(Cv+0uzwGtmvd$d}ddfNgh1?%I6K{2~2^&4<$l?nrN1k%y z?{FjYRUlJg0~;}u`7;-N=`!@Ce=rx@*QQo)K^_!;`xfLt2Y&X=w1WfsJ&8OhvU@Rl zlI+hqI;?NgMr3rMMPU}}LhIbo{a5~4_qX2n$K9yWJy)_9Yel&ZUDI~l-`BV40et=C z6+i4>Z;f3%FmRttVBkKPMB4K`o%8Onizh+0L>UeB?kIjwp{?a}UjFps`N**`i64I6u7u)VL z#HFmqfhBg}p_Co7kC*W+ClCy=o+)aZy^HwD0sMbN{yT{;;J1g!e+OZ)5noL_W*Mj@ic-^Lr_{47QKUS^%NJ4C*$0z&<_- zSYycl&+Owi;8xI&q;CjLVskMK3JWdeyR@Z7*o%F9H-4t?vXA>YuX^d%?BhLVq3e9` zRm>e0ftMEwc?ay{>i&f4SEBOtd)UVr-6=~&)4UrJp7*mC%Dn(zCHF>dxfcFL$B}W$ zeIfkbr8?Y~@n#I&aI3py@Al}s3^Jr#V=s8R7IOqYlcgI41c|>zwx7&$Xbq+f&Gm&tbceKItUF*dCNKpp?xv!wt%qkZwcXK z=2#nX={rk_$B|yr#nLSMGL0VHwb7D3|1okGRurFaG`x1nIM|2ARYOHtB`}vnNQl`KZ{^eYK z_*eJj6CT-lB(#HgYG+UAI&fITH`)L6FyD5Nem!xaZ;TGhi3@C@hw$$W;2?Cl9vt?v zW@ZU^ECdf(I}=-fBm5hqiPS}CBrwi{HZsOZexZfrmwZAGX@8-K&_j4w>My)2?J4|u z9_7o}B{YcDU;2aW&8Xscp}}bCHi~-5zLAmt0{;pfYJe$pk-j7CCVfiEls+W9EMX~E z%Gw)Se?xr)f5BS==M?-OvOmJ|jrBM0nj6UfEcu0hW&O=7>~GwQu4!fLl=V03M(fpb z=f-yU*b5GdKEHKff5b)ctnnw`;Qdc-*53GqpILk39zMX&*f!kQ`rPUARtCRC;)I`> z--YKi=5n1mU2#Y6WYLB3YkfHN>+@+G{JM>~^Ibi@-8)(B6uy62?7rCkw=lMLvG)Mu zHg|_<#?O&Yhl+0-T(?Z)E)?|SA;{K2d|VoOLIyIes_FD9UpRTz8=p{aRqweBinfc{)w`U29llI*D|XOcB>)d=UlslnS(? zE<1jwR@Uye>Yurq@hwavJdL%u7W@xV-nQ}+t{!*9wXXbA*HjgB9RkMBfP3bcFgQMo zI_zJs$cNuKAxub}KxS2ydlTPPz>b-GSb$3p5OI8TIbDHUOtmESZK_!8Gl zaGlINcT;k^YXbW&q;5{qIQ36l_pv@YhyMN<@P!W3DYwFX(k1kNk@P}GgWpDM{lKM_ zhog0wOnfe7zs$PvTd3bj^f95ctiP2ymIAxf^!e9lk`)Ms7ALhw>G1@5n}hjmFrCED z%N%G}nVW?^KcKFajPKG%b}+9CElT)a$M-4B-SS&Jw2}G?EXgZ0$e`>DXdvGtjg|V$ z;@f!WA!#b9^8fEYMEqRf_*&AMGFOFG5eD z&use0KPaz=x)-S~*9K@e0=ONt?{45p+Y7xCC|~-K&^k@u=bB&E^)>oPKY5BLXMlzm zL$4Tpgf`Nby7;XHItYD!1s(3^nZ;Nj^%j~)oo=8$cKYR3*7ytF(jP_)>I>3uMdtAW z!)rR_+QEK@UxKq0yhaSPZ>+D*FFWPB6g;H-izr9RkapMsY^ncL^0a@4pG(niH2Q?l zR_G}-hxWbbE>RveK{qQ;F*LRC1zu&OwhZ!|#=U#-8-S{N-f)5&NawxgvO?xAe-`Avk4% zkG&?~vVlvi>@0qhGNp~ByfQ~;$YJ5WTgL7{TAXK|E^Bk%jgD(u8T$mbF7?MxC%&_P z4d#)MlQoaBc5fqVkv6mb=~t}T`xR@g+^mC&%3rL5ippB7$&$OCW&PgZwdopqwcOn! zYtpyk2l_T$QP%nGGJSRK2RdSh#@)guNB;MnB$lW3IV5!@b`; zU_UTJgH!jZhJIZ+>05Q>yY;x}`6r?)$Id^Ib@H@tFCcpeMK7hWw14e0a@-DWWI80i0aMq}T3Nks0X8 z#n3zh`n@W)2W0PzEaqx-@m{J%q2mUZ%SKFOy8Z_%AsuvT9B+*)+zJ)A?*RNk*M ze~7H@9#|jmKH0zSO?2j;!?+e??_~PPnL4w`-vRyWI`c|&<}CKOmh%)L2j!v9%tuy{ zbyyDMrBcH3EswCAEix6oO?2jb(iZSd(#6uuAs)*sI4g!ixqE*!mZ7}g7A{v}XZx5ivjC+i6sb0V&oj4Q{HIR|&#zG-6!7ZVU zlWz7InK(2qF_{^ys_yDm6a%edw?Vk?&r|ha)8b6#{$BU~aqIPZUS~h&d%kD+F6W$Y z6~cGb^35fzyJT08zYUqE(Bo_PyM8ir-}UdlPga|fv96))9{4TEu4+?vw{?&Fa{Q8? zJK=DH<9P-_*Kt(g-KI=kK-Sm=yYTNy-&WHz3yq^u1zM>LCRE;KbJm4 z$nWA{0O4}dgbVTC^O2wbf$+Sn{CpMibFiQM`~h_eZtO@neVRkt!jX#`D{&w#yey!; zFl`Aht}HFwNR}3Ugd5?slCtW%`mHWlgxBFzI19R3>|=za2O^eaf*Jj!21`301_ zhH@vfFH%X{b<8Qv6SVKp^uX+m`BU1)uD{;%oLz9IS9OPw{@bz1XrsG*p>LUx0Ga7qsH zGxP{MDIM4<(0(KNdGS5N*Dhh7DP|3Cf-Sxgu@AJ&8s)rSacs?i z-$uqxws*qliT?mzgkQadXu`jpv|r(O^X?!V@0WjepZvQ?Ll4b7&Day#Ot_8j9M~{CgAD=n+I`n+f4|mmMe+dhFK_9YkG~~+3T6A+2O2>=zXrbZcxzF~I}O?Qse(_a zX6*!svy;j6mB5f9&kVw@eIYJiG-w?N#{Y}DpTWPFwWIP&SUdl3+Xr&-u!MHsrA^^O zItJYj6<%~dR5pEdKlEhwfjr>k8^Eo;3rFgQ@N)oHHbaC9*Cx<>#>E5P-Y2h%8{tLz zgg=n~Dkpu!3HE_B7i1qv_fNM`?iSv#xb}er&okindFuEr@csr^8-a6hKVHn8E85pw zzxF%V-_*yi_WmdPKyyAPKfmLnlIE-pKzqYCV64^?XrwJzv5)4tv^KXX7?;rhr|M^YSw5d1<8; zt**?Cwqhs5#uk{?YAbdKw5C(MG5gaw{0Av_i~c;(^uEE}9If*L*7;6sh3xVy=-E?y zrL)e5vd)K6wl6*YCA8SE*6U9(tn&`mdD^Ent~=n3_vWr$kDU<18Xw3Sf1fuP(viH) zdzL+{aoGTqzNL)+&lY{&hMk9(uaBN_eN@ z@Q2AGTOnHG%Cil>=<~}?JsJBJdkITl^dS0-D7G$SvqE+^`mbv@to5CQ)>M*T_B%vN zzT?;rkxic=j(wo-P={=Wyhh#>bZ8iMJ=&o`9ng=h#HAC-wE8j#`yHL7UX4zfeZ}N*n(7@e5ytq^s{&;ujtI7#dap z42Pj(r%69Xoa~2mQAT!yItlN_@8Y0~a2a9Y;voJ}=%<8}Q_+v*vA##59~;n5Kjz{? zxY62maq=$39RiGEBMFH|K(_@YfE#My6?P^0u{d&eqBqA!)r|9gumOruAk_q&XLQdf@yM z`Q-tu&9}4s@{;M9yCZ3I4=wOV?b21BW9IKi7uJgWIn>dIjc;fo+;RcuOj9^#;_P`r zV1H137sYx+j%MqZ4@+xn5-@Z(olL z>Y@BhIRWyyFZy&roA2Dnf7n0eex~Z(>u=*t_kY+g;(i6!t$%l6 zn{N_fwWBsJq25N?Q+?CXCyn9FcaS!tga2q>gFTKW>MbCDH!!O1-PEV@ZoS__&*DY* zF%@?qpLA@Cn-17lQLo;O`_><@d+5gq;taYI-Px!z+wFP8?>BL6JF1r?gt?9r% z$PQa|N)Hx55BEeQZLh!}g_IWZkJ|?42d6j<50FLj2lgqt-w&#+6uBY2x2+ThO z_D;%;2Cgpy&$ns&RB%{I9n$f=NS}n0kHEox$_)aR--81S-M|RzZTkZ9K0N3@?3-)e zwJ#(6GVdq$G{z~PZw5NJ+01YCqm;S&0Q#B-toQ5{1OLtbCb+qfdhZ2~?Vdl{Vba3r z7)#MHK7_t4P@Ay-Oy8o^d2ZtYTjMvJHYN;y<2X!L1OGf=-UrMd1E2c8EApOwK6x(y zM(J}j-oi(HWWRHlT4N{unD7>2ZAZA@Q;!Y}xgq#$Yn-1%Y|<<&pHw;CwjaxdmMP*Wj1zA2CnPqV1n!`{l6dK0dFyC@Pbve8d%@i@X|`G$!M;KA7Lbf%9A7V>;yrw}AOlV7{Ju zt_T1BT-R+cW=>hmlO@D0LHD}=dLv^6=VjTXLXqx|#4)(!RtUMezt>_NNegopg)!K@*j}(aT(vo{{sHXdGRm zbZ^q>X%DQH9ua&5_(~idbNN9F*!J}cYT|E=z^1h_-MraSku_|LAG?%em|cU`{5 zbyMMvcm=e`)jPD*SfbqW=G9 zb-$fXV3#7vyGp(DeGQuw3Eo@2fvdO1(pCP+GrZ?do)JCLL&`ozD|RZ9yub9rvq~4K zuyj=AqQHu)-q>i){_xPSCZ@7N>9>bTc|u5(?--K%`SFdN+*I_nX- zlnJqaGtsHF!y|B5xjwzvdWj3bzW|6ia9?KR`TwPa|nnllFXAhc2A>7V=$2{IROSJx%0qC*GI7d)2Y3 zqCJ1bA0{nKzGGDddpZcK>>=C@Q8VLy-mKlwxNe->v$4fqK!0-hCf(~fRd(B>0U*mzi4{_>aA}y~EDx zMh7q`WJY){jO7fltP#U%%!m;FL0ip;65I(PYeZg+H9~nhFCY)`uMw|&L&(4P;!K`0 z6Jvjf`6~Ig^EG;6zV6swJIXg2e<@|c_-(!c_yf3Zz3tSiI#t&S+B6ppSyPC ze$cen=HXJ#>3qMX&MV=!)y8GO7J}z41EwXEQJbpsH1h2r9EQhEQuZ=np9P;?2Hb)v zMZSaN%O&4#!t=Q6copZg%bhx{5%E@oz0SX+=g|Lp(!*nTKM3w#(tq?(pV}|uELZV@ zLold}!h%8VI$`G7^OU~=IMu$|5uCzPoPCUWcZ>QYnAE>U>K1Im)d%b`?S$2iU{RZb zRq&|2&TKns&#k+iGG!i5bapoX;OtwVtI+jZu=lEkzxA zLu&Kp2VVQ!BJP=}{L3mMdpX(sfj;`N)JH<9mfKl@qeLKA!63-AO_$5Qb)w4{o=sUh>4 zeU0}u+mHX&LEG)GK_`^A6kcXM`6t1{_AR5cz^U+UHJlB-&8PdpcD9b$(BRokhwU?= zWnXPPY!}52+iS6p^|L|S;2D_X#NA4Ls{aPwKy4@gcGGEZg%5~9BV(My#o;y7MqypA z9f)+=k-8)HKby4Och2|qH&91|>9Ci>>z)NHkMjPllekXPWgo>R-Zk{2u(j8|6qq;D zpV;;zc8K&4aDGagg7a3&Err)vTK88w9_hd)-Ai^Z=Y_kyN1eXwOzkKz`QcsE7uSZ8 z&g2JC_UG8JbK!3R{#&8pIa~i~Po_=by0aDAXtdQqn*(TP5^W0S>SM^H?18kW@lans z^&WHZQ=Ej}(`Hx1L}fE}BD$)zgWj~m!&z^P>ztlr^IPc8m!a_$^sj_|K1RPD0~acz zd~3kPqu|92tM9YOGYdEboAlM%@4K?=O?XiMCgOffzK_A-LD>}qX5s1Q)VGu|zYjc( zsq3)cp%0tLw~6s-Vm#GvA9<@8_j3pBvIF4lnz~QmU%KpP>Ho8g?*{NAJif90ugr~q zu}jD=JTy{|aPiLIe|5%xGJQX|?GxvGUU>O0=E+0kd5HeaqkadE^h5T)9-*EKz?bk; zOdcD2s2>;5$Cb1t95vCtr}c@ z!%5DF*RvKH8Apvlc06vWWIg%$svN$pwGV%G*tY0^zo znL2gm{1)_K8#YMgJ{97BGubPP`O2_Ks{OO<_Oij^z-V7QKTmLB}7 zy^`>oUTCeiiS`G?ot9K0A(*T^RZz}aq zUEgI-XYcrzx})~@kq2inMjOG)EXM6a(qD~zY;Pi5J&^bDo=@z3jHSl$<^pVnA}`*8 z{P+vfiy7A!aL3miwUhpRyz_Vs{Yt03&U4J3Vm0~ZTaCWn9lbd#>EpSzAK159F<%*Y zlq`A)cwNYtevh&Ep=YJ<18}LkFOsEq)BXtdq*?nu^zj3}FE!F%bIjfg-uK4R_G-pObZueXr}ix7o%%J4dG|eF_!D?m zzpJqoaImh^{x8i@@;EX%dV&X#^PPS&M_b4@uI8`o)BEhT^z#yE<8Q!q}ZpDoPEg}l4}3S;#g{rn#N6fXDD{%*=#Oh3o5cjgRy%lzAI&Sd()viV!*PQFce(ERKzWn+6z4p!E^cB)yS%1ixe?LSvUTZq+ zg;i$6<;?YPxf$Wkr#Zm?rq>%?F?g4KA3BErWUXFEzRloiGxPIV=I3O}OsT-e7VF|- z?m-0#&>x8=X6NGV^tF_}PT6%dXK$p_wwVhP=<6Z+x(+zB*0lbXLc>YBow zQ<)o>2meI8=JeC7vrg!(JNN&dxqlV(I>lINyfpWZg7b@k@nYuwFY#-BOl|tuo?P>e zy~=yUu4X){>Cf%V?YDsMP3}_tlW4y6Z?^17e2;ZI0v%#5^Lr#^9%6p{mHPe)zw#ma zrx)zguUQGV7jm=ZFk^5*V}2YqP}j{MtsMioH9?BUFzw;4)IQVIq_-Y zbD2ZJ?-T4lk24R_PCWV={M9dY<@l(_2j0)hGc(*hWEbVb#-YDUsriASW2QGcs%=)XLd=2nEKpzeE6&9nD%K=v%;75AUorH^UBjBP2T-2by z3i5d=R~SptM$#@f3A@0bfUi#4LC4RXxfuKp{>YAGPK^BJ!BkrB^3k_68)FT2Y~yI+!2cNI5>67gNJRD5TwJ?_rmYVt}>`yg>3eF*(@CFLr} z-;KO_Fp)^#M!9m*yAsI7iB$R)%HK-)bfP`op6Ez}=;)GII(~DkBi@lnBja|a7soo| zcC0I&Omw9K5i8ndhC~yI_tN~gMAS^hhClGm;clVY)c-yjct^FJZ_FXLUAMg$ZKr8N z?ImdMOIf+wg}(~;1#-+O_0-=)y^ZuGMqeZ&El2h?yz%H@j8sP?oFv+u zU>|IUqxb9JZFedj3#ZZ}u^Z@)w->uZ9%J$MJ?yi{)qZ0J8(d4aiGCc)mrWvM@O&?} z62rbwez_^hH@?dJn8$o7UEMFe-#nswgVOgo_YHZ+@#GVC-?Zu1-@B>B``KMWll{5+ zx}pJ*eZ|Zr=N_GR^a-|R@8JH6bah|!&a9CC1S?n?+PIW6x0Ve){ws{Hc4YK^@LeIj zn_SN7WIG~&-mZc(x=V?Be1WGozR=TKd3vz9<@dhkmKS`@&sTbS=aZ*^ybtS58oInN z{}HDASoQCf?Fi=np`W1xEZ{!gS3bV)73O$vCHL+c`AW^PM}C{VYgfTJ{iS|$$RCTW zsiAM{PBn)-=wyo~nB?y;uo>_d0lsuJhfu zy@Q?e{R(J-&i4zjeW~;P8f6RrKhQ7#RKiid#gyI6*TJWD-TB_%y@0$S=6MBq1lvr)yPWn_E~nvj!d-+X;{O1D znDwxmuypOEtcfIXvsl~ei`u)Da2m&0^xO zWbG%3SDytYATU#BTnc0mBh7^XExzl{4Ng4 z2nzd?AL23x=|3P#nKPuIc_Vhd77p(61s88F;FC28>3SX-4JmRU>{#anJW% z+z2nXIb}0rUO`^<-|f3_9isma?Yw#BmUxdFJzw*@M7hc`-{Sx{R0_IZ2F-$u;+tK-c;B)8ufAtBMDj#5< z)Bl5burVt-9-^Gi_kYE?ej~PK1Dxw8Nei%%FXN5OU-;(mUqMgtX^*VojK7?{prYwC z=-22?)gy!aAKz(F`GkseqOoki(nU~@m6p1*w#SQ zKQOYdwsd-%TYkg$vbVYMu+{tGGv4Oky=nEvQ}|!iZ9Swz+L*nXyYf8f1mV}xB10SD0|e~T!Gz_YQ7gdo?h8MX*r#J?;KxqW3H$7 z#gV?|-wpHht{;j2EMM~r<2=2}@6;*#FhS~^;OVWwzD&z(%3aTQr?2_NFy$sv?kvhJ zq}()5Z{zu%-lj_k-%6ebea(Wc(y_Tx$XW5=Xk*yZyX8mZokPAWJiYH9J?hwn5k4Q^ zHYnQolBe0*S{Mz0&#-XzvZpy#K)D;O-sbPnuOES*TlwzfyPNMmt9N}Z?h3vK`Bu^I zv%K`p+bsAU+?b+hQLrc~|L@jN$79&Ai4@Tn@Duhnzp#OF*Jp4f+%#^odbcbDw+pS_ zrtA5hA-$4vzp;9^30~~MggxxR)YrIB@D@4n#wrI!Tdwysw>;))Zkz_Z=Tq(?zDxMR ze6#uHQ1=>7bJINFUSRchQ{T{ES*tb2bnmPB!O+G^%{{)w%)jmXGxIJsA~WxLHP6nm znj6ounlEDh2?p7+Ro})i4+FtsXC5`LF}+(JGrc=WtJfTCGQIx^J~jVZHke*$WwhnK z(>69fV|ur0o_&Y^!dziFIIChVHojzfU%1g~{@n|vcm407ua8;HFVtGi@m=tCv~|LK zd!4*%tmen};XXq>zp;+bH{o;r`=u-g(mH`XMZTA4i+SOU$$o6IGtUCdvlmiU z^NWXR^Al|CYQ7z%%<16t98dELp8$`?g5FxaFO2jwzc>sWj>LZ!_#7wvdYUVNO>?&- zQW!0e4I*Hg0u5YZ_`D54-$6?{a(d=Uw4jSbI6%v+&l8N7CU{3 zamT0yo~AivZERU!Slb?8^KNXJ2p=-fG&en%v+-M$zw0UHR6)iTgZQyVYy~t{T5Z3@ zPS|tU4tNf`0Ws`_l~2f=(f$T|VLHE!VL!|d9%9%Qi(zv>d`1l0VKHonu}2<1mqkY4 z+NgQT?+ZO;eE;+R3JhT0Wq7<%$9cRDxp%1l6p-y_@p_MjY z1{3V9;j@1b+_-c|u=imfJQh5X_%iV}g^d}0Pkf%vWh*?U_aE?olka`*JL@i1zbkT2@w96^VL9>cT3`D4mkfi zt2@@Ato^1f$TPZU8R9=0hXA+uv$NsP<_sCS=V|z}XSj2j9KF9-?TSAe3V-%{_%oeD zy#;&+`|xLP-S!!O7T}(3k?2^KX0G5aY7w+=8{vugMMt;e&%~RC0O1{kmpkc{BhL=v zCKBG2&A%IeJ${u}{*{EquS~)(9!B|pNLqis%neW5n&Ho;Wb2zj_#OO$OFYs{!fNXs z{I5~3_>hV8!{tG?5+^=HuuY+F=M#3|$FKgpLAaAN!Sf1!@h1wqJjz1&ke$SfH&MM^ zx%d~f zr_!qb+IHS(c!o!>YVSygy?N0$OH7-_OZElSpL+6(7ZZ-&AuN0d7s9vjARMT?%86Ii z*o$XNl214hE~nsEU48j7@lVKi4z9$X2`}pZBe+-7xA|HAY&vyLqn-dbn+bn*{z>>V zcTN>iw#I=CKEIE@AnX63;J~kU$ZsOYl+v#f`VgiM;^@QyUuFFg#WO z{>;L5uI$eQvi#X5__GlA)y1C$NXzhN!}w2uVcf&c!){Gp!-d?z6n}PC)5r{OhHT}< zo_oe_z?e<#*blIu85zB=%UW#)ptl%nW+eIV6xr>oWS=(60$a)n%l@|+%73o#UnbksmY&9Xx04hv;^65MNXT<)vL4F)GVcEZ;~|Hadpy5T*3=%x6* zGrS|V)Wd`2myFmVI_ubv$By{;x)D9bJF>@Y_qBPwr}mtIJ@NdKQCq5V&E~4e#Hg3I zd}nw^VH5qdE!IObu#bM)mT|n_%P$$d1sWn+yIC}(+7w2eGQmQ}zWN#7(bPS<$A|6y z{Ox0?bDU#WU1i|)9NT_gZ0?*)2Q)?BY0eVb;d_ z1(8+Yc60mm$g1>Li37LQ{O67AttVz?@p^vNJumCd$hZY&QZz9wvdY6)c(6qy+^em` zxr$?4re^d1UDiD(vg!=RxExn-B+ibk8c#maXTgyAGIx~t&mJ#rSK^+*ylChDdGePP zZ1F(Hll(W&INE9lzH)FP+xyI&o*-j9c3I(;_OGbj;-36vMO!-f&!5!A>PKOZSyt53 z&j0o}c&HlC7J%+kXOBhNOyTJ=&BfK9;fe5ZJe6hfG&_r@OEWlf@G~phuhOhrl6Avb zH7nht1~9v;bH8@-uYxo0}x1pQxZo(4@AI9%tPgB^-zUE_pN)ngD z9x7OOljmB(Q+OYe!atkuJZF#QJqUj7*SYMqQ^-4j{Z{YS2D3jG6F-9eS?vbMm!giZ z;a9&@kLc6C5>|ah_)ldIS9m1*xbB0BK7BWtO#6vbJGqok;9mmX7K4icgoA`D^SJWFI>JF=P$ElOgissj4c0Ugpl(~14uF8n4qN%}p> zN}CJ(@{iec8nT>dROC!EBlVpOjdJ!4_MmdYTEB;(QK_3U`@!k#Bj>SaCchn71uffr z8f!VZO!;tc%(^#Z-K81V8)4sE5?M79dZxO)?13GNBde^cY_3SIf(5g(G?0FTDRXNIAp3RHvh9ZX&)}=Ni9^~f-RM}+M`q7)P7#j zQwR-AUCUm6O?EHG9lb2DCAlDz&mc#RT?T%x&g^}O`ATPh#C7PxRT;XFo|nN#>Pq%* zKGD@&=xSnaWK}Nvylm;J{nY=Za@2o?v(NUF@#;N*#BLj^TbUTjs8;``t`` zDsY`P?-ZT_Jzkf7-a&o0XK{`zoVVYmyaij5x2jLfgp8i5FkJHhAaO&%Ur)m@ZTq2xA$pig7juXNTd@Hj!`Nu3y9(3Y+ zl0V71KhC-hS@%a-_lJ>H&UoOep41N_t3t@x2Km|0J(fZbY_S@_0tJt(B}h zB((7nWZbG@rgsr^S2FFTxRP5JS=<|z+=@$jvt-|Ek#j4~GR^nlp3f(l!s5(e8!~V8 zFm#*9(EmvM0c7FuJww;3&QL!YxWtixSFE|8eY6Ofw<5NDO`Rk27CJKUNBw2sk=S#f zoxU<~w<7~%TMQXk^6wzNbC7{ULx%0yiwxX$@5r^1&6A^(jvV|Ha`4OW8UN;-Qw-j; zjy}D^c|`*}M#%C;*E#1Dr!|PbkepIyMmq9HHEtE*8r(|l|M&~>*WoY1U%^*JxSnt^ zUj_c^Y@QXz^NehG0DmT4GT=x@4!(uBiTHQ$sXd!=uH5UoTga2qx0{B$$s?WlR`SjA zj>N|ANJmB!OltQb(j@l@E?54oAx^ShDYi}3?kd7@(u?q~;Cr61`nMDR?f4}Jt|#1A z{R=OO>vgs(>aox=IV{H*-@;}CXu7$@-;&ycT}JnHvzj-T-&yq!<@5YB|F zM*J!#yr?dXyNes)xTc+^<-m4gGMN&fvQuI7PoAlcqMpEwWxLh|oSaCScYMc^d- zMICk4P_~*ngg@cE3V#iL^|t`O+Ex8(Pj@JPJmQPx-zPjqoUp*~YSdp=QMorXO8 z+4)2Tym+JD9%f}=i~nho3_Qoe9-3z;wgvK#h4UKTLL5Hu`M4A0;LSnyI?2I{poND2!IB(IoGSxw*8Y02zjmHv zv?6$dAp38EcO2w*WMIejXTm`E^InGxya<_h5i)QHSvQF6 z8$|9cMgF}Gxwo2jD){Q*C3Id9!d}f*_J~EuzKf8FL&&|Q$ivqm50_xm#*u%ap^p3u zZ5N%^c|@r0^d3v?AuBIJP7WalUxz%bx&wxEWa3P{W2h6^m%NLRkFP@(4k7<4trU59 z(f0AApF!DiTS}0XuR|_&W#a0rOssGf^g4u{TIp{?$ikWODt9LB^C2sTv2hzhMlL}{ z-qLfTj2whcmLns(_?L`KTu&+^Bd?Tm$+ z!pO%;qwgyvABQz&$j458v5Wd~o#%T7O$ zmmRkx>mn~ZVdQ1Gf-@C#>TzUd;*QJAf>|=N)reEOR0Ii#xJ(JI8 z&+9_x`z2^yxy5}K_E5urdGF!vO%3u!EwV{wufyIA;R3?7>_tWRL-mc|_|nc|Mb+my^GSJlfMm0~RAsRwF}JVhd#!X`*qWZ;}U#39GH&65fel^71ym z-w;+krTDeyOHNeSm7g1llZ+@?b2)j=BP_YH5q}ZiD}-kgRv%x*FBwu{SAHJG{=SoV z$&PX2B_lTxR()!J7GEJ@;puVwMfgWU0~9_T`nFH#O ztbR*=ehv9~7GeGWYnK@weHHn+75O<2I;FA6=yx;nv2de)3l61E$FIH#R^eZ83Mayc z>e5(CuOOV9Pu>ve>h}s<;n0<#B|B@(tv<4|a4+4!DEj3m{%@gg!h>)tyr``(e$h17 zuQudY+rncP=j{4_HObF{+X8Mc@amnc&fm@F=-bCWwNX!blhyAgnY+5v?&@~~Q@m@- z#|~`xrDz;^HMaxkdM#+&Q#mI3dagONRcG&K1)D3M(R~9!Yx0? zH2c|863E)+(7FV2HS}twWb9yPhTgd{b@pt2CHu*iitlL62eus6-f@$oqg%OvedaXw z*c39g>bRP4YMJukB2zo=4Ow?-#x0CYj;217saKYew*z@vGPU;2YqB!6vqvIR`=FoN z8?R$OkxX4Gw<@yg8un1h)XLX!qD)Pl8JT*P@*+z+d2yXOk*RftI}3V=tiIW)51HD@ zi!ANr#Z}%nz>{R^YpG`}dvgML`kSH$$kEpOr1XJslZ&dS&`baKZ=8bmZwI^0e?goBm11e9f}r zEgi_z;CV~x3c*R6xK97Sp}Gqk-MQK}5$+7o56RTpll#cjo9B}*nOgah$keLGm8pZs z)M3JZJbZ#ootYDL*)qt~3&GHES*3ml8RKf=1&8p{jw~%YD|xyD*;=$ULt~j!$kdwC@MzH3!k$&&BpHpY zD#*yxln0N5)n*cz+QA7jwS$ufop?v4c5s1A?YIqD7n#}#BTGBufvbA@%G9FkNn~n= zrXo}ShW6XyCy}YSFW7>-{OR|%KIz^K?BIMjb7nmF_?fZJi~F7xXa0BIY?7S(&1-`j z=a+{zUJC8Kr)gmHB53qm1?JEicw_kb`F`Z#d^6_V#NV0u5oovO%}m{^yJzg$eB@z+ zJRH&31BYZ(-OXI%z$lbhL#^xY*VDoVG ze==V?W$>OQ$i4Qxr*QWBPO)GUU+^W)e!mSLAp2U9efDEl|6TY110Nt+%JBba4amH* zM^a)=arl5r+$zE$+)DQB68r^5PeFbg|2di0m3`%k-iZbZKEXAO@XOd&5p0EgZ&2q`gujFTxA;X< z{y_LRe?XjQVVLqS)7}EgpN)Sje!=uS=~aZkf&X^WL?72v-sKNQKnK-F@dw+9e~NO# z$vKqCz<-KkljsVH z`P|PFUe4ow-W+7s8QjnFb3d=I{3|@DPZiX0HU4eXeGdNZ)F*stoP-xgUw|vTs4mqZ z+-NTJ5t8r7GGyFkjj)@Pb%)%bV@6L}3 z{IV+}`S*+T>ygj#2Zw!b8!mqkLjJ`b;&J|9BYZ)O_AGdU1oK^dK_2(?y119BdzJdH z_~Gyf74Qi5GXtUf{0|#yvT+^n7W!x{Tm zyk&oq|6kpRO`hCg=D8i%+-Ya+tz-Qsura-7FmH{4QFevr0Mjz=qld615pKjj0yrpX zOvXzaQ}J1ipWQX@yDnV+Ab9Gzu|&KqmW&Ukk3q(|qA`+|U3gC{lD-jlb}SVS#oFV` zNK<+h>9QB;BVD$^!?BKdNh}?|oU}pIVUsRf;&XAs%>Q!olyXO0|NW^tlxGQP+}&rN z$cxU#U++gZLtlQxJM=l6$}YR$s>F5RA&=k*lh1(%_j2M? zR&Zq6$aU->&!(LFZrts^>~E;w$`=B6DwipfvA-c(zm?P@7~MBHdf=@?=)j`8@3f$YoA~qX}`4ipPC@~tjDPn`)sQ*NNqu0P}Ij-D}7bk}p`I&>yu;p5ixMbMe(-oP64CAEZ?2d6~Wp)(Qx zc0Mv{fVg$&QGSO0B!ccFf(~U3`jfiR(>Ja|Pg26W49-nfR>2dlhR>@*kFpLO3O0ea z)S@?8gI;7EdJ*M=XI%NH_w*j!A1HyJTaE5y4Z4z_p);vRPqJ?N81jzWvJPEH9XgRP zW#HddhJ)NUfM-)XYtWlK>K#kDag-a^Q;V)-4Z4y?(Vf)QW$p~DLl3e}dJxKoBZc(s z%q=wyU)}g{-30RGlP|yL)(TvG~s4m?TP+r{=U~ISOj=-bK&|9GY@S39NYRYw>^LUuFO5*C^amAY{ zZ-}~dXF&G^bYCDsIq_r>@%a;-`g$VhJ!*(QTR1__p>vMoI3eu7ht9*n$?PmnW;yXa zN%R~}e@e10dJZRyp2Km2f{T9Qs-6_Ok`Vej(^?b-=Z>C3yiNo?$Cb4I?e!<&$xd?4 zkvFGi-((Z(cKEWY$$K38Dw965uX5Py+vH>JibwmHH#_c~zI!SML^suqJtBUsoI8%@ z0QVHAr^*DI7h@~NP_M!!Xrfiu^Ooqw@}6?uCRcH0QN^7~FK+DvIUCFGqW>R>acd z_YU~P9OCbX22_z}E&oGRJ}uZ=$yarcSsR0v)S}x{dL`*Cxa)CkU|9kTRaXRi6(`#- z>+kWdjq`u6%DcEv-b)GV>?YsOeWpUwYhl-A5&j^q?iUt|&m=6K^H^2!p10vOlcafw ze~b9mY`%$v?)tj zn&{-IxK)16c}#4dYyTNJ8~)VVQk?s!4 zR99x|a{Sz*Ra!gob%RZ>_DJ?qzCh2qx-mWFs~FG1ntim}UBR7@S4NrD8k=vNY3ASG za{8e?&;;fM=k22X{NL2ZNVl~q(!G}Qmb2EFJH{OJ3@?U1ur?j-KKjUiu+PV`Z_Q%7 zHM8IYzQj0f@(kV+8Y@~6*;hL$*gJ)LEtkS?iC3RRy7=#!eC%akmhvg?Quy$?ztew_ zd80ai(pgB1F9bj2;oX4`-A53&maz0IKKv#44SwmA9_RBBp2esCx|gm*g#T7}66YyX(NTRF{vu8M zx$vH_YjN8%=M)pxhw8hgEgIn}8zr$POH1pj&TP5okhc*nbYVNrHa38N$lQNX9sYX;uN}ny0VcS!TuZ$w z6I2=UMzl_X@1|QloHd25=6u62 ziIVq_)@KuIQ+xAjPwpP=ja9R)=DJgY(FLqm+1RRFW7xxkQN!8{`=>eODs^Ap6hyU` zSI#lL)n}RB#cSBBD}%kyQ_te-u?@r>p2~&1&AUF>yNmySUHqoW#4R8$F(O)dH}!6} zqLq(vKZiT_<+XgXL(Tcv@d&Z+m_W_G3gGhKiY68Cm2*Z{$vrd489w6mU))8+TL$`b z?AX3)kFOzd?5*zBV=djw$t-QlGbJr;T0y{*6}+rDO#>a~j3IrXYeGhtnKh`fqd zTZ#)Wh5oTOek*9LHfQ+H(VqAd_NV)QH|)^md1ihBzQe6sd!zQwiWWo5$FN#^iq&8BQ++hRk#EMoYxb^n?gt9b?iq*vFWWoB z+Ow58Vf^sJ+WRj{_|V^eZmxNlBZmJ;7QY@a+w2q@k$|OEy|i1!DwQ1J7*+w71@*-gRBJ+mZok6_lg z3m%Pq64*8VTY+8hYF<<_zYFg1ti6N(SXSQzxB8|&s+?d~-o)sSiUq&Ym8N*%S9#P= zr3HY?oo5A%k^I_6?f;C=2n0{2Ys!!WfC@N>649-#>HanEEC8v8oR_B z#XkS!oCN&3>eBmocV7OVyjAxv^&iok)tb<}MOW95KsM0){{wnCw>`HlU_YYtzWwpj zA3txK^ItsuP+=^XZw8i6s2Ea`Uzt}mA;3H5@Q`r+0u#y~4F6%^FSLfV&OE^x&Kl}C zc=VC&%t7sCnup>SEY^zd()#<{qx};1Xv?ZO z_`mdf@K=lzvT{^*_fm{c5cz%UGW5IrLoR z4?iIsx?YP224&~MNQe5?Yh3X?5!)+v-#NAGKC;krH zPFz2(==h#Kx(|(mMZb;O4ngn~go8a5=0DF?^#P863n>`vhoPAVlWh--5^#!u^X&+F1iP7&CYyFtue&*6v z%I{D2Uvs1%DZdpS!I)3Wp~>P8{;*uUd}Lnv%cfazGYBQ@s_as5@11AD!<6|wqr*`@N3_a zY$^G59cP+%v$t2m8wtj1fl>Xv(3m~n7z(|=^wdLNg5Il-t_);t$jCp=z8;Tso5v&F z=qVgJ|1)6Je&rcHz}cr>_{-5p%*u!MxwJmAjJfc?rSInl|M&F0s1JRIck4^v3!o7N z(Dw-c-5iEagb0UBLC$CXKu(BwGr3|yWPtf}a+cP6nHvULe?E3BG)_rqaDwyU{&QR5 zaFD%-^X4je!5Y?)_EXLGph?;R=6PuR=?$kjyzNKD5$Xz%w}5;V&{`{)j4NM;mKF8k zJwDHe2tM`06q>dQ#=3_8y^h@IKZ5KWEuU?iu`a)eI+2w%hR3P`lD9Wmzm9Zc*P`uF zbZ3%fbtYtpbH-=OutQ&BO`kC4>oa5QlxW;Y|dnE8=UuDdn1!pR+ zad+_M)(ySt%hOGQr|V=M=9%0*51eYATiw2Ox$MyE{Jn*|zZlM08Tbid2gt)GJhcR= z1AH!HevW3Jx`1yixVwnY!=7B|(1=vrA4|nYvJX$^)82nBUx58Jm;E<~{odf86gvfzgFw68@4zdpZYrU090n z&q;KoM+18$@YMpJ`f>sAFG{4-(o;((KbC$qlD?Jni|AK9aY5uY^)>G29R|2N>yu;i zZv{rdta6HQ;TS zIgQf6u?f?6ofLvI51(7VAADJS!maQO42Oh!;rp|7{e+yYH^Z$9O%PMJ4YfZ{NLvZ|nhRLi!=YNREA7Sp*P^SkyexS579x6)MR#|6S z^H_VPGxvX$+55f$Z)EUi_Or2vmSy!smiCBPq+5IC@pW-|G3}{0Pbl*CmXb_^bh>mof)tB~odNx;)f1o3Wn9SnGa}kGbe& zUS7qx&rNiuwWe}oUGXauUFoWb=HrlPS>nC4!L7$Wkzkg6BDJY`SMN7%vbC{}IpwzN zwl|5k)m9m8X-;WB>e~lzw$D`&<|nvOzctRfFXYTgF};aUr2xuh{8kL7>m)I%qe$==Pb z^(uHf!DId@(rrB!>8{Jt!&=5%>)#o7|3qip?_%5^>$CPHySwc%zrK(r?jD|z-9!`1 zX;1s_FR*1M99JrQEjnU&I?hSiH~DXK8#g@ ztkI%aXFPy>GnI8;zy0V$-ke;uvjP_OXE+oF3HFhy$P{lg?Ic|V* zl38r_jW-A{Nu<(asc#}M6am96iT1SGx-HR>Ry)&xX(}*%KaozW?R(fq%8gytp>XB_USB~<7p8(}W&+3Eb zI8BqhBUwu2D=4r3htTLAOshZDlyWbkHpm zD)TBQc*$!>^R2o%f8L-wCiLC!`}@b_VH1x0cdjnYFUEZ>Z;9-~eL8y1mHD>~s-9qo zyUXMs*-SgrX!Gh<7vx`w``t+Xkw50$IiVW4Fc85WH{ar~&(EI^%%`_roj)B{@C+yK zHGf~0Z%A*-yJLcv_{EeF%=N^H?o6aT->L=qar|ZYzZ;owWZs}VC+r$-qIb}C7q-5I zvrX_@7VsMK3ub1%*(_={q*%&Od>j>U!F(VSa35pEfsC9H~GLUV^+^ zf$lqmTg&|DKXwXN3bq^VBUOIj;|mZD;EKMM$i`n@^@PG9rTP9J1oKNGm);a6&1RkW zxu2u?E8U)<-O5|B$H1IqeYBO{RdJ+}`CN_;EzB8fC31e{OX%aNGic4puSDLj1imWD zSlV5dL!4c~Q$!*?E7X2`kGo)MJ z|4c`l=%-r|?Q!(V1sT0^33|H<&V;2es03eO*0{s7o{4VtjCI{Lq*v2-aM|YQCdga9 zwDO22@R{B}h+ajwtOW*3wijbxWP353FZjye%;+7SLa+E;{Jq}MXQj|HXwMOUR7D#h z>Z`cV^xlO|M7U?%uwh{ijYIEnBkgqtp84s;EvsUt_Kcj0| z6X_O>HOB1q1gAOlHTEui)x`@PzDoRx?pd0>kACh9p#XW)H^j4N8~bL(-GW7WRnO;S zc#Cs|D)wC24G9=Od+=7fLNWtq2t|~&C})O<$Lc7ybcVpWj(9AK{C>_5{ubGN2K<2V z;PQfc)8U?V6a(i5*3cMA(J-h@tzh*FS>&))54&TXO*ZT6p9~K1RafkRE z9YmbIRG5?|@XA+WH{}-10YCI61kC7^kEp)#`;f1kc@@qt(4LR3+hV;}v1a`2 zFD9=f-+!0?Nb2M) zGs=do$UL=OD4m|##vQx#drp3>eWfYhJsTPu!PZNkc#j!*LEo@<_=#c5p9!A~{`{#Y z=FJa|+|swM{K!bop}^rd@ITHlC#?q6BRpmBcdC=FI5TKn27eT}}`=#@ia`dczGuDX`od_fJTdHzofyvF+%McZc1z##`DR>C zkT-o+Y)Z6mycHRD93J7{FqRQB-s!K##hjMeleHK7xC_v?tS>U&InygI2==<;hTPhq za&9(I?=?JG@`me_}X)YQJ!B z^ojV1j6MMmmKpQen4g{*bB(vfc=yGD6&d4{JL!0rdl>ICPpH=rTa6P2~>+XFcV1>OSEK0!wtL^nS=5BiLLR(W;TUwD#k z)}7PtdK$BIW>11Uir?jKz)Z^Pj=-hJEkmc8`6}z?0&lxw7J%@#jv2>Zl^lLt8H14qzWo zcpHTN*)WH6rv0vW=%!(E|0^884S2cVMctyu z71ST0{y6oQ5&k7*IQQh<()OJp+?CWHMvob%&LOz-$rHmLrT!-J7L(^H)k)e=!b3?Hakc?U#8p!$}gwwFzpS;KQEa~Lj!<&Y{R#bsr1(chv!v$1Z8LNsoXz%UblZj zzZxljDrNk*wX~x?mvWCw{rs}ien&b)dG+@rehH$Xo1eO@x1 z7M_EA-%56-g$M4jN4wymZuS1BJ%_tt!ina|k2uR!e{~l{cu^kpS^aa$pqo(NbjrqhlpPma%9Lu^=2pi z+h(iH5N$gDb&0Ilj()?(e`6+C=Q*r9$uh+zv%YN)clVHGB&&E>m%5wOq;bXoh0=ynx26t9#R z-B}y~cHLc4nuq?XuNAt%>Z*l4-1wnREVP_I%-1{nmXH^TOKMeT}JjPGja> z&1KB(;ju(~0Q$_Yfp6aAGz54r!vC1?E+&%p;O54-qZDh84lJ|Xz^ekRX&IJ-=s&e5G&t0B(Y znUG-7d{CU@*IiDl!HZvTD{m3?Xss$fhxj0_;H+=OmM=KYC2nxP^A!)c@v{#pp9PNU zgC?qbsydhR^r^$bFa2d)`b+i_t?xW=uQ8eo?lneBu_1DN{V+z>4HZ4gqjaU^-SGK! zY?XAx&1G-<1VcUg0>MEW@DLG4|EYE~#;Vtu1GJ|xcJ8e)XEX;2?#W%d1ld`zXnqM6 z%`cVF{L((7b(a|3^|^a%1rGle=(AodgAEhPD^JD4$jRi(k9-#Alrtla=TX=M zeQlR?ahH;JKyF##L}|jwXm~Z@N&OdY)PLWn*wdi@Ikc^{rTs~IqZIFl+Fzhbene0HJN=K()&I0| zpVig>{4aGsH?nuCFWTGw|9pQ`caSSM3zRPMr~e<^A9dRc2DvB591+j2xhy_kXOh9= zcSsW_y+ay+C&=i!0y*Lj+&iSw1OK1g86EDwVZ!5_?aGE24KGE9%H3~+zPg_5^0ayM*C9pR+Xejn*x zx2$kWVL*4;u#v>Mq!ZsFohtHGYoxnA8%Mq#i@H5qBgjYGf#%cutjV3&sCV1uea+|E z-qNpa!cH5_U(ogo*|vYzuWjn~ym(^U1N*kko1V|L{cOLs2|H~+_XTY~pKbd${o1B( z&u>p`dw-g{OZ=bErn-LrC&XJc{daf^G{ChH04>?qfxh0$dmtb0f@X17yL4%F4>a{% z*7y7tW4(Je_xaZkXpk|%fvo>a$p^yc7jx%MaWHnHs(3f*<_Q%A zd+&!nYoE}&uyXG9mUFlF$>E&cNskRbWE#o{>5fk!%fyO?BVR)xxpIT@GE$dKbXM{`?l`g z`7$(Daj)Tjiumtfqh~SYnh0;@Q$9COYc|iz#I46q8x1#6_dihgF6w@QxP#O+%rm&5 z4fiJg)AVF~yBoKK{L_;M(w($>E@l2m9Ydkne}})5^1mVd9a|HHKF(Yo@g6q z|IQewZ^DW2p}I6LgcsrDb@Hkn;b1TB`+|-ByL}g~)&CKstN+i^P7!^ZLB9k~8)wQp z>DMd3`#P}x5jY3;lOr|uyQsI3vVQ;;&5IcRU9_h$*zUla8JlhR=OEv5E_x_Hzx=?h z|8^F{Hii{jM}?%UQn@S-%6a zYj+uIcOq-on_ag`gNNDY;k}W&Zq3t??h4i}vd59Wce}K9(Z}p@&e(o%@-sG%FPtA4 zWu7b1S*0T<_jMIMZDtw5% za5$EXzlZGb0kX=w+)?O8ZaKg`^fdCx*O(iJkWo6gYf%EOld;Zt5Z*r*p1%y4XfE#a z{Qvl)e6RD}#&-?hbNmmmyH-!;-ULZ%4(E}-hdFZrWh#K>7GQdq@qL)^BaHDM zahCwsV&JO=w%bTMmAKnU8%5b~1MAJeSPs0;llBp5TS(i2yNrJ7Kk=3T_vxf9ApdC6 zX5!vN|DUEWw*tpiq)jLPe9~6qK1shHr+0o*+=KyjWbBBBO85sKBJ4qwA!FN1eODgq5iXYa{{ zC=+6C>Wol#O>mE|C5J9P30-_5(mflR*neF;rTRDGy;1BnE2W07@&!LM; zpmU0I>7tvbbn<6(QL=z&qYZ7eKb+O@_88yVjnKwP(7f-M0ec3*FI_&BGe^!!)6m8D zu!B<;q~d+8su&m_TLyWh7q zZ3Zg&3YHEbGU==<6gd(`}i4r+dbk(-pcM}Z;2N{2HOtK z7e8v&uAr{P;Jgd_KN(&m*TMPXF_}0Q=Wd=Sc}I49PwR(s;rndxz03^V^EKq{*<*se z`>|z`X6)Vr=lyZ3@HTK#hh8quywW`VF?!QE;8^$G1I)Aa)_{f_Y`4AZ%(ZumRj2c& zmb_bo?dU*~$IsZ0oaUN=d;S0on4j3XJT_3evLOx)XxD%BV0UH~c&P_>H-9Dzv^u0r<)W0>cCkOpId(fd^PgLX-oI@wdcF{=eJSMR_b|~I%lzG`PlP| zs8e(2i^j*#Txtxq)Bnu<`FiQzz*#c*+5P#**r5#p_^*lVeMxlM!Nk_(Vd_M;*`Pc0 zq0*#thdx=FOuwBU{FJp8b@wfYK5+Nl$6fi7tlY%@;>b<+vsc~3{d$|dD)!?H-&J@| z&Ix>1p~-RhE_8xXrLi6zIVsj>4N2cz43Cs+a`psyye8ZK@@3KbjK*J}T42Kgb zmqVUJ;y}8c`=UkE5umKz5gtmQd!UZ#q#sOhe>4H_O+nE*`TU=Gmj8Or`JdnUZ++2ZvNzh7oKe>oa@Fk%WuO0hF!~2<WzUh36wr|gHQJ7qh_{Q6q@#Eqst?<@A0??gk{HiL~h^B=Jjm{Xsz6DrbuR?7a? z-xB+K88$-3{+7N99y0krd}?ABRA3iWyj!}a8eXWOt*?a_I^fp}Nk2i~ccQkFdzvQ^ zlDUZ{-)m8GetQG9&n7ef`-)4={3k-@dgSzaakC#{eXfkld{RH|p&ah><_=`bg3cUr z&vg|?Ou1kly3Ty^6ZsQ<3Z@_0*RWU1NBSDMm)+OMf59a(Us3!CtJD2XcAw*vxt7eu zk~LXxQCD_t_%?^`VV)Lq5m}q;0gn`oa2L!Ntv$6CyDw^D68d-QyqCIsi@v6WdifHz z&ItOW=g}R~uNN>kn=`7{oNmcqBlCp)=&ieIVE2CxXQP{+=Ks7{Jh_ALR?`0_X&0l5B^?*~Skmy5kK4$P1Klj?&Hx9$ z%=4R&ox8~2x5!^LWjF_HT+IE`ESzKIwgl%QAN9O1^ToAO!2{{}>5?BO@ya)HU-Gq( z|MCrT7Lj~yGN0?riPeIVzX<=Oj)&&WpnQ@iCwZGrzGjdINq-h;pH6*AS`xp+If=YU zTp65@!3WY;2u6^3=qa2)e7r08!o#=b_-z(W_!8|awyeVw3*8`N;UXi_N0?YazKf>j zr?Yo_EA!Kf)7V@1q7t6*xf#FWdvgpkJwH7o2O0az&iqcD`JXoCe2PD90e08IA-MdH z=;&;{P=V}c>xGIey&%snbfhqY;01uqnv75FTJ*!U?_RKG*d+boUikiA`2GfPLofMW zG{QabS*I4UG7cqU91HW@12kP9mHCy4qP&M2!Q&U1 zWq-4H0r6Of1AP){KnI$*fVj%s@Rb%n-i|$Q@?W%JP5p89WK(~L{d)9HThqZytW9FW z3jP=SHTQn(*T)UkF{kjsh1jhNue-M2{s49RAa(mApVSvu)o|G=1Uwms{l|CM{9W26txyz|eRd*CAcmd~d3u=K}v>evo8J8+Wa z;h#~*XR^1-#iK0`j|49)|BUw38|VsWz81NVa6aE9Y-7MQqreX%9$Uot^&2G2%a z__l7j@J*7m1m`oSLPH;)fj;~qKBc47tBwBq7wz4hcN4AvzjfG#t@&AdYv=84t(~vg za@QQB-OuM4dlRnN&U-rFDSTY_5U%I_2Hx-BeX*l&;hX<7zp<_Pc{)x>N7A^1Zz_0y zJMaIB_s_SCUGw8`Yv)02tQohY<>MWRzl(3P`mLi047;PQ`h8Yc>-{C*R&<9k%8^ zDIec{23w?oc<<(HGaEKZHDj@N+g?$(;*Wcp_^R-6R@u6g)Xg5gzmspIjwHW#QHBZ8 zSW@z}8JdU<^Y7fh+!|I=W+{I)-(99{RnORl(;mY(W2CjSg7p8>mba#jynH5_NZx~- ztT5B>B`>KmZ{>R__kZ%8lv&ELp6{jXck{i}&C6U*#4dUy{k`nHUcvnkyn#-N{8H;s zGR7|TBD^B=Zyup8ZlS)U3{v(-h*#QJQD!N>lvT=nGmr~E=}CD-kJq+`JIh*IJH;OncC#)E9WVA>6dCkD+J&PZZa@z@ z-J>7=hN$v$%B`8n~vUD(v*z@GWyAWAA0F0 z=%pW~{1>A0MKA45V*>GC$QpwVFoA*p!oY@d-lc=7hw7!&J(R>abTWD=_5T8N(uTB7 zGSEpnI!VVaJat6w!{0$CeU@_NYa_OOi9K2WL?7S)YZvf-44mBy4j7KzvXJum&GPTl z3ucN22%f3_^zAjzr_dnztCfH{z1IX zNd7DL@2xeG3C2wt>f)jLx}f1fn^2<86ox&QsFd^p3b^PmnJcs_gxzL5HobR@rJ)SJX7*V(p+ zq%UO-!F#r}pHkXD>aW%vV{XPiJxm-a8)T$8$4g_LhWP&taA}NobUKDT{HAHMzX^}- z)9c*WAH*T{hlTQFY!B1!UJnnhJF(q;5^XGYw_+Tx2HsQH6t54Cn+1ep}PPjn=03S6G@} zXWxnsO7uvAeIk?W4{2QGZW3P6kWGy}SLAvu*Q>1B^6w*i{c|`U0{r6ACTw#s-`{eH zEfQz%66W2v%w>#w@@8AaZDrRmt|!erHK?tyfb}irTFUHt%Up+fuNAUxwnQu?WBWZ; z?H#B4b3se{*#0{1TS~@pUM^?m&ap&z*6qCbOrDM7J<=}W%pSR?&F0=I{blC+I#x9Q6g>9pCRU-<{C!bKgAmKbYh#+6LwznroA8J=I)KKAmdmiwZ)=x6ZXiX3gZtn0E~ch?ck=5Dd1 z_at?)PD|?33*I}?x}4fOoJTx|KUhk;1rJ`bfHrg=J#=Mh(|i6B+SNSVV!7u z%FpwG%^Ep&uJA!l)4Re0SK4`3=UrRVpV8azudp_~KErbJo5Bk=N2Ky;cZ-|yl8?o) z;aUrMc`DjIEf_1PT{46EDlRs9Dw*$4D0Qf5Ef#cFjvM`@Yb~WE8gu=OC3g0>+vh$# zX!o(7d7d^@i3h$#fcpq%k9%#h-(Xd2H3oXG-tle;uj^8*vxT)3>sb!r;t=kfLmh~z16VGpIWL-#| zHu>xZV^aSnZCd|}l1@n~op?H(V$vy0r*n;ayqS(i8^2{?tu^8aTRE$W{k2%PF@tnM z;nRa9QESAlP3U(U*2p!iw^*p3-Bik2q6@TB&R$@Q>o3tJ_5Yf5tnh;DM-yZJf9fnM)hJr6_8PxHLVofcl(H`U&Q+ zo$Amd4sA@oBW#PzXU$Jh-khdu*h{sT`DxR&QD@J%uCV`9ZCro5l$G>6Yf74~(Ky>z z*Oq$m9rX^;{UU=ts~ev?=aKVVV;!pldsbsTs_12(tZOB#5F3Jf^54d_0j+?1+%veB z#IErUIaf6!-#)AR=nCfjcm%!C$xKbnD$g}x=tLlM}j?)rB2ES1J@O9 ziOU|z%-wU+PKjb;T_tnjXm@iD?n=sA>99vOa4*i>yBfDWBG2Q@p(}w$YPgQEA9IrZ znuRBG;FW#s;rwl%J@N+g1DOjSxrV)gs~E=#TvvSd>g#6ofBU-A`d6fR(lh*mzgT~M z_Pvz4vmpl#>amdet6(o(5L5 z!Ov2EA~(WQX8p0>wON0J^-_QAd;M&t{@DAvjyj<(dSdK*&GY_xUrvPQ{W12xZZL8p z^<2k4YplBv-fxilV^8fq_SO~|upt9)FmI~9HYd`{p4heSoX9mL+Q6fHv+26&XE#uH z_16{k7p7&+v*x0|ss4lyh5vNwuY$4)-wD6LXJ&m${lRZ7!hceye^32Ihr7-7_R$HN zxnI{G&u2~;_2{OY(!V**(^}rQO$bIe7vM)szdJVduI%j<Y-{glY6TtfOwX{%G{cYGyU#D@&m@~zJ{sox;Hh5gul zw#ogsTzPhr#HG={`PggSXTCF~|65g)`px_FWxlE@{ciLA)YLutTpxQ$`3kL(6|(2G z>|tF+8tmH~wM}_!#bxuGRqTkdnU`ldNJ3y}3PK?^$YVn^9D4*gzg4g03abq&|j zzekZ9u~W*J6X@f56=9ied?boYmAB_ar0;hQE1Sl1Q>V$^lyV(K#%`4m87`NQ{qN;| znDWNi@7>3|z<5b2jI!T5`z;jM@E1$nMm@+U@0s7R=eyLe?D;NrYuzjm?1hxLSI!*#7DdA+|Ar#bdT6l=KKF4@%s9s=$c&8 zPw`_xu-892C}Y}vkeROZweaijXq)mccw0oaJdMo?H z1)w%9V&q_dd$q{=OTXB(zWltV4fj}@HjLrCUh2hBwYc9xy~NuKf|cV_@|h?c8Ptha zY))fxN;W;zfygHONxmkD?mFs(UuQae(~@Jgr5n6swm6UnBfwb_ZMMh}^pRm5+y7(h zm@Vrsoz=9#iri8cQ)~5zS!Ub$sWPKS3`vKx8}3K1nB{`?y8UqF9got$*nYO-9wk zEsg|v7X64`GthsMHwS6T`5ColzBnJl49Ac^&KgbgxM4#dnfJ%`Kfw7JgZV>0xy}28 znKrSV!WkRn30XJ%q=ODN5*G6I`KApYoYS-cUHe(`=d8N8UwAa7CvvHSsitnov_&QQ zSNQR@V#|H`w1t#se#z7=XQ6|>P<2ZG9O8A@rfzYNmV$}e&DCh~*(_|{lgYR;|ZRJ@kx$!34LT;$Nw%N{z&tS0lW zzhG^Nj!i$Kul2CEm-N39mzL^-M`L5PL?@)*q3^b|gM(}iaL~f0H%%P00BlnVwkZJz zdBHWFn~$9f7Q&tp9|M>OKYb2dk!7c=CVdQ&?zsWN4l(9%ibKVC2TF|4_l`}pXuLf zozlMxebQ>3+W&H3YJdCvTGMkQIg=aRft}Gj4m-nvjiOs|2d~w?z3PQY4mRf>v=`L%lSA(#2>zaGlluT z_Xfun?R4aVehggAeflZ-GRebvoPPu6X|8s=f^xR7Jd^&BZ~CP_G(-A3Go-(e(4n0X zjMHaGTuE#I^Bek(a%eYc?Y+S@cz&(*&=pGkV;jwLi%_!UhEX}8*CKwT|zTnY?W7uqYt}8>OpJ*Idj-0 zwt{cLzpq30ueXx1zJ1Jl|~{%kyzt_Ik%|X|(LSx!OVaJN#m9d$kJ648rOG9B z5dTuD9TV6cN!F_mw&8{5`~A@i(jn*5@O^)DK`L};pACx5l8(PW93K|hdjn_ZV7Hic zi@jpLkF8>c*eYfn6Po#;ym4$6c~{OSmNLb$RbtpE?c6IT+ztQ5uu+5`64)oN-XQCi zih^>svT3K$7Gcsf&nEt=8P}F_o{8R+Z(1ck*e)^F=u0|PMv>WWaqO;eK=SMCm$Vj0 zeO*DEoX;~@U;H=oDfM-E>ihU*sk(ByKl>rCUz#r8zof&Z>F|cU?IV_3DL`S@?x4`BJt zoMm<~SW$df7f|L$IbVDc*!!#ah-QIdzRdl9X0Ng{wNtiv{@Fe7hGyAj%^$YLf-l)Y zoF%%urEFv_YY@R<#OYw)E7r&_Dnw_m!oK<`W56DKSIgMDsz@8TtynvGTQxq1%6ISC zUN631_R#V=7z1FOhrKA*B=Bz?u#G-l?632~*KB##Hs;0=%zZsSykU!*{in+A@E`fl zT=tZ@o^8M!b7(DBcn;GuFLy z1LsNIgr2G&5mDxQV0WLfu2XpXM$unjs~e1UyNF9{`S$pTNbfbG1Ht>(i!AZ|)#Qt3 zFH62Fg!c-~^KBE?A@g5Pm*-jui~2hPBO_+Hl)P8mpS+51#dk{|v*U*8{gUU7RQ~$+ zzKmUeWy-Fnujr2kB@Ul?7HxdaxL~3xHz+oR_(??{N`DihZ~j4{<-YJ&-7R%F_z>xP ztYE6LJJ^%!d)@-^mC_aw*T?K#>9#SXQNj_kZh zYdMQ_u|xQe9|zv|ASY9Z+i$aObFK7mf!~8pLeg5y{J}*<@cahB6tZraYcKDXAV+TG z=K^GEHT-rV@>HtXwk^=KZKcS8k(LAIm6&p%G2X{ss%!l4_%Qf?zQuCmaQJ^1{O^VT zg|FeMNZB3NA8{LCH28WL{6F{}{EsY}{6F+P;eW=GKEnUuH2;^AW`_4AOsuTf!aP4S z{lv<~Et<*ypX*45|FP3d{*ToNMl_ZfoGIqxdIQ)tR?QmpvF-ux^+)fO zbH`}Q)yBH}B&+htVg{k}4{q(oIANyfC#8PyN&jb08`?d1U`t-APXGY3lo!aMujthNfmucE4$G08$kPBWU z`L$MQQ`^|bw0A}ZZ`yV2fe_<#+;1Md&mK?9xR0F4{qDj0?&(1v_kYCwd7kPe|1uI= zT5KF>sx~@!`#MXD(>*%4>V8Yh+1Q)6zMu_^$9}l0M;j3PyxnH>ta?#no;G$lXDgQV zX#=ZX(FR=nU-cSg@#X|q#kuz)@en8D1I*WzapueG&1TZW-`@jyTJC=Pb)W z#W`Hx!F@09-p_kae3*uu)mWsB4PyH>i{0m6$h+&TE#+V3yCs%^Z#~9$Un8BXEd!&d zPdS6J+-sveT1(lR;4bRw)^DENv?`#H4@-;GvEL~ zhvfg*rj-{_KaWwLyeqc8*BBf0hoL9%v1{XktCmq;_gGq1mRnlxd~NA#9k&ji_GPk3rE5=wjiVodK4tN{y>Md+B`r=$%@V zc?KdfBxh1T{>yW2KE#-sjJ29)B5peG=7TmZ_%8j~WB+mP&A$YTzsFp#Cv20=GZ4cg z84DEMPM`9X`?aNx5j!W>t=6V^EZW=+R?CeD%~Ev0=s=D(MdsBZW22qeZ1SHmhjE!} z-+kKLR%B7?y@0sBM870+>&oVq9JSVNnC!mGI=18%_i*gFmh0}ajlEz*-XhU2npVy} znPuR*Q|+}E7|Cx}YI9x8tq}gtWsaW27iLc{r#32h$_oR<723$)MU3}3qT!l8Ti)qk zh_=@hMLTNtPSuvrjCR(X72R6Xmg631XUvOpTh_okYc*{q`$pt5w1xC%D5wEJA5n=Ue^ZR)Kv-=i)+dAmBp8dFlPhN=knA}UTAR?@o5E^&5quUkENnNedUEhqV|EPRi1 zd|p*|{%5Kz!FUgA1HN6QYa@tx*;3de^>m^Fe(x>3#d;SJih<-liVj{Jw5s-l&iDY*zB!sduUm z$YVj}OKMhPyIR58jul!${V2Mv#>TvDE9G#L&syrBpz=jE$B1#STh&qz1(iFMKM+$( z^LCi!^b&`?KFa+aX8u}9-^(}B)_0KR<`G?H-4s-AS6;sTO2ckBGDb;zdikcHGNLBZ zt}*gcM!S5S@aw!=f2C1VP}!}@XqzhXVx!K!&UariwyO7szsmics(#kZ-0$UnM15I1 zrU!ob1aa(8k5I4AEDzWpZ|>74)+f~J&2JGW^OJ3@`t8isv5`h0Jha#mEuA?H z>TBchE;Y>^v0I_*Xj^MI-Z?AYs-CsKrk<%hq`pu6{HE)DdskPVeagx0%2OCFwrx)E zeMFr;>jl+1=LPkpxY25%{Tn9gFrj5@V_8WDS zdwYzRR0N)jR2@^D!(UT3z$babeyir#wyPgky`lCPFRJ}jAE=OVOnuSGS|7_Byt7k% z2idqJ7EOxm>@jw#;=l(gh+N-O`Ih=Jb#N1WBRsyx*rA@y>r}g|-crv{&YR$ypYV*8H%BW3qE<(+Qz40$ZDzpAdQI;3_ypR|h{g`bbw zMb0wvX$vPhzd!p0wR!kPX~kVIZl7(JtTNp2*yT`8!M*b8*jA z`G#`R&J(NN9h9llH0p--7kTnnTTS`##A3<+S1!^J`OL`W2<;EL=$~h*Xdn2%2>eN9V-vad5~t|% zADD9ZqI#Tm`W!OX!uulUlk}I>cIw@W+&qm=_mcKAluKlJgnPSPZx~;?JH?VXFal+zf1j$Huu9T=fj6vY;CHZa@JSvSJSA2FQO-IXgH)w z(6cL{!joT9yIwegeu${k(3_{x9_OLw7V8l;0=@JV^7a+Wn`+Up=T$%7uSB**-hT}L zzkv*&i(c4_tj}@1r@mkL2X$lRo2m{y6{0OyBIlN2t!jhq4fO`!UXR?&arLU7@ZL|U z!^QDV^&~v^ZQ6Au^4{4Mv&V+-Ro5d+%c!&Iu6NX3!#dSZke>xJ%k_HNc_p%csu5SG zql2zT-nNhEQ~}yL2*0dE_LtD+^~iurdtIH1&bSU4`~zvY_VEwrgm+?^yfQLF)e! z*zt}!hyE*PrcY1F_YU>ML9VAD=NUaP8QB;4 zeh@y`g4~zU?jrNoAnOg(-9yND8SQ(1;XCSzyjRpY$g#Aq$odDH_V6sC=EU38Xxjf8 zWLVm`{e{=-siu>kQ&sT8J$#=} zJLgyRE8&ZihVN2d+kO>!VZh!(95>PyH)2cOgRM0`f44e9eCN@Y-xV3I>{nM%=GUqc zssWkbh$O&WKDuQVvM%?f z-d3VZwxAb=VN1~!+HA>Vd-N`3`a#<28S1E#dYzA+Sb|LUyb!f_(pDR552*$DooX0$HH@~= zXqWlu2;t=(+N4M8Q`_^plxFlR(b;j%MS0Rls%6%LY8d~)IyKUdi%cy^gq1;^wmu)X z2dHb2p;yrHb+lKl*fGe^naGaVH}by@nfa_1H|@`7Y{&@pQc3yiD8Ja8mr!Qu^J?L7 zEBtPOa3Q=fI{qNDEAHes1o?j1sTXf34G>)40yi;zH&hZ{9Ypc4rHJ=O5ht8WWdiQ@P`XB;9-9r z_#|%^*WId(cDGZ<;pY?f6567iwvfF*wj*05l)Hp7FF^0xsLy&W$q+$QmGHe_79XZPk}J!o_6}n0C1pThtDXh6k)*F*|%;OFDMau@Y|sX=mEnPdmGf zxbi^_={6p0UwFlA-xIboLklMFq}tiJpS8w!-@V?#nw4uuX>((_`-;U^fd6N$6JMYe z|A803K|9!9!*}qtXlun**J$_`mf%BJ!M#!V z0ZxHGYGmR{uu0CHEC| zf9{LwnP*cr*Mu3ps$=6pHDShp>X<%2xSw#pdVk~|_2-eVsevbt>4%>@sy{elw|b!Y zh`tzpSPq|*5|$DQ{$38BltO~Lm%}5akl^a&@JJ~nxOzD}QVI!{UJj3xLV}T(!y~1T zVBzKPNGT*3cvk+4sygpwb!py9%KQ9&d+GDN_DkCi+k>=U(Z(n|6j8yVZYE~*s&#oC zYH@X3mF65!MXTc~kVk$RckBAzSaPi`f z{he+2W!CB4YHf8?H6njjFi3^9LtWe`>5y0U2+&#Qs!i|Kwbk#a>T2YP^bANx2LzzX z>U~fjl!VX$#O2W7joLlB#`m(%`pE6a9%!|?2k>j{Ka;hC__ZFwul2Bn^$+;9%r)cR z$34I64tVh8a}N3G5lAu4k5D_hwLM8I^&6XTK+cYc3kF)I18QR$;NAV47R3yo^*3w@sNp5nbQ^_6SuP)Wi$ z8tnmvr$>}+27VgCjP8?AWBr%-rW~XID_;% zcvejMK0+JuFMgMG$%HHV*@uff%^^=Eq%n(pSqazitQ`H=Oj!BO+sQ)8BB}BFem)vRFyOPk!2Y=NCMCl6azoGl{2$Jg+0qQQle0JB^Yr;`#g^ zqRDFs=e`cMB+ox2&wjqYk372wr7pU{mf&ss@r7}{kG+q{*Sr%=2Do1f zHSnE{_c!v6i|0=AK6L$4S?KMMFBA=RF;={fwRZu9JGXKA0gf0M-LWF4Q=-IwfQd~N}A;N9$heWAG?==I`E zd>-O+xalv6)1uK=JNV8`yC75ZdX7CXSJQqj*Jp7p`y)PK``VG8UwKc{FF8B;(M@;V z{MdiodGq7H%wYyZCI|CoI_@dKtJlTQ|+H#9$IQuG&)koMD z0TAbEuQ4x)d5U9u!!=Q4+w422*FKy5^aklSP%IbGhd9nFIl4F*uKAZ_Yt2vSW0oY_ zYaT`K*NM#Y{xJFizpP`R|2WMuGk7EWKy4&ko%?}W(u-{Di>QRYQ?)|k2QCgri+2&8 zO;}!ZKpFH)4#M)HWAM~5!uJT@Qx}fds=fwpUI13Rpn0D@317;n5xdmH=6*c~JKj&9 zWy8iVC-lig6My&W|k?gwVyqIYs{VQ+g) zA>TFd&4S*x8b9e@&-r1t>R0eb|3>+Wwkt>IusY2iHUDR>-MyVP<&Fscvo=-I+gjt| zo%`pk)c3AF#Jh3T(-%=ka+M``=i4^!_i){# zc5(LMOYr4{>V4dca4(`>THVKWH`m=)Z)0era_={bJh@`>(gXZ-15kf5N?S zb=#(16~Nc@zV$UTo|keC6X%QS&W1huWz}&tKDS>@Ny;8Gmf&IR4i|QZ2fM>U{mi6p z#;5I$OR1M0><+Ov#4a6$O*$SrtMhQD3%g?`^9d?kZ()c*6@&4B~(QF z1|Wm-7}b4H5=tm{bxdg*JTJBewy4${O|r%&*cxMBo4f8_FLNs@9NOGyZf|iN`a^Vs z*rAMdMZ^{rJG24)aSiSN_1>cz= zkNO4je=AdUR)A49A^%S{AJA_Bt1NHcuP;P@^daL52s;VI{%jOnLg**#L*6@~M#vBK z2`+~kAwSfIymvy4kRR$p-aDa2$Pe`)@10O1OlTWN>MiopT=@@!B(SBU1mLiJ`LB@7`>{{x?fq*=d;lHCFt|p&^x!Hhb*j_ zDWi>?*!=bA{`dIqTH39FZz@Dz(3VRB9ZI1SW^o4Ref7KbW27~1)-C!yq~)j0|DExS zb@=tJ=DnUdzgJJ^?p4!_SJbn}=6u?Z4NKK-e0i;f+tt#-_tjPP2MGt%66+E5V{pPl z$aXi+9|kA<2>HI4=S!^UE9zn``dM^!WJW|^yt+-TMK_C%Ud%gd(aWNrmr%B~=w#8& zi^<>Gs+3+1g74O%i$y2TwI0^jBTrAEXV#*RMK5o*w(2Wf;bIT87JV$bc^vv?EOdVO zVCSg(SJBHatJyiUO(3d9ZF|Qaq#fomjy5|VzX#(7LFzvkcvr1}76%Tf<-Uqtc`p0#n>RDMYq%63TC*NHg%zMM)Tch%0C7Gpq2P(m{m4m*B6h;;O;5O~1@sGXr`(qE(Wv~eQlwi|5giT{& z5o{V0i`ezCgIL6V*H{yaNLb6Be}Y94V3DEcCduBhg_^!C%05h*xd)To+=FQmd!{{# zj@iU>;bU3Xzma;A{bAj1#^c!+unRq9!7lj;b2DY{#|s{RJ5>63G~|6e7IHrx5A|Vx zU;KC?RPuOl$cx?I``Kaf=T*EMd~=(9HdjLoM@x(lxo5j<)X`YtQHzCE-GCyP}Putj z_B5`iKkegrp71nlUZo%Hf~U24B}X46-|zr)JaX3Luup~X_9FK7E2R!)pRw2Bac^xj z>{*R07$PZzprWaFy^d4Qa2ZI)^H~8X}*exZ(sN<2P`S&$)qoQt~G(j z!5kT0)82SHX~o`J#Qf3h`WSj$LOx{=4~f@J-Bv)7j-=@)uceR`k~;Uh^>@Xy%T1X9=|^5Q{d!3F8K5~ zSpz4#J_aYB0Zz^xF?`XY6i)8W;N%iyQ0hYbpGn*B)1{954lPnG_ANG35IgFJ*g8^g z>#&J7Vk``CBeoQCA$u4+u19tKxZ0OUl{U5>J z5_~+>)Qgtj1K4B#j=g*$e0(wZc-`NDkFU(a$CHQP<3j8;!N)Gba%?Uqp@+~xn8C;8 z*j}D2d|ZzG<;lXw<=9{zD1(p7vBf-41|OGWi+P|7J}$=&^FSGVT#gNPF1D$MQ1J0N z*r=a~kK4h=?QwhkHt_MbzYibJ%)-YrhT!Arw0Q;}7yk|T*g;#OmrZ<+T`1t+5 z3Lj7V1bloRZ72A6-U;yWyc6K#c|-8=yexb?FAE>fI{`kPmxYh#W#Qv_S@^hR+kkyH zwyxmg`@zSq;k#9T7CwF%d^|CYkI%{-P!ky!-euYcC&I|@pAaMCXdcAKAou}}XFeB3SgSnQRd`1nb%@tprh@bOt-VZq25JUkRD=OF77 zka_+0;N#z?@UhCm#|>bqYJ6XRBR=lV;Nx4-LARvvadX*Uz{i(n;o}$6_;~!R+XnIR z9`JF`C*b2tv+(hyX?%QX8XxZlAHSN$$FG2oUp@go7G0f5PX>8mBHtqo%_YA?tv+7g$cro}p8y}C}w%`8OW8_1F7`giY5=PEo ziNfFhWqhn>VF^8rB_zz?EH8Prrt>O!lYH8sM)Fuo{_4qJoVe=9Um2m~sUD0TkbB^BsS}Aq z$~qJud&sloCmSC-iCfB7Oa0b?H#EMNyw(y&T{N1M`CZxgID{PvKJGpdKCZhsjgN`% zMEKapzJjYweB76fkGqe@$MS77l#P$SvF$^i{y2R6aXz0}3eg^yD{pA0@0 zpO4ts8GI}}{UJWi1s~_G$;JQkQGA>`1Rr;sIMWXH|73h@|C{l#VAveutsrFX$sj(i z10M&n@Nouj+d|;uroRp!R}r7!V>90d_&Axy$8QKewhh6@sk{%x$GQJk@iD$M@*5!E zf{&%HGx#`De!<64cwKyL8GIgv*TtW-4_+61EWV&p@Ue_pn!FCrN5QI_{sKNOOXFiF zdGL}4Nk4;+iE}?^HiX1yL^z0#+wd8E3_k8YF+NVk`*HZV;rS2oaV^)Mh>x?@3a0iF zJi&TFzadI0$QrqUm9MbY?Eq`Z4)g3V@sG5&teS3Zku-~qQ^Y3jcDh;9cYt+)_p>fA zpLKz(2`n4QT09r)?^yG<>WkJE8~ZcJyP0)?^1p(0fi}4}nKgf5;y8yjf2;{Co6a|v zlFm1v)vOC#LOiSqte8!lH}DQ?0{vg)I>3F_{H=O~_kQtV8WpSyWPiG#g*0ScV8une z`w;5_Srh2Lly!km@*Qge%gQYS`P8$Mb%FkJ)&(ABjobk(wJz`g>jGD6P{B>01FyOT{->6ZlQ2i+FA$?&n$0_nTu6+`dF>DP(P6rK}CSRBI`p zZ3$M$y1>uL`b|sluGzeQj5UDAa+_8?p|#+v>Xvrva*q#&SSKj5xon{}(8t<9)-JY` zeT}wU$GX6;@?DqK5-V`Gs3ojJe2loS)&{=S#@fSW3>@P6jne}*>KG79~JO(yH+R}tR=0Rs#=3q^rm$N1`-CdxK@D|AYsrpm2xzfK$ zosPjDBz)V2&q>w=%KVJi9a^M|cy~oxO@9z;_)p&&ZLjHOzFvg+dY#d(8rul>z>etF zntUBSIn_Nde4=|`Se|=e0`V`?^4RZ>ee2mLcOTa`5}pRhKI7RoTlRGv`@>h4nyVpw z?H>M%PudBtp2Aq|m0D6wBb-LqGQ5NNyuuTA?dqa<+mccsss_d5r(PLU;~g zxnrMlK;?|zI-qjLe!~6gOUxO)aKy{%isk{mU~dzu#W*1;=`~)G4PK872?ORLNPFq0TtrQ zutG6#kO39q$FM>%FpvQi;>)l?G4PK8$(leJ7j!a*eNx_Q%3%I!6?0K5S?3Yx8nE9E z4m}4dY&gX8mzjrrNV$3U4#sEiV9fL`nXAFION*&<8IM1wiZN{45oKkpuFUp6^IZp& zhwIyU=XT?ea`1j3*IYFdG*xF+}XCle2K5i%n$jMyp&;siqFIO_6O`sa`$={ z{bk1(nV;HQY=P%Q7kTM>MMGO@EyVgVM4tGU%d!VeV%zhvzQmq4L@y#&*m~OU^?@HbjFx_8UL5HhV6tF z!a70+)XO}8cBl?=K)uWZXou<`2h__vfOe=3azMSz189fpAP3YN=;414|9kk~!~Y2X zBm4(TLB04l+o3wh0aY`u@8^6Hr#TOZxd!20dviEpuYE3NuY0b~ZU^G*9etmgfgY(~o`*$e9uRs#LmxP(>u#RQ zT+?3kL=L`|(Zn;Fc_@X%QOJCendGH-_V3kP?vG<0&@AFDh@2AM+rr%tey(JTjdFR{sd#6yZNp$vo_>X^xPx*d) zN$c?a+mM+D@$u&%C&OtI9a+eyU8d3&*RvO^$OAeTeQjayc=oD=JY0*Ob}@bsZcOQ9 zk>h3jmw9y|^m9RRw|LkKd1H~Gcu>95k4;>EH8RjIiT_) z^bAy9beQn4TEtwM{1F}K=Dlh(V+JyxPH*njuW9~3w==&kf$sIAi{pf{wm3%UB#aV@ z?D)~gvcA{}iR}2%$FjD`35o3Z(Z{lG(Fuv{_|eC*KFJA*?D)~gvIfZsiR}2%$Fk1Q z35o3Z(Z^oM35o2a#t1r)oxSL>PNg$v#?H8abz97CX^+~g;8U5qU(q;#?rv9hLRr^R z1+Q1Zi$Uf_)Nx&>r{>I+$b6}s{VGU3Q~yB=yeaeMD!5X(^2hpdK3>)sCKVIG|o`EetY?jp+9_`Y)LQS*Q1+F(tdn{fgM@{ze0r5tU1 zW9Eyr`pDx9=8bf)&SgK(6lp0vp{}JoPSP$YimM1zQ{Bt_$$jcH^57&7Vcu`xUS@va zbkXgUp;hlQWzNU^BdNEHU)$L$XZklbi&$)kVHeshkS&Lvz>H22T^VkCs(e=6T zz3BTY`27KRdz9-`yNr>oMh1fLd;p$b04A$8=YYjR*yC&c$dT|oHf!@r`nfIId+G~D zg89;2__&z|ncJ=sIqhl^{3q$_ zdZ-d|L!#sBp-RXNiH@&_Dj_!{I=&vdpE{@{bVK9NC4Th0tV3|pmUjB@o%lSB=Mwhd zbJ!BUjoGVyo3y*o`7-ZoaqT{H%}EuZ13oCie_CYSucqTmEu;R*=%*EYP-?&fTA#Ae zXE$JU_;+n(J#^utRzpf#TOgcmzqCj>{BxKEbAZ3iE|9PeiVB8 z3euQoysS#eugK3OjBPI z?irlhG@icd^Q?QjC2&wVv0n~Y-&6ZZyW4tLaZV+3r4BOZX&-*ILuv-^ZQ@=?qwLr+ zwb(MX=Km<`$LK>G^c|3!{8;jlG3J6;An8Zm{3q{+eaZg;oZXhf*=uF*F~=wE%M(2_ zxVr1u1C3w`AASt#{wP@cXl>Si&0RK4?qx9dp(!TjZpJ1`?Zq<`a~tD7E#__pZ#0L7 z;BIwT8|VaI55eBePO!I$xmSOPxz$H8x0%l@%-x*E+|B<$%x$J2nA-{FMvpZ6hhXlq zEX?f(bDv3_3+68WWX#=c3#TzRc)R=&!Py^+xtm32Wnu2-zZG-mktf01g0;)Q+Je6W zVDFE^+|pKds7srW!Q0Kp;q9xl@HY7TBbfVZAI04JI*&cD@YcTqb6>0nck%A0#oT{9 z|^ihH-N>g~cS@znon|9Qw z;CT9|?_!s2=bK&hQxnjOuiJ*5-c3Ihp^xgJkJ?G!rPII3o;f?{s{}{qqATUB;T&`& z=Ne*<<%6U1nctEBvG_TF&EQMhWMVrM^8Y9#SX%nkJoYu5!kqLg^+Reh;bg+w=?gNp zS_K%|1GUf(hj>4Oqpzkflzk2Y;2Q@N0Pi@U0Ba#+Jwyga3x*c_EI3*)wP0w$(!FBy ziOohRI66isINDsJNmzufmW`u}u+_40bP={%HjXaBR?EiGMc8WDIJyX1EgMG{VXI~1 z=xT8E6=@tj85|v8jb8Qh19qb=X0L4fv;9Z(dxE2jHXSzK^AKv_=!dX-9@2Z&kLd?9 zHjRm+?;TLpx!`DQo3h;ZRVn{HT$}G#ALcAgS%cKAJGgdM|5+!*Rng2HPoj>y&49&Hyy%5~&#@;N$F4HKR3?m=dj?Bq+gA_5qwC?>b?~gr zNt({QEU~X@;8)@OGX4v8C?d>YJ@F&Fto5r%G@{PN#+ps|L$KW}Y%Ck}5j^dVC#Sm( zVpkkg(_JZhYq~3CXJzno4?Gotw**(u0as`6wAfh*Y$~y{+R}EG;AtO}z_x0G1W)^* z1h!QhBzW2fC9tj9Ai>i=X3?3x9HPVs|av$(LY3bA1}Qhyt< zrNkey9Ghsm5o2CZSHg$v?yUv_{ zbF4^TRvS0>K4~Y;FyF4mj&fo*l{=!O*~@w$<^}W2&9jWZsE&M85Kl$z0aYdGbtUW? z@k!pqPvf9n!=$Ovh9AMvtVI)ls2_i*VBYWlleV-%{Gs2|KjIJd=(_0-txo$x<$uN> zD%Xu?rsmj*UsZ5)C4SIC^m5@XCBrMw$umaiiz>j) zz3YS?Lf4AVvY4=#usp4E%hNhn)}e{cy%1gdb=Ec)fRU$wKfZ=sT*W$P!N`-44?nm? z=G2uD)}do%kB>N^kI+YGL+94vvy4MNNYoYhrr=RYz5 z$(pk|e3o&@2g#bVI((LK$Op-qvpRg1amZ)-E?+?Fu)?FR8*vR8?p zHB@ov&c@VQ`fCVfO;H*3Bsx{Go+-g~g0*@BtbMYe+kOT16}&v3`C8}le-+nZ-n*Ok z?!NbsI>LKZ;LB>(7KzUP5%+H=t^lE{dYAgOZ8yHJJ<3VClS#{gJ~s9ArbA$gR&__w zQDy2{JxZR#s<1kyYDrUYhL39}7@(arCet@W!73F+ab-sz7o)!?CsXUI>U8;rwGg7G zx$oh>oByWX#uwn>+R=`$fVy#@4=j{BjQnQnb+cbVuc!2R#~@y=1SePG6Lq4?_l-La zC$E*Wx-&Rg)=3FYuI^3YWWmVyqQlps%d61g3*E7h=y5ADQqHyb^%oNgR(lYc-vvg# z%;;6yqg(O0Z&kUu9jZ5{<0BZk&v8HnpgspS0@UY75GL@0?ovD9(WPMIC1B)k_;V{5 z`4TYlLNIa>I=cfsT}aqK=pqaddY}&UbpsTDJWvPvx&aD69;gF--2eq357dFaZh!)i z2kJmyH$VZ%19hOU8=wH>fjZFF4bUm*ivXbq5`3ERiF(oB)4|AfzwNa*{x)H603+9< zziVi#g-~N{6n%-mgs_ZvS5sfBwO+NBK0mV;#0BuyMkA?oE9=P6(Q$2`>fnDl*JV=Q z=<=EPbMEEad(ov!cz+Hy!E{0=YhNy0hnZxUyJdX5M`afy9&b{&~U2xKIBi_Zd@7$J0D2*vS3Nez%`L&BWMi!Psj*-0yb6$L@Dq^*8Ky zD{)G{C;Q!oj0r(-+}iB@Zd(Ow58dx}{KxNiD}FPHGYey{mHlqvL*Ywmfw z%-ZtT>~|~vZEVi9POx=F3R|x&W4yZze4W_~_v7}vT}pkL7~A{t``v29E%~%*6N7)v zez#z3Ge4hpzuSKzPcATam5gaK&U~W%Zl!IcO+xO8=6<)iT>m5XyB$T^|GNCI+wayK z-w?YDU7s1J{@sj^$IPA~lSc?tFt zSRd`ISxwwI*p)w&F=)ofW$al;cjwY?O(gy<{Kqo>EaT4AT<`mYv1hU0(BUC>UCMqF ztmMaDJD;)7uWNm&F;GJ3|3*U%xi2dZ^egN%*>841#$Kb}ON}vOr_mRdgJm4hg^V>{ zJpx}j_F8J38T+mIsA;bWPOeJZYn6np*k^&Xy=D-~ShLt`t!aBr#+t=mYfam0GS)2i zT5H-~ld)#8*ILu|nv6Azz1Etx*JP|&?6uaky=J8Cwbrz~mKkdn-@e#uf_+1bH8-I9 z>z`*#uq$eRn!e8mEoeB*JDl}RA0gu!Pt#vKttHj3`7Yxhz7u@&HG}a1#+ohkZ+^y_ z7gVKu!vWr}=Y8?{n&TDtZDqW|<6yj^796ZaQ{xrsYmGJj?jpu3@Wp1HOF!cx4M!}R zbdavt+JR^^DL#-Wq3Qo%f1?I$r835|0_Ofk@nXRw89PbjUhJe&_|FP2)xdKye!M=- zb8F$lWu>u@j3M6(zj?Vfbp<@vf^8?`#y!2=>`{-Y=nJxj}E@ixUA+}O6Hc>KdBguHN*hn&-PzEKji!x&gWn3q* zi!x&gWn3q*i!x&gWn3q*i!x&gWn3q*i!x&gWn3q*i!x&gWn3q*i85meWn72AdVa=E z#WtFWjSzb-Y42nFAQ6t+li_#lZSch=XkjCEE;dY((8m~aJN48K=IQ3Up<`Y$jx094 zjCC!;ju(7e%zqg-up-kMGTp(qGDgsd4PMFEmd@B#6})0FwpG{|S59nX`JcHq2FJDJ znP61mlTH(p`$}U;+AwK>j&4U4da(?>=t}EF7jt(Oq8AHC zo%(2E=4#};_hT&o3-Hlr6~ww%+Sgg-;@trgyW z3O?20Wjl43OC9FHt1>soYo1F#Y)y!8AC$-5HKPB#=syDzxsm;roP+u=nbvneTq=#Q~g~!5c&Ow=s^4-GWIL_TlAm@ zvi=o%@T5~ey?t0XojF_Bhtr4ZLHx?12TRd|PJDOS_F*ITVJG(CK6p&*L*dWY)Apec zJ-8|D!<&>$*@ua=4{uDeqh@R}<--&HJ|(%ehRrDk@~J=0-Z6c6Vjp^$zb|W3E@BS< zX;3aCdhp}O+ZYYiLLytDA5HrZU((lg>_fuIgc*O{Q2jV)9}fES(2Ml{<=6ra=tKSZ zKh!?NpVxqXtZ&0UL_ZGNhm2#G`mr%>A7TSMt*7lnu4TN!v=8a?YZyZj8^Di`ZUO5w z3%L&PPCf6J^WI12vtS?UY5P#dOt?1f!@+((bri6HsYXuOxuXD4)kM3mVT^F>qkOU zKT=Qa;4ITdBfxx=%{6V zSz14K4cd<%;^)O+=P`dLex911tNlL;KVv_d`VsrFHmx7!oR$oJE)-i2KK(Dj&+xq9 zXHD=CwxZ}pH=$r@(T@gpq+kNkk1^AJw5Bng9pnmK=p?*Ap{V2Ah*pONF zW4A5KeiYj=g6+8E@30^LN9xB8^kc^f@OAB{w;zi$wxj6Be~|s?qAwLcV@f}EDj&9^ zC2d1~oPNxVzx)^C>+UqZ?*4o6bsoGrjJ{?lzRm+%&-ibGum4Bdk6HThIQub;uM5G~ zrv3O|fv>S0MMsJ~;7;pDu^X*ii{J5Yz}MZM0$(4eAOAnT{%?-2u^mN6X6#3IT0fQ( zX6whJcRt&c%esB@Jl2wvB69xfLC#*i#cB!4*{r|xpWoDS<9SWLT5)dEs=hncE#pk% zN~^7@D&N|)mpvH6oHbEBQX9~~$2IxdK!HQszdDEiwf8=x9bx~K-aFQP;CF0`+BlQh z%3P9Z*vHH<@r^uwKLZ#0K!B@Ri||SN8I0rn4)-8dx1p?WA#j0%X# zQH1yVJ5?nu>V5JI@8|tvfA-$z?6b$UetYk=*IB!MlDlOM_a9fG53o4kpWU?%TL`jqu;zSs%LCkh9KzN?{pIAl1a}8{ z&nF-5Kd!>o!J0DCOmo?l*g9Bq8_$EJT|>IZkC&0U|G1Aba?uH?L^otjt-B?BIeB2~ zVC@#ZLmyyVS0fK1k)`^f`78>bd{8{tj2m8ty-?R^g-&;1u4b0!Gqj?T#0T-)o54r{<9e;?myPpXiS=| zQyhH|K??~FJ+Q|g4{c+VNhz%a(anXW9@5RfpO{=yo{q)$PZ1PE`PP6g#Ty;|YGH8>&G0CHVXNM@G z7I$8yvpmlE2zefXkyU`IKFtdKkY=TR`5~xN>as6k&^}5P1_i ztcC5h%beZ69`NTgh9rBwp8@E$x&sx{7a*Q^_u^n>-Efd~wf_J)hb%$%D`1 zz2>eM_qTLCbNnus?S!{O$0^#salGuwCTPFZF#c8aox%Imy-DH$=}}R?sNThf(Ef?{ zB^5x^>4vvEH%a^XC(!<*(0&7H!27NA)mG7m?o-H}Rs5OyYzOUB|Lx@-m0Vl_ZBsuE z{|Y|H{$7W<0H-la^>2<>^jn*jmZbl=#EXcJNz(5vq@OZ`{+}W~c?kXAO!_H9=zk;e z$;7Adz4%9Eo_7NMs}4mc(0}0x^sjn}{#75*zv?)Y{>8InDMR%WuR3)+^nP4*3(&sn z`ED2Q^0;rPop522{*_iVG?_YmPXGJAp8oej|9ghef1JFw;|`Fw@)zx^Kl7mZd}zE7 zTK7@6D=0_#i~c9me?`>mMEYkA+NyCaWh{M+rT9T(nU@?xjZp>kUrBkZzlUxB<*4qW z`4s&Z455Du`mb^5e@`KFzg6@v+zgVx;zRksHw&Jo9PvW-taj5)8OM1cmgI$)!wa4v zykHP+<)2d*>ni4f<=<>_c;VE>zDr085x7DOCs(aBRJHItn_#^aIe#DvM z6g?-eANdZ!%dz+jcg(r_GB<XUlS%9Fax-#vMd=cJ`h zjeOsP-eMDX8*jj`z&~x&U(M`oHqTx*D{zLV&uk>^Cf;9!3O-1X=)Hd*MU(VhzY^^|`-I*mU@f3fLG+9+K- z+E+-uuSdsm!9crnCuJe^KR?zNZv!K3blQS$&IX^{>b~^u_Z{@k}A6dX1)Mqz+Z2pb@sHDtJ z_Sd?HL}NXd`(6J=-~47oyE%({Z)b6*blKK^?|RDD{Umd+#e1iNAklzL? z&i5~xf8~zZztMjO$ZHkPHWY{WW;f4z%}b{&_0Dg6jr1>(w%42&+QD<~uAXuO&tBvi zcJp0>-c8(H`8WDf_B=LVyLGnuH~$0j+-**FwNd|F=6^6A2YjuCzaIX&`Qye|b7B4= z-uIdr{+={1t~9r`@INwMGyh1P50LM}^yQ=w|Ks!RYtY{4f!EFHTVr0`z53(Uy`7tA zw=1o~?0DhRv#r{yPFvW&-CWPR zZI_0sC+Iww`j%4PvxajAY-Wc!3H?&t>)A?se2n`e*eKt)b&vNs#<7%opUwTuGb#to zU3|Bz@~GLvowTCuLHhOA4SnW%!usDTKz)8d+9~0qW;XZCJ`BI*k@p~dEgjx-hPQFI zd#L)n@L_ZLNjpsOsQ7a}dXnFz-rqI)Nh^I`?mWjm*?vDUPsx_K}YkU zEAi|L9_~biK3upf;aA<^t-EH=@b{*5?)-b&F#Kof>tOhkgpO^v$NWL-zRo%5Ar_&d z`YL7qfqrimzoort&V;VSuZ<0ZX2(usB+$hb@aN6c>n{EQu6S~<_c^79$8?|a0?#Mr zT<+<90ovG*E#; zUNZgI6R!t5L|2*6iTK~e-Sbb7<{s!-xTX84H$wyUV9IdU+uqI4favTz>uqOl*FE4* z@cpCEfH0vRjM>cii)IWkZv;HCZ|gqq1&n_nueER+^zmkYEy0VaGh?{Jj>KK)pA@54v-1m_rZ87>k!b$BMYI$H4}z1FoT6*Dya6h!z-cjkB{( zfd5k%AuJJQtb@lj&ccix;Du->g%k6c--I6;b76+?Kjx4Gt~HX0|ITKF`%W0}Tli%Hc2F39hw-#;}9BZG?`rHn<&Lch(Njenkj8 z&>DhtHLgA09q{5NXsL@i;$h>j&e(~6i=e42(IfTQ&3Z$4@&>#;1-m>M(8on-ou;rN zo$wv-x5o4bt$R8vJn%gK`Dz_{5zj?yKk_6nsK(oF3TF<(@4}Icv>j$Bqs{Ex`B~bV z+$pbh#_yPGv_>pvythLGkAUyG3-Su$S|g`1Zf|i1#nsTvcE()myxm%e>(Q|_cHcDa6$9eg8nwsMV>A&W%Q`mSVtf6_H-Rc6OOzIpPvPt z&gEP2`F0=m=lN{b3{xooO=#vY_h@c{E&{wS19N7xW~hKSWW(u9=<-bW0n)u>p2fPT zfp7g5_Z6~+kUghN%G?OuyvaEGS+~z-Es+xfub`7V!GWR>cK)*3_(CKt=s1Z8J@br0)LIbiR(g;25g=Qu}1ES^K`K``zxE zj1!Jqd(B%0+RQ%2u)-Q}bQ4?A>zWO2W%GS5?>EuL8r}(m4c4cHylba@F7)|_k;gCt zdkd83L&twU@3bxyFAgItTyEprHpa{k|2Y^;+r?`;NFQ=(UCi2veo!Ce(f(HW=*lGh zyJ@%DUjh%!Ztd^Pr#ugI>`FtHMPHOrN8PzuOdA8Vu>|@TUzCupgmTN+_XP2M^!E|T@%Aw{YyWslti$y2t#oB(Qzw%)kH%>%Ho%)XF~)`OHbDcETVsX7 z;9xq>;1}VmpLnIO5C4$4oPX|a#;)M?*b+3ckKpHd6Lg*jk2K=D@IBn)>E+(eJb1%} z6Caeo2YK*;3s(Z|=Rx}}TnTiZ2c5fcCD3;s^zFixK;L=Lw+mMSZRbJTE?fz8t^eo> zp_LMAm)XWXV>>nvMB5q%jX?qPb}RqYnNC{=_?H{(;$4h)&OMs6-OW2UG$Z<1Zw)$h zQ%atB7VX3}LH{n+)&clL>*{=?-&+QKRM1D-qqQ4t-UZNy+n?Bfxd?Y5tDggXnvw$*Xi=>kJ>HoYiWtHPp&IZQ63}3V`n>6cjjl9#m;rP&k<3kJbOQ92=(dE!u ziWb_ijv?GTZkX!|QYn=uE8}w3+T;|uvQGSM;WO=N; z`d7$Drq7Bs{}>0IR7(z15$mkhebKkYTC0DKjOGetE5)RrP5L>cpG&#`X%-_xxe7Xy zET$b9&I)XdPDJ1Qj~TC+*?V6#*JkWCpWM-(_MKU=cpG|+xyW{YU30)pVf`(8UNsLF z+2-<$9{hvm1%wY54dNd(Pd({1^OTcbH^)DD#5>{1&%77#d;xvG0F0i6U!XPFsK1#% z+x98XUN#GGL1=FQ*js=LLU#+m*#cY;np*&-7T|)=+ybz)02hSj7J#J%xF9sQ04y!Q z1);eq+>ctt|35)!F4}$|t+stIZ5DGw5c>tS8)DcL=rF6Gy+yQnQTjnM$U1T@<2|@B zX8yc}yHCCSW)%H_sCN+F?l5b4Hj8IL@?B8XZx+bHt+dG zt%X)WYoYD{&B0CSIMC_b16q~52bA(ZzXz1^jpQA{e)6?&!W0Kjs<;QVY7Z`9BR0VI zK7;ilXU2ZUMDq51+y1fp(%=02zI6WS!zQZ8pAj6_v5d|AH=V~53>I;aI0|@IN5SFaI0|@IN5SFaI0|@IN5SFaI0|@IN5SF zaI0|@IN5SFaI0|@IN5SFaI0|@xFB{|CbC}2W`8G}F_}A#q#4}5dm8s4XM+o6tnYr< zV54i(ZkDkoD`W3h!J6OAoL6TInm@$<4QW1IPa5*5AWa2n%1HANSUQpSKQ#Ky6_qj5 zTK}5YU%A6{8%Mq01*diI@K$izo%N=<8TrSQ+}6Tb7V8P{Itv$KZBs}5Irc7@-d$$4 zWt(N>VTi}cC)=sl^Uhtn6E$w(#9g~8^9ss%2>|;UYVnFo*CJUT_m;yc+sm<3-+FZ$oW zy^p;gm=}OMAE1AJK5l<{r)lC2L5ovcV}-xO*FUZqV0|P1Zear+6T-gzv{C{^gdwB6ba!C$6NwTK_YiwgX!?yRcQ(`TT*j1@vVf^Tgy0{m?yYUizxf zyVo4x8yEO|J^yA+#vdTf^-9COYa{EI)ckvp^an|=wX)`(F{GW09VE@i?O<3hc&{^* zLp-0$J@?ke*SrUrXRN9nW-Tt;_}Du(IoG_zT(gzACXCDW?@AksyQ<^EPOtcZdBpGj z*gFPZN~d2p!b{?f7x^aJse6ZcAK%58r?eN;o!g?_4C<7@e6**_@gK&YU)^&xCceK^=zePFPw`s2YJ)ib#B(y?<1 z4>mJz>EFyhK?`TO&WkQ%KHJN)S@@~BOa6upvF4KIq|I@#;gZ1@sxRiQyvgL9OWwL4 zvxu_tDfc?`>g&A+%pc>Qjz4;kIRLjm<5jZ>mzuver{=Gs4@^J*VS0<0$FNK8En*%k z_>lSQ^)Jj{rz6W4I)Al;37WrJ@il+#!q@!Of&c%{{Du5r$o%!z3!kOM+V`h@%35$g zYd>fH+Hg2Af6+H(tbLvN3mUIu-S&gA@6b=a&R5AkRL`D8owdft4PxylV+ zo(?~q4qpc0#a(M3cgkK(z9+-OW#py3%a5r~J7d@cuWRnozW1We{hbYxBYE4+Fl9{Q z9B?9azqo3zISYOcQ%)88@QLDI=JAQ}Vm3TK5nl9@PQ3iu%Fp0q*1^nSM$MoZgeNtJ z1>wv7!NmWfU%y`cTVfs~twmbRW4X*@rOrI&jy%si7Rz|c`S*T1G(Xg)d1@Z3f`;#d zS7fVA|CP#~x&959>t`N=fA}x4S=gz0Y&N{KmO1-lgZYa+*9S4?FWmn04zmLHrTHuG zpc(Qpf8}v^g^&3w4_xy77xNc)>h`T6`sKehhn;OFyKhvqN((3!s)lJggR)n_E< zFV;lY8_Zw$&ith`%wILkU$Yp4Vld?(=?{|LnZH<9jUnx1gZYc`U<`KkvW_Wc{&It5 zT1y<_{ao&sw2*-vWIx`(etaA53-g$}&ASbmcL=9F(^%XuT0iVebJlfVGmr62w$p}A z^FF@oXZ@C%$I>*9QMU}%d_QkZ&ST+zvzfJ62KCWAwh2GI>G(X>sdkocWBn?1G*+mmNLnjKh09t}Vy5yL=F60=E7`ev0$wdV61-3IW#OUOkr3g~ zp+F?}Nb!C9Mpj3r7$>27H7v4_xin?#U^IFu`KK9EvwVL0E%u7y>&diP|74_3WR1$) zI-BP;R9%hq%zd)@oNi}PH=BWcj* z2OEi+ex1uxHv~=HgQJOs9jA+yF9`MqE3t1Xqr} zhwPbNjl4znmYZZB3)@)#-hMc(p*@y%HT`^{^ZcT%=Z zf5qJTOXi+n#wX5t`XcO^x>pW3HchV~{WaK){uT4^uU39!mT;~yk#B#!@)Psw;eRzt zD5GRD@<-B@QkL&)Y=;&P=gg3~vYfj5Si`%9xAN`(FsE~d8OB|ME9F^??|%RvH|>qZ z|LDPvR&xGI*)N?QPy8SJD(~OmeafC`>U}Ei*e~V2k$^X5mTYI0$X?n-pZMs9Qp#6) zH}5=PN?ui;S;8K|k1yF~31vt=k+6sQk?G{+P1v}0(+1g$P+JV@oQDhG48D<$Z+~)b z4&n!)(?)#Bm^J@aF#m?(zYsRSD&fH@BPTN2nTrn=ronq%$+J>s&BfxsL3r*k zJf*#66;A8f{me6a;l}~^ZKJ=xIS!At;j;*_mykw#OU(rjg0HgsFdcmCiS1xs-obrR z9o#3?@g>_}dwd@-4}W0FergCO`>C3jQ?{>DHn0EDyQF0MdXRmjY=br8WczyPT~e}r zJ;**%w!s>4vVA@DE-Bf*9%LUW+hC12*}fiRPL^%3MqCMQkUivfTqCXom$I8$#N3jN zU7W^_!L&^s18EJHc0ogziK1gX6!-VsmnQA z$#5s^K5R7N=1S(9BIXy_O#P5_A2LV1i2ow~Zv5TWhs?OZa)|VyN zOD)YqhDw?W=D&twr&$Ns|vjktfV36M71JdS^E{}5a#XlB&U?k338i@Df+HfVLFQcq7 z%3_Te|LoVrn^U$|oq4g+=-K0OZ~5R;L;urkIYxXigZ~RWhFvknzd4tEq-9tO`-{2n zmAQ4+7-O^ki781pS_;wA+^{0;w1%Hgy0Wy)-O}et-%>KnXo-1F-eU59M}^yH`5pHp zDn80EeoNlb4?gv8manok*B{%?yfwnVxzA%n^F|n(E4iDJXP?j8_1~ZAbv<9%o8hv0 z`}bP4@mH+c!A`4oV53$0*{_Yw&i_E=x!ob^rhkGSnS9}m&VNBo`ObeqTmEUrjrup} z_urm=qy7(ieCD@rO#LHdJ?pa5D}pUqtTC|T-O|e3U9!!v|8qs=X(f*v_OL^D?6&^k zvhTj#f8UaAe*4D9{dOz!@SEtp-}AJ~ewlxYikOEly?tEWT^n8YJ=tyY6cazIr%KF7xm)p&)@Xvzo+Br zlxEc(F8f&dnce!|X%A^@ZcD_S@U05xc01u)65)?Yqh}u`edpaxdYAlHYH1=}jQ7?O zh0jd5Wt;;@x{txkw&t<0@i}dV_{}^{*nTs%e?Sc*lJY%-hU+%H3 zg&x~4TfF{LqcPT$H~;?V+Sk#oZ#^2kPxATJkNgpXb=Yvm^ac0uZtE1|sdT;%T@$dg z&>Nr0xMUL7+Up$tS+Q=TPV@S_dNy;paiIFz0QN;a(Pg8JMU6&!B!iTiRTh-C+x>fBVJBi<^O_kIQCvVpLiuY=T)&-yp(6vvA+0rp5>C} z=fvj_&Ldom+f6*3cnRTN!Zoq}xZ*2g1M$_d!T8-qX0(&%(O8^w+cZ?WGa`A(JXEIg z*-l(_m_xXN@Y>iOr@S?>z480|V)5lXd!VlmI7*AOl4c3<0>b)UeXx>vkhuEd3c|nb z>yNh+zprnA`QII_?Hi0&xiX_?1sG4pZ0X0x7F|U;jf2K(krU3KZfTJsT!4JkXR4F> z%a5;qQC`YJeIvS1|EO=qk;X?FwO#F2KNOLN+V3K4(FZ@nS0DVAw$;)uFV9Zq`>}jK zp6|x-os0BC|DDk|Hc-DloR{xK6F%}SChQ`d>Pv;wc`mxk3>ne0z=$g9UrC+A)HOso zRs5UN%)c{vBaJ7(gf}V%c%ZXuQ-k`UH^1H~NHP8WrGJO8G;+eTdwD1_V z=E=hcW({-haNk!LCSUOfJQq<~hhO~f#0_u5!q!ad7OQqli#3A(6xZNiK8!t^)oU#r z#=X(59_yN6wox1ItzV39jETe_J-Sx>to_`YTLQM{vC7^Xg1J%Ex!moESV7V;Cs=d% zK8Y2#uRFHZ3NJof1}22uKRA3HIAJYz*xiWlg|dxj2#j9{z#*&)dCqZ{y~VH=bIMWAqGoMr@hs zHV*9fWNjHfmj5AKp6JY5j05S$xX7b9U>bd2YK)GEmVEf)85h2A#Z6exL=%bUqT|sH zt`zc2=^Q%2PbV%O_7k2=Sah!MmHs^9!j*vAh!neBk$Lp5n|Ie0KzSr2QFUF9!kM|mblc}@%%|l#uS0AbEsdj6uTWP!c zS8dlg2&-SDZM$h#y59W*_>rO=^^1>kaw*S4IFGREA{ufLRy~9t*=}!i%4pU1UF!c{ zyqz|*Q4VLx4u1GX8BbKfCn=n8LEoi(udy}2huqe-PM3RJM6!TfzDolm{8L8P<(@Ju z@~mMzrM9{{RF`oPm-dlfLwBGY$lZHv(dQU(&6t)3VZ^my#Q8~#mZ6dtdF-)g{v8~V?PT4(d!sl)6r_)$G>nBB^H!W0e^4YRBA zhH)`tWv}q0!tISzPa0;YHL=lmGe15k9Jw-yBMTBZG6(DkUzNa-`Gom5*?QdLtU(+c zdHgtztetZLju_J&9Jzw}z5$M`ema38|1t;sg+AT}M~tT9IC2R%GHS#maOAzhXizxv zzPGj(9GRa;f7vONHzhS;hH^xV_ zKJnA{0c`swa3m{HeO?{#7^_{RrV=tW1dZwQ~bWva7N@9JI5lP{TFgTAqg|8``xrJxK zng3OMQ9r0}kK;?CzY_S8pe^Bx#zOdlUP^Qs>yxj;mlD<|U&NR9y#c-t@_hexd>IB#w0nB2(cp>&zKlxX zOULG;Yi|foa`qy^3GGL=-gj(m-4}Jk7wz{nh2P5WEruHbSw794$mhndKBIMoVe@|iPtsPibu50NX^4T z@gbAv4z7?+7~|oaGMv^QDU9(Feg%9`{AKXrCE)|l{sKN|jqW3T7iBIXoN9k+{gJ|l z-6!Bf?^oc1)*ouO`bHS4_9xaK@Em!k)*mT+5H1KGgpaC&uuAksW;Mw7>XwSP&`(~0=tQ~N2`?bHWsBrKZy-@ykL<0pId$MIq87x1AC zd}v7GgW7EvVN0iLU9`?7y1|BH1u5q_m*ScH4kmW)2E#@O*E9UITe{=Ehj1}IKV?UjEWybV| zwC@_mrSGh`?Y{6G0oz&^u=_GL7tS$^?r&1=-K>S~xhqIQqOl0>;SkA7}5GOsSEqS z;hA6rWsmY3IoXzxvwcQG+DWZO&M3o`w8yD z7jczeZlp(xW3#yKzR63yqg4}(1!}{pBdkZ0=tslDs*J8&v9KpDm4J&Syl z$2shqPi%vW`Ww_+dh+TQg{$~qDVIFd?f_-^$v?>ZW^7D^y~dPT(1C0cP<|x!O%S~W zr7t0^bmM2UZZd_p=vg&07KuoywTz z&0=5f57^(H8nCBd5wI`1I$#G_YfpndTp8pw+~|3eb?4;QPODq9(PN*2|1LCQZ7fE% zc8aqXUU`Y+(X~H?Ue92T6TP~Sf%;gl`u0nfHtW9hzpvO`XryQ$ zje%xQqrW+=G1#2mSloPK-z$D{!)49qH~5?VvC9~*%i}o>mp5lO{Bv`Ve%H7f4T0ti z-p^t@XEUCzhG4V1p}2Vt#qLYg+c3M?(=e;~%Gm7qg4mpRTEm>?^oF_3SH$Kr z7M^I(7!jQt`yT7B5z(sij2_j0zC%Zs@!sv|HmPjr=Rm65RC$vrJ3tvKZ!YDXNJAd# z@21Wg^D6qupzbcdF$`}spEl)@uaCCm(w1DFRYOD82;+%CY$Sx}PoKXSRVl{7UmP#@ z8_{a$hL4|$jc+bge;fWe%`yL+xceldCj{?n%=J8|ac}b2Wv5~vYQ?E_6Af2477^@s zPcs$?Bdn%kJ8&d$-x+@yb0Bb7XVt;`mO;0n3y;&px@jK!!SfyYDsqyu9om=xZR{LE z8*XUB4{i99v@s0YxYQWdUBY@K6PnI~KJvk{GnktOJ*S=>8DlJ}rhbz>o~SXe(R;=M ze`$l<@& zGt$iB`F5UdeEyq~VJ+w&{QKv>5vk$1@_dXusskm}?Zmr?ZzOz~{O5}zzo)DU!##W# z--LO;l6T4{MT@FWB9DT|ZqoEIW~sVuB;Thbqeu34&AC=ReY!SP2{KV_dv^P%b#)jrjoQ9sMp?DalDG~erRn2dHk8QVZK#A zRrCAtO}Uvf1-% z`jhn-pzLKs>QiRgLo49UY`e_t=t=T5jGmr)V8hb<}N7*m!iUkM)J-B+W(45zB8x=2=O*s*u5W zvwu3tLOv5_pOV3OZ4S0uO3(A#%Sr9hUtxVDEjzRrgPgX?4raHSFtyhP`YB`Jmsktcds}#P1|d-;~p?WoH|9 z`82~We!yFI{e|Ej^+fivJj`0?M)p1{wLZFyGS(R_>!{xz#^+P!(j`lbmL<%Y3xB!f zNZALs?=G8zUA5chw%oA9-*Ok}=a6Ox=lkxg?9+U|y8g%wXZ!8BJS#ibZ@+D1cHdBh zT^PgNJ^EK?9l0S79e`iu9r?WMn=)D+8wtK$;y}*TxA!o&E;J@Z{=&N@(>M?7KRv2vdp+4_ck%3@TQXYIuFIHn@4RVl%U$GK zJ~98?_jo@HejCnN<_&ZFw%=7YY5wx;)6U8rUUviXr+N9O)t!}V^u(9`Kad#Cd#(Gx!+i-1@gIuVJql zF#1ft5&KfyIs0xn#QT_Oah_f>tYlKd(r+FqWo|SmGxn2j99e8#_smtCU%%-dih}_-Hv#@*3qwcFJ9t2AdgmQ`1KrK5y~1$D*!5e^ zGV)H3mLhA9^k>-_kIdVg^&@n#3jB83RPHQ%VE$$geBquBy}%FDF*+9>y!(wTd(Dch zy1VjRHgi?9dQX=9is9{EISEQvN%`fZ zq-y{e_(%7>}KB2RyQrYTr_Klgy6w)KC;Ubb_y9xUU7Zc7UthhnEfcR|ZeJ1hr z2&a_9^12P|pZj>$%pQ6!&&o)1i1=i}s$)Lx1L7IPO9&q% zyb<|?;+r@h*^2z`-&kA5dHw{lJGDpcRbMC%^-CUZfcW*qiwO@B{x|mUia*Uh{zK#w z2Y7ZE`9vDeRL(}?tlyCXCECAe(jpgo?v^L?cgE*u7j8o`pTxO-g6|XQ6MTO>{pWm7ddUbSqibS3zKZWt&&2;BXrYNR zTS+hZq;xeT>ubYFKDnNHOZF-GWZ02Uep$al^^@Fg3~9OuONLp3+f7_L2`<9DglnLE z#aF`rtKt8l`V~Q*OTMK(SwdKCD8p?ho=)6PxP!3tD-=)ZSM=~q`V}etj3VL{yziq; z1GHr&apk>-cBqg35&a6aNBwdZynPkl2rpFcfa-^@eyD_Zq*E~yp09$3)b@m2FwJSV z+TbC*@~Q?4)b>=n#rGCGu0Dyv_v-g)IO$j12medI;vYF5P0^K?Z+(=b{__k8yOUw{ zrOM3wpXgWQCiN?-pxtWdJPb{zXyvPXV_w{A(XZv?k38pqbSC^m^()B3w_;e`aA)uE zPGOjQzo1_sp7HNHu3xeAm7siTG#&>{fRSvpS@h`9j))H zsf*rgUo(sK@6s`>*?p}0SsRxZ1nk^J#%a&|vf{|9bk-ei_9>*PJZji)8Sd_7k}bTN z*5abfe*WjS-bicFoWe%~a;N3e-5T_a+af!UF4kcwJC7mC*Zrw& zH=lmxw~@zX8Lmsa#u`(}7jaLY7h(4TPyU%{&yj~@oacZo!X4Rud~Tj(oUZ8i&;xek z%XaD&4evK!)zH`M^BFmpLQ{(yV$F*h2Ab2!+gD=bENtj+4mQM_PbMDYY-Lu%VDs|E z_nOO~>s-soaq-{C&5iFjZ^G}y{i3n2`M3DDHpZG4;=AC1bIAKz%2q z_-XJ&o6+FSfcDR!tRUsyMjGWgi*mn%KN_Ae-3{I`;K4Z!M$Q$~WeI6i-U8~PGEW01 zYCR3!Q{aN<-ysx4i#&uJTSv|kZd z8&r3-L3LFfu+tMywL^7w(+<@$n>vm#ywL^JQT55gSAW$e`%d*JrEePfUj5Yl74q94 z{h+Z8P@i(-XI{q9MZAizBeO-8TScB~S1t}aXYp_!I#qqK_}z?g8uGX%WV!|9Ejp@V zuB-A%R-5=wF;DrCcP@F##) zvM$SB!n*=oiDB$&<3CTGhvxbxMME{bzm{(ngnRpr9oy<5O|CUHYE*=KLrW5QDSfX0 zjA&?8mR(S$231-!x^} zRksnIPk3XNUHaLv{kd0M6s=#FWrr@$vMcZ4`IapE-Y;!iY#>&6Y^7HCryvQ|Zqmz5o|uuTsfg?OygM?Z`?} zbFJ2Ax&7#uFz&6c5zhMTJ@(wHM;`9ww${$~(EBPT{1V~3{`cZHk$-;w`|$$yMr}MR zWN)Opl#?d0MoF~mT;eB_zn^#Qt=)@O^T zgZkh~>hL~$s)f{J0rkj6S54#N=&#Wqee{F+M(Z=xe}H~a`~1{H`CUL*{iL?5UzC^f zP~T|W)j#SR?a_RsQQK4P)>_F&nYZBQlZV=`HQH3#b^-0m0l)u|^;s$TmhgQ6-?|8k zM)HS*^O9i?&vOaC&;BeM{j~zxl~0}XsB13uoPu7P^k0oH>96hcstk>7YJb+}IyLhC zko{TP#1VDIDd~~ToU4fT4Cp(zgZd27U+YWm&l<;Cy}m5#7G!w6)~h)!Rxqol{*9cL zl564li@?Hznf5~;Wjbfa^`B(grPrd1b~Mx8*}xtOUHDlpYvCGXHpaKYz2Ni00Dckv z+DYJEQ%27^H}ap}OuK5SZ@Q0n)%Yd6x0dEkFCmWZ{B*0`8@1lZWX+e=6LP0Tt$xBy zJllgG&g!xDQU26$uOPv?5L}!GzAHa`<>$w*QNH-fuNB<(H29*Ne@CtJNk2FF?InZ* z$#3zUZ}FXP@twN#d!zMpMz>hwNbBd><2fz$MT9B4eiYAxgfHj$tC@D?*@@@jbHVdz zVEHgGeH7u*wEfg9yOBOBS&Xi~VMJr|(Z88%)s`*<%jmCxIpF*{?AXuZ-;mi>?L%Pb zK(ST3Ct%fvz~a73H4jWa91B{t+Vh6i`0a=EUxMGNt>(XjYSM=kpQ-o0!zI_S4_;d2 z;IMV?as3@V7v=&Wiyqv09CO#a;I{AYa@!BIC$YC=tRpX5M4exyu`@k7EB#C1-PAF9 zZ?WxLe_Yq^EHHO9IGiye3*6mXcn@_m=KbBfY72K|@ZGy$@1x-EysNx**gJXZpBy>a z@GZx{<@dneWl8Kk=E%t=M20(ZvT^S&6+rgef z-UpP9XFmKn#B&L|2~Q^MA*}R%;x`kYf^&f-9i|Le%dNYl zR%IxE?QgsI&O`Vwge3=BLLMm@P#e!A2b#mPGSa+4yoj*A&&O&1r}iu%EbNkOsFiq1 zKC}&-5&kCRW8>JPC;C8ns6X;>+j(D3d=B9X!vD%1ay#)S*+*Utb}Z-FVsK7v*Z0ET zLVcfX_a@@%FSTFz`+ear@rB^;PB3#3_&Xacd_Q3HXpDrvt$e$k^y(YU8?E$--mCrk zMq``m0|%ceS8Y}sQ)8oXQQ!QGXX-!ogW8{JyD+$c_N(o}UhR+nSLI_R^*n`=U3=Men$eKWhxbxIch zAxnRleg}Jf#)QxH`=+ED2ik_p$8O7MX#j`o?*M<>GZXqdU728BdWEOX`a`B2^PIM&vet0q^RF0b-7D`k?5d|T9ohVM>XE-KM*g-S zu`cbu>;&0-jmHj!vp0vshJ8;`XYg~m{I=tGbN}NG&a8HqoaNxmg|s6E&aA#SvBvwC z8o&K;%|9TQ4-0FgTa5j&RbU(Q`i&{QLFDr1pj&*RT>hP;-e5{D9|3Pta@1UCKzkN9 z@*W?)@J2FCH{ry*oep-SgD(l0t9a9|bUf2{!kg5$iM8HwIeu!b=lTca@+k}&Dxd$D z{Ku1jD>ALU?o3BsueD1X@)yi-GjbRCSmXd!0fB3hKZ~}i4;ROC9 z`cn1%|3W@rf_%O)DW7-x#lfGkpW~0@^MRrGbAC=stMF$U`15cQf11FP{$V}V7Oq?NtrnPANCaQ^IaF;ePnpLUou?XKk=k>Uu}%#KTjYY%8y6PVF7*Cb6=IHkf z+wvQpFJtZFXRl{SZxmVyB7;Gn?SKLA7|3A^7NOo_YddO z2TGCAsekT&Hqk$8|G=8`=~Vv|I{owC=^x2J##SWczO>Vk``$R)STvoz1oyQ#vfc-f zrFuyNEi8Yx*jO}K`wV1DnlI}cGMBI9y$f0I|3J>$j-0oZd9sr^aq>j(Y0o3?{S$P% zojLP`2EX0C)o=gHLG;Uz`C4xn_U~Qp?(lmC|KqTJe;L`yKJLaVnz-3|)v!CE|2w-3 zd(|Hd`}v3X{`Y*l)3A*VX?1^E&Abb*RQIBT@dDp%9KSixoL;xt<>_Aav|+DzWp+ol z8TOg1r^}I7)I4t3n~|?Q;u~4_!ibS|-GtwP9;+56WX+Czc_TE`a!V6pOw*PZ@9RlD=B*pBX=%F?mP?Ip0j>FYj`Dnu^PFv=a$p2EJ5aXx#79A zVXhV5I?b4hLhQnAv-`Z0h8YX;R4?3{$l4DgFW$@g{Ui9Q`#kEz^O5u3_KuqOj`z)C z$sJwMldv~Yg?)xx*5NobR7xjMR#rGitUehqpycRj{YUI8(*ff}l+ki81 zuj00&Ls8lEz8S;jqz^wtyb)hE$Cu*YfPaHAU}m9jQHD%%BJqhv%$$Kg!{{@gxAvH4 zg<_`cJ|Dq0y$@OAP#XUscIJPGo%tVQbN(ph6;sZ3@^y#ym<4%8P7Qsri8|MN-ZuZl zySI5a9sdDq&~#Bw3+)&*jEMFG9~mux`yv+MS-uF@7 z3)JNWV~@Fmw7Z+`iOV*{9=`bAY> zX_h_Giz(-A>T?$FH!x4%R{5!!4=p_1u(z4TnRA}6a+Lq0++XoV<=@S%lqtH?d(}Bk zxtZjZ$r$e-?Izy4p)q}Pg!=YTr;Dl6#f;TA7%S0hiZ+WWuQ1P*vxz#bg?8@X-is8y zR&!1unhaVob9It-UZ%Xg$vzT|-bFhfq&(5TXiN3kPMIm1o)UEBDE$MZ5k0?5ofZaN z(W9gpVBFp~$5n} zdWC%U@Xd4dX{%?Ow-7ph7<*ikc>f`Jyh8t~4bQ+gxzKsJwa;v!o+?|q7e^R}BgS6r zf$T8FXX2M9pvMc=-xGh6cW)Yd%vNZ(fIK%qgN>Avt8$=G4}8)|T{=BS%^$%hK?@u9 z%A2}AO?&zA#L4eBjG4i>ba4lg#xZ0Jngirh9X@34rGAdxaK8VTwy5tvcIxek#Q5$F z%FhiSFe{*6@wn>PfFENl3Zcy@ZdcB;)*-XOX;b2R(c4GrU(zbS*U9fA+EsuJGDBm? z_nOBx;J?EhJ`}TthAY8TjpLL&BWHDTj5VG<{#($q9lTo@M3<8Beq*?F^tXA}Q+5T| z(n)#y32&m0pQis+p6nKqr|F^(T#V24@L|e+d&*Wz5j0l~-3%}$Zs=HcZDhMWKzM-h z7Pjo54u!0BIx~zZUe;kl>pV29diDhlI#{9l%0AJ;Jm;>>NVEPApuSGMm{&p#mSZ=j zBROWShOf6DV=xCPeHt=TzOUA~lg^lQzU02+_WLBqp5@D`3!XW=Zj^_A6qw&)8SfQ( zD5rU@Rjqnd^NmISdC4n4AN2(WnwvTMO4zQcj5m|t*VUn#a?~HW4OPy+4*!~d{5&i7 z-;XVdf8VNI$vR}<8f1JwuxjgTvRfo`ed}sufAcfB*Oz_x{($}W5kdYr2-@$UOZxVh zpxwVUVDHObu(_nnuw&UlTkFaPZqKR#FU4>^}!C%I$EZH9dj z=Qpt>R_$8Xgzi%GM(dt^_^5(Aqh>o=G`y{`3;!2|2I_c`f=u^15o-)^K6Xz&qP*SjvV+lzg;I8Z-wN; z_%|eEFasq?dGU3M=N;}ZBduh{rHbb|;~5&p-Ybl3MsnqAB_oDjew;{mS?b@;aN^%i z?T^;ndt6rYz$&-BwkElr^!uFkXSkz3S;9U|HVZ~` zZgDAcnmpuZ(yJIO#L7w&`i2jKhnz{Ymh7v;h!43qpIz*$W@^GT~Kp+B_~d{RB6E2Q(eo#3qW zZ*)Evbk66-MT$AsnT2dt=X0~2^SN=6n@A)1XfgF@Cok1kvIogYJ%pzdo`Y;w^2WKy zMy^0EaxHS%LY^<+e5#E)mXj`z_~oQ2RT#IOG9-7roUr5&-*?XE#zhu$j`h+&;(Ttm zV_yRKFy%@`Tm|J;l^N zK)r+1d7=C3>`T1u6>aHzF!?|L{mFjLHg!H1h{YWH60TD->Pk+@##W`y=R||!zjQt) z{mF4)ZUC&UFUoF-dB&Zs`64tf({9BsP3aPFC=VR*hI=16HGv)VlQOxhKGS~g!J}&j ze*&*-zFBJ3P6M~=Z#}7H%`GRjJk*|H*LP*uKK7+~>`NV7SZ3AcKjXJcY7N`>h~KUh zru>v=nanp6f{rZ5;><~NM9G@u{BWbN1WfvGR;|*f=7|!`4bNs!x08BGn47E@2)BPH z+D@Hf*wRYP3&r4ji73re5?;C-oKoA`!=P|J1qV9&{F=-xH*aa|4#zb`)*2LzjR=| z(8nmdrK+y=Jan#6YNpTKtSmhV$P{l72yk#pup9iw*?+mbh>>;!%3 z%#S)aXMSM2zPk);ch3C4_AF%ZI`fNx={gtEnO`?Dco*2N^Q1!PeHqxE;5p8T9G?5) znV;V2ysemb;wKkQXGXJ#3;#+8mpRW9XMU;l!gleL;s$9xm%)QgUw7u0!gl#7`MZPf zeE)s&)B0ZLi8{}EnYhluiU|LLu;lMLdrQgROL->wyRdINX@u{ovp_%b-NaL8dA)=s ze^xvtf7kh6C(k8&F6X(@;JfHV<6b~M zq5&6S(U34*XQwX00m2%KJi;fQ|1}~HZlauK&i!t^DhTGp10YI*2F-d~boyCw#0?>Ba))BBvIhU(qZ{V69v>!0s z-Q|Sc{-9mKIoh-p?z&RL)g5LHU-~fngI`;Iu)e za7O*k=`-rjy=VsVP`lENZrDOtaTIzS=){JVgYIxpHnn^rg${cbN z{^j@!GwdR@vxaqh6?n`%@}Tg$T9}Q0m#`U~kC5W5$E_rGS0=GLoWO4F!$QL@-E7^K zT(|!wxo*EBkuG(|hT!{6=yWV~(|%*W+nDKKdu(mu|EIgINvzxN37^$o_K#a4jY_(Wfv zHFZKiOnoB#IQ5C@p!K_S`XsaHApCEAdmJ6VZGG5pV*TF3v%j!@ADJv?Bk^w%4kdL8 zHxXAIQu=i-IqUcFkr$Ke_uZ`D|9rywUHzeUH_|u4X!VKK>1w~$>{_d*`d}gNrGFQo zeyR3q%%p3kzWEvNJ;XJ(YJaNj!rlhjueNJmore2Y+V&Lf8VSDtBlcOO`=-7XzPkt; zgoWek;}lJ4JTw+6FSUN(K)ciywV{!5e2jIy@ZI+%{kpfjDx+NW2jBJoQy>374b`s; z1V_}hP8c0|)LFl)4qvv(@x?T9*x5}zrvc_+>lE;JnqkHNXk8D}HaAeCs1f01a%y>K65*hN(fj zc~;P_e>&ZM@DJ(8fN~H2`-=2B>4_!Q=Ew)gJGLf?#pqpp0gG2nonbY(qoMHB8R43# zGb;C`+vVt2ti6{q*5TYI_gD|(hr!?`{5;|t@yn)0t&h^3b$FZOt&lBr$sA2AszEl{d?0`f8&Zqw$wj6 zl7BTw+lveH-OKp>--_1PjBK%v5^nl-w0=#xUEiN>uiJy)h5tgj-LAH-MF;w~VCZ7z z3Gg>oi>}>$R&AXy_yOc_QEW4>MlQFs{BY$$>DLt;9=unWTa?hP`sF8bSaRL1cPV|l2bLVi=Cx(~6LKy1d`)WYJ<7r7Us6xm*E=Jr zZ+91Ujow;p8$0Gcf#i-;Pc!ccya}@to;AOX}G2ES-}WH!krXfrsOIqTsl$L zIfcnX{h|0Qj1fLd?^pQ?Z-p7cDdDZKS3I3hnJH{a;j`*2Ed4oYgx|s{A5Pe`6WkR( z^@5YaCt+<0qqc!hojeytsV%~R6h4;{PT{k#Ev5e~e3t(6)8N?9^>;aGQu@#T6+VBJ z{_|zXIfm*#Uq!uBI^kN2YkX7(^-T)5)mMI=>AMtepD_fth0Pa`Mtw03UpVf_Vu%p{W_ zxS^=|^o#I)pU=z(hlt&t_4Rx4$LICA`#tyEd(S=h+;h)Or_aVXQiKbwmhmC@ci=Yk zpM^fJqc59!(Pz`w=<|Ela`H>R2>)$@K1WmZ*_4v6G!DtFj}Eb=X9kYeX%W1~0095!m<7tglY)vQ&~kY*sDdfNKBztU%qi4AoLiSgC|( zb05QeTCgcFq-TTK)E#l4jc{gf6C z4DV@NdEUlI;Pjqt`AS=F9?`RHkkZP(Ja(Vr-by$yxF>2kZPPaMke+n`;)W?L7y6~R zyVAJi)}DBYzb-tIa<~)HSg15pOMv?;oQ*w!jg70-xv>lVb32{%Cz6&sDDevd`W=*xXMJ^Fa1SL+ zzGqVOSnl&m{;8BBWt!NdG*XW6&-t|7xPuZshShrf&p^|qPxZdMakAc*`SfKJx*P{y zk%>g9CpOt%w~4kj1N%nm6Z!Yqz2x6Qs|`9GqkYk7{yL%6n@RsT`6Q3%N6*0K{^Hy7 z>m$g)x2EXzHsan#UuP-&w9xBq$V&1U>pAe#<-BE6fnJ61G==;N@Voe%@$-Hb{{AUh zNk8asKWIb$@t-vBMoY#i^J@QHUlX07onJ$<5kegbOn>q-yA@3EKt4JfXtWbxc zzy7X}@XR`_lr1zb1NpD`Gm%Z?A(t2lT@?P=j_kLRaA~K|=OWzFPQgu;_U3q^q|D5dWBz;cePw2DYSYQ)e%Gi=Rq|P<)$y?En zw$d&OFq?tZ1e{`bS@`Gh*W@Gb!9OSa*5IH0tc`2Z^rIVx^iQMD0>fAG?|B)z9Uxsl zIzE>92@man7cR%m9DX)7##gs(Nx`$xA<#>BT#<=KNBio2Bm7y39@i7SFi;mSmbrae zFpLeviuFp9`R}-&IZd3%pc{oBJlj_%a_C~dNRy?#$(%oRU4H)5=ED4`jZz-=NSZh| zY~^18ZEobhPRzZKA7iB6C^7^$6`~beFV80;lyPihOm?z;h-F1*VdzZT#0QDV*BGznOo4 z|2F=W{DrpSem3sV!+PQc{3qv6eGVLi1NNS9+v6 zuz65VxXs+YEs)>yT*f&Y8_o8f57u&@rAgQA3`M8W#`6Pp&q{ly29o%vol6y&rm_6ZQV-G2Ic^SDx+EWUUEd>oz(&P?xCo*Dd;mQxjSpEeq6j)c7eEw+pyy z{dF6}{hY7vUDkn{s9(OWU3VP1uPWed2mbB;idZGOKdhsjbkFOU|o4#JG z1UH?sUYwa)FDN@koj<275z5#^`;Rfl=doTy)8sDc_ZOqU6`LaK#R2P9fsZykPQE8` zOI|rY-EjNJ`rUk8tQ)VS?ld+KcMuu-X4Vb4)7St_vLd6Lqpurw=zF>?emnEru*GkO zW*fHnCEU(j{K^);8Mh+L#b5Y*H*QHk6So7mIhB4Q{<(ZEcpMLXa0UFi*=#>y-7t9k zD@o@^UR+38WzN@W{6z9dT~f~gXzxVwi{1QzxC6-7Z={}T&F+ehLN_1HEby~ zU+m9xLd(}c`=zgB{U`t*4)7qj(fNB|DI$M9`K4V_p78F{cLJN>Maq&g1UE7U1V4hC z%6!~Vo+zr^1Q9xBK$cqzc`z->u$n^SJ7 zL+Zp%RcH{Y@CIMm=da-Gcxl@D(RzA5_iK{(8wD38UB4Y!KYG{b zw(Iu!<@_`@)mJx!_2VthOUrS8!J6^x634T#^L0A?>@&=Fu^ACP&j(Lh&=WmZ5ATUh z@zs^Dcf!Xa*DlO#Us`wcq1d+wDwoHUZ>NUVs+?cbiQMxi>BzvW6b}J%>U{1Z@Rp;2tG42 z*P`pd3(bhaTZ5jOlKunqux20^C_)#!5?Ud;7S~bdLG(RDUMqG=jCpDNMgLpu zcDlboKi>IQ^y9^zjp%=42SL}5cQK|!KfZN{C8Zy4)Ahe=IEN7Z@9pS+XM!8yy^Xz< z*_XTrK1uM-o+7$Ia9Pn)$hymV{H%k$7r0yg0XB=pA5XP^`db5+%i6Jy_B+v=UdVaJ z0c>$f+BjthAMZd9x`aL-jV`pj3%!0x;j@Ljc{vMR=rOrjbN2UDQ_So|GWwuXNxm5N zUMJ+J1s&%LU5;AcEx_h3@}er*7erUTBK%RLGK?*Ta4fPg9FJ6iI|G*|`;Wucf&*Q- zMdTZg4L9+-8hzN3vIf1BBXNb|Po=A%TqB()m9CO{BwcY@x~gzTM9LUXzR`qVjC*0Y zQ%@IZ^LepJ@d7p}td#K{cwP_wBTK&DvrBNG
Xo=Lk# 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

6{y$Nc%o{?#fJ&-KkfuWPc%d<~BES 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 literal 0 HcmV?d00001 diff --git a/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 b/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 new file mode 100644 index 00000000..87abb788 --- /dev/null +++ b/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 @@ -0,0 +1,254 @@ +#include "scalelib.h" +program test_mesh_cubedsphere3d + use scale_precision + use scale_prc + use scale_io + use scale + use scale_element_hexahedral + use scale_mesh_cubedspheredom3d + use scale_localmesh_3d + + implicit none + + type(HexahedralElement) :: refElem + integer, parameter :: PolyOrder_h = 2 + integer, parameter :: PolyOrder_v = 2 + integer, parameter :: NeGX = 3 + integer, parameter :: NeGY = 3 + integer, parameter :: NeGZ = 2 + integer, parameter :: NLocalMeshPerPrc = 6 + real(RP), parameter :: RPlanet = 6.327E6_RP + + real(RP), parameter :: dom_zmin = 0.0_RP + real(RP), parameter :: dom_zmax = 1.0_RP + + type(MeshCubedSphereDom3D) :: mesh + integer :: n + + !------------------------------------------------- + call init() + stop + do n=1, mesh%LOCAL_MESH_NUM + call check_connectivity( mesh%lcmesh_list(n), refElem ) + end do + call final() + +contains + subroutine init() + implicit none + integer :: comm, myrank, nprocs + logical :: ismaster + !------------------------------- + + call PRC_MPIstart( comm ) + + call PRC_SINGLECOM_setup( comm, & ! [IN] + nprocs, myrank, ismaster ) ! [OUT] + + call PRC_ERRHANDLER_setup( .false., ismaster ) ! [IN] + + ! setup scale_io + call IO_setup( "test", allow_noconf = .true. ) + + ! setup log + call IO_LOG_setup( myrank, ismaster ) + + !------ + call refElem%Init(PolyOrder_h, PolyOrder_v, .true.) + + call mesh%Init( NeGX, NeGY, NeGZ, RPlanet, dom_zmin, dom_zmax, refElem, NLocalMeshPerPrc ) + + call mesh%Generate() + stop + return + end subroutine init + + subroutine final() + implicit none + !------------------------------- + + call mesh%Final() + call refElem%Final() + + call PRC_MPIfinish() + + return + end subroutine final + + subroutine check_connectivity( lcmesh, elem ) + type(LocalMesh3D), intent(in) :: lcmesh + type(HexahedralElement), intent(in) :: elem + + integer :: ke, i, j, k + integer :: p, q, n + integer :: EToE_ans(elem%Nfaces,lcmesh%Ne) + integer :: EToF_ans(elem%Nfaces,lcmesh%Ne) + integer :: VMapM_h_ans(elem%Nfp_h,elem%Nfaces_h,lcmesh%Ne) + integer :: VMapP_h_ans(elem%Nfp_h,elem%Nfaces_h,lcmesh%Ne) + integer :: VMapM_v_ans(elem%Nfp_v,elem%Nfaces_v,lcmesh%Ne) + integer :: VMapP_v_ans(elem%Nfp_v,elem%Nfaces_v,lcmesh%Ne) + integer :: Np, Nnode_h1D, Nnode_v + integer :: Nfaces_h, Nfp_h, Nfp_v + integer :: NeX, NeY, NeZ + integer :: vs, ve + !--------------------------- + + !-- Set answer + + Np = elem%Np + Nnode_h1D = elem%Nnode_h1D + Nnode_v = elem%Nnode_v + Nfaces_h = elem%Nfaces_h + Nfp_h = elem%Nfp_h + Nfp_v = elem%Nfp_v + NeX = lcmesh%NeX + NeY = lcmesh%NeY + NeZ = lcmesh%NeZ + + LOG_INFO("check_connectivity",*) 'Set information about correct values..' + + do k=1, NeZ + do j=1, NeY + do i=1, NeX + ke = i + (j-1)*NeX + (k-1)*NeX*NeY + EToE_ans(:,ke) = (/ & + elemID(lcmesh,i,j-1,k), elemID(lcmesh,i+1,j,k), elemID(lcmesh,i,j+1,k), elemID(lcmesh,i-1,j,k), & + elemID(lcmesh,i,j,k-1), elemID(lcmesh,i,j,k+1) /) + EToF_ans(:,ke) = (/ 3, 4, 1, 2, 6, 5 /) + do q=1, Nnode_v + do p=1, Nnode_h1D + n = p + (q-1)*Nnode_h1D + VMapM_h_ans(n,:,ke) = (ke-1)*Np & + + (/ nodeID(elem,p,1,q), nodeID(elem,Nnode_h1D,p,q), nodeID(elem,p,Nnode_h1D,q), nodeID(elem,1,p,q) /) + VMapP_h_ans(n,:,ke) = (EToE_ans(1:Nfaces_h,ke)-1)*Np & + + (/ nodeID(elem,p,Nnode_h1D,q), nodeID(elem,1,p,q), nodeID(elem,p,1,q), nodeID(elem,Nnode_h1D,p,q) /) + end do + end do + + do q=1, Nnode_h1D + do p=1, Nnode_h1D + n = p + (q-1)*Nnode_h1D + VMapM_v_ans(n,:,ke) = (ke-1)*Np & + + (/ nodeID(elem,p,q,1), nodeID(elem,p,q,Nnode_v) /) + VMapP_v_ans(n,:,ke) = (EToE_ans(Nfaces_h+1:elem%Nfaces,ke)-1)*Np & + + (/ nodeID(elem,p,q,Nnode_v), nodeID(elem,p,q,1) /) + end do + end do + + if (j==1) then + EToE_ans(1,ke) = ke; EToF_ans(1,ke) = 1 + do p=1, Nfp_h + VMapP_h_ans(p,1,ke) = lcmesh%Ne*Np + (p + ((i-1) + (k-1)*NeX)*Nfp_h) + end do + end if + if (i==NeX) then + EToE_ans(2,ke) = ke; EToF_ans(2,ke) = 2 + do p=1, Nfp_h + VMapP_h_ans(p,2,ke) = lcmesh%Ne*Np + Nfp_h*NeX*NeZ + (p + ((j-1) + (k-1)*NeY)*Nfp_h) + end do + end if + if (j==NeY) then + EToE_ans(3,ke) = ke; EToF_ans(3,ke) = 3 + do p=1, Nfp_h + VMapP_h_ans(p,3,ke) = lcmesh%Ne*Np + Nfp_h*(NeX + NeY)*NeZ + (p + ((i-1) + (k-1)*NeX)*Nfp_h) + end do + end if + if (i==1) then + EToE_ans(4,ke) = ke; EToF_ans(4,ke) = 4 + do p=1, Nfp_h + VMapP_h_ans(p,4,ke) = lcmesh%Ne*Np + Nfp_h*(2*NeX + NeY)*NeZ + (p + ((j-1) + (k-1)*NeY)*Nfp_h) + end do + end if + if (k==1) then + EToE_ans(5,ke) = ke; EToF_ans(5,ke) = 5 + do p=1, Nfp_v + VMapP_v_ans(p,1,ke) = lcmesh%Ne*Np + 2*Nfp_h*(NeX + NeY)*NeZ + (p + ((i-1) + (j-1)*NeX)*Nfp_v) + end do + end if + if (k==NeZ) then + EToE_ans(6,ke) = ke; EToF_ans(6,ke) = 6 + do p=1, Nfp_v + VMapP_v_ans(p,2,ke) = lcmesh%Ne*Np + 2*Nfp_h*(NeX + NeY)*NeZ + NeX*NeY*Nfp_v + (p + ((i-1) + (j-1)*NeX)*Nfp_v) + end do + end if + end do + end do + end do + + !--- + LOG_INFO("check_connectivity",*) 'Check the connectivity of 3D mesh..' + + write(*,*) "** my_rank=", lcmesh%PRC_myrank + write(*,*) " tileID:", lcmesh%tileID + !write(*,*) " pnlID:", lcmesh%panelID, "-- i (within a panel)=", pi_table(tileID) + write(*,*) " local mesh:", n, "( total", mesh%LOCAL_MESH_NUM, ")" + write(*,*) " panel_connect:", mesh%tilePanelID_globalMap(:,lcmesh%tileID) + write(*,*) " tile_connect:", mesh%tileID_globalMap(:,lcmesh%tileID) + write(*,*) " face_connect:", mesh%tileFaceID_globalMap(:,lcmesh%tileID) + write(*,*) " domain size" + write(*,*) " NeX, NeY, NeZ:", lcmesh%NeX, lcmesh%NeY, lcmesh%NeZ + write(*,*) " [X] :", lcmesh%xmin, lcmesh%xmax + write(*,*) " [Y] :", lcmesh%ymin, lcmesh%ymax + write(*,*) " [Z] :", lcmesh%zmin, lcmesh%zmax + + do ke=1, lcmesh%Ne + write(*,*) "k=", ke + call assert(ke, lcmesh%EToE(ke,:), EToE_ans(:,ke), "EtoE", elem%Nfaces) + call assert(ke, lcmesh%EToF(ke,:), EToF_ans(:,ke), "EtoF", elem%Nfaces) + + vs = 1 + ve = Nfp_h*elem%Nfaces_h + call assert(ke, lcmesh%VMapM(vs:ve,ke), VMapM_h_ans(:,:,ke), "VMapM_h", Nfp_h*elem%Nfaces_h) + call assert(ke, lcmesh%VMapP(vs:ve,ke), VMapP_h_ans(:,:,ke), "VMapP_h", Nfp_h*elem%Nfaces_h) + + vs = ve+1 + ve = elem%NfpTot + call assert(ke, lcmesh%VMapM(vs:ve,ke), VMapM_v_ans(:,:,ke), "VMapM_v", Nfp_v*elem%Nfaces_v) + call assert(ke, lcmesh%VMapP(vs:ve,ke), VMapP_v_ans(:,:,ke), "VMapP_v", Nfp_v*elem%Nfaces_v) + write(*,*) "--------------------------" + end do + write(*,*) "***********************************************************************" + + return + end subroutine check_connectivity + + subroutine assert(k, vals, ans, name, val_size) + integer, intent(in) :: val_size + integer, intent(in) :: k + integer, intent(in) :: vals(val_size) + integer, intent(in) :: ans(val_size) + character(*), intent(in) :: name + + real(RP), parameter :: EPS = 1.0E-15_RP + + !-------------------------------------- + + write(*,*) trim(name), "=", vals(:) + if ( sum((vals(:) - ans(:))**2) > EPS ) then + LOG_ERROR('chechk_connectivity',*) 'The value of '//trim(name)//' is unexcepted!', & + ' k=', k, ": val=", vals(:), " ans=", ans(:) + call PRC_abort + end if + end subroutine assert + + function elemID(lmesh, i, j, k) result(eid) + type(LocalMesh3D), intent(in) :: lmesh + integer, intent(in) :: i, j, k + integer :: eid + !-------------------------------------- + eid = i + (j-1)*lmesh%NeX + (k-1)*lmesh%NeX*lmesh%NeY + return + end function elemID + + function nodeID(elem, i, j, k) result(nid) + type(HexahedralElement), intent(in) :: elem + integer, intent(in) :: i, j, k + integer :: nid + !-------------------------------------- + nid = i + (j-1)*elem%Nnode_h1D + (k-1)*elem%Nnode_h1D**2 + return + end function nodeID + + !-------------------------- + +end program test_mesh_cubedsphere3d \ No newline at end of file From ee8cc3e458ac8f98ccf1e641d68115af1c548a4b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 16 May 2021 21:37:28 +0900 Subject: [PATCH 19/98] Add a module for MPI communication when 3D cubed sphere mesh is used. --- .../scale_meshfieldcomm_cubedspheredom3d.F90 | 443 ++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 diff --git a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 new file mode 100644 index 00000000..320e86ca --- /dev/null +++ b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 @@ -0,0 +1,443 @@ +#include "scaleFElib.h" +module scale_meshfieldcomm_cubedspheredom3d + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + + use scale_element_base, only: elementbase, elementBase3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + use scale_meshfield_base, only: MeshField3D + use scale_meshfieldcomm_base, only: & + MeshFieldCommBase, & + MeshFieldCommBase_Init, MeshFieldCommBase_Final, & + MeshFieldCommBase_extract_bounddata, & + MeshFieldCommBase_set_bounddata, & + MeshFieldContainer + + use scale_localmesh_2d, only: Localmesh2D + use scale_localmesh_3d, only: Localmesh3D + + + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public type & procedure + ! + + type :: VecCovariantComp + type(MeshField3D), pointer :: u1 => null() + type(MeshField3D), pointer :: u2 => null() + end type + + type, public, extends(MeshFieldCommBase) :: MeshFieldCommCubedSphereDom3D + class(MeshCubedSphereDom3D), pointer :: mesh3d + type(VecCovariantComp), allocatable :: vec_covariant_comp_ptrlist(:) + contains + procedure, public :: Init => MeshFieldCommCubedSphereDom3D_Init + procedure, public :: Put => MeshFieldCommCubedSphereDom3D_put + procedure, public :: Get => MeshFieldCommCubedSphereDom3D_get + procedure, public :: Exchange => MeshFieldCommCubedSphereDom3D_exchange + procedure, public :: SetCovariantVec => MeshFieldCommCubedSphereDom3D_set_covariantvec + procedure, public :: Final => MeshFieldCommCubedSphereDom3D_Final + end type MeshFieldCommCubedSphereDom3D + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private type & procedure + ! + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + integer :: bufsize_per_field + +contains + subroutine MeshFieldCommCubedSphereDom3D_Init( this, & + sfield_num, hvfield_num, mesh3d ) + + implicit none + + class(MeshFieldCommCubedSphereDom3D), intent(inout) :: this + integer, intent(in) :: sfield_num + integer, intent(in) :: hvfield_num + class(MeshCubedSphereDom3D), intent(in), target :: mesh3d + + type(LocalMesh3D), pointer :: lcmesh + type(ElementBase3D), pointer :: elem + !----------------------------------------------------------------------------- + + this%mesh3d => mesh3d + lcmesh => mesh3d%lcmesh_list(1) + elem => lcmesh%refElem3D + + bufsize_per_field = 2*(lcmesh%NeX + lcmesh%NeY)*lcmesh%NeZ*elem%Nfp_h & + + 2*lcmesh%NeX*lcmesh%NeY*elem%Nfp_v + call MeshFieldCommBase_Init( this, sfield_num, hvfield_num, bufsize_per_field, 6, mesh3d) + + if (hvfield_num > 0) then + allocate( this%vec_covariant_comp_ptrlist(hvfield_num) ) + end if + + return + end subroutine MeshFieldCommCubedSphereDom3D_Init + + subroutine MeshFieldCommCubedSphereDom3D_Final( this ) + + implicit none + + class(MeshFieldCommCubedSphereDom3D), intent(inout) :: this + !----------------------------------------------------------------------------- + + if ( this%hvfield_num > 0 ) then + deallocate( this%vec_covariant_comp_ptrlist ) + end if + + call MeshFieldCommBase_Final( this ) + + return + end subroutine MeshFieldCommCubedSphereDom3D_Final + + subroutine MeshFieldCommCubedSphereDom3D_set_covariantvec( & + this, hvfield_ID, u1, u2 ) + implicit none + class(MeshFieldCommCubedSphereDom3D), intent(inout) :: this + integer, intent(in) :: hvfield_ID + type(MeshField3D), intent(in), target :: u1 + type(MeshField3D), intent(in), target :: u2 + !-------------------------------------------------------------- + + this%vec_covariant_comp_ptrlist(hvfield_ID)%u1 => u1 + this%vec_covariant_comp_ptrlist(hvfield_ID)%u2 => u2 + + return + end subroutine MeshFieldCommCubedSphereDom3D_set_covariantvec + + subroutine MeshFieldCommCubedSphereDom3D_put(this, field_list, varid_s) + implicit none + class(MeshFieldCommCubedSphereDom3D), intent(inout) :: this + type(MeshFieldContainer), intent(in) :: field_list(:) + integer, intent(in) :: varid_s + + integer :: i + integer :: n + type(Localmesh3D), pointer :: lcmesh + !----------------------------------------------------------------------------- + + do i=1, size(field_list) + do n=1, this%mesh%LOCAL_MESH_NUM + lcmesh => this%mesh3d%lcmesh_list(n) + call MeshFieldCommBase_extract_bounddata( field_list(i)%field3d%local(n)%val, lcmesh%refElem, lcmesh, & ! (in) + this%send_buf(:,varid_s+i-1,n) ) ! (out) + end do + end do + + return + end subroutine MeshFieldCommCubedSphereDom3D_put + + subroutine MeshFieldCommCubedSphereDom3D_get(this, field_list, varid_s) + implicit none + + class(MeshFieldCommCubedSphereDom3D), intent(in) :: this + type(MeshFieldContainer), intent(inout) :: field_list(:) + integer, intent(in) :: varid_s + + integer :: i + integer :: n + type(Localmesh3D), pointer :: lcmesh + + integer :: varnum + integer :: varid_e + integer :: varid_vec_s + !----------------------------------------------------------------------------- + + varnum = size(field_list) + + do i=1, varnum + do n=1, this%mesh3d%LOCAL_MESH_NUM + lcmesh => this%mesh3d%lcmesh_list(n) + call MeshFieldCommBase_set_bounddata( this%recv_buf(:,varid_s+i-1,n), lcmesh%refElem, lcmesh, & !(in) + field_list(i)%field3d%local(n)%val ) !(out) + end do + end do + + varid_e = varid_s + varnum - 1 + if ( varid_e > this%sfield_num ) then + do i=1, this%hvfield_num + + varid_vec_s = this%sfield_num + 2*i - 1 + if ( varid_vec_s > varid_e ) exit + + if ( associated(this%vec_covariant_comp_ptrlist(i)%u1 ) & + .and. associated(this%vec_covariant_comp_ptrlist(i)%u2 ) ) then + + do n=1, this%mesh3d%LOCAL_MESH_NUM + call set_boundary_data2D_u1u2( & + this%recv_buf(:,varid_vec_s,n), this%recv_buf(:,varid_vec_s+1,n), & ! (in) + lcmesh%refElem3D, lcmesh, lcmesh%G_ij, & ! (in) + this%vec_covariant_comp_ptrlist(i)%u1%local(n)%val, & ! (out) + this%vec_covariant_comp_ptrlist(i)%u2%local(n)%val ) ! (out) + end do + end if + end do + end if + + return + end subroutine MeshFieldCommCubedSphereDom3D_get + + subroutine MeshFieldCommCubedSphereDom3D_exchange( this ) + + use scale_prc, only: & + PRC_LOCAL_COMM_WORLD, PRC_abort, PRC_MPIbarrier + + use scale_meshfieldcomm_base, only: & + MeshFieldCommBase_exchange_core, & + LocalMeshCommData + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatVec, & + CubedSphereCnv_LonLat2CSVec + + implicit none + + class(MeshFieldCommCubedSphereDom3D), intent(inout) :: this + + integer :: n, f + integer :: varid + + real(RP), allocatable :: fpos3D(:,:) + real(RP), allocatable :: lcfpos3D(:,:) + real(RP), allocatable :: tmp_svec3D(:,:) + + class(ElementBase3D), pointer :: elem + type(LocalMesh3D), pointer :: lcmesh + integer :: Nnode_LCMeshFace(this%nfaces_comm) + integer :: is_f(this%nfaces_comm) + type(LocalMeshCommData), target :: commdata_list(this%nfaces_comm, this%mesh%LOCAL_MESH_NUM) + type(LocalMeshCommData), pointer :: commdata + + integer :: irs, ire + !----------------------------------------------------------------------------- + + do n=1, this%mesh%LOCAL_MESH_NUM + lcmesh => this%mesh3d%lcmesh_list(n) + elem => lcmesh%refElem3D + + Nnode_LCMeshFace(:) = & + (/ lcmesh%NeX, lcmesh%NeY, lcmesh%NeX, lcmesh%NeY, 0, 0 /) * lcmesh%NeZ * lcmesh%refElem3D%Nfp_h & + + (/ 0, 0, 0, 0, 1, 1 /) * lcmesh%NeX*lcmesh%NeY * lcmesh%refElem3D%Nfp_v + is_f(1) = 1 + do f=2, this%nfaces_comm + is_f(f) = is_f(f-1) + Nnode_LCMeshFace(f-1) + end do + + allocate( fpos3D(sum(Nnode_LCMeshFace(:)),2) ) + call extract_boundary_data3D( lcmesh%pos_en(:,:,1), elem, lcmesh, fpos3D(:,1) ) + call extract_boundary_data3D( lcmesh%pos_en(:,:,2), elem, lcmesh, fpos3D(:,2) ) + + irs = 1 + do f=1, this%nfaces_comm + commdata => commdata_list(f,n) + call commdata%Init( this, lcmesh, f, Nnode_LCMeshFace(f) ) + + call push_localsendbuf( commdata%send_buf(:,:), & ! (inout) + this%send_buf(:,:,n), commdata%s_faceID, is_f(f), & ! (in) + commdata%Nnode_LCMeshFace, this%field_num_tot, & ! (in) + lcmesh, elem ) ! (in) + + if ( commdata%s_panelID /= lcmesh%panelID ) then + if ( this%hvfield_num > 0 ) then + + allocate( lcfpos3D(Nnode_LCMeshFace(f),2) ) + allocate( tmp_svec3D(Nnode_LCMeshFace(f),2) ) + call push_localsendbuf( lcfpos3D, & + fpos3D, commdata%s_faceID, is_f(f), Nnode_LCMeshFace(f), 2, & + lcmesh, elem ) + + ire = irs + commdata%Nnode_LCMeshFace - 1 + + do varid=this%sfield_num+1, this%field_num_tot-1,2 + tmp_svec3D(:,1) = commdata%send_buf(:,varid ) + tmp_svec3D(:,2) = commdata%send_buf(:,varid+1) + call CubedSphereCnv_CS2LonLatVec( & + lcmesh%panelID, lcfpos3D(:,1), lcfpos3D(:,2), Nnode_LCMeshFace(f), & + this%mesh3d%RPlanet, & + tmp_svec3D(:,1), tmp_svec3D(:,2), & + commdata%send_buf(:,varid), commdata%send_buf(:,varid+1) ) + end do + + deallocate( lcfpos3D, tmp_svec3D ) + end if + end if + + irs = ire + 1 + end do + deallocate( fpos3D ) + end do + + !----------------------- + + call MeshFieldCommBase_exchange_core(this, commdata_list(:,:)) + + !----------------------- + + do n=1, this%mesh%LOCAL_MESH_NUM + lcmesh => this%mesh3d%lcmesh_list(n) + elem => lcmesh%refElem3D + + allocate( fpos3D(sum(Nnode_LCMeshFace(:)),2) ) + call extract_boundary_data3D( lcmesh%pos_en(:,:,1), elem, lcmesh, fpos3D(:,1) ) + call extract_boundary_data3D( lcmesh%pos_en(:,:,2), elem, lcmesh, fpos3D(:,2) ) + + Nnode_LCMeshFace(:) = & + (/ lcmesh%NeX, lcmesh%NeY, lcmesh%NeX, lcmesh%NeY, 0, 0 /) * lcmesh%NeZ * lcmesh%refElem3D%Nfp_h & + + (/ 0, 0, 0, 0, 1, 1 /) * lcmesh%NeX*lcmesh%NeY * lcmesh%refElem3D%Nfp_v + + is_f(1) = 1 + do f=2, this%nfaces_comm + is_f(f) = is_f(f-1) + Nnode_LCMeshFace(f-1) + end do + + irs = 1 + do f=1, this%nfaces_comm + commdata => commdata_list(f,n) + + if ( commdata%s_panelID /= lcmesh%panelID ) then + if ( this%hvfield_num > 0 ) then + + allocate( lcfpos3D(Nnode_LCMeshFace(f),2) ) + call push_localsendbuf( lcfpos3D, & + fpos3D, f, is_f(f), Nnode_LCMeshFace(f), 2, & + lcmesh, elem ) + + ire = irs + commdata%Nnode_LCMeshFace - 1 + do varid=this%sfield_num+1, this%field_num_tot-1, 2 + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcfpos3D(:,1), lcfpos3D(:,2), Nnode_LCMeshFace(f), & + this%mesh3d%RPlanet, & + commdata%recv_buf(:,varid), commdata%recv_buf(:,varid+1), & + this%recv_buf(irs:ire,varid,n), this%recv_buf(irs:ire,varid+1,n) ) + end do + deallocate( lcfpos3D ) + end if + end if + + call commdata%Final() + irs = ire + 1 + end do + + deallocate( fpos3D ) + end do + + return + end subroutine MeshFieldCommCubedSphereDom3D_exchange + +!---------------------------- + + subroutine push_localsendbuf( lc_send_buf, send_buf, s_faceID, is, Nnode_LCMeshFace, var_num, & + mesh3D, elem3D ) + implicit none + + integer, intent(in) :: var_num + integer, intent(in) :: Nnode_LCMeshFace + real(RP), intent(inout) :: lc_send_buf(Nnode_LCMeshFace,var_num) + real(RP), intent(in) :: send_buf(bufsize_per_field,var_num) + integer, intent(in) :: s_faceID, is + type(LocalMesh3D), pointer :: mesh3D + type(ElementBase3D), intent(in) :: elem3D + + integer :: ie + !----------------------------------------------------------------------------- + + ie = is + Nnode_LCMeshFace - 1 + if ( s_faceID > 0 ) then + lc_send_buf(:,:) = send_buf(is:ie,:) + else + call revert_hori( lc_send_buf, send_buf(is:ie,:), mesh3D, elem3D, mesh3D%lcmesh2D ) + end if + + return + contains + subroutine revert_hori( revert, ori, mesh, e3D, mesh2D ) + implicit none + type(LocalMesh3D), intent(in) :: mesh + type(ElementBase3D), intent(in) :: e3D + type(LocalMesh2D), intent(in) :: mesh2D + real(RP), intent(out) :: revert(e3D%Nnode_h1D,e3D%Nnode_v,mesh2D%NeX,mesh%NeZ, var_num) + real(RP), intent(in) :: ori(e3D%Nnode_h1D,e3D%Nnode_v,mesh2D%NeX,mesh%NeZ, var_num) + + integer :: p1, p3, i, k, n + integer :: i_, p1_ + !------------------------------------------------------------------------ + + do n=1, var_num + do k=1, mesh%NeZ + do i=1, mesh2D%NeX + i_ = mesh2D%NeX - i + 1 + do p3=1, e3D%Nnode_v + do p1=1, e3D%Nnode_h1D + p1_ = e3D%Nnode_h1D - p1 + 1 + revert(p1,p3,i,k,n) = ori(p1_,p3,i_,k,n) + end do + end do + end do + end do + end do + + return + end subroutine revert_hori + end subroutine push_localsendbuf + + subroutine extract_boundary_data3D( var, elem, mesh, buf ) + implicit none + + type(elementbase3D), intent(in) :: elem + type(LocalMesh3D), intent(in) :: mesh + real(DP), intent(in) :: var(elem%Np * mesh%Ne) + real(DP), intent(inout) :: buf( 2*(mesh%NeX + mesh%NeY)*mesh%NeZ*elem%Nfp_h & + + 2*mesh%NeX*mesh%NeY*elem%Nfp_v ) + !------------------------------------------------------------ + + buf(:) = var(mesh%VmapB(:)) + + return + end subroutine extract_boundary_data3D + + subroutine set_boundary_data3D_u1u2( buf_U, buf_V, & + elem, mesh, G_ij, & + u1, u2) + + implicit none + + type(ElementBase3D), intent(in) :: elem + type(LocalMesh3D), intent(in) :: mesh + real(DP), intent(in) :: buf_U(2*(mesh%NeX + mesh%NeY)*mesh%NeZ*elem%Nfp_h & + + 2*mesh%NeX*mesh%NeY*elem%Nfp_v) + real(DP), intent(in) :: buf_V(2*(mesh%NeX + mesh%NeY)*mesh%NeZ*elem%Nfp_h & + + 2*mesh%NeX*mesh%NeY*elem%Nfp_v) + real(DP), intent(in) :: G_ij(elem%Np * mesh%Ne,2,2) + real(DP), intent(inout) :: u1(elem%Np * mesh%NeA) + real(DP), intent(inout) :: u2(elem%Np * mesh%NeA) + !------------------------------------------------------------ + + u1(elem%Np*mesh%NeE+1:elem%Np*mesh%NeE+size(buf_U)) & + = G_ij(mesh%VmapB,1,1) * buf_U(:) + G_ij(mesh%VmapB,1,2) * buf_V(:) + u2(elem%Np*mesh%NeE+1:elem%Np*mesh%NeE+size(buf_U)) & + = G_ij(mesh%VmapB,2,1) * buf_U(:) + G_ij(mesh%VmapB,2,2) * buf_V(:) + + return + end subroutine set_boundary_data3D_u1u2 + +end module scale_meshfieldcomm_cubedspheredom3d \ No newline at end of file From 28b43c1074a65f98e4b63673067b0d5987a08e0a Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 16 May 2021 21:47:59 +0900 Subject: [PATCH 20/98] Remove a binary file. --- .../test_mesh_cubedsphere3d | Bin 1465424 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d diff --git a/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d b/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d deleted file mode 100755 index fbc53794669aa6d392dcedd6efbc9bdc7a0319ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1465424 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ℜq_qk4lR5BZUSc&JYJW? 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%0AJ;Jm;>>NVEPApuSGMm{&p#mSZ=j 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

Xo=Lk# zjg%?<5CQ*H=nFc~`IBaII5%6l#$2!OYd0nL zwTW{WU$U>gB)PAR{u=#@Of|QMz3nk%IL*}4xWwD@EIg9zR|Cue=L*Yk_llvz6?YWe ze1le)>c2~U_w-i_j=eqb&>rS_)RyE~HVA#o0Jrkb^y_@vaUSNrQ92LvPqb^9&?)K` zJINN>tkb0w>?UZA>0?)L95$23ez4-TY-~k-ADhV~eRzM5ed{*T&4Hdp=^HceYRcWC zZBBJ)4|jRQPOv%bif~sgWWrvsHSCF4!q`a;mql#h(uiVhlKEmM-9+NW=CupEriMLa zchr^eU~kn-J`?#$vAJ4?%~dP;#TN1m?5{g~S%J*hH@KnL~4z*#$$wWBK6gfU)o{RXVfzWn52%G)WKcAkTKqS&v6s*E7Ddm zH$(?lN!eM*n`n=d^4<6ojQ6nh#CIc%a{S;-?okv_hU}k|Cut{H#&>i`pWr6W9HN6a zl?ZO79_5*pXg~(c9&JHC`b)-&F0bgNyWxQE%;u~&HuykE^a6jKeWt%T&Y0_fc8Xj^ z`gsd;WGnPDr&@(JFy74IM9N!+U7=OC_p4w3fBMyr>#Lr!QcvsDs7?A^a3yw$a-fll zH9CgQhv?L88_QULJ{E<4(##xfE)4sdt6U3 zOUyciH0P6N(3ZIMT=EShO=-9~Q5N zu-c$|qr)|nZ=u}Jtl%m%1~~GlUufWha9yGXnmC_4ks-7JSj9fJ)FJT_HV`-l0EeWL zHckc}S<|f4Z2~T{4!1Q_7QR1mMG7t(@XV(SceplT+VY9Dl<+wzx@h!oF>qLPIIzPF zEi9y5v9}{Qkn&}$ShsXq&D7yRm)I2!==8CX@lwisHhXHC%fW9=0cZN;lXb|!IFa;{ z*2Xwd+&zAoak8C0lD<&9ckI}5$m(qNC$JS7dQ|TJ9pbLrrsQ63TBfr982dY>?;Kko zXHT-{7P*@2ySv!O_=fuST}Yq%v$I<|;Z1mJq~)h=L)zmzh|9KVKaV=K#~$N+r*Ld& z^IJ}BBYI_9|HwWHow6;jIJHf`acYn6c4`rH&VF)%(ni6XWU>cZ1-x3VAIN?6_ z^*hl`fIkph6fXAnPTYYdW2Oa~Orh$+!R`LaG1GjD#!Rc8VbiMJgWDfGVATSj^Tmg> z2mZ`Iz&pW5`J0Ef2h27t;2skS%(H2g`JDB%jhp7%#n&}<8oJ5oBG_naZYXe`O}EKg zJ)1Hs2e(&W#=mJ?sQOC&OL(g;J{FxcV0d{PdIsaBRSzTIS$yWcp}+y+KBTlR5_XV869{o%UeX?5ix^ku^{Oc&n{D`$?PD)0aJkuJi+wUo4 z&nssuao*@FP1#NLVxUQ`URrfmFO3U z{hq$0k$RH)1%rC&7YsVCUywY%O4^SQU4i-RZ+o9#2|ff5qF?Y&z$5q&JPgDwco7`S z`JVKF;6(5tWyx7qGw1cv?{a=6d)rp_gT}d)?1|+pP;@I~zbX0!a(-p#82r8GSE45- zcu($clkVjHHtA08Z35%zdBl9V=(!qeBgGtM=0_tM=TzN&8_Y z?3tId_f*(1AH}*>Q0{KYQk5gcj;ilki)QXqG1ByJv1^szHOiG$G18)(qs&?5Bde^g zQBLI^rL3M&zBbF3ec7k_uEk!%vqgt;SeFVoqY@rjcuKSHe4U@%PMv4LPf9()lk~Q; zYJq+iE6X16@RZ~=v*(mOfUgprGw$Ok)^B6oH2(Vj)Q7FRZ`hx@*`L+`kCb8LN&ic^ zZsDt(u>^Yy{r!n%ou}$7IbN@`L%&aKv}aYJ`Ahx0?;6!2?KHPusJHKK+UFbT)*c*& zZe6}xd!V0NE8nFw-yr_aDeci~oGsAe*qYq0{1z^KIIc5LiO0?mOITB`1tDa zs^w1hP+Ny_rxyF?eqfildhDVHxUXCTZ(oZ|O6y^#Hsc1%aI@8=O}Wi`#FEQez2B*| z5^q)3J>RE2V$W}J9`@J9J6l$AC&^u7sUOwZcljJ}^3&|3JzTL@c~^#6Gxjrgo6Xvl zwB_k!UoDru>a+~q#C~O%g?+M#eX{8mR}T7lEo0dy`?)8T!Co0$`ieKY(L`)1Cu*n103&76P1Z!cHyDhIJ0pAY{dycPS0P$qno9iB>sJ0e#2wv2Eh zk{9lZI8Ek|hj+!jeDfMViga@aZGK}kG6{crfA)3{qU>R$oxq-OJoh-N8UqQJ$s8O? zeGd>mn=_db_#{QWZ{eRqoQtrd&B#nQ4B3P2iOFO1!{yR?2OZd1lIgM(STqdZ~X7<-dVj;DYa*TZ&ui z6uxvlZt2Hr{$4&~zazY>QI`UzMjetTwbxl*1Lp}$FDos+2VJ2z;h*lcVh^8rH`l3US2(pkc9(YgG~ONf9`AUcW%$E|LIEjxz$$g-;L?H8@@~QvR1*ru7+n5eWHK42j1=vzPdT^ucDh( z3e70rg?$44UOvCMC=?8oOj}i{;Aw}qKU!zi*0@zD*i=02?#iLl4<47 zL%ZCgL;jboTFv_6X|>~vrrouv82#9yX$_C_U(~0iq7D75SF^Zt2fw<6_Wa7K`JdQ0ke{Rwq_{5|M?KYRoyFu1X*}(i3^zz*lkGl%kTYK%f z^Pq=z-A3A>k~P3BI<@z*pO8Gl-v*J*{vQ7JZur~rDI00miQLxGKgr*kETQW-AILzS ze31QpQnv=ZbNCL?YZskI(WQ6eFT`!=x{JP(_$6*3ab>;I&%o~>UhY!}e=Fq}WgGmh z34YB2zm^G)7AM}Iv%TMt?;CBKVk;wH?ui=k^YhMn2Cu!f)_dak$VcK@pqC|+HbU7_{~<@e=C2%o#0>}Z8P3C90Yy`P==h}oCdy5 z_C9+#WeSdjzjfhu;x581V?g>)#*)BTgj?zpJ=xiu-+a^ir_QgP-x&I{U)e`%L_ce5 z+WCzG`)E;Q6i@yI{aN8}MSs==ZEpBkR?G4G5%a9c`w=h0uRfC1;;SqSJ$fbd=Nf3r zwN_27N!my2hHl5+_SK0VZ2@K6y<~CEPt7CRJO3T|#fOG&fwqziieXWkcS z8Wq}E?9_IjK4asqT=vdKEn0&a-Z{gnu?`+ugdWs-qrX7a2r0 z^~Sn=bxvq^)gaNWtq$8-BmffeN|w1d!TFN zwCd5&#{m4OdqjH`G=Fu|@b-t^=B*-kLFk?XBd7V?j%hw~VaVTQ(W`OKDvE1}nM+H)2-8V0WNq0y8120@G6 zNm_mP0qiuLXVvci(4wunfbwSm&q%9Q`w4F=eVcrRtO>KN+WSG)sQs*q9U@C8@9FFW zhY4_)A+(qC`}ah4P}vhOr}Syxm2}7$;-ujpjfo#wLo}sZ`%X$W@h8cLZY?xi>|2fk z=R&uAS6Z~+rDPDbSEkYE57TJ$0cdm=G&*id$|2MRI*o1w)<2}vXkh${G#Z%GY4p}K z8vXqgjqXOiY0&5iB7;by(R-lLG3JiYfPa)mEAq?yPs$*Y^D`-fkolRUcYldSi~K?8 zO%(dwO*yh(7G3@rZYfu2kkBNV_ac7~Iwb3bL4yqX+)bF!)5D|@+F60SfbUcMGx3{o z8}wQH28~Lm&x;8cIu%bVLtqg4EbW|$TjK$n*3pPW{c3+hI`r5zHCX# zA6|u~7LE)x?BmVFH!a#DtB*eP%lUV1eEK_gY<#Bb_Kht|S8V+C%|G7w*q9$J+jRE7 zEZcJaZOa~?{=;S4(DnTC$IgunS4_9ITCRK3bBRYQyMlSI)WIdZhqXhLk+Q2R%3Lx9-lh)t}Az zRwq1L27Bq>Gv7C}myW@gQ6@ZD)}{m4zX~$vJ-4wxm%T1;VNAbK9lH3t$SahEb4?Z8 z3=J4#>KiQQ`xI8EugVE#Vlytx+o+%5-@v=S{RsOEw}hW*LLZOsWBg6qB`hb{m+&b6 zM*Q8lC4ID4`VRc-iO-Yt=A7V@lt0FVjtSv6>--CQ$6wBP zu8MY|OP>`gq>M$3eW@1_K`Uxw828W(bjVO9mGkSt8lj?105r6?s^9q;0p*F5Y7b*}<>8@i2h&-()|sfN`^dGEFI1x`9olxh*NT^o1GsY`+RQkcCwM ze>pH$(T|nXBYFs;pIL-FY$1CZCu4Lb<5u2pF{!@rW8jW?T+qt;z5Yy z7oF>M%++${D*2yAepH{Cnx{*dr(>0+-hv-kLJ~LgS>D`5{xstf-v8w+z3hIMcEtjh zc1-3h^K~-tnP$bTh8@Jd@M8UW&){O_uI#lYoSR?&A+#$x_)v-Dxs)|r_E!bW<4<{` zZ4_bg)c$HeYxgL|M;5vX2bs4wnDc^5(7U>C=k}eKnDT?)Gvx(W^WVUr|5w}+)`a_7 z+~SwGcKqx4($k0WquWdV{9p}b@uqojizP4kyd^(ahQFHcHQZ8{qnZp`xCbX#bagej5b^GKbC^YhWmbCkn-08gInc= z>VRVva46=X^pDKnwUjCC7hFo)=8~QkL|$fg8cg8{k9m za3yJ9mbBC@ZNG)`1wO&S6~tvzzu@3B+BT4O&B8yAw#}!EtH^UDd9EOBPA~hfOMvGF za8#OtZw;_{(%kNpdoAHk++vGVF@LSVZvke3RZ$OPQlGynCC@g-hhpptE^np|WMhZa z&eol?kfZ7LHpwUJx9qDFbW^dmw=%XB^xz}jihNanFERsNI^K6nt>K@}cW?ai$DWPM z=GvX>1)szGt!LN=F&#j zyEGf`Z7bgDuHg*Lai_es{BTK@X;_Zf=N?S>r<`*~@-phjsf;~$V!wNFQ^T-M%8YTI z9J|q#qsj*icdW1u7|Yx9Hr~wZR#|h#uK3Z~Smp-Gu>}uXhK!edzvKM4FJ(67swwu; zM(Y`zTYhM`(ZW-6QVp%D&lTvRko3 z`h?45-|9EnU4)nOnF-sgp0qCFGuG?g{|%)3ICgpBKGI0JdYP2n6>}y=6IQCnyApX4 zPhC>>ChF^oxf3%8bL#P)#K(GmliiJ9V0hJ(5$cMSCZz6}>_MOL4F1lPpKdj8a#O z@;@Rz!ny5go0?S0{&5fcr={Rj@^fd=KAShkrS5Xl%H51I_|C%?>-ZOynxg2JY|?UW z(5_U(>P$EjqQ9L5->KAq9LCRbKl+ECGxk2S3>Y7^ST<#>Jo?Zm!eflJcg=&BHu68` zJLZ-tKhA79_d0XS1y$yjPv_5IOqVgHOBvIijYltZYR4>Qop1GA#9G#T;#$@hJ!nHt zBzsSh0j2LfMMflhPeVS`AbU*4ZBj1e(RH02=sFj_zv4BUvhLZAu5*E*hep~tjJKI9 zT-xr#=yyA1A883?bI#A$4K77LWeMM&o6XY?C#V$vz^#@$!hZ(G{^Z zIwO`wcO3YxQPFDgsjIN*KW9&q99i2#ti!=pJ zXQbTe)a4JQ6Fu6Dut%FYh5n!F(cVqT3ExFdcqV(57ew~(a8gcKfPA5g`yA|vL7CpeHXQHAWG0vSUE`tKW#xYo+Jc&uk;u!OO(SlRYizI3m3 zu`fA;@$r3V7;_W5cWV3x$R(GuH<_IpCu-I@Ys1{+Sjk~;HV3)G*`|IuyP=UEoBHI; zeQ9hk%iJgDL;RP$bQU&v%4_=*o|mEKa$jcdURQbTS*HFuvq<+5{&wQ7cxhtLMmV~? zb2CUk>!q`UXH&*R@<G zNIg<+Ci#}rrvkUYCNRBD8U3jHM*3M`K1BHMi621tEXrO)-{<4@(*FX7z$N9)r93<3 zEo5BxBP2Oc_HcY_#{su;R4Ui%#o$c4-@`1lT`aw=JZX>l`FuH^jmh%u?13|v|C^i*rnal zUTK?=N9vM#q@7Zav`fZBo{opJb=*mtq<^Ii0)GZ^0`GEQyD@$fO#P>%00aj_?1L^SS>O{8!|*I^xd-YGkBHHv8VAxm3brgUp8q=O&kC3&1&PZ zYV3|>D(yE%-CB5y zQ>2n%LL)dc2^nd^kGS+Zd_o^C&awo#TlPpHG@|fhcQ7AXGaDN5J?_a&QX}@fe42Xd z67EY_QnVpv$%i&%Z8~V_vuO{qisn1ell$zB*UqAE)hyocg?@^>=5la&1v>l<(|E^* zdl-RMN3gB&^2iS8@UBKzL|@09&e}?4%JH`rA_ubM6yX=JvhYC0saIJ0*kaq+95c2fwoG!chJ6_v_tqZX`8gi9QPyyeoMSG@d@x+ zfmPs&0hhpH1Ex7?^VyhJ#$W1sfi^7#uImrfM60bUu?{cR_&QW9Ne+sT3~N$IMCkbj+N@Pe;GE9x4B05;u!`;bw6PH^RF}TtiA9&6lQ&Rt#=zxmNCeB}&$h zPU1$=eE@EDUy@m03~mBCUz>IOez4dPQ0nv(a3gK~kK^a`lj27W<^HRVpVM{xbkiQ% zq~8yQ?uR~|U&`9xf%kXA`@2{VoXD-qSQEZ3xAq)%Ycn2&AMA0Tzz=SPAKW45#_)qO z&c^oI4~$LQ4@jKzblJzgRpQEXX)^|LepbLc+(Vd4tRwQ)wRu*TwcqU~&Ys+B-yfJ& zfAQgqgZnt28vCVZ?VQ}KJ$cje>+czw6%?DAlIH_t*JI%kv-Pv6e!3pXdz>jBgg*>` zZ_y>2i_UA1^`H{_FQ zj5J~VM&3r;Zqh!__gm7GlKurLgL98x;;*E>1;q6p)9L<)+uC-H!4}N(7O6Ks_y@^P zo+iq;7XPm(^JZY*iT|HTI|-XHza)M%c4JD=y<1G!M0D?dOa2JypCbQ!$&XvgyP5cR zi2Eh^_YqfsZpST@=ZJSCiqX6KHnj9U(iCC;M(UMwkSD2A;1+yIIV*{ODg|FHZh4;J`1og9IPNxW)dDlrQ#wv zh@t-{?U6nZ+&m53f(ya5;QlJ$Ya?E8BKVMef)C?;LcxpRiu2_wIgg*od3;WjG3B05co;YLw{`tL<9%uea2Eit@jkV?mwt(2PDmZnFGByqoEMj{CmzT85(Ylu z4>vQ<CWnZR8BpVS9QpS$8dr5|!iKjftP zA&l9XjN^YuKSaiRx_*e1a}xcK&-yFP)9KbO`D0m&$Z#*;&s=`1tOfpispxh!m`qDA zWsSbOZ|ksvCzG=12`l;xUuaYIbXoKSl?;>p*f`>hG_!BHtK~B4o{n79r~2f`+CAep zF3r){Fzgp9C+B)()Z@6zH13v*bNZY52hRkCJm^oEO|^gPcFTYl|HXUcrGYN(mp6}? z4=<4OGVA@GVwaY|p7q;mz?^>_q^7v;aIXEhV5}{iqvqPkUr-vevbJ;IDQ{B;dL=p7 zB(Y-K?-2T7HBs*BnN8RM=og%Xp3$gTYWW;wk}JdVE@CY5bb+!zRj%yyVeXlSJ0g!D ze?DxnZ~6uQ>To>ra5xc(_>?^m?u>|Cf(OGNMncHvwrB12N*UkE-s`<1XRlYvT1%Le zvx0x`IiK$LL%*A;cS=(%B5&wf$v>?r8u5_tXV7(*Ic)t`)}m(Mn%dM6d4M!hUtv=` zvXlBAWj&f<30v33I}*)dWgp#?h}4lrU^%a;Ga~R*vrczVP7P~Rb5!0#%L+|u`Y7@U z>DH323f}m_rVk?*k@kM#gjcR*UF6P>eI5CbKh70gZGty0qwZq%HUhVV3oHVslp*;B zQii}=<>USlc1d=nV07S@ekrDHPtsmDKw& z4%{^&d&MrwO_b@7viW4aEu^kV;GjfgrPxU+rhK{k?m$i}wj7PJ<=;ek4$9Wc1V5x- zJ}*_C!-bAsfzs_y%xrqn7QT~vROo?<4aJ{vm&(J~uAt2h?i!XeuA`YpOF9_qZLS!_ z(N5lm%j69-hbx-chWy{eKB&Qzv2;6gch+s0Ef-r&8u!+;IY*Q>^ZHEW_3n+I^>=C~ z)h`*Ww6Z_Kr{C|C4jOw!){6>7_F^CQWBd;%0=oH^f|bHaoQ#c)9#h?%2R@ zkHBrlR!keb`Yd?#S%+r@-(S(czAyawyxhKfp0tgqj}88$m8KEsCARHcEHYvIZsHR7t4Mz>?mg7Cm^7afm)_sK-M7IL zj^>WF)GKxVf&A|PtJL`+-<$A`cTmS3%6bF$MDALPe+>7nC&i+PU4#|HVhMro4$>?D z27&)Y>X-6vraa!v0LBsAMQ_{bK=<-y{Kc^j&L=t(XCdP#2ZkbS2fs$WQpSz=1#Y7a zvImgzKc$Shlz%=phAYk1;Cb9Xe*+jigo*y=OXROKj|e)b=lj%Q;Gr1*d*l~dUSuo?UW7+) zBaO6M+Wb2BdPm@(&KblNQtwTaFYTAT%(=8}3hlc1B>ee|lkn$lz$3Vpy_vw&4NQU$ z!!6@Q+(!v_;ubwIxt~)^yNZC@0o(<^D}1}0KYyJ+k6LByzC#_tpGV=(Gm-yf!JkJ{ z{P{27&kN}f;m^%xTZ%vL4`0qc4EiyN`z*3I*ZK3oC(durUgq?DoX5QG)=J+xabEw9 zGqIiQzr(5hw}UsqGg-r@b7muQ9*43Wm-9$m19MVe!+V^X$W(a4_z@@b*m;by3m(( z(Qda&zW*)w`b+Yi@$d^GTax{Z;Li!JMZR;r;7rPAFVl_8*1;$8oeJ!1eNC^f)ve81 z1CDmMHP3GF^$KrnnUebLqfDlQLjP=i!BaRXrzq%!r-C#*Nu1Cw!PD&fo!Z3@bB75$ zU4lIp6K7JU&s@Q8fh*IB?0UI}ZSFf_&pjhl{Y3ba*x-1{g!qU^LwDcz8_LFubUnc3T_(eYPDQ?kuRFprExZX4`-7oTqF6M&ND|LQB z`8NZrly{U*WD*1D!`mtDYx`T z6t}#?C-3uh0)GcE$AC2ooMM+l=wI*mJ>(v_)FFDq@J2fQn+dIxcZ?1C*Th_I1s4kX zR}QTgdF@tgjBqZF<1dJK|dU(&{ zmLW&(?D|pNCHJ|ti?1ka8ID}VGq$Yd(udvJWskbG%foJMcC%aLI=Y-_I&z}lm8u2B z$ccQ-NjVWR-{Gz36Q;|FMyq6)6&@3LvfW7YBKC4z$c5k+mkZz2GcL1!iOR^yLgrJ0 z&6|(7{}e<{ge*BHc*~re=cZ-W7cF#ZqoFNg$7c*Oq8}hH+Pi$j{GY14IaS$8dj-C@ z2s%_XUTHeG&WGh1_ATDkLv^UdI#IJRhVq@@N&^&Q*KgMQ z*1oeoux@j!<+3L@4SPvh$mN3*)PezxA4T#TqmhA)F?81AkwJ|ek-?3f5qo1If^J`E z5pT&~$5+E=<9nO$1>TjfYWmFkUeR9b#r*yF{rora&*oo=OyMHOUh74s_q^8=cD?HG z7W8?^I}P_V74y1%9o{3=$Gq!i`f7Lky1ac<)LVdkmvy{dpU(Fg?(b06cT5MoPmfn~ zzt`twue9SRaCoTy1?n^VyS#gflzkC;jG45h!SbH>CF0&AZYuwWeVtwtbquAAbGR?u z&RN7&@C$FkBmCNz@cy>?fcNIcdlMH?CUTzOKH>|T?n&GLyf*-Q6K~HSBK=LIDW`3c z?>ge!RFic&uuZ3(6KLQ5iLZKBQr~FmHC12V=QSVa!d)`~9>%wzh^`1xkLAlRNeJ=yg%c{%U2t1QXzqje$ z#Llc;-b3WOz44xeUo~1UCe6hv?k&w~^Nt{Y74Q_T`^@X}|Jl1|owDBuJo)tRLF(B; zTrP2|tB-gi^us{3ygAeXpH*WqeBf4~Z|M?kvj7 zqR;n{Hj{XBR;yR?93d`dZnPTX^9=e;#8Pj*u)@k&M%oB+hcwV4RW9&1=Yv1vh?2>0H>15pB3S9TQ zO`)Tt>rm^gtM?yUkYS4JWBR9z-AUMsy90P+4Cio$cN5=5{$t*U2$yjyeP+y&&*>W( zrw8c+4|C;e`uHvI4LzuRx=_vS2Cfmzku3B{&cS^@JhIS^IQWW_ZZt5=1-5;RT?b=$ zFt*tLNZ5)(`iJ;i@ynd~KlIyVNNJF-%6Gs!ih4#_db|h_^}fl-dCPm4_Wc3aT9Kjt zg0c89{_{zHEp=VX7`8-aBX?WkhTT*qA5 z-patI-Y&{HpLT`#T!Bx#3mMbp%%?q!&vz^)yWsA-zE8cyzE5=6WDLpJ7X5OgKbC{@ zD=B{ha7*9*i8{`sj)jzy$Gkjf`)2(TOXElSynCle*`@7*|JDnEpMH|C``s!unK0?I zr?b`aD(YGYtq~jvEt2vJ=*wzoiwWF1=%>ZZLoaSGZ7Jkm$UGX&SgU0`b*OHynK8T_ zTCxtm3wIT83N4a$80A(FR)VbKu?*~ZBZD#Maqs_jU=%`+`_}uBF;z7B5(R0no5Jzq@D%}{z*Pav0+V9RlJqwAd^Tj;JFpRU5c$vb7hwAd z`S!i#x%EG}zHj|PY>{eaHDxwyqltdEP**flD{+>^tgYDej5|9b#lT?#E+=)H!_|o> zV+i8FKNN0=iD;46t!`U+PW2Md5tF$?m-%AN1C&I6lse{#KdcJiN$Kg$0s{(s~TKj3_e|7iZN^M@C3w(>9J{~P`z z`9I5l82_jE590p>|9t*ilqU8U9=BY5XKp)gf8oxQ{e|@V z-JTluZ9b1SYZd2qYfjv|$r*gQZq2w}x;5j{bZaEec_XrVc&|%Wuy?zSy&F8xDCAgT zBhoyp+q%Wkr@jzbU*TbQa3XiSKS7p13pv&V^lJLM^6T$KuO^z(t3hVJ;Ck+OC-rLb zj_cJ-KyKwnZY4SzlaM8Fhhael@=Vcx7{lIP-W&NI^87;nPrlf;^INzjY&~u_Zt=_e z7G7CLy1ijGX73&RF97&UoUy&W^;G&admwR8p?AtCX?|sY}L(C(Z3jxz8b7 zvb5wr*C7u zzJc}n#uL};OMA&$|LS^ub!xp{$a-DQdi~vhe7%q7h{yRe}iRN2J-w3k2qTj`5)s9;{*2I z$J9XGro%BcU}?gVIleFV922>(4+}p!a5(1}x=jc66}nA_JI(62O$P~+^N|SWBL$Qv z{@<>4X+M7)doG-lT!!vz_y;a+^MfvJm#K1Osj}r*ctfJ;rlj4M(d4ndqLr}Um}}!r ziDT&7^yR*zym5Mo%GqPsX&bv@MEzX$?}Kvfd%oTEqt_;{$f=JG{=B4o>>@qSJ=mZq zjJ{QpiN0ZU;_tmNWUxLy^H}6jk0E!;iXj7xe$8K~$9EGS^~T5U^M1NJX0zMXQx%0{ zZ3WqiH)HZsHs5$3mHU$yBf}hZwK_DBv;02nsm8Nsnv<&**w^!J!1`FEk2yQ^1$Xw< z`e-C?eFt~l%^~ypcqDUuXJp9wL}bMJ?ns~YU6FGmA4VpkV=x(e`;#IcMZSZL|I?94 zT@Z;yvIukIE{H_+cMH;ah>_H@fbdV)2M#9B5%z-9`)v0Pq3%J{`G48RK0$b#eQOKl zi~xo{)W5&0BO!Hlvxk>@?7(swFnz&3R_Z>+J~lvnHv8LQz^H&x-aY%6z3pz|zo1>{ zE`&7ppz=;Z9)86;Xo8C+$n6B4Jkm)X2^YA|11`y<(4`W%p3&p2lw%DEd{0x3$ZUGU zChZfLJ_feWf$IxkkorHP?gQ+5r7kI7$`qKTEV+*-cv9fU3?AI*!ip^dxz~tJ>>+ti zKyb?K#)KO?XJVUC?kB2V@2HLA>`wH81@{-LzQ{;)9aueoLCQXw%RCa@nUTTI(eseE zUSzB&(iViH5vfP9pXOe-eb-p;$a&aN%R;}8`LVq5z_A5wgk#rX{JY{uXKj?py0n6S z)AN>=$a9t!v1Kv;pN~GY;W_YhIt6Zw=r(-EOIaIi+$g@FYr0ha#0QC8^zS%y3jNrl^Mh|cc$0U) zOVD%U{kOlUANLBjFGN3X7kEcE|B#Qoq93lBG?%icN$L)(}ia< zeHWuUw;37aixzt?-C?_~TbtA!wx{V1+tCqD#+|4;Ea8Ukusuz8*p6PV{V(Va+k;=} z2Pex->IWz5{7OIA-b+8&eiHp)dzyZ*y_bHlz>%&WZ2t!R;A9y|{b1@$={P6#gYCWa zgY75L52o$M^@Hub^n>la^n>kxML#%+j}!HS?dZwcQ~JU7lzy=NZ_p3sUF6t*m40v% z*Gc_gdzyZ5((OVf7-tOpH5J|Xy8}+aY_B)=OB7Fa6-s8$6E$>pUffk>Mo?0Je-E($s-#NS3 zqm{6K!-n3J)#!SK(G7zxa(A)crcQXngV-~ZyUcrulQZ~H1!{R-T;A)>({1ThaCdDH zJhC_Z&2OFG$DK6ZS`Jo`R&1+>@SB=^$jkZ!E6IBwaij5D3spONkYEL6)nIeoj=whS zOB9oCQ8*s46IX+OBH_ijz2OeR`UIu?BJxYw3&V0RGMl$HRLD%2yxpsK-(299_su2k zT-GNmX{8)L<%xR|<*iJWU5Y(;qui2Ix$Jl5>gD=W$V!;tC?|ENuab5dZLFX@MqYtO z&*Kz)CGYVSl2_X9WuIb6y>IRWzjAl42G|^Y(sspKVC)eUWtzY}Vfy>#zOX+b<(9FA zG@{c`zu;ZZR3iPw9;jXVtHK$L6i}wvwKvheQRr0o*_#|w8B1OKMbAL) zqLfZyeOc(yJX778`y%%VZ!7$c`>7jPkE5x#6$*H37vuH4Y^Ei{WPFO94kOKsEEUw( zmyU-^WQ{T23m=aiq*>TO%2Zi<4q!vii5(>UEmzheS%)|CX823AcQbbM#xZWi7R@sH zP3+Pg6}7EcLjnh3uS zTR6U$Gcl3$4*VhP`rH-6-WKT#NM9ZEBxE9j-N|$da1UimJ$~vj z#*@+S#@_+_1*CN|_GJG%j(x7|e;cVMO!;E3C~=Z~uaSQodJg*jmogX^hkQT9lW7L?tiGTGvYJsa9Pr9`4=NwE=RUJ7TNL{$d)IbC|j2Eqkrg* z(nMs-Q&O_!seiw0`FHRkBTjNhX-}`S;idlz&xWOsPMr^*Iv2_?D?)o zY+CC3uRGa)eZZZ}g<=zFO>+NL)Jt!xC{1rm;u@fB!h594po-aR`B~F4lxa^hvL+w0 zrcUHwLI;Dan`PxLZ87ok_AYnOLJ^gDe7!U1mhlfqKS?I$Ux1X&v zk+<*PU|n|L=ayyfKVx3jROtS)k@tM3!wZ}_MJM=qH9!;$L;mW^u8@{Tl9hN^LoD$J@Jxjol2YURLE zmVf6cD|ueXb&YDwa*y(<(oz3{e0@lkYt*jMYDxt9VPhhZl{t<+8R#Eg9pB)#;%=gg5fu>I2c%+6SZCYex-H%kPi2)z(E{s0~GT z)UJ*0sl6-uO6`5o-_@>+zFPZe^!K$QWBnfW23a%WQ^U6R3zWUvsq8iA#1`?5b13^b z{%&+rYxu;zf;+s|Tf5x9z9#G2-Y1=Jd+Yd?*Z51^S^thaxK00NW&Oz;AimfX zw$`okm%Kh>x7RZ1dTSYJEY8<$cNFin{%qx^-fdYsy$R}X%Y4myEazQsgt{Ws;jw<= zeJ|%v-p$nGu^#fqCoZhWE|OUiP~8cG!*v zyS!zSmRN1hH*JNT(L^P1HJ`E9T66EG-lM@I-dWOi;0jn@!{6b}>a*MXJ~%JSO~Umq zVQ09My&AYi61S=)YTW`{Wx2FJXScTjxRwLg4Zu|mT)V-~LEt)gM!R+MnvcDqT7QWd z+`OOjZ{CuN-|z~~D_@V>Hm~W@aW60z?nk~4Tn7F(uQ}qq7`R3Om-NBrHOIW;(5de( z$Bs6A@Bw|}y@#+0WuFdQ5?AwV)VdkCq+goR&GrIU9dI2)PrL!R#`XD=-d{!^-E_CV z#0pNNFK1l(hFAKr^WQsd(sxFG7Qc^9Aan>?GFQg$5^PaRze<00(|6Ke3HrE}KF$W# zao|bPN(*aHo(8rRdl70=)uLtPYQtCPo-0yW$Up0Ms z-QD}W)$~~nxHy)>_@>+hedMK&WbD@LIA-(GC)+Q7!&^*$Sb^P3KX})4de`w)GKZvp z%~H>fxUDdSn^v2el1^6*cL#m+Gtvv5ilvXhmFRF+>2o)1tztfT!Tq|_d<`*Ip?ACq z{qNx7h1B;a@4gwhOW&Y<`)pq3XD##7z+*LIp_=~gq%EDyy@kxZg);Z(pM^DXZ#7>f zbJ*SvdYyyl(k^OtPTdfV$PRV5D2m6G4<-e0(JJKyq}fPbRz3vWio zAG~?bMXlS>wcoB1-a_sU6#6>((8ouw+{IUbEf_`mf?ZLYtX=0=)YBWDM;2Oh?Z!AZ z%sR2b)Ma&P-TR$d<7lOourCX97p+mLJx<)s!<4pz^}A`LLj65sPxwufww`-rk+)4+ z6#2l0eI~8(Rg>2AvPo;+WzxcJgtLZ+e{l4n&HG&1rdM6WxrlRVjcqRNI@b0}k=)|D;ax*y3>L}TO9=n`nNxFNG-M*KXRlf`Q?JMvX3HF2yDf#W0$RDwZtn(C&oL@zh zH6-?r8#%vfq-y)+8ZB0ABDjCX~N$?ONyKRIYK`tY< zbq>jxdyTek9%Xu_@7&~L& znaX^o`h)puipH9~A6}sRxSS{(8&}p%n~@Q?kr53>SD8Kfa(7f=TO%Ww!`lpVk&nzr zhH(k|U>C9-XE+}5AiF6;Rx>Z0h+G-&iUioho}2w|-rM*>+-GqxXV!9mC6E6C^8bkc z4d_-^aaQ<1<3kB?&!Eg^!X@ls!aPzo`Hgh`RJtXy2UbdRLcT?sr= zzoe@nY%Z|*)6)4;>E;9P-c-FpV*-S`X`2!oRkVFIHmb^r-vVwe$S#_28!$`R9?BGW zjrbk-4Ok^!U=uhWPvsYwZcMfP=c%w|DZf!hE9s^F9}sSCdPt{z$Oz_k5H4kkEvaVQ z!cPh;Z}A!O1}FG6aNz={M%j`_mt$amO3?=C6Tv|vpUAHm>yt{;>`oQZ-^QAd{&!Ml z1#rpvhrmL<1StRJV#vED0jFeYP+H$~o7XDnipb9nNY z$n!P(DIdGESyv;QIPB6qJ=kVFqRT|}JL+_ z^Y)belz+^A%5fbJc~3OTJYT>(?_{3uXP&=*;ynL{@24o{x%D5P=UbWQr|zfFzo+aY zowAR_IgMifbu#-%C)02J^2ggYzRX+UIo9yJoIbvr#_?X5ZY!jEP`hp;WK7aV$SrMI zNjo8DPg_=7XlfT*AzRL$x=ieeJU;#WWxu}p!i{1xr20yw`2#r{&rr@5i}JNJJa2Bf zp1n@ZJf*F!G->|ZbBC{D4_GxwX~E~rEvnqz61YZbfp~Uk)oi6X;G5y84;8`ZF66%K zc+RchS?s3~p0h#?_g|(&U*%9K{O%IsYrd_tyBC?X?^9;OK68uTJfded`&!UWS_FUQQbtFt3o*k5M?$jUJguQ;TX_tL_c6~W} zw7UbR_pEX&t@a1Wa;_rXbn+DNui(C~Z-uJ&n@{h7$2&9#n4`!mUs`(fAz$D-J!X?{ zU&qbUF+0_R~&oDZ@#+67r3U! zmto!Lo1MHTbdS8d@|!`2=AdumyH#l>`n|(4a8tug3R~Ig33I`>Ls9gdr_crtFb7Jz zWFI5#NNmwaqUQf#}^}L3E5pf>e`*4qr#uMTn6YWS$jCLl@VDGY%@JZ1G z=gP9j$_xflWk}nsd@taaIs>?O;66XvrNeMuv^((tXBX{+JsgWAgwL0HM&mc(miz+4 z82od^N7`+)S#VrUxQRcy6(PZ^wEtHA=g_vvw97>JY2bGt zdBr}Ryw7d|U%l<;8)L^pUMFQr`>nVuaZCGMxMd6pEHa+5c)LY(X^UuIG3{{BkA>7D zI@DsH&Vf8)q0EW=(v8*nn2lO%8JlkMvnSH+=a)P8C$duSv&(odfY#*b@30&!2{5i@ zoI4q#iu&|%&wK6)`r4Z1yUAAv%`5QjYk1Jy;=9bG6)+!s^Gur0Y;N~m!{419YPiy* z{c6e4hpvy?^f|n=oH-m=(Bm^-)#HPf${hAXlY9ZC-_bu4T{M}?6M(zn2Vc!)=J8&0 zYpy`J3i)Ip?|hTt?p0doGK8eIIrZPMFKsIgq(5_XCaokiK<- zGfx`sr5_}$iZ}_!t{-+ORd6BxGCt`eBaO^uBd^S5E9s@|4!-;F+xet_C66(e)AzlG z+nC?$*aH~zdp&jf^tzJsdp%`V;+MJlx6bbX>7^|)c4a#tO zA3_6Ut_wYoc`tNN=JX)a`bZ;qllBNs(&xD`zXdNczh&M}VSb;Jn%`o7^0dEke#@Me z`R%3-W3G$aoE9$i8S}fCwiE$-A#gj==66wQe%I!EHv08(oUr=9o0L_>{FXUekUqbe z11HRH#`+2KTgphE-%HFb1v0;X!2G@-HNU^jypA)!XYg<86KZgqwCBHn^r2eju@&CH zSLs9s?Av#Jz#6J5%n#K}HfaxHW5f^r;c-Dt`TB&ey875dF^8|t7ns{4{7GO*MUOu) zzvqEFpaa?FjsAX0ll_;8a<&aqhoDCb9$ca{S<`ho;2f^g0Vnmo3mv$Rx@A2NVvFQw zcfb=+=Jldy2H#`c5xNBar+;oPI=dg0g!(zPI=53>3C|^Imkq@>_Z_DC%lLAk7prw0 z-o7bYAN@9o{s%TYc{}Z(RqTD(uy-W%!NVHjL=IH}o-HDe!e7Z>`VoCGJuXQfGML-w z?h^MEeMqMF5SBrDk#Uyeo{75>x0O%IG}d~B{LhRHnM{*8*h!p06Vm?=lDCnuvV*zQ zL0(zQUSv*5xmLbUbibLgofZ5HcN1f3CS|Q-Ts1SUVuVE)!vgzE(#RMWxTClQmIe50 z@Jkzo7OiJ3E5*No_3R1Ov!_|-gpYZW`5`bO%hcEZOx#Y~0z(J!i}6?E?!^5|=8*V* z!902zTl9wr`xQ3#1s_$UnStMi+i3p=`~rjEL1^bQ*u{tA{RsDzW;4&F zuVnofJQz4J@F94rBV1sTev>u}J|v&u!?6D$coCc==|e{FFnL~NjtLH>{YKkmzJ_VP z;8of$xcdcddx~~(p02O|1O5tqZ~}vea)my~7?6JR;FdlR{JU|N;}-l&eTMyyX4?p$8AYZ+y8VxG@`?O3aBfz8>(Jcb?>Uc< z^wJNC@$SS{i0s82oUgo-sSdf&|2WPEOg6VTg-)CYofw&-6NR$=TjAmPv)^hMZPK2) zo;?J7ykb99K3cV~ZZGdUOU@g7^L*K+7KzIzt}b7-T!$^NOJ{KAbB7u*3c0b+0OtM^ zCTN1t0rP$1bs8|8GRKX#!lYwh~Bp7$j>>iT%&ArUgoWXc;@>h<^9x`KiM^V<9+jVTZ%0;S^2{!!As3x zzgNpwp5gp*7j;JXDyXvn{fUAfl^p4xmgYs`7E!OHX}xXnk?6ma9C?Di(DV0mektLK zJObkf7pVm^IFo#suY~sRV6Jyr29M9o%dW3Mui^pvS<+p4A#WI=pSu|tOx&+@a2GP? z>YVz3svNo0L3!U_dSn9mYt9%v+%>jhq*?AkpQyH&-UBjR@IZthezbEguwzj&Yb-W@U9$aB<`h14^c_Yyv^j2u7I8M6+D zuN)?IqEGs^W2{ZHoVID(B+dt@JLgQb;E3h_vG*?UQB~*O|JpM<7m@%8cL9@`33n6$ z5d{_Y%!GjAgOKhN^S+gbGt`pF*Hsc4z=X&3zhTDX2HYu znggM4QO;ilRl(_mlW%>1a!#e3wRx(33VbXe&qng}lIMK#l<&S7d1dfl#^xiTdh*=f z`awqO+t+5l6FP^qB{}`G{IbUy71*y8zi@GIs{ri+N#fP+)8RS_)Ii=n`-B-<)cDnt;qw}Pm z)TxA7C&d3V=Vzfus8eJ3HmQ0x5coSI+cYH?ud^c1;c@A%hg_hvIg!)uVJ*%aj)gp^WXtUjDv!xF9 zE;$mR>-gq#2`_c4gZeteaWqtb+{?9i=*PJ~4`rbnq~5p*(?XiRCC%SbU*5FyAB$Y? zChxaf_hH=)znTXn#h2~3#| zRuTSJlw%0?c&Wp`uHi^XzVQY-uXUz=iHD}EgQ0&@pM`ek z{35iK`ns3&oWx1hi)uUkZqnSn<}!(mE#GDVGWPI2QgVxvXB=Hn z!#DF0R^;zTH#XANYwR?Gt?>*m`m4%zKdqm9?~dpj_B1Sa^DRX``>4C~i+LM~`c^_c zb0b5YZ!wg7s-!P*p@&IVbfd_`k1Wb)2SIr3>h_!ev!96ns@O-=n8r_#ee$Ev$k}uT zd@1@BjXtJ>zEAqKTKYff%QEO|mT2AT_t4KM^#fgh;*C)F)t0^bhIc~ig%{5DXTe_; zci0-31N03}&i)ra0YBUg5a9g3X9Rs5wA>S5-3uW12E;;P`nP8K#K5+?1buS>{rmFZ z%e;*OT@Kyy($RTga0z&;Krl{Vm?89X!9P{Ij?SwAuV~DtggxOmZ*%-xr<-}}^T0S& z)mqd2j?A`rad_haPk7^_>$RqXL&6)|$AmX73K()<_2G(ZjAUq*ksQgqZMYTe;>e6V z_%r5AUuTYbvAgp-=NZY>phumHJ*$}ZENPFx<4`pzFW23 zTBf(vw`-C69#hFXtFt0^RfG9_8I$UKnQeEpGl#o5Ytr4D^|tSA&WzNSW=sl~Wk+fs z%bHYuamJ(#+p{KZ_*v$pM=#5m^yo8LlOBB?`UT^uH zO0IuFC2M+U$=e-T^40??dGCwNzh`R6J9}x#yFQ?-KT*j$aQQsUwlUAdIx)JMuazh zFg(2RI^ygfM*N}SjSns!*;$WlA4UFk$g>_lQei}7oi@0uFF&Sd=BEiaex>+go% z1#jOgWvn~d3M=E+*LW-T157UC*X8#3bt+@qPq=SF#;=Asem$hin;n^|&>p|`Wn9J` zl8gf!*iL1+%W(Ul#ZShsmVaO7cY4)V;LgBQL)X~hE7QU+gw{>}zKmsh9h=`WxQErp zy{yw6GJfrQ(($XzjDKr!PluMdp;pFk!pkd+U*CvzB;K*duWhkJLdp;$Ts7g! zp|hYnFd`2h?i%P4=yzhgFNOP;v4e@;`(ugO`1Rc%PbmD#36qKY0CcMSui!R$pd2!O z?Z^8n!b7k9`#E=(AL+yUDw$p0R}q=WfAU_6j9IrLACbx9$VOx!-#H}%8S9FyglCbH zj8`8gFZq_jlgLNPohq}8Q{_8q*v_P1i`k z9>12I(`%D)T5kPM&GG9YUA~o~z8h)dSM>C;@#{J0T5~Sj!}t>&%s90vd_TIhT94fK z5W43PmArp5dZ*&^2kxT1{qBPB#`yW+jWx8_4!zh2PY7?k3;of4Ho9bdc;mM`M)Ik1S1-MD zb5`4Zi${0Xpik~VPuDCS+Ibr~CRk`BpPBldrT3v<9$0)9y2XR->a0T71enW{J9ks} z?KWf>Pa~738#V9Kn$n(bC}_S=<%ch997+E&LM30~ZG_Lh+wz3$ck(ae%=Sw3lCsWf zyri_>-^slD*M8^Lg&wlk)Y8vxyqcG>=`8eC2f8d%>HB)3n@;x5t>`EJ1S1(HTn2A_ zPFzvi|-5vYq~` zeg3O`p0s^ZN2gP7zgGK{`kmfBB^|qcp0J;A5p8wtiEUNZu+r~U`A2s~d1qK-fYLnf z)Xyh9!$@A*hp`@gtB1WR-I%LRy*2ysTJEjqea0N#o4q72XWwNPcH1<2U`~C!{~v}* z_&eE0xSe+VZ;S>0#CtsS|A#;4zPcr}VV}bpk#X`%H>kt2xHm@n*M*Mm+;`NCcNAOp z&R|Z~$DL(ajG5=)&gLGwcKn82Rsz?U#XD{ujSYXv?2_@NnxA zmh={q?w@e4B)<*ho0_W}!2en8A12DkZv+2bNm$8G_>lBg@&65km$Yu&-Lkh=`$xPF z+r8e&JI1|PJ6edJV(m!yT}hligg;1pNh=rkVbYUwN&d5-Ggv$N6Yfmbj`a49goAaX z0BJaQm-!y@IY>S$aQ7iS;dc?~)Zku;ThhA+x_|qDgt+^)A545B7E4s)cNI8U@|8J< z1o6$U@@FcP=2j$X)VG$wuUI1>xKA&zJPbQ_3VVNR@v&|BDRz^1sNSfU@ON zF5ySYHji>$3BOms>vZ_cbsk?^l5bch<%Gu)J0FpsKaKX;wB&0*^FD6m$Gz2Io$@&0 z-y!dC^BrYeAp2J~_w0)QW4y1}o%`#lpJ4bHV~AJG_hygZAN6x^|7NX6y`p{#<~QG( zW!-8H_uh}g$o=)NW0;#c+;WmL%tveFj?8Y{k(s^iFIQ)6`?NfBTXIRpw!ho=V}9@h z2WM@xr60YdmL9E9ZT@_t=@w<(!NQs6C3j9!^C~%8(|m^-6t?fi9IZ0VyD@2($L_`y zKb>(u^F;+N=32x(J=@!KQNYpx1DVUZ7+q6xfsvd6CNM@ANk96)dj@*p8YB5R>p2Hm zqq#8TYx*5)Lh^=%anrYs^Z;j{shs?$ zx|{Dgi@EfCrOj;5`ebMpmiUeaM8`Y?sF8fm36CNxhlwKeqQA{>$};uTfJznTfO*& zb*p^N=~(MlFMe^|D%V=KDkkk<4e!p0y(MkkD);5kc>IuunZLDe)oHI=b*8Oby?By! zs~7Ect4?d(ihDLsT({~xwr(|!Ioah6ou^#4DrVivE$ddC_nqx{QSX)Wp1E!{`h<0> zPJ7*|(_FVoU!TgB^^DZ|6l(_;cKg+_^@9`Fr(R@E;Q0E~WXf%=Pj!a2<-TXGPl?>E z^{GyCj(bi+I59s@|HArI5qTb4pCV5Od7gZI>ctb*r#wb#eX5i7srN#DrU@Dp2yawkkwJnJfD1h>ctb*r#ykw`c!A=0Oh=vJRRg|txt8@>r>%` zL7rXLr)HApvGpmwv7CWF`TEq0C#+9R4yV?qI$583FH|CP{N!n^Lv)&J7n#V`fo!|3 zPhG^iz_Ily&Jr&}wkKbodQnebpK>>()~7l{Qir5X89kl$`V@JxW-)_2eeyk7pNjTj zeTudy>r=88C3QvWg!s!ENS#WAGQTK zMQVL2wT9&(yqk1nZR*Fgh2PK?bk>qOwseN1eu)gmb$c(gg8x>qR&^WeMhjV!l6B47 zbAD>p32En#s-q#Db*b^;{h{GGuY{tkA$80BY3ME1azqD=v-8m?`x~V725VF`*!#)n z?bbhLWRce#zMt?th5Q#Zc7|jPv=O<;n&;`%sfpQdhjxSygyN(bB)^()2jzP&^fTuN zp((6i4I>Y0J*qQw1?fHC`bma|vJD}hA*@M_g-=r!WxyIFtR=+Y04Uv8#i-%Cp}v(_=NwKYw#^?^Z5GIi}v~ycOaPSQ}3O)K1KVm z)}uN@C$3K&cb{y1$_p=2CuMyqd{xg)`LaGmA5ukMBK@12{w;(4MAoFF4^#9dUgr<= zA*@ZgUu6!RwJCGY1#45okXx$nYW*5(Q|gJj#H1`$@M$J%Q+tojTO#)li!54>&I7|l z{xo+6SZ6v|rxdI+4Xh*Qiv64`_JMW0U>$?IaxdBjHi~@VykrGt8bN;SMtDWV$&%{?XIMKNdg7$3Iq@$HzbVF^qqF{G+Fhf2_2QkAL(o z;~)JL;~zb3{G)dn|L9%DKl(|=KYH5u$I4T1zcv1WzZ1qk`ad!L(YuU)bbI`xpJM!D z<@v?&5APH*zFEY3h5z;AAM!jl{;}j|jejiK8vj`Ne*N)}-evsLo%?i89RKW=b5r*C zXES#Y8mAcloa_!K^(8-P`=9qL>O90*nxlK1ZE?RA`CW~X{O~_!ZTsMRMskG8+~zrh zcL*7K$oON(9s0JRE|qj?M$;m6PBq5Qos<=vn;JG)B{LZN3?IN7!`v~Tcw>2FAC(;Q zoVKl;F~O*8l~ilj-Q&tr+dK_DMh;!3nqcj22kSLznLG0R1)o0v50THayq%^_+9UVN z@vgz#jBS60Ki-1oZ3EqU+o0TuUUO{w`wiN*L&F)j`5kTh&*kmH6-HBVmC@v2%rFe& zV@_o{cT7~@p2glc^}L6?p2*4C)Qxf4OAg2HSxAy~{fPMK_#K2!g}HUQdTufM_7;28 zbKhQLH05*mQZZvR*^3xpeZ7n^OMZrGD;vgJ%B<@!hoo1qh7)4Fclkv29CGjGA@(Qg zvF5rlYkLmL=|DBlL0MhMu$ZxtjL-0I^X2s%M3~uE-V|W0*kh18`^Lgvgqb*NZV~sHPtXY4 z$sH$A_6P07eu@2{9n4YHbC0RE!Gqr7rI#1!zHn=)Q#sDj;K z&?y1jVO1~@|FQW0%JzE}Tf)eHZq=Yq#|+}VRFAVkFUFn>u8U({;jK=&6H4xvk+>3X z7Fg*GaMBv~Wwl@*ByL75miR81=snyQlGkU1{|RBQ!SC1j4JYqetYLacdo^Lbm?@G! z`DNh08sjHU26HH>^e+s6sqt$foksGMyxO3zX0GLL6XicCv+$R4&xY?d@)KS~_QG$9uY)F^A16d6!nepw z_!hoIR>Ie8jPN1+2rq)wgn!{l_}K$3d`O;>$8Ow`M@klwo}aLimQPGtTB$Tfr_C{W zkgwat-Co=$A>UtUu={f1&q`C)W*qPngC7TXPBiH9-GyH_M)DW_e1sQ1HTvmPwMvatIYUXB!pcq_X9~@Goc*oIsBQ(|Ldh|#Z zdc;E;BL3_O^oZyaKkdtbxei^j#MUKc=#r(Je+ZyYzTLw}{+2e%#`)RbLbr@s+hb5I zdL>GnJ?ND6n(^6~LO4tnK>&}Hb9Pq5=owU4_<>boO@S?HA@dSf2uEKS?zV9qF) zIiuOg{yODAzx-k7nuonbS3W$iXbWN5(Gj9w{+hkAaNcCv`s5o5n;!NTb!L|rPFpg+ z=#!l96z)Oa99VE=(bc(Y3WqQJW|2Ghrot%tCV#=KqSmXfC|a}R>Y{^ztBTwe-lBf< zON*||omS)yOfL%B`bVKdrEFSW>q9QytxxHoGdTk)G7^2GQBIF(!gCaQ$Ivu%&vy!a z*{cc*&_CzRn^*MBOXd`f9boC8$=uPDk;5A^*wPLK@wNu?XY#w zZ_;#7dVTClOTAx58+@NSDEvtqzLvD)E%u+{Hv+z-EtZk*8p28&5ZD(w*|D@)43CG4ejq$9c|T|ccM+>cM8pHjR^9MMlAk97TX zHGGS%6<+1L2)`-5()E+@E%Fq7B7BJ)g|DkI={hCFzwp#mKS>_x`bpAE=_g66tA0wQ zk*=Ro`a$$lN>_<~veFXyo~WNhXZSH9-yr6n)lc%~bTxHR_Rgo*fmHsq1M;-=(ll(j zFXvSH$>qqczr@y0ZtA}S<5bV;adgw>bo~UK&An8ne%gO@UhG^WIqRCw9|*8FPH{Fq z$X*sVm@htBHOaYm#XAY{EY5F&r{ZTT_S0ya8o*R;FjeeqBUz~T-IQnID)sv(!By}a ziQ_*-_1%<-zl727a}i$Ri@*4B@7Qx?W6*Qx#@PM`hX&aTw_-ec@hsI80L%H{q5W*t z)P9!Hn@$OW7Bj-3nsyl(JZw^B3v(2n9$Ra5+2c$jK5ow0T;_rNu9@1San zWidz3ou{r1%t6C{JLyT;uBHB-IfQq4&`&N*0{KjiwUZ z?Zd&Qd5%Fb?E6KgdD@_OPa}CH<@yF?+QYl+`&pN`S?&#ULib1h#VR>hIdl79;=PTg ztCW_D91G&tswRy%@vGq*|I_g28#XlzR1;#?8clVjjr#EEjrzgSMzZCv>)!eV_p_J} z3A6drb#J*j2fqS$Z^HPX4>+?&jbpFZ0F&rt~_W zPAl#SJdLnds4cp*zpF4eV!|;a@dD<471duu-)$wGzhQUhT*3L6X7#v!B|2@GbBEr< ze^A2WG1 znr_1VAf`IzO>D({>WJ!3gLhlQsz78TWjhGXS0mmBf#>-?eqvF3=#n^hCrFHh9s|2lMk=q1>Sw3G46P5tbH{snY7 zw#f1JzaE|U;rT{WKjd~5JhvL$O(FbXXCs$$p+{mX+&*Zx*qHlmSqjG41^qJev+uN< z9UxpeVMK-(bJzM~jvaahwA{P?7ss>g$J=SjaU6U0l=`9G7kSG5y>`NUOc;^n>)0Qj znsqHs5iu_Z~-HeT@3v=*+9{KtDLZ zl2Y##w$40Y2kos~#z&ZH+SD-G6uP1fJ<)a$_ZCbLqvIc@?R3z#eCj#94!RY)gEo2) zyBy=j)M8j>Bdk9W#jY#yC8|rjiS;E$VtT1R;V<|R9lD0v-@p;v?N zTDtr<^BGV39n1wzV=l0Sxj;W-W*=i_FJoqz|0~^gbPwN$IRLq5C5!!y=G`j(UMJkG z^8D3Pwr%HLl~diR65wvg;G0@9fS#_xRBYFhwdnZrXS8I7)o%=v{v-GhcSfQYg70!> z7&Fh%Td;2z_LreeFXgO89V_eLIbw`xhbbH)9KwQt=*m`XcrF?JDmKWh!O z4+S3Ktpxk761j&&{1yJcb@4y`F(-4h+*1PpxCBw|S zN&@YaiTL8)Ph4f+b5j1kgmIaE<*!?`q#bxsXtx#jCu#Hxn(WIwT=}jySz!D~Z=_Ca zh3{-RTg_g|@Fzz79?GV8_kc62`!dyzIhB_=n{LZj`y|fqooZ&R|F)qEv$gsUoSFM1 zt)-$zc~>rYnZHReLURxGoD+Q;cj}`=K2P#S;Vom;;U&D4P}=OSkJGR2DVbe2Olh-A zn}^l!Hfe`RH=DF`Hg`;z?!CArj_6^D_eNU0puRzWB`vNOcdH#=($#RkY`U$q8gX0s zW|(PfnHzK~?@ZGj=YK2zEYsbBTk?0SY~1epD%|BR)h1=x&fS^9kLjk2RzBM7AYmkL zD<7*&Ui_?lj+aZrPx5NSuEGQ{UW|rG$9(DiPfB+5Z-@U``3Ya?X;+c{UdE)A>@7?` zyDRx9>Vx0@K8(?3GlzdTP-4^xPjdfg)qvdG+fW2v!nlmtb(-3siws;t;9FHb5~Q9S z+?B|EtAYESO#$BH%%Lq_%ed-t#)o3xxkSx#XQ(&M#0N)b&@>i$DCY648=5k_L{m4O~u$VD>pRF z(QcCcL!7`ybk1Md7fzaz zhN-hSYZAn*)^0E{aB!jqCJw*pyAJ*{^EW9ye^dF-RC0^h+f{Op*mp7inSniCOV)_p zOH2B*u>VLnalgr#5ec_bC7t5FpLpQ#@{PoM!AS1mUV!pv@Y8q~=XL!4YWsZz-Op?N z-vfOpaX%mpNt?SI%9$r9mvje0GjD0qe$zn-^^ELY^ zQ-Cu#hNLq}OYRZ3hxFFNJ9PPG&gqEXL~pWuH#`zA&YMBa++z?JgI*PzbK&Lf%*FQb zT5itq#Fl$=gCEgHfx83i98IwTHM2$2>VpU9uU-fHk8w7c?pEB-fLHl1FwC0_K8AZE z`&J}f&Y_$BnfTwXEWgjm=YakH`_Qd6{S)ZNZ2A!iOM2D#t@AY*oLzSD4R4|hfr*yi zcgK_FDBPutIVO9Pt3A+b_-~9iSyo6{2jX6Z8=fk9L9c-3TZD3;uZO0r3m>|6+oHc2 z$-rXV@c6AiLRUib{T6=!T?UN|mb4qm>)yq^05`lZeG_^<^!v>7O#bG!z!lJM8_8w6 z@t*@tnU=o@eHrvm7#r<0lIynPz8LolMsnq5=u&9pcH=|PK4{9m>VD`c(2p3&@7x7F z85&sz#$(@(JqCL{_9*OX>|xj&dGCOJB(RRVd(clZ9t*6vd|TLWL<5_>$$|3UD%SM; z-%L#MbB4@+b@aQ~hTlkp{oZI`1!G3W%9i`8XyAGyIl%nimjJsF-X8_C+5eYB1B*GU zb<9028mKgqQQNKlvhFRgA#qBh!V{Q~c+(SL!N?l;oS)_2X*gBABT$u8yi213VPs4l zv&SBRfs_ZH*A5hHpE}-J;w?E`)?Rk%{01||%=eu_E*GCV-UYS$gVt*AQ>csp9!g9q-qC z*Y~NDC;jeIP95)I^1Js``At4`ydM$o`BTN4cyIsu0cOA zj*Ezn6hF}cYtWshpXf^3yh)3mth8y-lhSr2p6E&1pGk|3q)nN$=t$a$NsEr8?whpe zNb03Yi;kqOnY8Ff>W@i_exy#AwCG2^vq_77A5nzsV7s{wG&#`kXwm>4Un9O`p?4Y=<}5Q|!-;WWLycGm-^j|5ff{ z!Tuw2bz*;HB>RZ{fsyPh_5mZ=PwaLh*>y!7n4jZbL7cIq31)1IW4>KzB)1TEDE~>g9?V%TC(LTh zFw)wKdmZ#p=tjawI$H^!u*19YA4(Vxwii2ui9s(UPUtS)h%hcsJV9Cd`h1BAzLLaT zUuoh^|3!(=?O>cr%CR1dv<_Uf%A2gb-fP}-GXcK7Rpw28OuU8Fyd{fWw#J)`U{|d0 zCf~%aTI*9%e=|O&^O{&>YbU$@L!tH{g)&(|78h>-q~Rm48NJajBQ75aJP5 z%I`6zM_q<5I>ac6GOlQ2KULc}qcl3)SP&g+TofI~_ZVti87)Tcn*Varo0U-h*`z-w zQQ)7K$nsy2$oF59$n<}Md@oKo{WBAR`~Bv;v%KA2_6T`b_l(@+>lqP#Ck9mHyZpZr z`kgY>W-#6{n7>wxWgN^cYwQK^365bN*o`govw~}6&Q`F{eD+nJgXxb+AFp<$!w%+; zou_ffT3MmtG@4``tpUI0>cS)97lUqb6de)&FqpWx`t(l4yhO93uruZyu)TTx)TQ$> z)xFKt3yyp@i@SW(>cVEnwMW7Z*}Jj2@ZMf3(p-J*5pbC4rhkYuJB-g7?EjzV{}}YA z*o}P_B;?PBi3#oR|<<~<(&Xzg3)sVv^{*flh;n|r$%-=E3;E*UQ_zFBSh zOKF7x}nI_iWPLf`2joUc$6MOZYOvc;I6Qd3wk*f&Wna z%L$YD6PG>=x{5Hx@Lmi*Zul9F|8V^42r~JR#DcAT8Z=wobH^OUVt1l}2x2hhIdlE)M%A7q(wTV10?&Pjf z+*1Bll^4k#hd*)`S-40uz5Fin5*eJT-0ilUq^wSO6xm2w-O!RpHU2(m;bn`YkKKr$ zM`-Ms_FJl5>$bQp{v46)Zt#XoGj<$kU+ z+3!;J5N-Zl#=x-$hmK-R=vwNutW)`z`*YLQ4eGyJ)~aX&GWR!>wWy1j^NTar$9%*N z=Zr?qCp7B6clH_OQ|^e5e0|JWl#{N^@tw)O8P3x`=ao5hbi#h8W0ZWOnYoMO9*<#-+c-|^}h_1r(2yA=A)SI?~HosisizI)57fy5py zBe#`32UR}}B-Xz=tiBOj;z*kE|9ax4(%@~7T>7lpHLn)eKTSOO|1oUl_RaWrkaiHi z*NDG|uvVI9)^k^FoA4|1dy=p4n9UhCDT}00NqFI}mi(n0RrpD{UZy;iq+_Oq-^=*P z|KcxUa@l7haV0%TS9m7f!)7}8i`z_#|GTCw|C#BZB%H*V#(bX6U3^2nq;86wb-v#s zo39iPwbZrNS4Y&hyjo$_FK2efpr6VdAK%gZUhq>+8Giry zxjfM#bA8gMT;^{o$1bC8G6%hH#9D2TMjZ`gJNGT751Fa7eU~u5mC~sJ!gsq_4Z72% z=ABchp36WFpF_Ul|5y%pgG2XcKKW(#e@T5`ijJ+ql*}QcG5l!+$GpE(a$nJ zFr0eX&}c*(d5d;Z!{yN}yrDa!!5f|2;EVpS(HDJM(^;$5BM$!CMHmn5@j~bom;%CO z5bk`^sKjI$59sDtp74{P?{?j-FT`tH*=5^p@=(%Xj6 zQoh0P^`FLl`V`{-8)hV7M-p}?>3kplZi2sT{4c_N3wBiuz2muC*NAg9`N!bTMfl;+ zbIGp~``(z55Sf^J8F0@ge1ZQyy%@eqgg5dq`6m5){rBrqo?lTO*^?#v9EAUTuaxO> z^7AI#?z{Ck@uPf~`S82K>zPz8DfuD|B`jK+z0JQLQ02z2OyUqTs zfj*~U=w^7U!j!>}eE(|XRs|ojh8yMFK(o&M0%J1ts+@nKwG(jaZF znDm3BFKJ7?l{CSt37I1sN}qO>L-95!rc&nS_kv$bShouNgg4=!j~1xq z#bZ?@__{Z_Q*;*mEmiD!U_B$Qa?QK+121@!4g5Egx8}doeC@8gFo${D`xEw*J^~*- znu~U=!5)wQ7+>M8kLUx(EVyvw1^8Xfy!}$0{~SfT202vI10BZ5LZzD6piwa8qbVaN z|8eTb9=nTn_19I?nrx$K3}MgBR88Y2Y9nQi@_hU*%~J)E?-=ec?Vh8WWUlhA&Ra&F zmaUq=*E47TgrVg zYs$iVtxH8dX750X_bBca@O~zFmP1o7BV(#b1Ntbk7XB6V6w*5Pg$qYsN*R4p9^$z1 z?@l?-tS;JhX0?ip-(9q;mq$gUj8pJma+0?23Gxz|`bcLM;Us?_VI|)=#Fc#EZ}~Ic z!d=4ej;g|4*EioXQh0l&rEu36;y$Al?YfKnr7X|fHf5xw)x+jj&XL_3IO@IDy)?4ce=U8tZ=g!tA6`0h(NV=)B1BlSN>eV{L{4^c;Iu@lsd^mZ)Y zd$`U2GvvkiDDrfHxrcfAt-Gd-TnNvs-9?@u%qtlAKI}`2-1YF(k@77wXhW=>6|nxa zyzzIm&vktU1>vI%egdyMn*!r|M&>`E?oIWdPcz22ue*9qQP;Q8U%m|1n#zTfxvaD5 z)NzN>3ZzX-ot}o6kr598}m%qsSMA)w8is+E$P?S6A3x?yCuw$Dmac2|+pk>{u zPxHd)faXO}Nh_~87`>QuWW6f8d2w_m@dAO0#1h;Ufly*_^O9%@dDIe5k@hswSr({F zL~*YSEKKO+RjM)zT5;!-&vcblusX0PA!m)R3j`CA7xxDj2yc?7moh90EKUd?YXeIX zBf)1F+f@l>a5eH+VruE(GArmcdH0*mE_k> z-x8x=IoRlp#=$HfgNfqwEr;@@;<|xGo`O%E!Ha{7U`t@i*$Pj$ft!Zv1z2SA#ElrLmYYEUvrd z?CD;Imij_u;n$-PuQM(rYEZ${$-Y5F91teDV`V!EpL#DX)Z)GDm3_ z2l+m~COp`GwtTO}jBQipevC3)&-ZzadT}d!JqF*B=RVwz!LRTjybLBSk;hZyA!(vV zX8!;qZR!s45_yT-M1CSi$xHGT`K4(2evE0Bi|k$vE=@c`ULwDxbCfAXM z$V9$%HTmC7e)p2rgTY`T_auFT)DNi}jpQM6Swei#36c+c)d~)VncJcM#v2XlvpEJ| zE^-}0J*dU@!)qC)3NziPsH?=(VH9p1J3zh_Co`B9sO2X~5w7ZIUbkuHZ z{;GQ>_aQLXCHwo+-z3u6>jUW9=hCfrOq^iP4s==Iefqn0(s*Caj%tjV*iXlvWuL*` z0K&MS6?=aLhq|x@pNf79fGJ<@GOv-6kE9hOU4>qB8SM#4Uu>TX{7769LoX(VN;t`1 z86Am$@E|sNk$AI<(1~ZVpQsl7m%-d%Ci|baO4%rHIdRG)P3nSshl-@~P1#xM+FjXd z!LDpAYvv(Moip;On@4sZd-KQ~!jJ4K=1f!>rV$gy$Q(KSahrej$RlMK@9Ggp z0+?(t#6jM$AMQ}+oIyXH6~1=YNc?i3vyDf0jSfG$tA_Y-<}p3k1}2Mi7MW=cC#~Vf z(yFEG3VsFaxUs=H%lCrES~xS(K|7G|xS4wBrw*8XQa0yFseh?5rQ15?bHYcBa?Y%Q zw;Ax00dLds)8Q)@6VB!nEdU{~;e}AgdD;YaKj(T^-qF(NQ zaXB23Sv%v=**n{#zMcD{({^@5^Ox-jW$xhKZtUJG_Jqb^hHU;g>e?QQ4u2*dt>wRT zd3U9IZ;eI!5oUs2(b0_x}|EN8> z5PJeS>*eTKLiuK8}>)X?dXUKKb5$Jx9J^aiItcupw$x{(fhEU!?;yu#Ixh$ zsPJ9dSx!^RjAT9aadha8SX9bUtDKQl_*aleIkXS+jU(45qRlF@61x=t)&Xj^$nIy1 z#oeSS?(wv1;kkf*P0Awa3?pnW%Bl#XLrWS`R{1W^;&%|^!|cE>pRxxjXGTMN)WEKw z90qYJDZ_N=GI$bxmdCD7X!vg?p22@!{Dns!{xWwavQB-!T6B?&bLQ|3rM(OxP62rd zKVz{ykMS<^X3EX~6|q1f(D7~ZV6KS&rCbJXFaC0FLC$A2OIst4Ms#5{?M&)@u?u}q zU6Ol{LW}__s7uTroV4Ag>Omv27TqOt6X>etW0y6X`2`wcQOV!TGfX>z2N(HEdk>-e z!`-{p2m5xbf0c6*4%(m#9z-`vy>-uP2aD&k{s}H$Ng0jysJr2vP>}cvThckm80T%y z-p3P1=cV7-DR+j-eW7wssN4@KcY(@%pWJ(M?5@t@Y-8IkiZMU)z{RvZ=;e2!Ptoi9 zN@$#XBbuf@ z<1M6m#eW+A<-3CBe;WTO`#(uX<_}1JoSv3mO0FsUOVdE!(*Lx=FZv8zL?4Zx7hRg# zQ*7-g&NlZG{|Ona^k|XiYYIE%Eyl&YyvghOd6UZrdXp;(y~%HTnByGgO)eV6y66~h za@}~=7bkj?*H30%Ux3T}WTOaDT?T+nzw?(#dPxQrow%zUNz3sL& zy|&$Tmr7pBnpUeb+_aE0%9<8#`T#Q&)6EfXYR2AzE^I}=%QrZLo?Fk}gbKbz&Fw0g ziEb<7zxC{0sO0SMSAg$fpX|?p`j7?$oOo;xiVlRS^ zJ0q$%XLH*+m6UpLo0i90E_wC!3siD6cYoEe@8Kop#UJM$>EDvpt?XH7B`x8Rx7#1O zh5yRsKkORzEpRsQp+})Nuyn4|E5CAKI=!ZH?WVQ7W%jBhi&GK$kd+bWA8h%KO#KQV2wfcUe}%Qe|Y>U{O6p) zztr;ANarZ&#jxG>{%*-v_F8M~*%n*&aVKOCHatBF?d1P3bQ%9k*t${j2BmwSyi>WK za5e1L5O*B9$|JPLqFJ{;Mh_I)W%>6@qkE-=>5)d~q=m_}=osmT9mth)?tPJWT;99- z0vd)70`OnRjfYFOjn{VCI5i=x9ScS}JQK(8Hkxr$0+y`v!C?G;ti2q9E1|?srCp zleaIR3ZCcOX)ErP_(!qt!4|wA{rj_o5kBS4?qGV#Hj4S2vu)nK zL7viw3coV0@WDq5e)GtCH(}86W<25lFYqg6h{KQYo#M3$UW7l%?*?q)p&DEGiQ9P} zVyu=p=8eo-`NlC!36o%az?0SS}d_2AW>bJM7w)UYmNnE%|9n`gb6Q;M4w}zM3od?bN$hvE= z&!P|NshalZ(x!VGNjZ-c=X|8MkCChdclZa>wiWMEXqo$Nz{p(ev?pliwBO$o{$s|o zXJXcIe#K8aKG2i1n#=qQ0rY*RYq|TDFpswA<~7V6@@z%pLVN=b%y74(1&+#z~x++#Y4lqLDeXgWNZG zfd3kp50f@s^F&ma|D=snJ<+IV8veTd@S0_K>sqkGPc-Q1Z7QAqA@TYcM%}x#XF13C zH|+6hv+jky5nIw87BdnXF*jm%lE0+?ZkTmv36GsYIEi}>cGVL<)Q7XaR)@I}6K(KC zg^$)|^aZ>e#J+)W!e3wP@Dn@r2{E6k3q%jx!+MzLuN%$vM8+Cfo&$TEh7FCc?AuC3z{zv;w!p$uy?bl@orN&9Crq4{qU8(h|P>j?MZU`JeDN z;4iu<%72x}v9QBP5%~wm zSH2zlm7H;!&=;m(Q8nEhwbr=nZJ)Ge#- zo?h=}zlxW7?4f=EC-_En+?^Rj=%Lw$2o-wbFM=GdKKtaZevf3badXdCUr746AL z?&mzS7cA-_ZE<^Y#({FkM6XO9<-01w2y-S>+K^|Kiqs5sqa$vqz+15lr>zbW6zuI zW7-Mr!)w!i&_`RDJ$u+D8NJBS^j{YagjHihh$aNSiy}K8!ByBfq}gkzc=mq18Sbj*VpLpwsu}`dLekOaweqi=}x!{0o`un^A;FGZR zhLp@Z=g?1Ge{3{2Ej zf2r7|d{g#lFs4%M9Z`H|#kY{X95R1w*k>9ge%H9-_K>F32}9yA2VE!g)dMo?zsJ0@ zwdCeXlk;%o?99(X&Ra}5XM>e8z)89JMzY6h^DdsluOZW( z$XUO+`=$?^J+@Cp&g^ZQ_f&q*O$VLoxpq^|d8VBAF+U&HQgY5cCg=Zi`R0B>zTwld zxa&ydn|n;YA0uC6d|1x1vmY;lTn@)=`OX#jA~Tm#&x^b-$1V3l{%LLr<4Ql{N+07& zFXKuh`Pp};ac87vo*94X%Bi}(q593wzN@yG^E~B4_Wf|~ROY@WFO|6-IX5n6#+#O0 zz?|6m+hop1&P$iAAG9s-n3jz5URS^~G*bQ;>m`fao$;yRji!B>ZQo+sciDC$Z+QhR zx?`Exp3d?Tu-^`7rIJPA0i8u$<509{NM{*ieo4z`&JTF3Guaz8&JM7)F$h6_}d4cs;Z1% z5a2B|83%~lV~+!53{XZq`46RRjsw!evp=ROR_2%>{A6>7l;dGAEM?Kr6Pb(wx-A0t zU&0vK)(IKAjAZu;Fgka+{GM@mka%I{vuc>*X$2!Av%?=abM}3#W!ImF9aY`;O?2k& zD;v+;)eh2Tp63?ANPcCQ{2v*dhqvZ|R^awM#~1|na^`j9o!ywT+rI1B&pMs+2y?EW zO)>8^g*mU~f4;2#dcxPPE!=d$=l**N7*DLoRLK?Sv=yJssjsZmn%47%UF9m~;l`+B z>E|W)tl;cx!%sX3gTC;;;dk{j7Ku}RX#+1{SOSS)N<=zWo$Q@bMfap zv-dS*RV9L#DX>cSeIXCubb*l!7ILOn>%LEMcR-*LzcKg?WW2z=j=_Fn7wil60`sVz z`+_eha}F$6Nf_`>a53jkNrQU>-YVm)NwAEx4z77C_z3=)l>2(gOWPN?jQ`$LoKGc< z-Gq^}enOZWtKI~9K+h*{%AxMY5BUeK;NBC)Crjr#%=eN5&&ao@et^L=zEf}*aR~3e zfVPRw3Oq*qD~PvUYbt-n+Y}U<|0|%&h!d20H;j7;w^N1+>Sdl|Q#oPK-EHo>orB~* zS-*AXk(LJ@7M00Vb@xeTy1*nY{dn`XuA$)qx|f z)n!M5{fwjs+I?Q2&~*1QlEwI!J;rzuKl4BC`4T?00P^A-kMF$lLZur;u57g_xO-S6 zFo$v>zl)Tw$fZj?Qjx$E$}a!)Ab;AaoOPA9YRa!x`c&ovr43G2qPLQFGKP{qQ@(dN zPcF|0zbSM^Her}we2MVCXOB)0x@}0l6^Onw!ObYW5F!z<9D(-wiey z(%_F4H~6B%8aN};n8%OwAgbUCw3f^%McR21c!B8<@!b5yF@hf8fL?~90 z7(zP5q*EE2mRJ@mO?XIeSi^MEE{)cP9jwVr2Ycm26lNj)ts6T!f_Ed}cROoV<$y{$QCp+RJC z`d4BT*E);mO_<+)KJ`9a#5ok|gU_xH_@#6=?Z>PWW<8i_w=KJF$T_}1snm_4PBX3R zNlOjvJd-=%WX|%MURE8c%Vn>T>`A14mJ#QrMcfrKg1D4H>V`rtZe;yrcQr4+A-q*J z)NExxS0tn1ds_<{sbCZ7sNLGH;nuCi&7bVeZ&<%osf@_@=Gb0?ILIdA zX-@3bh%>DD@ZJpKO=#}etMlLR=7W0+Nb~IGKkc2^{MWtbnDMKL?=1HkRof+KOW{2q${${7pWtcvfsHDMLu&%IUl9#zEZ>?ie z5L^E9Zh*GKO})dSr*2hE;x~1kmA|`LYx7=Z(GtfU!+lMfTRGai0n6=iIoc$yr^0pz z9A=q3Ywhr*^b?CL+7)n4qHLB7Dx4-Cu0_sCsWKE@XVFE!wq#SZOeGcPVU#M4xK>(e zn6h>0k-%NF@zs_rG{ebTKf@wg*a~CDaS^B1jx*lioG0NY*x?&AEBppqmN92!tH^SU zVfH=cq!n04`0zkerds$a({`wDcFMO2s6nP%!f9cP=6tUeCVZtG$8u}xDm%{U_Wzcx zsY2V0jSdnl_oz~bKV*MlK6!|)k}_qHr`U&>%k4&567~<^I5p#-o->dBkg>;y%ySOC zIe$|rW-a%ne~)#Jc4x-+qx|;~^NXX|kJzl7k)z8Q_o>tB_i={KP<>c$&okc&^dPlvYr`!F`i<6Wlay#*Kv=fo_fZ;{oIR|&mC_aiP5~##GMOm@@?dOD3OcEvk@LdJ`zs;pNGFC+dS@b&7;rl zQ!g@+GKx&(TZ>#oCjAI2Jk7-}<9{i8s@xiW0m?oHTVy5WKNnicCgsXSclSa!_Kkh{ z`>-M>k@FDZ3SaWgq`ruJL>3O4mU#fl^L6&UvIia>KTMRvcNshf;dcrCQRX@0oT(BW zoWds>_1hpVsiSW6u-4qNw^=)l_nxe^D!~`wzJoWFWzOB!0>0R7j(d??R#lz$vhZv1}`l5wd<=jJ1 zXoL6S=)Z!K!PjEHV9v+ZFZmjnH6>fI1-}YbOvkTd1;hOl_*Jmwm*LlC|3mPr$Ugvn zbun%|C4S|*D3N0&;S9sVuYx(ly-Z!5`sV-L@aF*V)1>Cu-V4A?f@M?qa}fCRT(DVJ z{5kL+;?K@6;Lpqx@aNx;;m?KO!Ed62PQ;&o+xrH59I^4|ez4o8gfVCnUl)I-Fz1yv z1{Lfn81c*T=cgwA^!@|Ll=K6{4Z?d0e>U3q)6@|*ZWR0}dM|}P6>H(%Za0 zPjfe9M7$j;DRG0P=*u^(|6C23$MNUZObdTLk$D_{K4sBGPg$}ldM6Ek{@O}I?hbLq zEE$MwR5&x@I%NH4;!XqH`3F1f?Svhh9#)IEKC#@&l@-aN|By5S>$s0i`W)5U!h~wJ zX=~xx7Iq9<{t|}1*8b17)hs(sU&{{9vg258P4%<=En8FlO}&&sUnFC(rQEfyr{T?P z@|1q@ci_id(vmuv!`?PEVD{^@W`Zo<% zo|%R#U0reI9IL(8|AV>ECs{-MXXZlxHUDY#&tEqGDRa(W6+gyDhBr#TC3mM8tYf8r z-|qGt<^^eUm_xeGVGbcrutWMBCIiO*>vNd>!9N#(SXRv0?VXAJ{9H!pwIEKuIw!=-$v*@WM z4hu&Pv3PKYGupf(EZW474Y=SS~4jzG?~M^+nmEJvC=Rx^;(a-JPlFytA^ zl$n%S1;CJ3rR13tStT+YVd;#ZjU&B_TqXvL54Ze9kHlDWm-rs!92=IRU7fMf7VW}6 zJ~X^BAYq4Ceu6hWskDmI(i&s^FS0S?dBPhd59)%cyL^j+opCp`__>b96J3_Volk>1 zWsb9*{A0wExp%>#f;-OuX9}+)7L}Q6IHTb$g+Wh+KV=`KV33cTUGZl>6MqKj%L6tR z(6Cc@QgDKWIW7DtbBHMnQNe%HOdN4M{C^exyh_pqUsZuWH-p^-166@P4R{lLC3BX7 zKLyv_2rXDkux3~M>BCR3kKi_o_Z%~g8*py{J4#wBpap}8JB7mpe}?cE{3Yp1K4rKs zg-+qmE#ODNc`5wa-^QQ)z-i~$`18E4fIlbL`15QVe~v#1{tP1nDYwYR!kiX9m-45u zXgc1Matr1b9NHUN?~;Lm?F|Cy>!Lx`)9o+7Ve zXsK6HzocFXE)`iyUS9`)N*?7>hGY1%-&eq&{l0)dQ~JAw`A=ar{|v zTt5{pO6eQ)_jNWM%ZdEJ`xWr#i)r{%=u^yV{tJKp*R8*Qo%zf5^XLQ6y+QD&#y+cb z{F$1={O^E2W&ZM9Fi+R@^TDTBKmR)OmnY)SBPZa`E5Cq0|MuT%{rs!UUp92Xpa1Oo zc|&Ub9IR@tpRWSz7-4h$TrjIj$Drnau|!ITnHV%?>#Z?h&<>kkY2!4ogll!04qI#M zEhDSV6}IVcZsalJ^9SOStUBKZ++x;!>c2UUS!-iZBhSQ}o|3#tW%l~DXNKiB^%C3e z@F=#le&3mu?e}n!1gSNZbc0X*pU3u0z`g3-C<}p1D7VUC% zKaN3%bT@f(jp%+HgPvj0MVC06q&!7Wq+!sfY?<6e``%&En(A(?hwrk|H!-LI2K|v8 z77VJ5P$mY|414Xo+4@g4bdUT383ugj-YoWSS$6xmwjQxDspt|J7qm}I;Z09x{Cq1+ z`#Ir_3fT+ha}ln6vK7Vy{)+5n zrDM|WDNIWKG2(p{Oe$xMQgfo$*mI)km^Al}n5?s>nZlid&;6v4KL6Rrp8xDk-_a}f<@2AZx}%eh)EkkR z)D@{GUk87FasB;}E_n$4lyxX;{k{JQ>+fGa|JnZp{26EdGo`yt{JFtt>LyKe_Z>F< zY8w9hxvhIdf4yPr8Ux+^pEm945$QSg^9S0e*m~wN3$K`a2CLcA%bxPU#fG(alr-Ae zGwNVGD($^&jXJg#|5f&n9>c6_PF#!6{TgfW|C&EN$^0pDP2WHIPtBhaN2RU5w;OhS zn4eZ3)>9w6RzJW#>f?JyS15CiwS6XWHd_7L$#Cydd){?z+PrH;YTk7PV;R{y>N1i6 zcuAjk-S_`s-Ziz(CHqIu2melPK5_oF|JR;>{YU#pKRp5eUi}69Yt6sD`#*jDm3m;} zU#XYqO>_O8I^yD6bX~tchJV4fCjON;hP8h*NE}64$L3&9hJSZhdebdB^f`;xer;n! z!M`y}R|>8w>ag`@L$@~9A)9XQ5jk)n`1ca4&3pm>{=vq-;hq-$t?hXn|8B7Srru%O z9Zn1X{@Kdk)7;I%zn!)_X1kBrZk1#GuN+BpUeaZ|b=w{2Y2n|&mb+{t_&3|4U4i`L z__re8!oQ31kK^C#EV^j0ZsFg2M>3|XPs};kJ`NMd1_l2PuxQQ5xA3paO5Y4CbFf3~ zu!4Vw*!b6FSe5D(Ar+{CrL=qP_*_%%Xsh8PC|lSX)QsEs4Y%H25fCre9iQ# z{J!g)85rI~ZSUva``r7-{_K6u*?aA^)?RDvb@thNo#guKj1#QCrmwlC^CaE>y%M}W zjsGj-EcB%NzazOP-~VNOHr@X{+4`%-zW$Ny>rcfcOO2oKQg|l*ukcS~MfjB}3ooTC zy!`vEzmE9~>#t*u@_&8De*gcnWt&Xf{8c^T#D+Vk+7hDYa?d$4X?rLa%}LrCvEAn< z%ijF(W#@nX^;bW0jrg<2o`w3~_1C{){S}@b<-b0K4fQkkf71R@ne)^9*WRm>ek$v) z$A16+#P!!t@I(JIzWF^-1q;Z_m3tH`=7FZ^!V@pADH_` z|2^q{%Kp&-eAK_?`~QFB`K8aj{`z_RPh{}8_1Ba5pDO(fQ!vejHRusTY*=N|M-%_^ zqBI+JNz!fwb9$VYC(CMRxavHl&rG3{u<@FCha=L^>u02D!0ddecE-?&@gAGtUUnupYEHi zXU?W!NBqy$VV3{-$gm^+=N7A6^yj4id8_Gv?lk?+l@<(h4?yq;e^hW-*m;-r4F7Yd zlJ(cSlXdYwoleXD6q=P{55U?a51qrq-++hS)yehOdMl6pqh&{q+Y|6*>%O@s;Qv^B zKl~m4OUdu}U$yGE@%j3$q7Lh=z5ig{ll50=EAv$EqBL079s}#jB&=(!I_92$g_LDa zz!gW@rTe32CH>J}`j1JwG=KCG{87R4qU1X9v3mmK4AiGze=R(`{wjW!_y=xs@j=C> zlyyj1=d)8Tp)9_okL2ZA{83rA)F`KXQ1M5Lc`o(Bhj5{X(~#f0A`)`Tn2UXDWWG?3IQMxsy7 zS3khNvyV9gWvIfVe9+_0Kuydr-;Yfn^vn#)e*ZAd2Yv8}eJW~7+8eRot;urJ@bF{h zmJd3p!P*=Co3qrS!Po}#{380B%l#a5cLRHKzI&!xw3L`B=TA~Uf6YF2b4>o}cMkt8 zE0Z{AYO{~M;$F^el{LlMY@`5oZZY$8GxwXgU&1||RdF9rk;gFahTJkagS*P>Q3i_5Y@IX_wzCG|#bFA$F zU`(OUQgG0~E2i%Z?BxD>?pM<10{Rzxz9W6zZzQHUb_M>xbBWo!0-wsxxGe{M4X_)t zUkE(u*d5r#^Lwd31h_hI{c2xezhh6}1@3>}>~AFf@y&q#_HfUD7QsW{w*t2TxEaVo zD{vnJ?zHTlfZg#*U@diiPyHI;E(dP6?fpQ%{)fO1xc>_Ghk&mR+)lMWu$$`@;41tT zxLv@l1Fi%4=mPF@z#W|x4Fuuyebo6K^;?1a7;tOB*Pi*ZiId=01Kj1nZB+e-`OuKL zGq9a!{lKjUuIvx!2ksldU6K8Kpcj1Wfh)Xx4!B*w9Syxva1#Cq&W{1N6}Zx$;QKF* z7Xrc`!Pf)axxkfut(CxC09=u`xtV*+aetZmZveL+xHD95;9bUZ8~0Yzz6-d|0ayA< zjhoHUX^ty#os?bm0CoaFxmouOXJE$Yn~NviOgT$c?~T&i(t6a`GNBA#zj+Op&EF;&kz!O5Wo~ zh62FfM_FLB@@y{mDv?`>oy_uKzz@AbtH{v{$ic&uSCKlXJ0ARZQXUTtF6wtsu2g-2 zKH9X}-V11sj=&MoW9JQzRY}N$ftJ%tY^u-xG#OtPsr>?PxeEuaW+=sK}~`N*Ym{cz*egV zt@xqW68G}a)72u$T`%=sBhSR1PnW$9oNKM-%xldie9~rjkv7OT&gSJ^m3W{R5Qk1; z`rbfp|GGQJx7kQsM@&$an>F7->}_|RM$9v#$d=_D$G@YA;~6WP#6OvwBOJsJcNZDN zfl+!zk>;G3A>ZB=aU=Td*^_gL?K^@04xGU}(yOb-XN;=+$k!>d#Ju+$XRUr|(dd2F zif?)Y|1onDOE@||yRe#f@W3=}eRURffmi(`XRWUDZS^g7M_M(lFl)G)SwoDwJpOlZ z(4Mimk#Z3+4SR{7mcuumAIB7H!?Y=$m{Bxc)xN>IymuFIPZ=98{l>VS&p$HWYJRir zZDjsHb8p+h=DxOA^FIEK;t20=exq%8c1OTNk~#+%Z>cB$O_|2MTH}R4x?H8o?@@OY zbypajfv)(C@r?c(;~&uO1@6@vPY1gG;*Dqg*&C11-$>xBFnXxxqnI$KK zDRF}p{R=))U+xQD+qoz8^Rm?yg0J)~>q_!Z0KqkrYvE}M=M?{ABlQUL`*TLZ4vZl8 zuDEDhKnF+fv&cO8LWdPo)cqPd{1`E$h$&{qliF;SYb9os@3D^-nenCM88OBro|xd} zCFYp>M?8DZo!B`$xt7>^B(B+6bJF6Pt+SsvuGzW@E3Vo7b}OzK*Tv~^&1mQ4Sq3jB z#bQ6w>U*Vpj%}vsy2Lg6di|Ji*$?@)zLr>uE3q%wqbb)Ji8Jpr5@#DmVnU^nm^#Nu zob^>B(WZitYGP^C6ECYy;$cv}R;hz`6Z>EOvwI6j-0`OUv>o{euLzyb{eL1J*)MFT?Re6bxnpsSkyx6||LL|8)BNYy zfZ>M3Pd>Q#PsH8_&c$Y2{p|JI->V9JjsMWsI7q<#8tM8e_Q;vUGrOLD$uIYF?eIj_ zTtpnRJc*@DEJ1C^4z)73aQPaIwU;-_a&3b{e^HsCw}?skn08v|DO=u-t+v5CBDNtr zyp!#bCVO4ndolk^_!IImT}wzzGryL<}>pB@E)H){1ka! znS5rDmm*W1Ilgf<_t+!p_1Lr0Q%wpIi_Cqi@572)t3UK)`Nv7$E@a3>EHX2;+5_x4 z$zmRpxMX{JuW>aQMQV_DTnY10G4acgu_Culd@@y0q?nhQ<_F`|_f$l@@YttRj?i8W zebo;EM{;;&Lv9o@y2_yv)gMC(G*>_5PWT>xPr7}*@2{*2pUbyZc;LFuyVX}^kNDn4 z-lZ&KNBn!Q#~v~FvJ~^J_HE!vEVL=wkyvOe&2=6t7TP#15wxkq;q!lt>EZK#l+9RZ z=eo`FzUKKq%KmX&8)@tRkHHsWd3~1k|9MSD+ke;i5pu?nv2JS!D%R7E#6L^XBWLqJ zG5(qGi|_kKo&STUN3H+EXYT^WLe~GUqQ1mGBRAup(O&#AA8nNI5uJ2O{0NWy?<5)f zY`m6mCgW9lFR;cQndtG3K_*1!k}}{OLqC&628sr}R}<^eHfG>A$vrE-PusK7mD;mH z{loFj=s$hW${Cy?{m+PZmYO$H`TvCTga1{&A2gpR{seL%@@?*4L0(ie)_v6el{NgI zSN3m{iwv9J518kisr}p1W+HYApGMkx&1bv|^8G;Kp9TF{5%09%t__Q`BEea@`Q0;k zuAT_CXg%H`$g+oWy(_%o0zL7Cb3XpT`ucwyFoMkxWuj|x$f}Y~? zU~!4LCcnN)Pt+|W^=UnISCQLnJ#|-;7n5Hjd2zVz7CqscjGl}yDGyFADUb0^A#3w> ze)?Rlo4U1ON=f;K1;ynX?$3&BcrGiVV)n52Ht@QcI<}H<@HSoclsvASl<%NTwmY$5 zfu7i~l=3aqBhGEGcyKsaPyLpX@ZHc*U;pKSIver49PUJYec?b|_WAAJrPQk*GvH*+ ztgik`1NF8q4+L$613||Z+Up$`5HA<|jh_Dse@52F_2k;xT>^(^YpDNc-dl3;Ee0jy zG;F{}kr)kC#AjGSI`#gH5y|}-g{*TAGS@4eq28V>X?Y#s5$#LsaOpcyA#n=tOm-aulA(ntDPY+z$l;0SDXJi_8q6@*Z=YRkMX}w z>A%7I&+5OK{#Si6_E*wB`^5djpWuuAXYU_AS^U`(#s4ZiW&DOy?H@i>{Mmm$?)=<~ ztd$z9v9wM7uNQyzbMN24XOeXw(Rs0JDgVp)_x8W0W7ow0nnnIl(!RA|)9UR#-l6y; zn<;mehBs`|6MvYF|7BZv#Q$1dX8B)h%F63n>^;HyvhtvRyybsAhL80Wsngz5_e=6V z@=kJ_-cz@o++P;1+ne;i7LP9vE*&raml+?S?pgZWjg7qx8+%V#`G)1=%Qq|@6xr|) zIKIp?&-ie#&-A<2%KnJpe(|-a`y_tXE}pl5w+)}`Pn7${htI|~*W0cbsH-QY)lz&e z$ISM6+X(!tVV1vTyL_O&{_=rf{jh=H>T}xbSI;`i-+Gi-tcU$Afg%1D^-tt)$^L_s zzm+=w6-$drAm_h&l@)_^D&GR+{FlssDmnj&Pa|`&o7~2HD87mKD&lX6{~^AM_*j)( z2T1Zv?#n&#w`|G!;%}wb7r&xb>L258rS>1B{D&*4Bff>q)8fw*a4mjD6Mjo-|AF9e z?D;Pj_k@O7)UTi{bO;UK;QCQ~Bk`4fj-Mm`mH0mC{#6_I#lI4|Z=jygZBQ1U%+Iy> z3*tKnJnE%VU!~$-ooN4o_<|{(ETSy@5E_Ly!WZ$o z&f&hBd$KPf<#!#z=T7lP{44RJn!#%rxfedB?|~J6M`QoNP;%j~@F2DSV5-XEUpuk* ztXOaSoLFCcHv11;vE%o@itGrlOMxLg6CS1bB{&N&1xJJOr}3{&bpA_ZO2$^^Nq4lP zyHm5yf4RX=;$NNGzdHI1SZe=)>0iB^v_E^v-%i?}_tEE}=<{FE-;YWD3E}&vCD)~s zbLrsIByI@t{_&O6;AFi2l;3o&ctCV%sW7e~N^q+JF>yyr3ooN5-=)c*2I@S5B zgy}z}pTFAk|Dykd4E){vCt#g){mPadX%hd*ksS#-G7_?W6U@%QW@YqvN8*PJrEHrR z-Y_I1@!hFboGWwfYWqafcUr&HYx+}l&rU3_tIy~Oc1|o0woEd8sNkka^yYPu@vBnY@pDirk+VuB*zh*0DBEI^si3r{4=QEFbE*iRBv}n^eAGR(52=a`5!< ztbS5BcyWfTU9C0Ot`<;Ne5i35i4EuSobMRHzT9wdA?4!9;l1GAOMEHupMvP5(Ai5| zDJe@#se0&$5l^aqsTE7APOga~RVUZPk&^pn8{$WqZHOIZwjpMe*@oCpW*g!~nQe#{ zCHK?Uy>3YD3r)s~O6?21YpKul#n#a0{J&}aYoxjU8v|f3`Vk-yXwmT%ELU*I+9~Vk`XEhQ*|o$>Awye+K`I^%PmhHvKco z|Iz;0|LFfSeH#CaG5E~>nZ$>>+L{Z*M*ny9&k8x8^jX%o#-7qY`}gj@?f*(2{s*jY z#k$SdtDJ|DSofbUzJ07)*46%=@$H*V6d&sEvA*?5{@JeVNL2i@-Po_?N&9s(Hp`RQ ze`Zh6c4m37?@Y@-+ka;H`aAH! z){yEmd+P2He~f$`c_;b(mEz`XMZ}gJeoXzUiSd~Zc6%RL(VMU@CM0|6WMS< zP9(UQXPsw;gFnqknDu3i>&c{lwi^Geh3D*733lS2Jw@4nR`?ch_m1a3nu@(R#a7-c zv6s^QHDWHAz8CS9Okaz5OQx?yoFmg0BgT^HixFcrCV776^M9`tU(WL5taT&tg~ZpB z^|KPn;`@m&mpV^=vh_0`-zQt}p=7;B{4?`45mDtXX2m9dQ$rOnfRTuc2rG0`M&7q`clf$r@+|=453lht;A1F_s@=w-}&kM zGb?@)d&@r|erNjk$xq{-rLVEcdYI7uX}(V$>z~Q`nS6JZ`0>NAU!TW6OZj9X8{(50 z@UDWg^p)jqKQqto;GcCI^L{)EXbELkr!rRZpwh<%A$G$XEf90Qw%lQYd#7COq zJ`xLOF?QvcHJ3-zzEL(E`;C&d9r5LIl51^;VOCr|Kw z65gioFY_`6z6JPTvXAVllk6{}P5S<_UWt$7vHZ7~$imIY0eQq3eZ^5R&f&Z7y z^ZUWQ1^=&@a?8~4`+_^MhkW>ZhkZ9<4w=3i@rF!ajd(+*uST37)0ZPYkvSI-V@U3s z{vNS~%r?XoGV2gm$gD$LAQJ|0h)fv75|aDr{@&sBIpD{r|7rZa&$d5p)ZzVU;@8N0 z>?Tk7Y_dLA%v>veR|RG9dF0x~wfH@JRGt5*^*KNOpY)SYl65Efep<}G#&4l4 z>r?W5G_^kGm-{9K9+xq@0YgJC0wLT}`5XJu!e zpq%pm>|CesPfPiK;wPoz2Yr_HIqUrPk^N~WiXW8j{|OIHwLX{b|BW#5|NQ=+#6?Q^ zf2WS0Y5CeBA8vRierL-6QtP*5@R)j`&=r|3zFL)BhqSkLiCAi^uf8h=mj6`(|)y@j#3i zJaW&hPwXADK5=*Cc`xyHZbg=Jg%=G9lJg!-%Dk$ zR%(524%f0iCve3_ORdk@DSz7aIr)|<^au=DpA$UJqAcrH;-87Hbt3=FOT9-~pA-K~ zd_dXrCA3#_EqstQCZSu-4~Wl@`oGRJ?#cN9*+(b--6r~!HNq6F$DSYfH0yKXlcjhv z!z^2CmZ>uZ!tY(+i(*#p>yhe-aJ;k^?q|7;NZoG#>>^W3)M+E$g!JWQol@yt0iALTSbkzz zua6BC-Aa_&ONcJ0}uEg$%Ql~AeJJ11a>A#nL6fs#!9bEyz zp#wNG$k!5=XE?dU(UEu`PT*AQy93gf0j$yFF<{LlrbkQm@5~q~5;H|&%1F!-iDgr> zj&%oOeQ234n)pZ@oto8JLSnk~>)THlmm#%3L#I!PpEHDhC4Np`_Rhcr;+gz^z}-dM zfm9ro>R?}BF)>{Ba&H6AD(QOxc)5bHKv-~C&3Ad?&Ah;KIpZ8a_U!CwuL1sYU`u=# z53z8*PhE+rB5`{pX3tydKp+6#67%Ijo=pL6DR8%`{ekDXSLLu`;0XLy;MR#ubEfq% z;I<0S;b}DURWrWJKhwSjxXXbnF;R-a_df2u0vsK<60_%V6*prK3A~KV-vxfhvo7GS z0Mtu+DROs8sIJmuJo7U!}*z39GrgO zt_806XA)bcAGjhDtB9W?d|FHUF5pVMp7D%dC;Sus?B72?8ux893_^H$jLn9WHB-!awKtcM3y9GR0Z%C&`&8z=xO4< z7u*BDDFL5;WT{(aFek+VP4Kx9yhM&#s8`G^#byql%sd&>#w?FH z5;9Z`Fyp^Kd?~8m_8{sEcw7b*1I(7-q%Fxyg)`lbIGPXWZr; z?8|;rV&%|RDpt+{iILOkwqoVbw~R$jTCAMr`N77|8!zXB6U4`PAKCsLaZ-+rk0bGS zK23a_17^M79Ty*`$Bbtq@o|WqbBg#lLX*U&NyW#Jm^G=`I1($zh0Lbn;-tsKNykrO z_DGx>iK`>Ab0mI`hrE`UH4+;q6(=W!ODaB&(48JHNaF20caj)6eef@Z3o$Jkd*NLw zMvjNM!AX+%I4dMRPcr_{vGC%=sTz`uk>eyr&QxT_jFH2b-^h52j*2{-W;-pUi0PP` zJ0%xA7hVYt&t<4uH?-y(9RadHYzLBPJA3c@ozNFMu|*GTW2yp zj-9sBZynF`iI39)j1JPmWNe%|iH&m)axC$0h!f&nW0q?rR!MU&@o(-=KD(c1>yppb z*(2_ktk^h%#((^SpIv!p`x9Teqx~1vx3@=@t!)3772j@uWWsGX{EBaAAAQ?szw`17 z^{D;Y-G^3bJs*8Lqy3#L_4fC^VsHPT+SZ;}rnUe33e|pSm959#DzQwA$ejxNFjFn6 z$?X`^zf473ck6|{(0HxVmhDh#Q3<&AE;AzTT&=M8MrFpy&oYRu zW8I^E@}AW7O;a;79wbH;=OwiBjf9SEvJ+b;*Gr6_u|^{E86)8sWhC-`jgP4lTPsH; zG|sNJf!`XE;MrTmJ?vEP8RTClFCpK_KMsCipJdN968$*_{!%XQY8g9rk@^Z$;&yUd z7JVrr@!HcB?fqvMiT%H*m~?Jd!yXRKGZMeO-9GGA zZP1S2)?SvgePw>(M5XW0h`DnG@boSt@&4`lu-nw29na;Doc}M>+y506DdT!Su-=%U zBG27%+r18(W5*krD$zH=Aih{j*|qf1$8$G*G$`ASVr*&gO`e=DuGELQ@&?T>zWug) zd#_cI-puB*z8UIp9Glo|6^RuYW-Ob*!`RPqBfNmtRjjkV#eIRv-nV;QQ`Pz*xwiGO zOe1jy_WA~F+;2%S=wwe$?G41-ct2OoT$!(WwvpZ|FcKfwM^5%KNBfime>yYtkUc+i zuYG9fKKtqH7sv{I-##LAXr!tQWvNBcjYgZV#b~Q1b!~LF?X}y&8!10w)53ukciRf` z)#Ue)r|Z`)+WmxjDrUr8q?@So9g>G~H7N?LpK-0n-0?D!uf;KP2;~{Sn}3L(Q_yET3+cHOeu@ zu8FagdP=U5W3$a`Mm(lDtTtvj(`sXuv#k1*mub1I1LSf>eKaw{Mu+mivEvPJn0-Xf z&Ox_D)(Vg<ZZP>I*6BeMKm&J8v@)D=y{x9j_g5!r`sxw5hgk@ti*ORaZ_ zeOP(Ny@QcOWH9lDL#_WK^7pf({M~396MEM^$dtdE_`W1Ec!zD2DTga;8K(SgVBCI$ z?8TamHVvM3!t4HKw>dvlCwZQM?Bv1w?WRl~EqgLf2Wfi~b(Qd*lu7;Pshb+_81QaR zlRphv>qO>c+;1ZFH+$NuxtEV@iOfwP7kSI0oB`bJ;Pj?u$={V}@^^Dm{_aEmgbtCv zB}tq`P6Qvp`@YX8e=i&(fBT@%23&#lCUa~D_;}O$x$o1;-wbRjsqb1NBC;iM<^1#| za^)h~@V6^k>5H`vkD2p6jIZvdT#OA-@<=PnYNXMQ-i68CDRs6-99|0zYhvEZ(Z;T2}x zhSCb=Dyw|pLr+4>vdYR?k*KM%+B6J!63tPgF-meVcX@|e{VZ8*!B%+{i35uIOOy4- zRwS0J!{$>LeRU)v4GWUJkrTy*qE|LB&2KS{}M5k`ev*ata^{gdFG+-}%mggf?BDPW$ zx}@DEm8jxfp@Z^Bo=4xm0DgPnkw+yC@O;TFToW(UTW=&5 z6LUTr*gg+&$%tjqEAV!!LEJx#;4#-7RN#Gx{7>X58eir5 z>E!iz@@w-sOWIuj00Gsgf7b&p;#;|hZ6>kg4pqB$NSw1jF~?mK*bAOtX`hVo! zt9k0+*DjEIt{ocnqfPY>?C1XB_P|_xzxBMA`@VDqcl0HnN&o)kX)u0i;Sl4w#25A6VVy_3A%iof@X1MRJ?C3SNPSp&Zw4{>#^bB7 zuZs8E;4T~e^lSY0=plTC=+-is7gKYX=#k7x9_pyrrEwKoKw|F1J}K5cWc|^|RX=H< zy|hiWOXbquFL2F0G|ZWX3I}Mji9Lj|f=y-8#_ZRa8~3iZaQ=J~*#P%UUw7g}8r>JlmPIcw9qpZc%<#U|jd8s-g<+ z<&C+#XkM_Q$evX_?%ur0qWY|wac#Q0=dnjokigl=s2nZ$7i>AC4+WpREq~UF=(C*q6QaNAo=v|`*j@=trC-^Dc%SX} z0SA4pu2y@7FCdi7Vq!EKY6-o!@$W~ps^pxR*k7@MUZ z99onGUy7kqXpsAp;LA{WA@oX{a`@$dCl5lijCnr1$^@@mcvk@LWDG8VpM&Z9LU7F6 z@*3mtwmvc1!+7oNz6l-;r|y&X&cHNy*`WR{(4t-nl+n*Hcqn7%f;Z!%FLY0jJ`atr z1}1>deb7;@UI`4d^#tas?!X_w+og5|8r0K)GqAhqV=HC!HeBsg2S*}X`QRn;C3NH= zZ-T!KI!A%G;9CH%M}V(BwYz&1V>OGh zknw#YiO+pD)`)C7!S%(!|Aoc|_}GSzT&Fsq^AFsAo_Odl1l(NLt8IaQAoq^7<{{CW z6de`ljfZs_pWuiM*BCpA!S#f#BT&XX_QFk^Kq-r^iC)GEddoE0H33i2 zPVxP2L@*j?`lVBEvXy3N>URO>zdCiND$a1JXtM0ea8fpi&FaM-6fw5m3iaWmN!=fl z)P3V5y8n7o_kG1i;>sDf=?h7M&sF4CkVL*NC!b52M{;2^Ed96iUSnMBjFrwBaD0cu^AF);$~<){*yuE$`_gkns0qW3dtb58Vk-B&ZVa~ONk z{}qghhMX_7Z421IWjA^$x;M@ChkzZN@@#tpSzA8TPY17mL56ku`A}^S3_|}egpLc) zsqxWgx+g@tps|m>8e4_VEK~nK(lgNi(cth0a44p}3%X0tt*h-X21Fl4|5qSW!i$AA z)>lm&_5=#RX&U`_o71|LO4Md}tJ!ME@^URsf>m2brk)40sAI&4@LJca~W zf%m)Ud%m;*~0N90cM zO3C3g@K}i5-3={Q!`nP~wF11_u=NMfZ_)o=Y!;z11KVu70+sgX59|NcJWuJr=uQcG zA+jppZbkoH;F{8ZA7g*D{fPcIqx)X;-i!X%$$U&XRuC(5(pJ&V3p@op=a!gh1IAzj zj9)o*!!9=9X z@NE@^)E_-?Xg2=T{YIktA^ahH%|nMW+7BJlN%r<*;yHXvo)gEx2i}XP8wnYUTPyOw zH4j|#2Ym9JSP~{2Vo2O7*Tjx6+YvM3Ho2ahye1BeJQw~8?}S%+5WM`Sg^wG9meVZS zit{YmTF6f@2EzMMLK874e4J-IOcOCEOk9X(Vd6rZ2@@C2K&I0wV`b9H*+;48}3YMW26&MPDDe z(09z(34JjK^x4g|oqX}3y;qs#TJf*z+L)KClK%E~%isRXk|H(XhI&)h&bI&;DimUCfGT+v>b}(0E z(Z9Sm%*6%|0`73;#!<|#v%q@-{^)cQhkwJCe`NaCr$evIuj81fi= zM^pZF5quF|EKd5}F7V2N2gT52&9AR?7s4Z{*qLxpZ@ZoQ{f=1}obCo!L9n7A`P zfZs6Q6GnrN%u_ONEfk*w9=rfQuCVt6#!z<_{`4ID1@Wh6M_=wP1CMI_Z{hRv(08tF zH}lvY=C7v%bC_rUkvZ%BlgzIga+LD1b>t}%y2Q^GxsthdI5dgxCb)^;CU~F2{N(~S z!9O2=yA(WRp3h+H#K)6)SLRy5OXg4E{WN4Q4_ZY2%I#guulOtAwVQXCg^bTA=3ALx zHT$kWr|soHsU6>&`B(gFKQvuQ?o0aD8`J!213i)XRb<r_0SjmUHZ{;CsKTKVW}3P-yzsoxCsq0UNX%TwdxHdnWJKTGGEBx8-AfH2Qx!`tu4n zh|HCka=I5Bo)3J1wxa(B)XqR2cs``~50Ht&p1`mq4m~CgzeoQQrhgql=R}u>1M{nP z>peQ9|6}0GInXKeiCqx>$h$@#G)kL6Ngj1TtLVR+qZ|fa!t<%{QQkiW!@pd3Hw_z* zwdJq)t^Il>Jjq1IhtlU9Z0LKY|0#TVN1uvLoXh*defAdu6M-RPIRo7*$G?{KgYD2X zPwfd@fKRwiJrno^`qKvOqj`^c5Swr!|Jt6W|2A-x_iC{N`Or5E8PiM~VBtLixw2&G zEz=H&?hgYmkvSV=-tT56eeCVCiP!*M)X2twIZqiKH+WJ`}KC}AFKa9{Oe})UhIL` z0MUO%JFnF)SD}6A9ikGZkHk4+sV9D-PtKZ)Z*+lG*GEhV@6FWDPS)kD zp$U^Sh9*qT7@9CSm+Tv2B>ca`4}KOuYbiEQd_>MIn$J12DD@Bfh|BR2#mDZ;Io^jV z&Q1F1oVzsZaDGzyHQ}+x-@M1({^RHrAH6vH zcsl*rNk5<5^z(C0O6NZao$0>f_N1?fZ`k}}e8p|oZbkO;z1xbmdf!hzW6jpL@X#W= ztkK?K%@b!4+tydleiFVHq<>qm^F5?g*>^PMC%-K?`5wYPG4Dg{2bsD=kCU!tUg#&^ zN9rT>l42y;^C)qm&{^qqk4vfr-yY%s-CSb(LyGR>J5n$AlvnMp{BR5D}f#boJ3auC8 z3kYscL6h8*de@qEbUrv<0&Wk0+XM7{Y1>F}Zll~l8UgOZ>9?A)ha_~mBqwE7JOC~a z=mAm#X&?7GNzJ4nX&L`8J9hrFzTeow9>(Nxa2W+}EgsK@=1b`7QfOWP&6hzl-|^`$ zvtli{t<~eCR?;expX4SvNdfj#DAlaH)keKuwdwoRCf%u;bf0R`Cy?Vi{G^iaS*h`n z?^m+-OzfN6aJRYmhBd(m>SEve&F@&P<~JSTw7r|zr&HE5vP#fMr5~!v<;c0sCS$>fV_6(d*e&eS6wv~zOXhvn5e9t>pel_IRl37{j zPRgu0UVfD+zxEv8J?tGTYFap&Z}kQIL+3)fIyiIVh6ntt0|fcDKL?q0>U{J5(0#8O zaEE-{pM~6y;JaY#n&7(G*EzR($>siqlzTaA)>IYTW&R7EvtV*xV9mLX*qxlWOV%6c z<&2q^zNMb5IcO@kC&oEbsq2=yUaRh`>zs4sxy{LQ&bUeYVxIT;=!bX)a;>5zVJH8S zH{lq$J$;;eGt0?)DwfmZF62xM{rR@@Us&1av?RE0gH0VAk);yfhsII;TKkB8TYIo& z!vl(a3F$QVUKd<98hQn0!F8^!KCY!)M7aZ6Q+@R=w(k4sW0d@pK5)3+K=0SAvMouk z%^2L%TXW=I?^3Hg@;aAAub1c5Y0sBg^x9M@b2R)&!3k2&f25u~Q_jIX8A3036f;(% zp>fns=-X*)_p*0{_psW*y5p2+13qqaCBNY=CJqddivkM zUbXA#`}H$(*I&=xvz)J8zjX>}zNR7zGF0R&){t&sZ_14s>WXFTZ}~O(ROo+>dn3qS zzdfh$M&NwUeOlp7d^5hDI=R`og>SK6^hW4-)P36e?;#5}f&Xv6khgvTII)ko$D-1$p`I&H_ylZe|%7dubr%FUm!-qFDbJ( zEc7F6{V&dK%IIZ&-s(~Lzo=LFj`Nx_wsxxgKJNd*rsX$mGTJiao=3}nqF&3d+jLo5 zc$25?ZJvK~$E?tIHo4orzX^YVI(vX|-=+%oW;((j*f#3hnHOI?a9O-TJ&u3yxPGk7 zPrv@wjya({^uINU&kyLgce^+40md(YTl%y&E_K?teu{eA4;b+Sz}!#$QrqLY;MIA+ z9e=S?<=?tvcIZWL_kfe&I)Sze!6(8qow7Wy;aceHJ|O!%AJ@yM`!jN(XV-y>_)F0H ztsUi|-Owzw3XQ{QJIcOM7hWvnU$8T{79I$l!kexGm2sg{_P_77JHo<~eqahu^0>DL zUI=f5Pcjxu2M#To#&e-V#^BZ@eL}OqH}}y~U&c~+@gj7)!TX!wFLdmIo(9?rFE)`& z`vX$XrsWGS{M5}iahx661I|LL&?EKwsn-FW4xV>{x8R$jAMZD%#z^oJT4gVP9%&)} zmKC0heB8%%F*L|HH^ZwZps!ExAm0tng0J*f3|*<`o$$iNb;kjNzHQ+Qd@1&?Piti_ zPTo-dl}%#rBmHUSK6>fjhF;zQ4gzC0u%#c`)au|M`w|77YrhevO;~X0dfFeK%YOPd z*|&PrRqhD?i^_SN@(l~!kw@8kUWd;78C|`b|55qTnPoesgjTW7(WRc${rGVH4sSdM zJeILX(bsFl74HTQW~y3WjCTd>f?S*S>1wlFEB2ypFVEQjCid#lGRsC(cVgS+eQ`JT z*`pwp_LP)ihc;r*mVnbC?kxe2k|CMvm+S&Ido%yYIhiHT8Hs)5gKR2dcc{pv z{5N|UXLzK|S=h4W*sXQgsgb~1Qkz-GTE!J#vsf^L9*xrPF@Z`7cLpFzq zkzb81d-V)e`wjMyZ=+nTvO}-)&b1vG5t$KP6TQ*IK6P4lP4uG`nGw4tdLcTo6*|oxF=7i2&rSkVA`~3y* zQ}#=6s6o%hJaevTzXYGf{g(X_yvC!ut@Q8jcgN>!Q~9HSb)H=_ZLr`pkG5jJ#I}jP zj(O(1&tJ%<54$jh_*t1gTNKgM?Tq8Fl*#pr~bp{T~^w?A_h=Ma;&E9#9`W7|X@d@&>5hTd(bFRk~` zBC!GVn_rDRs>W6c4%O`Ib-j9M(aFyJY(D#2H*A@G>v89QK0d8z;LtYJ^XH9o+u!<8 zRr?=jSGFHykA5hFb)~`l_nADGJj=nkn;}NxVy>InqZlQD(@xh5u{)eL<0HkMz2>o% zALTiH>p`|G&J=K7XJz*KpIoooRzPseBe z$#s*rF1TaJ`uTU{tiR}vto4m^a@Vgp^R)F1&b;*-v5C&>N%p<%n zco(aL0X*+7RYcZ7yyK0;x!7oD)M&JkS}qI5z2kUqqb%=UE>dcLxOcCLa2PV*dnZ0H zdo6u0tH?QAyQ#AkzO$b_GK=dMDIemUrI&XU<~4I~v`h9-PvQOSPWDw7!y~?>%DbAz zyV^|NS$xpo)PYGJ<2_IDj_16{7V&beT@~C_bV;&2QDYyaJuLOcoN1MdrdqkvdE^-} z6T;4!*0qcIM~h{Zo3LV8VKbkjnSC|s>TzY1hMl9*+D5a&&hxEn0Mp#AKZ_$;YtPTWlnp zQ!O48&$M#q9G+b)K0q+yt%85@&c}PN?_7(ACf|&-_ug}jM1i~mGTtfPdoM_<`@(kl@F7lq7;`;!;3HMyW_YbYIrr;Meo4nJH@Tw>)$)}hWcD`l7mO9E{Jl{>bZqmc7 zh?~6Af|=GBv)>96Ab_d%;(HTA|cCELKeLCB1))w&-3h?U#6SoxU8tz7## zIsEo+RS9YD`&TQ!^(HI7?dw+VztzgWzA||oOg?Y0a^GE6?!7yCz1HH}>`E&?_aZAV zzQoFBUY@*OlzjeWD=+`5l{>u_exqwt;!ftmT7HJ)hL*2_TE2s_!Z)ubrQS^>&j*J1 zdrszMC(i_4p0opA33K!+?g?Bcenpc!PlI2AU$KpQ(vK6L!fBKC$-d~5ckFNpK8Bt9 zF3Q!T)D?pN(hu23MxXNBya#=${-w`4U~VLJk)&T2{geQ|6j%Z$hj*P64Z;Hj&TMT_&^twzK_#D8M^MZ}M*D!BSt4XdeOM5r`l(rTeEiCi8v~|)ZgEi)$mKFMu zQZu8BiK4EoC#$4y&_La~gNGI!z?OfTcO3Uye8Xo9y?d>*dVfI%oLq}6O_%%2m1!^R z=c5aZy+`)GnR>@H`_QDFcPVwym9NVhjl)QcL(ZiA2+3(vKrZu+%yrCB<~!4Ga;$#5 z<7m6wh}cB7Xk&0D$2%FgPwiDk;>MvyVmZ%l zxYw{Rgp$sciYyd$zw}z z+xi;$AT2vInUor{^t^%dhxjvLe6nx^d+i}V&z=+7PJTV#lg_gb4lOtH(?aE(e?7qc z>0JNgFcr?qSK(XDXX8SXC|^uk`R1LIT#N<#xANuOdwGZFi{x64q z;H|Repi7Ab;me-aK7{$h;EaXAnW2fim&&=JOY_u@SOIUx7vaNF-|sOJ*Wxo=N*w*p z_wIPUX0e=&*4IZzsh{WK?cN0tva|#IYO^v>)JX? zP1*mB%F6j8sZ`6#dAM^zsJYT;Y~*@#XIZF^^4z&bV|(YM&}Qz5_-5ek#OCbe+lSCEIP~<-HF5Y8?doYKG*r@dBW2;2;8054 z7yGN?yZh(GH_>JU?^TNaS zS3t*v(9r#raR>3T?&e>TGJY3x#zA-^{MZcMQrCROcnhCWJP`WtGy5qE#i=`keuQSB zMff4K3eH0BI_k;z3(YN*!7=QnzRxZGWpZs}f+aw=DLjAbWd*+Dk}@ptuq6jOD&37D=ZiUO%^Fl#+Dd!~Ju9oQZ?p>ihHoyy_d3I9tf3xjCLuTW zoONNb{RiD~bT_GwgV9It1-y@;kD`|os4HS=epz^K_hs{yT(7M%$)IBW=nLpS+S>+D!t+YU*9V^>$!10RMZyDC7QG zuK%Pmat`opzsd&oq)-EO({)gA`62bBjW2d7V_@MlTlzun1gG~YZzh+1&Y|p&Er?gg zE{n_a8u;qsp7a~wy!OTP`$f_VNti<8I?6(4BlX{*?&6pyz9d!=UqhRlVwLe5MgO=j z^wh@Y#)ZC8+O^PbEq$)$x`OAz2cbdt7>(bIRmE?K&5N%B@Ap`Ptfj8tFwl#vQZGOn zPaA13JopaJEgqDF@@W5VuP2^`PQBe*5f`4k(_0zer)7ngp?@-7qJP30;fLIlx-z!H zqZIu@yU^AE4uYHTL3kp(5?%wgyt@;SJSqW+y`x6 zhqjG8{~3M!6j-gm+8C>dx6n3S|5Ealh3+jA-J`vXnc&n$zKZKqxjtDIy%1TdftG5< z($84>=!bYwrv6nQqkpMB8fYW>(`>jKMXocnj8GQ(*GyZ{KYLbYVGH{AYxHkbXGzG1 zj#pEUm=Ga1Ix70-NAEnq@bmswCwj>InS{uF#6-vZ`N zo-1N^oXNGuny<#1?*#nx)ABOs?`OTYm$lqA@=k`2^A~&0WDR|kHiMZLZM=hf(bX?b zRO`PpT+NKLZrX1jwE0)~r3C3-RLuJ5udY+I2C=d#RBnhsXXe=3;D25d-;A3o+A^AC z|AV_Nv&qw@vj=2YQzhS*=e3m>H}TE6s!b6qcDmthG^lTbkHtoyQKQXxqqZ@Fb~BBd zMxAF9j3tfvz?)&LXq;u-(s+*9-a~tbxnCt+H>E5xI2JhP0sCCTXTq29s)pyIfjbAd z(wD$qjGQcqdEy1Y7rdnJJn+3aRuNx;+-TrE0XWl*m5mDgzmDAbq468Y+fech=$Qe$ znZ~z(SJfu^RSR8Tp)VWx72qNG&N9B)csVf+&h3-6-rR5r>x6UqjJSdS-8NNSA-uf! zua^GQ0$1)yy|z5b^|0_gMMDZ_!ErY9xuF9;llUQ(aVNM6j)Gq)cnLlg@JZ-R(KmrM zPWt{5JgEdv4?L)V2UWnE2MmIl9e$TMmbWSXHVEGGJ^_6i{qx=zmcCuU_8!&^>LBAy z@@@gldgQADdGR1GCxV;0C*!AhhwuVdVvPt~L-3?5`&*pMVQ=#8VFRAXpK3MQ3}8Ad zy^RvL0UtO2QQ|f<{}Ekz(ug=uS2IOdeCUGYkIMYD=92d6H;hOX?-NdR!~e1oxrA>Y z#eCzfwq4SGDSGl4@2_X8A@i3|=h6{sX68jr`k(k-5Vxzz)w~m|WxdqTJHfSsRc$5v zx8#g+8To3`kCOWE$W)d8lgomQ?RhG{D>^YGG^t=+S)DPj(G_ecGihxKmo{|Gi+4pQ zg@WAggZ`TzakuHg`ZCX&y0XolBaMHU#xgLxIDu?k@_RJ z2u!0TTq-_LcW`67=$4_>dLf> z<~Ekx)lg=%HkA4+ZDpCy%#F8P;a?w7bgGPw89qGYkC`K4!BQ zLFkkHiH||Q=%(;O=o37$&{3iLP5P{B4VIQtmi~lCer$yXe++clB`K-DYoVzX9>swn za<5$^d}!5U9aZsWo;{);t)I^!(=GHbc*I4%=|k`kx}$Du{OZv^gZnPh)4;h0TpQ>^ z;Cs8mtZOyv!rN~8Y`UnbQD|3ptrGleQ|(gtJx)Cnugb9A0jyqh(Ty$^ql<&l#lFl( z%XDNf8Z8cqeg%-RO8OH$+y;KdTsNajah~^a?YgV3%u!j{xD6TE1RcJMw6ct@%DCv9 z^O4o18hYwQRu>zUjTutrzSxA4%AmfDG4`>C)O(S_KCsq^?nzyL6n}=YKdFDBdv5M| ze`!RFu}9C5zd`r>wy#Vw^$z_Jz4M}19^&J8(Ye*hd9#MHf2FN(v(k5zqL1>-gYMmp zPJS1ioT3KL&&7Wf9Twet8ak`N^>OmoiMJ_psm!5wA~(}$C;Im~y7x!Bwprx)5kuv- z%_G(&YieR2kJiD)6Y5~P{o9OE$pV> z1HfN~{s|vN|9(v0BJZXi!aqy@&NlVW#ruZ~n)-OY3|$mDE(4y-Iiim-@LUD`BF_f; zD0<+7XF{XU7Zbf~!*0>PDf32H@5L7ENa|o}+}gq6Y3LFhyucKE#K)2TzSuFzn&aR_ zFE*z**l60NW*KYfQB8HFVhhC%uHw0g3p(iyt}X-TT01z|u{+1=;o3Akbb)U(dRUJh zHlv4A(8E~fV`X;aumkxEAcrOJUgnEduA|I%6&)p^Hp9~vL>5bvvLoZ$0-lbGDjK)l z)mXL(9Q}r^Onasx?nQQ+o6yILJf@D7RaP`Qq|ANMN0|#Z!aKLxq zqZR0*$FzN-i*;Npy=kF*bBbp1{W55MJFD~a9jzhx9j%LRz_RW_9p^KwVUtU_=+{0#IZVm#kXsT)43rTr&G~?(Z8$V zX3WkCt>Cf{HQIkzW3>OZ zL<<|X;KEj2t@U@7gbmKx8o;cmRz2G2x?R_1sz`%T7B*Im8}NKjwO`9wlRIzL<$K*) zzA1CRXdq@Ev-w)iXjIyZ2Cn4{`8VFSCw#Z)iEBAmZsdRbgR54ZKG45Pg)@QsCHuGm zUV_5CtSx_e)!2c3tS|4kXKwyS`{@G$)7CUT9J3GG{M(1sec(zgw+dppd5Goa27jad zV`2dws?f|hZinp9OCRrC35{RTOgi6(<`1f&)1KM$!Nv@ewr1e&Ysu(29rLN^zjX$&!hFcQ(rjnZvD7{cWtK+9AaO9 zQfh6TuHI6Yb8Z3pWA$U9zhLt_HfX7*4*LOm>)AVDD;(&vjT<<`xAjAer8>WESKlf} zIL0^s80WL?f`|O?0zSm}h90wz+`JK*n{2!z<*1qO@%^?tJGkpmXTjEb`ujdI7$ooa z+j=^Ri^K9wByJlu@Lqkv)_wK19#3#WxVzICc0?zH->n}taG=xH6Dzj$9I}lb=&v6= z&|5!pV8AwV&OX~1@ES1?w-pQw3>`UVfBlGo1NCDD-Z<^!AG}wezcogm@jiRcq0aoR zU413teVl{uv*|q@p0aSfe%QbP&e8Ap=slb)d8?6>rA-XC856@X+t7hni@oRFdd}|K zh7G*7w1j^1=reClpKbU+uPvYc^5(>sP8irS$q z7ThXZ#jTo!3tH-1sJ2=~xyd9!9j%NT)~HNK1`Jw@m0D7_kT76PYl)(wRhdaL35p6~ z%>{w~=X+-c0^<9&zxRFq&-4C%&GX#nPVPPDyPxm*o^!tE+;CAsb1UBwX<}oi6 zMXrvtqoSV9T6KZVu-s`gtasZCd4}Fk`6urV-}`p-96@)|_wq}+u*Z0giP&rW{J`y; z=M=G8SGUqm579p7kxwxP8&p)M@u`h97|E+3r>0<(V$`#~TVPR)yBZRF1*4c-Dorrg zex*GP@2wi`*xx~Hu7xs17S?Tm!&;CbaQpOGt4v3O`@i1rXlSFypsGEOxI$dyC8Uubk~W8HDc2iZ+qni0e)Jw>Ueao5E-hA@pF+p?;ztglcjhCTe$D!3 zaUyY9g{8I_pK^?D=Emf=_+H&QV%>80h;@=TqT>^t;Ltt8xS@+T}+ttJU$F;yc=rqun~dn?T)C&#W$q-74|T#mH|?sm1rqlF7BD=)5S= zRojlAnVgZ~<4nzkDr?<0P^S>P565#y{!G&j#osIHl#c|L;B0n(o zWa$&b!M#EK9zO%?qd3TwIDwDTz$3mgjDM81a8rh*oNbK!q^$5F@LTYUg1ZQriH|!< zzZq?ZJ$>=E8JC?!Ir|ttr^?@p#sceKF#CQFeIaLC?>Xgp-F=%w`3m0%K~HY(_?OTW z#R%oIXM#Cu+S@vF_8-5$m>Gdui=9{NGl5UZ}Uz=r3ia#9<8+SiX9E>Zg`rz`Ce* z8!<d;{ zt#A2g9Ps*fg^0t#Qtsktxy2%r#vZ-`WO5HOxf7Wz7MYB88Xrr!d9iZHM9E0?6(Eay zN=K}_6WJ`bAQy5=|0d-gkHbSQo}Rt}e^Jb5YS&Nf2m){f1p*zbDmO;!4=tHK7;oPE}*dY>+b*>?JNsn&kJG@ZNBuZwd9 znxB;VKabXTWb|lOsBexfl(cnz>Q8Z|t+Qiu()R4wol@N2XHQlPyHjbNVpEKAsqc;9 zr~Wbg`iLn0`Vs3?<@6|i{q!!?J;0ZyjO%s zzB?+v?({1IWAYn_{07G4H>gX^7>4|~D}%d~dP{Sz)PFQu{{;Ez{bKn0fxmwYe}Cv7 z0saA9_5v&T2Xvh;^Gr3TgRG>8HKzky7Kh37pS)NsD9ZGUjT2Jzv zv7@v;iki&Nn_tj4@j=(ap*FoPdroQHV)BuSyPe})_$hPo4sE9oO5g#Ik-uY6`Pb#&?!_;s^v2JaNkdoI6*v1D;( zQ&Oz#wph9Kl)D8OPU<=+C+A3)Ul}bc^;&?d@T`;=;AnA1ll)&w9B}M6vB0t4^t;D? z)1MwK9vv+|QGPp`!qhD}SAN@@Li{eUsK#>7;I8GwrDe0}OR=R=tJPQH9_d^D`=mNg zqs6Dcm{fNi{7Ap7TSxjz|6w&OkLmB1>1jS)slT)g8!B_2?JN7c)hOAP)-XSFD`ld-8SO@30!BwE>ky~#U);)Qz)ljcejDd4fYKPBBtsQu4&)UMLi2WB^ji=nhC##HehHdFp zJLFD$%wxoDcN0sd=ygLD@&7}|?b!j1g%z|*Xe=z1_OE)?GQ~)TCOPlM!FkO3&yjcW zaK;zh-NSv8p)riC^dBpW{jPoB>jEkS(zP*2KL50(J$~tVay+$!Enl-R?(i+-q zDe=i#+BJMkTF3wQ(+@&_!9CPptW?_T74r;f1)3$-so+<<9|WD(pzBbAPtO+`hxzmy zxm&s4!d>XEhyE%2ZXN2=i@Cdp`94XF(f%uBnh)J>=spv=&jr>7!R<88e+POuL+`D_ zYwdr9hAlk52f7=FOty!h6C1gxjc31z(fJ=SI=?=N&Y$vJ=o}4fXOd4(6IzD&^oiUX zxnIcLl=C>BKA7LtJiC~?b*S(6aXNnrod*)?mhDNXd(sM>Nx<4AxS?||bbbe&2W{eB}8T{0Fpp22Zv#4i=eSMDBgT+!(Dz*Z?whVh7H>PH#G6WK*U$<1dBQqZVMK z`t$=9=o#$OQ=!Mhy?2b(dT8CryJDX8=NbKdS)A6Jp>-9sRzvGQEXML}z`9j%L+j5} z?=>m|a|fT!e>@!Rt@<>3Jj{lN znegx`Jp2h*BZMY+u*1U`co+u{>`k#}a-GGyYsIDqPPQ}Wa1r}X&UdQDq#T~la2och z{Jx53)40##*^hX3U6j{JH}QX7OfT6d>E#{fBE;4&!`_6a-$RFeq)%TZbaQ6H>)fr} z-{x-GIy^1sck2Lr8F%+U-^e&mm%&pKJXzt%3r~*%>#z9MJb2n{H7?$2HO>!Njf>i_ ztu0)i@h)5Jz5itUc62Oy`I=`JourowVtSbn)5|$Ay^O=xch}1qis2U?mVmc_wzyd6 z?C;Yb=ibPD8Fy1J6MXtz{I2F%C3oup-#00-_Id_9{K;0g>{VOclg02b4_N03P4F-Y z9-Qzn6&|jF{!6%+(~-0HpYrsZY@f#SS-ii_YD~I`=M&ID0l(+)>{jkSLgy%W4w-x@j5KV>!Oo*9mL$7@OlgM)#F=d3qSpQ`h4yl?my>l>I+`4;de35 z?%>|o&-aHouY=%q9=sOA>&5Uo1z5V!1g~ZA`Y?1q0Z&iE=L1|zd6zEjsPAO^vpo0n zz6QQt;Q2`SdWqj_c(#`NI-U*V*&Fam-#n?FyLCj@)96^)gU{`Ek{$N3MeXo3Vpien zLeZh!r=Kgd_x0&+?r!e++)W+wjp@<+&fwXV+=*2e!B?31Nb6v}nLXH6SC-MoS8na& z^YpeDrSv0$yP~x>u=@ClPoppF58wSQM%i$SkpxZd0XD;3@9@n_QH;@xlPX;!Y=$e- zX8d@F&A8FdeT>ZrV{bQ{#hw0kPCuvF-xek+#`3`yqXfEg#@P&qKG9d6W-)F!&t~Lb zVlzBR7TRr}$t6csqawp%%z#dzM`#_)I8Em8nCCy^I-&bxYn`3=;kOxTv;Kj#PG?;C z^iI`qJE3JN*EHzJfu5_l&$1aeTxTO6komMd#7YNL~GS$C5^y(H<^%QpeH1K-ekn(vuyDzx>UypXcjTJ^dM!Tn5zrFq%og8MYz@@3Y# zr~j@RPkx{p>p4GV`NvXzcvp#aNY^v}V6KyT`j1>j#mz2b$ptQ>^ahuqGgl=0&lYK z`_f`_v8TGfLj9%Gi|5h#fwhYNi^$U}4v|w1yei<$3ArO$C?`?_+-l&?4dwFvC-NkK zztW!%u4s^cP+9>q9%)k2Y)B?Bllc^i0!k)>!IUE5mMnhTYtX-AD`|cB3-ZvSTOq zlfG3`kgBY;VoNs0L^e6U%EG=v#v#j*tJpyY`H{>&jQOvN_D9^!q5rGAiU7YnFYhFz2} zX4jePl{Wv##m>4VGs)4Ilg;--lbUD;3w6#@iRaOeCBMl*e$#03L{b&?%5&vgm`N{Y zWr42(`lS3L^d0NTuc_xOlawJz=04Uj18l>;WUbx8c`+I0Ue*+IFY6BWAG*k?kM3pV zj0XIN?8B73r~UNke%8MA?B7$=zApBb_G3?}>|xF1x9l~|RXb?7#BVk2d$o6*`^e?5{~(Lf+(3x(O77%O z@$9F(dyqUY*}GTG^9cWYc$ev7uMc(S@@zc6WzU_!mVJtk0z>xvE#RHh>oCiX^~(G1 zeT)3Qn=+3AXFYw%F6vm>?SD`x>7#8+O zEdhqeD1-MRqlciW4R{~W2ft6>TLH|y?7eE{Sq1Q9@0HLXGRUKj$VuRB;=Ra0lvpp^fR?m&N|SSN8?e6S)OqpZ`<@yOD&tvHQV)H z5|1pK+pS$oy!k^hODIKIE3s$|eTndp9gA1w+li^tpZKp1sKjL|aCG@_%j}R%2?&(KIA`(Ki$|+HumGfj-vg-iScI%aw9G=<4mJzN@&!s~I(?h? z>HhxGntuMW8qseOXP8?!``*U+?UVT3$6r!2!0)M1{N**jw1jOlx!RSmEy-U|qbLbJ z55HCH#K!ZbTo*L%3C`r%04_yfS;Mvojr)RGjjcf|FvmBx1#Q4Qzj0Tv4{$GR+#4JK z>`{&FLBoVwS~IE92u=o0e`u1}znJG@U-I3p)A@aIV@vQN;0f+2;K&W_jO2wv5eslb zJiD~q4QgK|8b}_a&4$BVuOwjlippy^C|NL zzZGbh9g0L`+;Uy0J(2`HeUOjPbU|ZBQ0Tvj-y)CeLmiQ+jFB&f78Ti?2fan$m;|kp z8@~%S0&frW3=8j!6zi(bLJs!n;ZTIR@90czqrfp9920cprFrY3;gu!UfnDNH2jfqr zEfyBg9+%M`?{*r+IZpF?yDMx;rOs7IOjh`^V*Fb6@`>+V*3I`$Jl;<6y=yE>6U_Gc z(}W|-<{fLFPj_pd(K#arb4H_xsib|Xj2AQUy&F#9d(ZqAeDD7){#WTX{+GT+rJoTW zApX~h|CKof7kzj(&%}O8V&ng4-|G%Iu%GV!m&({pAS?Pl5C5AN^}mmwUwVhvH)*4N+gauVGKHy&>uk#7B2FM1Ak>hN$n|-w^e^2O16p zjRqsQ$AnpG`Zj5^UDS{JV6m^$p;LU*cfdRZ4)H^FaCY~Ey9QOB>$U4eW6ciUkfikcN4cwX(2%Bi&lFFTD}j}XTyL%igf8n>?IH#xNr zFuqm3WPex!W7=LWBXPXTuo-+GV7kjt_mRhvPdrj$J(+4z1smL}%rIJ1!T;%VeL zzoi(hJim9*(8`iW@ddB325VKkPR7#(e^!iM>|>kqvlMgu{B*`~f3Peq7K<$%Zu)|q z)+5U}17(2zsEhfZtyzi0ViMsoWzxC&@opklBJam>nfVly^Q3&J3EcH5A8P_r`ewl)u*au1 zYe}h_v}${s=CX%0@dH0}Db$(5bsg9J;Q0yli@-C2dlpw2cs>Qk#p#=E_onaGJlM8j z-)tM2-maB|LXkLqLi;T03k}y&U+9R_+&A?LjUd}s#`eYo0OyC$D)5Ci z!Pi0jAamSy-pLw;gG<&ZHWKfME*Iig=HX9F*zoAFw`f(|ReQwbRp2z8Vq6=SXFhm~ zx#BSMz*ER2I7KIMeL@HJ71gQGAhfh5H)`vX*B{eUF|-sy%Y0(YT*kU#+IbnVT513M zT0LfCalG-n)!7~> zW9Z@0c31g9TJ1B3$emNH-qKXoF0IxkPm*fL`kj72F{DpUXY8B3d8{v$_Neb+4sE2g zQ_eTx>}jXm-&N}_Hvf0kv5#toDrd1VHz(&>+a-7Iee&ZtU(|2mS;`HyGDjD0$8|PK zrQb4;{ZERouti~AnfNv~j_+bDweqK)x|*BubMHBgb>!meQ<xw69UGRg+Hj0n%Gz}s$3Y?|FO(OWP;shom6RXxTWHF2k` zL6MVcu2HPp&%6LWMtC=4&T*NhANrf+$g-c}hy0I;ABx7Dar)zHmEGe`S1j(7^(X&D zd~5nD!oQgt-hqHk{Vl8X^m3lsmYLU0rFkO zEWXt^TE0nFRaTSN*btO&y-jNj1`~*R+>MRF>5ZF$NyM`<29)m%XHr(|V`gK0@H}8h zoGRnW8I2o)0xyBGqwopt#x1<>u-S+S$1&a%*rTa$AtoLlYKctaz1=KdRx>fw8WB7) zMUESM=;f{H6Kb963h^ zpIP|P(OG50YWf2|t}S_DdadVK_VDZYS8SBH%BQb&8f7))lk+SUO>BKnc*o?y;3S|0Q0~!97z$kwtkmYX+IGCI1?px*ecC6W#d2QcPfi(05Hk_oH~V9jOhv4F9M%=e7)cL2XVP{#bw!ca#<@;fB2V;=3r z!F}TxrCDf<=6CFja1Nl4{-6AgP$a-_;Vq6Yjwc@)1jjsZ6jP@AoKSZj9MEs4Y#DZK z=5}!3i2WDBPXX{H&WT{}>#_G5?7e$k`Mm-ensEs*N|9w5ZNNbra8g(DI~vrUUX`mB zpPNlt2W6Z!p@6+D6zRY|rM1_pQR8zREcEG;H+u+*7!}8258MOdE1zLoQ1^M`>$T_i^f3__djEXn&1oZtZl;IwOq>dOxdh;q-@X z{y&HB>6`_O2F8vp{*b07zpwq7Ya!#czAHl76XXA`hqRGAE5PUVOWvZ5v+U9)TJ~tZ9$T~zdA|?1*~tysJ=TNT#d=svwRUMP;5&f7 z%F>~&w6trbN}D!^XEvVwlCkTLfq5Ue$CDm7LD{XXhyU+@^_~BKwp7`rJ+AE0HbDQ6 zpl24mY~}Z9$l!YL58zs2ZP!L5f3Drv<8y5!a7V6a)gA(e)Om{kF980@el`C8pDhQq zaQgdN9_2U0R>yZQ3tAhqPj4sP|U<^Gx2)td3~S@KtDkUt122DU?s1_;<~UjckUW=aj=* znddw0=kPNExF3~V%Q$@YHv-do26V?>kyv>29qI9M6Me0`DiR z_*yfphE@fR=aJi6;CKi7uwhd_hmXr44g=z0NpC1B%^g6Cr8kTwxr ztpQIMJO@f!wFiUk2?^lvq<&_~cqKAk+v6SWdh1bb7&xBS+q8|~_zO5*0LKf}JG9Z* zi3?s9fnyOgeF-m#w3{{H_)yuWy^oFj9URzCK-xt11|#7p_@wPz4~*Y}qdny>+Ue>M zZ2T`;Uv$#}juvpVAfFchS6Zd@kX8sEH-qCX%HN7zCDC3sgX28wUhR6%L2V~EhJmA8 zY13{C9!@w6j-#pDv`k=ZfcFK^pI+LbC2?O=x<^Y^hkAQ3|F94m7FKs@A6oZmE^tib z|Hr}c0yvUs^Si)NK|9N&ee}k*RB(JvnX70sR|H!Uz68$-+S^g^q*3qB!1rNS!@1v# z?#F`X4DkE`+W)X(zjh}!s%E^eJxlq|pzAqw(u4Nd8~fU2-K8DX(LZ=PfSZoIQZ{ua z3<2ku9)Hma!RtcCKHAQYEl1G%=h~$_yARvH0z6lM=Rxp1xZ)eFf_Ao^wz7x!{h{j$ z_(|d0ALGDtkwSY%|JQ(LB(PJlu^rgmha2}L2;M=dTaWpH>yzKrE-l$h+kIDi7X9}| zH~YZz4)ni6n_qxWsX}gX-*6lJ$oZ$&fG6%F`k%|_gd_sM%q2L zy&PWOrkn@aiH~WejEDaXrg@gome(NHx!85wXZ#YI9e`gEpOOuX!?f+?=tJ5?F4rRE zJFT_!fR+i)Oxk{6b9=)3_=eYjI|$s;Z}_-pQgFGS7^{t4&F8$ynoxBuo=AP zVWZMde25SGTsf+Bz@HVHeFGfTN~@OrPFq3(@Df&hW%dnaz-<85T=ZHB?9%G6mPnm7 zwEriRy=I?q6ZPC5?n)@7Ug?T1t(EeQ&EF-=!Us7htNwj&g37ZiZOYoXzd!jd{Wxc2 zbxL0=eYo_m1?WlUo^$BOGHEX*=%)l8OX;gst_=8d)6RPV^)VK0x;`WjoJ#`kwxZ4;X6!)=IP9W~LFb2L{u{K#4D_CRWgK<2+ zowbU3#*Xn^jB|;pdiLzyv;%$%)INMC{_CvM$oWrJdUYT35CN@@v9@TWVSYH`KHRf)n1;TDUfkdr!Nc>$RGY_85J|Z0_UH zam&iqKxk!Kzy|EZm2Fz%sx~dBrZuoDnb>M&B(QbVX4}@p{aP^PBP~pyypR9)B_7ab z0&6JOmdwqzEw*;;v*eB1z5Kq{)~ek{pZc0DqD6>hF0_TU^D8>F@XGeUbrrj{k>Dv> zc|^0XI-&_r`*^pN=LdlGSn>zjNNAtPwH!QY6}z;Gr0=vvqc_{$D2r&f0{?}i!`ijn zueG&kVxt+5UdR%APg zYYgwk2#?sQ1^CaeYS9*ePXiw`X&Zo7x1>|ckp2}~J5xT>EH#n9C0zGb?9q-c>CmPw zIjCI@ zuFtsMWPV^u+m{iU8yM5}RYdeC^95q35AiJ*(dl4p^eC|8xs;F3BfNs$T!?N5E!nMI zR?`v?-9C-Z2cYNv&_4rxR-@mWki|{57VXFA^>y@aLzkBVZ%^h?Ev{eTe>%Kh3-6-G z(V2&}3gGNY*{02?XwgP2=^~c?Tq|A@L7(_5WLK29M_ZWkfmTbtsa=vx#lt$mq6~NNU3O=PbJWSdm41 z?nBzH%zd=dR>QR00~U)f4}Ih!=Q;3}&gH4WhjDG75B4Jq4H`At(>&T!I=|Dgvr*`$ zysS-Yg?0;kt+%yn)%@?`w;MWL&?xhbS@_&~=2hnWC+kmD_@uaBk$D!GFL6Lm34TZB zTGII~?W+))oZV>15L*XdA+!lz2RJ3a(#cr&Yvv+VVh6s9<`tf;_;BG3f36k4Q#yWI z;xH424h;G+7kBBan49d&yv@S(%t6YYjrf|(0OkpwuyTf*l`--;s-Yh_z8-Ukxxf;c zucUmXr*Bt!PnVIoH#*Or!I?ge?Yz57<@-^#rgG-T=P;jhSDB?UXMnA8&M4K8{L1)# z5I)*>YE&o)0CHoYLtkJzb|IV*GzQ5;(@+;%(E9U-= z*!oJrsq!mj|A#X-P(XgA^y!7nooMJ*=9UWwkvqSLxT1`Ffd#D1-NCwI0rADpqHA$w z^!K`=G-+q3#@*OLLAq)@!Z&60JD6)B2SCoTklwXiNTn)Qo`td+?6LON?5cGgLx|Ic83WCrbO8uP2sb%{N;JqCC`4 z_6MI6d>Pc)*YII5F=eAR&EImuzO%TG>uO+q0U9P#{{mnhXlM+U6I)1|&ts1FBGybS zDa~3YFlW%dcQt$h?r>n#OM7gS;bnKjr$I&LF@Ud8e*8=OZTArKpAUaUl(#@fq+w$) zk$G-e^O*=Qoej;w*5s|)5Pw@h)=ehAWZ0gf|4xVBVbrnG&kAoge+1t4*+#?nKJacN zp6TOn4_HIth{NP>k4^ffeyNO6;a&XSpioOh`c1PxLk}s&(OHAwZy7wvTu=hM2w(9z za;ejf3^L(;BkM`RqtNW&c^UVBuK30w1JSkUrWN@J{|fxx1)PuQ$9JP6Ek<|W)DN{R zWFx%pZP*;_58oE}jG)^=legCGlTmGix1W5k8`=tEM z`2J1V-xtrH|F8VJ^zRv4+(!ClH|MChjbi+F5qY}B=`N#af@-91cN>lkZo@NQHHzs2 z2ADqGWw^-+V_vTX`@3{SM~SmoSfx{XPA2e%}?J zOONJUEI4?0*)uBkGhggyYnJ$Xf#2QdkH+VJNt}_)_kK5>6ZQG+tP90`{s8Q`0NhPy zD6@+2`!4)`G5|M+{fj3i`<)m#+rHx8#ew~2)x7Z$kx!pDjUnKcN z2k=3qvAR#k>dJbvz`T+1Q59pJ?}*{t8HcofDgV%F(!<&-#DIOEV;^+|PlPfLy}aL6 zfPdJP9?_m7&U;R2(+)Iz5S001iSLVeRz$qFhkUJ$hONP^(pM-U?Na7dWUfKxdsXI3 zvYFQryan_}-P_B_zk4wM9{}%u=2tI+m$}rR%RI}o@bZeaO&bc%>!DfXR|8EVry_l~ z_7h~Zui>+x>gm#i_HpW$(7waAv2?$t=!_BYZ^CZ|DTbI?B$3p0>7d!X&bkp1ChVTW`2zJ z=XA!<4Ic+@W}Z!CEcP`Ge(wRsFzoqNaF@OdV*)}-&zn$hEZ@Z1g_ zX%|*#v{2WA?H9n4@N$tSqRo%tj<+RgM(MqMa=flby*7`!^Pv5P7(KhvnU|zJ ziM@!8i4APh+mE%c1n`Ls^oLgAD*!yv!5+$pOtYXB?r(TUBtutkXj zB!q#A!^A(ti_jd#2hGJ+vbY-kA+3yxpK@T(Gs zC|nYY2wi4e0ZsqR7}W(Hjd&;2cFzYzX8$paxlD`q1&hpOZqF*B-w;18xzB~}2WvzY zPW-*(;>7Wo<7tyu#`H1%PBj)TIETJUVZ1wmHQjm980T!hTP**ly))d*Q!e1V6g9RU z{Dh}xGlWIlmpHDF-^{@h z#}4@3p4#p{Sad0EJe&P2_Ru#GJO0RyKJ3Uze2wHMx!A8!c8c5%fy1)2IY$uJhg0NB z9ic@TVq<@-$h8$5v2wiEZ*-e^OXmJ+_FgNJxAZGZojT~qEIEhxWzX#I{&?g4wSOwU zueNUfqT1K*xVQF&(f8cG`rKdN{?dha-~Kjp2#4>Do=fZ|S2K@sVeU;X1K+fRe9Bqd z6m`e%$S2y+v;G2*aI}CPtT?j=7p0MomLqd{6f~b%)gA|3==6Yc^eOt zuc0$O4D*f4G@iBa?EyJIW;JucJFwX+)C9iCY4xT#qvwWX2d)V?1FpbyHPN@5{BRfl zO$)dK(*xOoyg+UsKadl+g1x`pb=LiNF7-24Is@75?6GNgMzVqB28OfU6`9_i9dYuX z3s}?I-I4tEoX9j_P6uXQdu}ABJufmH*m+>d2b-K3liQvjnPK6~7=F9kf5i7HQ+x{f zMMAIS7YQEOhpE^(GX#8B@=aFBdlG!Yui%X1%78Ax;|5RaDaIDUhs)$2`f2;(tFIvU znVjOz!U*TbM4VsJxLa; zS79Gg2j7wFV>!+HJGF;*Cl@wgo*z@sS^Ms3E+dCM``NQNOFCvx%dw|ke8;*Rd-5-h z+S4fVfxFw&C?&zPrvUaO@7_ihlGE!q_jn#3my9;|kR>&R8JE~;vtetZX(xPBde#QX zUq;RkDD2H-9Wog^d66;7S618VFUd`tR&{kCx9UfMsq78so4da0Ro4XERjxoz74oaf z4$Q1N@oX89uTFfQ$op~Ot0P(AA4N*Y?_ENSKR$d-Bs1)cEM;HtW5^~W?24p^vm@pH z?10bD_ZP$N$f$5mIc`28&?_;C z1^6m(6?n12OEPjP7hCCezKql9VtW9&icVL=L4Q_`O@x$0Z+R@o*XeWy3Y^Y}sr#$Y zea(q_zx^b=XP%_@%x-#@cR!@}_;}QTe~9YcX6pS#^qxP?X*>|qJv#UGK=0d?WUq`* zzv4Tb9q8VP?%grnUyi(Hp!;d)eme5YNB7yM(7ot?6!j7)6Jjja%2+NF7!K<0W=z*f zTd)H|zIn7OqpFlx;Q(t*z;~C@HzVR}-*Relq8hM87TUbILpM6%ekHOze z9|fGioa{Qs2&M9B<}tCGg)2C7CZF%!{boqQ@cae&sb6vKOb+MH=#%^j`HJnzY|fnt zC9TTJVVzgX|Be2JbIxYG+fzAjGiRJk<%}8mmKNs(FKoiD(swDow6V&HBDj(zgMa73-D0B)9c#r|d>- zH5Wg#iL+>Fz?}a z8Tsr?sa{GZPIN2NSxxm?QsZT#O?J)QF7yyx=FTYskc4eH0JSIE0>DDxuMbM=>c-M|RA zlt0-n9oBr`j$_amWm^jb&3SIqpFSH4-8(2lsyw3MHWJX$Vd1W8hr4h@_aUZ?6vf*4^ihlXvpQg&^HMhzM|YUTp5(}QD10S z!22i-XLv{Pd?GYFtlH?4qjZdi4$klKz2{BQq$Vo0^>Ln-I!0$LSrWzY4h}pmy%x!lcL!6;l%`t?`jmx{mrVX&K z1skxluf@(8+Hy{F59X$`n44AxD{CKPZbD^lx)t3{q5PSg>*bv4H1hY||G|~4TXyJ* zZ$9lt>|n|Q$pugK%K0%nu!o;v1GlRQzByH8HS?+}Y6{rvw4kb_=4Jf)D&Eay-_tLv zJT>>Rm+Y>p@|vQmB{c!c_;~&rSDCWg*1B@$sBat(B> zuMYwLNboJ*A7(Dt8fuLU3$;Z;{_>g+dG?R`UEn^I%WK8;^eq%osR&PTm>BKN8oRrldBl=3Ex1IoICPoJ(tEu53Q@HO%1{xtBPN zC6qgxem2kPG_E<%X-NO{J2jcHqS9H$oPB_cF|W5nP4cFad-Ab=XJ8-KPUi0aMxXzY zKNQ%@)#(ohy8JBxi5WlP_a=U?q#rM%Y=BFr%nGi@c=sw-1@G5z$s8rYqpy{-Oa4?P zXSHn61paH}Rtj7>r=^2DsA_wg=CYr9kJoQ0{{~kBR|wc!sdpII&vSp9>maa$z>S~J z(n{am#+sBZyhmU2GJH^@WIV-fuFyc|3$xb{JxoYArc8ik%Xo-*+J zxdfM-AtK*2kLTISI-rAiLgM{bfVYZz0>7FyQnx*#m2g*)ncxzb|JnI0>!G2QD-LrL zINP}d-$ud7JJF%6ImGqILV-z326+%+)-~h$sRmya_|t~$ekYF9Wghxl9aLPGrCz~!(jz5sEL1016Jl2FJzpQS+U>CGIP!rYLo zn|+(*0;U_7x!}kK2YGAW3@2yIaQV5i!+hYr8++77 zzgwNmH?EUv4f!VUg?wjhRl@CG{oZ!_*MG9!{_WeA+b131n;*kn#)XHR#>Ge3D{XZd zW0G9P*i@Hs9^Y$BA530uf7-Z3>HOwAh40o5ijHqB{de5X|NhfHdPdzcsIr8)DRohQ z+OcZRO)a*l=G>HOi$0UKPR!?vmyz#BiLPah^Bm@8B^T#xg?(kQvoYgsK1tgA+0i}w zA=>CR>V(mSpDK26%sBVL!$= z#*vmj-XrYonD0<#by`QRejFQk${(WbpT7FHw38*YkzLGtmHS&+`)H#rC;Dz!u`}Ra z5em#8?|VGIFXi_ySj+#A>q2ro+F1)I_&gr_5;1n{U6)~hrxXl`}YJ_ zE_WN(NZQ&+YnRr8J!Xsey~uhO_Q7jk;z18-%6P&D_R00TXsg4l(uVM(k3e4^+vr# zE7l|06UZ&Og?$>({vqWL(_U@@))(Y%=C1hMHcThiTyN99B!A%-$mJL0Jj@}-VHz;s zgg24nQO>R^_OxhYRZQEj<`JRuVkF^EHq3YPvUXt z6@8uF(h`xqb4w_HlrhW=zwb;Rkme$CJ%TtAL_#V2|n+45~f^sZ3$ z5WaK1}D=0|w{2(mc~If|eC4LZG&a$>*dAsew_nd80?8HlWefAPV>`(@a> zjNOFK;pko3-Av^A9lDIS9zz&joY|TvNh+Sakde)StC67spJDj3Kz}PVr}BO7?(Hi6+k+jHpi^`G8hK4eULvdatHow4 zzG=uz{KW^=p}-f`=-C;vSHvzhhAsBt@?Z-p*T0%KV^3++vbn4&>$O5IKjZ8btve&t zA^H+NEAIf{tX+Kq53UaH0js*Hir|cV~U$d|dqOkU!WbPa6$jXl4&VnWz zct_#8WzUHVI%=RN$R+p$?>~c62cOCn;=70&cOG7r*_(ZVsZOKSGNeiRtg-9~wD;${ zkHPe#w27QsZIz|UaPM5j*7TLd(scFY6Z^EkO(K4!Pb;ENE2U2>qEFjN-zn=Yi!Bzj zPb*4}K8we%@iN);X^UfhTA$<|l@h~R>CevMx4PHuJ(D>0cKRvy6gH(!Ajh;@9NS{; zy}Fg}4$VJXnU%?TY+0Ps_AO_=H)saVPD66S3%S<^nfiC(lv-kI251OZ=&U zPw2~aH#&HTdjj_`m+S}Mvx5E7w8!DxKgQN=Je%V`sLiT6s5MrHiR}(*o3Z)P+~c{1 zKcju$M!DPQqvq4UJ%&$uOli{|z!#w3vJ`oLt1U>2ihTEzE0n>5kK=5?deHk%{S?fPYnt#oKD_?uMVJ1s3)flIJfnuHc=>dmMcJsWlwQ=1hgD_`yBUdH@(5&?)kLtF*(isu4j?$D^|WKuC!|}pua!z|F`(B3iLP={k;jlQcraDAiqUFLc`nW zJg!5*E4Y$-G@CXn;|v*xTv&b3)Ni&f?`=NOuf&?Kqu+7p@n-b9Q5XG&0#?fA(?1@lJZlrha{dQkq2rc#@UE| zpQ4V){S9U2MOw08g}-iEukD?YNO%>hm(F<><^7QL=TucE)% z=u>nlyjLM(8Mlsu7tzc9P$(jDS%t1dM-|*fFQvd(gUyN_L^nR_$rw@kZ3ovXWSob5 zMSdd3V(d`%pG*U8W=g$gr>(C*CT{8D;ll|ZO(*54Hp;jeA0^|rY^UOT1-Z$Z&|}=+ zqyJum45Y7noV)b5GLHLx|9X%<>)^lKzdGq#)47W2TU9PQytL5AWog`k!1EJ)U0`ou`lISDk8IRPw9-yYuw_PtVVjJM~|#k5b0oZGBY6 z_*2W6FWky^(LZC}q>cHF?aY^ly2{Dl+0miQeO_{}(o}WFBYgY9(yRU%r$3(WVyXP{ zd-I3UXA*yrgTwq`^#7kRe|QUi-q~&LQ1){6B92NW=DM|yvQ{x;t{$GY6Q? zy6Hp2SJGcdt}f#(uk=?)(o?$7ka7Pmd6_4 zF7m})tkt!$XE2*}(Khzs>Gk!&rS+SGp8CdMS^b9Ko|igpyE&&a?ki4pFR%ZAa=>Jb zt)B6Sum1huZh;N%&5TQQ^F27AqmePvQuDo(_tb1)T;ws|OZl>zAmg7h-g8EtZ#Q&F zADRtM?=dElF=R7ip=15C>^%qHyUYp7GofR;tn*Pv%1WNC;Fmr&3_a4{I*^(4t&f4D z9h#TcuMY}MLWf?zG1vmmFg$ze8{mI^Q0NidGk_y_1fRf+*OBu#UC`$=@kZwa&HP?` zyx&p)AFl5yd^`E zy{YD$+m5U-YmN0zS!Yb}+GAxE%8C!mc?Vn7$vOY4)0ny$+ucImM=a0dsN`sIMqotp zgrAM)ou8N|49sJB!glgS7b7p(zn^a-?_6OIH1--l!}4nEwGVmbV|(^$`r58k`tkE2 z&azCw$M?q9OWoh~RAzlcF0ucF@k5{0Ud{-70DF{t;#4)!n=I#-s5b8o#<2?mI|FkA z;lM&b@&=w$9%FH=mNZEAGI+)hZw@uoKb*WcK`MmaU zB)7dKGM9SusF%~;N}hLHWDfN;>O0#bk?i(%$#?P<1Ui7(9+3R<>FpiF8PWW5SNpf* zWSy8_E_mYk<$`Z&EWcdviERnaI4%ct2_6@CQcuboj<=;k=r4d?b9_!;EoW;>jG#uC zr;dck8K(b^*-H)f60aA(kD>jWxu?LG%G_i;zg+4{etE6rfgoRnKGlhQ#ZDx*{0j9n zzE7G&UJ>gI*jyFyuGt5!!+sXIjLYAkFRaH0Zuq|av`dcPG5bk8AxA{=`>go7ji#?l zjO7VoKiJMRY^bE0{alItoYgb6N#cX#MM;&tMk$qH&ayd|vGzHP#h1tIX9xBZ9e*a9 zzOaS4Rk5EQG5a|KKUmA}vE&np{Y)b!%c}|pqI(v4tj@0rk%QhE$gOH2S11y2SG676 zvoM{q>5M(65j*7*H%+6Si}HEIe7VGXdDP3NUJmi6yQM9XL;YOpJ4xNhZfTFm{sd=L z2QXvy)6&g;7+0LUKSA&uvmfwX9=9Lxnf3$DI4%ct2_6@Ce#m}Y(C>uaxc$WUCphpo z_AqXEO~ChH4*nExk^i`fslK4w2h ztrq6?lWO;zG=HB{gI(QC-slV1)l2lNYw%BNPqeMyw~$I>3+^YU_DbyCm7raYIj)}bah_2LYu5c?TqPsW+>8pgMzUBy0^ zOO#nxsVecQ>hmCntJvExj<$F^&q~ez`*;J~Z|C`V#p+we@0I5BzTOG+E4L$yC(Zx+ zdH-OR>+3z2T$`u({fha#H};%JxqjXf^Z(PlYs_-Jy-#re8EtVD_p>>>PUn6WIW|90 zdwK8YdX+f}IY00x%uhA(Th4y0;eL>@-8$wwfK*oZUAPIL}k>UdkWh{x)!K;l73Q0pGE1*Y2X;9n`Dj zedUT)?JMqIt!UA1_3S;ihOir$a`xj|-ff|7Pw0IPU+}z|>K$SEP8-K~^i^w$_b zYmavsi|*F`zp}38lIwOEIdL~ChqRfT zyEYR%jliu?+O%6X9Zk3goB`HEvw>l$`bI0`OupBc$M_?6IhV1I#pX@J&pZdr=c)~@ z!_r}%Wq2p$?}VnmAg`swHaCM~s{o5#9y?JJx8?h;J5%BN8tU4Kde=9PM-rluBH4SXu1s?KJxhbTT;C?OPe;3 z^^(iLA+%?M;~!HT8wQnc&z8+#49%kKWLca6kAQ%=61RcmZ(C21g~fwiX<6 z&L8W`-VXfU2<&o1)edbAw5s43P5BPWUryV2R89K-*n1c7sH$`Sf9*Y!JC_8)HI~dI zBq+5O5HH|`J(BTo zgDd*5I#B)zK43z-V3+1>`)kqy$`E{2A8EqKV@byE%Wp&8n<(SQ)cYmM_!DK^4zF$x zd{}-2tUj-EXL%0se@hvIDdTSXl&_HAVd{(WZ1rjRE0htUj7gNSy7S$nRg~dEhFZvD z24xIoy`#BuFKzxx`9ZKyw^GJ4l<}3w_vU@&x5P0;@1cxOh<`F=+@+=Y-=T~W?NIqt zjWs07*hU!|Yn*p+OMBeO*y$O{_*{Kn{u#J}_fUq|Fdwq}4j8PWFNN?WVK2sjS2-VDdYZc3 z!bn3hc+7j9*3P)oAeik>zV& zcsFTq>O1Ana5nx{>}ex(4#h4!j2`bMO+NWo(SCL4p6LE8e$T>oG(-RM;88vcE~V)D z+t7Fmbo`XI`wUw1$y;zB^RZK1r0K#ATub{rhMf@k?k2wI^-|&MeA%f;h_v5Agc{I{G?v&GCI%p7r{{ zq;}$$laJsk+9<15KUBU}?qz7FIkIK#A~ zrC+ihC;FqIKU)31@}=04a{8rv(3O)(qrLn|l0kf<;jiUw#A|#0-K0T$ujhZy>xYtj zgkjc(5@TBlPsQHlVVk7iGy>p!VKc4qE@KWk(`-XtJ@DU49lWg91z5k-p)C*ICa@a& z{rsjGHt&wn7v-j^CE&`;nnIXB{}PL?71)b zeZegJK)zoU)HwGg_!TmKO8U*^%_)zw&$ZPslbZ}PEy7;cFAYuL#VUYqEM_sD*+aY;eT%cx6%~y{-$bQ#B&XKO+-68y>G8}5wAJF4d(Zye~ zcDQB|_gdkvC1c%(;Lj!4`YY?Zo33E|Tg;gKVb*~kW1mOHOHG^EE8N`8n0!x@o3Z+3 zjM<;sEaUinP0wuJ+cbzZ_U)`~Kgr|gf1|-He=T5^e@3{0an(}xSzB2@9?kDU_CQt= z=Z8FH=vV`fhJ1;gOhVqI|9KSsc#^T$@A?1t*o5a9llh6mg+Aq*uu-ncL*)U{18mx7 z*va1V{V4A=bUhndO4xJiq%Ol6B28JWeeb0o`@L^pd1}SyK zqaA1Sem3nVZTC2BH;*!>uwT&x)>gG|PkDg0l=kz0i*pric5=nOa;LAmd>8iKMmyPP zr!3m3n|!)ymwmL$CfZ~#ac`qtT=*Gm_Vs`zf3RHlh0C9VCwBO$!Oz9KpU%6??nqBc zceh~q9<#=H^ophZ11$^(=>y7m#49#HEpb+)w5PI1DoO| zwEP7cO^fCP{-yLQdUg0H_N0rolv9}N;{UnCyX(lTcgL`AkkjitRe(9|jmPdAZ2c$i z8ywfapSA1b?Hio%@BjKf!T;9zD){?f**}=N7~lRo!E)Zf`q|G|gZ%~T9pSxepJg5P zx%mEpoVn`{9%O^8cW~ay$DWn!4Sal@{R4T|d;dUwFFMZtf%qX_#Qp(muRB^eCu>-1 zt^_gjL>uh6PEfo)y~i9|8Jzf z^I}Ke1zUwec7k(7pYjY*P+?8VZ5EsI20W3~HVrarRP zw~@VfdxP8~rummdy5*d&g-;@U7yQR1)NdAbT1GvTLv<~sZjw&oXHs9Orww~2dl^zk zp_#PbP5mXH-+yWXp!~s9&ERb{cC%#d=q0R zhpVE|kU0VSC$jd9jXoHnURqnIQz4rQniVv4vWD(sovj|<})!CJ|PV{RPJwtxFSxhH&L|JQ}9 z$g%h;$DEJF#`oU;wbrlC!S{Sj@}l>@o3!Y|v+RpLo?=@hbEFybS--vxo4#1qva#u_ z4D*Wc+iNfIVe6|6^BVStoAlWJ@HHBHZTOtKWq^vA&Gsri?H)|VCToF^c^pN|HxiQ*GKdTGR{1RU!C~p3HGDL zS?k|p>jjVRWb8zQ|7Fd70{cNSpS9*xU_dJNfz#O&{vPAIjQYw(js0NRcbdxhSm*!C z7*kJY%zFXj+%4dlN&LoNzi*c`zX)ybypO%&M(`fxTRj+T0lwWEYU|t#&Yt8ad3}qr zwRkzd#E1H4A?|b}Y+&9|x%uPrAorq3UImP2r}8@szn%L+p`&@oeC;x9Lo;LCX4O+3 zA`CTrT>b^~vwJDOnBT>Wp|i#EH10(_0i z7_%qrN#9Vz7F?{FBD} zLa%o2$1hsy<@ANiAA}!ES<5W*{k42Nwo+)-8Mhx~z3`#Um5rmZIa{G^EA`s~{emI0 zn|e>;?wIqjn|A7Ar%q3UsTlEnakOq>$`)Rnj9py{USiAUipG0GZ+AAc4il^Qj?PZC z559b8mpaQB+wBA2k3Pg1j`Rpm#P^JKT)*(*b?)GKaI>#*YenqN%LKm`f+-?0BlryC z;Kc;S2f6U&2Fkwyo{WN5PUK z=*`Ya$Zev|W2xKELYDY;^iiII+JwgQLdYHKq)sF8ox(-e2;sQWWC=J=iOClZ5BTk^KCKhJQJEH zpwrT}Ry}=xIjU2lFDs$U!&-hK&(> zBjX40X)DGSxv@(!AKeNDMk;ni=AkjW6UKL=t+N8VQO^8Y=60I{AA|ka$=vkg|I)lP zADW#)FXcCZ{pe+0I=a_=2NC10##40m*Rin|U{mvG84B`{u-@rYCQMzKc~(DjXQ z86#l}|IuKsTFJh+i?wMtYt`#5{Ko?YoALd?kJKs;Kbe|{;cLue+~Q>{{Y}eoQJ;6m zOrw9BO8-_&|5mi{DTRpI4!>Lzj!3V&qDNmC}{ zy70$6A=)DZ{o9cp*`IC#ORe!Zeh~>7DkLAtPsY+sGBzY_Iq52f>)anGXV}68tchB2 z6yIdbr+WR#@53vfZ9WX9;}Kg@*OO)EHGe^0`{>LmoLy7?$N%;G=3v!H(IZu=>s@~5 z_N=H~*aEKCGlu!&omVt3*m7m_i0>QCH#g{hL-&=GDdX^bu(p&<1yz;am7Ai11Ho0g zOWvg@xnF$e0P;$$8Xo=dt0OOGmFZoTq*-5)=I^&h>l!#vnf+}eq8Ae{vuZ>%)i#Rf zB%YB`RW&sFqpyxUe1To9-%~NspW1f1zn-+VD!$o;Ygu&I6RjBAK~2-dT{RqJ=k-m9!#yujiyxP zM00J!qsdjnqFGgx1-8_Udk=5aYK1>nMpLNch%w46Z@2m9R@(ept}-LGA&hUbTZVpH zaerh=%U&LpugtJ*Sj&+$s`>3#j%*Z+&ZGF8RX>RK#^XHFp}M}JuAj`*nm?r-KZEB- ziuA72XBo}DU9OiZK z%_Q|2tO=ubYB?IRn1? zt|2rCo!p1)Brmxa`AC^_hvNTF>Br@6}a*^U!q0RXrBqbo#jiFe}1X*-hIrQRdB4JKu3SnuTbavBZGJbliF&RNROb5IOKiao zxAM1l_w(<*(iYs-(9b`cHgaMolnR~K@oUXIi{I^!Xr_*?cDVcbw>_bmA$Na&TZ3lq z`juwBeurl6eu{Ux@4UU(2+6w|8{zbw;eY*JzTeIFXEd{&wr<;^ncHeLv*SMAwQJ@L z=th-p1P5ncKk8HT&$EE@P&Ol|+l<56X}+cHc^Q5$|BvH&!JXkh8J^a+EC0NEXEeXM zOAk)s_jWx4T8+b=QNEo^ROzU)x#U5(`yD;lgdBdr6Iu#=r5XNf#lDpq=IhI#r&2RZ z&i0JTJA3h{-77S64&TNksmq;O>8OdjB3GAPZJ0geQ}ssV>T633^M%!#IsT{ zR<|lCr}~AWTx@)BEOxRa{l-y6sb!-coRJ)SAXx>k1y^w{X~p)AA-}TFnf_+dy|*eY z=k#fp=bn+iWYn!HDPu!sac*VmoKgE#N=C~i$-(_9C*!xe3Z8w7agQ$donOK|>FkZo z;JjAzAQhbP>5Q5iW|ZVUKJAKJ|A3-gccwe{2ZxL9`E9xi-akME8waHZn}((a8%DwF z1)BM0UdE)x88dU;{Vvb#DAmmE>ojw-D(0wsac;zL=eF}~{)_E!;49nVdfk4wA=!TT zlJ3JBf0w7sWX-qp$wFmz;3Mf-W86~-e>=O={HJGIeM?@tzvD{HY`r?U`KiguY@eZ-Z=h3Umss~=uXh_~`P(NW7neZG`O35n^aXd9 zXlCbZ&1}0`GoNxRvzv2s3Hw#LMz1TIrp#?_>eHPzsR8+Med)T#6?N52hA(;0`xJ6^ zA9A`G8eg5P2e-9z*ZBE*u%W%b-+SnS=FSH0VW~{@KZ)Fhx>Nlfd78PBa-M3?Ok0XC z_&enIcgSWv@?QT0_dY;Z`$%XkL{7&dv!`jMv}IZ7EWh`B!+f$uGk^OCG*5u0hSW)7 zW5vFD*JyPegW&U-;13kJO?^of<{T(IKVKw zq4Rlnvj4XqQ>VOS|8wm18N!Dd@ZgYUCWX%She|n5^tonM+iAyNX~8w{qJ5__SHh3Y z`cVH-Yop$xEKp*{;mz_Q40?>sabM!7!6@eLEW}GyU83B!5S@ z-QV7T?6fn#zC;UlwjjGR;O!rDX(qwhM{q~ zM=A3rp>q^;lD>nnPD6K=e>C)NZ?O5>S3uieRIrorPsiQL-2Igb21Y_>x6S|LD9Xy? z85^ThWbvs&=sXQNCs1}JG>+uS!?vv>?H$ls3y&IXlS)TI>zTUg4MFQtXq~K^o%hCR z9omOhcbwKi%DhNu9R#hUp9YN`rMiDxC37S9VE^u4tKh3GD%kGk9Pw;rzJ9eb1Jj_D zvG0>Jpz{)*D`T{7ySrcWQzg(k8yW^s{?)oEeZ-uhoB=W>``czfZz=s2^43^Neda=6 ziO8!ysSJLWrSol#t*-rg>W3_N(fiHU$LUOFtR-~P&wEKf7do*M{`Nf0zqujXzx!(F zoDENzqivsn9GnlGOQEw=^FO%^8dvaC>gH3cp>G{!-=Uk?$bpxByWLH_(6QZ^!LMQF1BXP?u?Ylhdg(avw?X_J0etD7BTmDxE>S$3)6KI#XJlhCEVh7WHH{))UC zbn~$-l+!}^YkogMSx@L@!#i%Xai804eM&bsce~A|oo@4Y&*)~L-EG#tBN#;CFu z`6{$bWDfT%`YCvh&%>|STrGwPJ_hX7^vskUkzp+bRl`%P`P^OX5$|Vw+#R30T|?R( zl;u;*-9oJeob5k~cdEjIkr>18S70ow@TELP556?k{LLN5?w53Z$9D1?fAW~W4{6-Y z-_|mByMuX~N9Mp%)?TAWFh|OGPGLV-V~!pW*}mIlKGmMN(O!90h*!R_!j zl{grmj%0i~jIrr(u&YP3Ty~b)purRP^0ISrfnWF8;LVVhdzniFo^sLGiC(+R2J)Pf zDdXEAEo;wF8v=ve=JR}ejImPv`EIj;@z&;hX}f8L*#r$+NP9o&nn~C1440YiPxEJF zDgUR;bKd{1-uy0exes4g&72uBFP*M7G?2%3@(Z|!`|C@G`8Si#a}!-==lV4NHp)G+ zCaw9%npB3z1s5pzhuu%yRWKcy zDnzE#=v3|~*ixX!U1?;`g2&m#Z209QKtFqvzrtS#M-452ij? znLU^C#IQ1DeSq_J*4+?)Prk;I=P9fqNg8KdzSbdMF7}ipjl+`FRMudSF}}AkhEJ>s zq&V){`5t5KcUix%)(6VQ?C3i`i&77nqshF+nx|EPC1j&5nNO{(M0ba&=F$PGS+g0Z zoW(rNu}bBPU@qci4rl`#AUPlWp;yxVcKpPW$_z85Bi-MPe^eNm3FE*1oq1{lqFche z>fnolsht95GDh*?;OWkI7!hgp_*)#J=qe*?0 zx~AGtmkVv}hR34I3tia03yn;bfgySaC z?`;X*6EDI0Oeczb>@%)a*e=j!Cp;RzA#R%>OSAHvY zXe=`5p?{Zoe>L;|dFV;18nz>ic_RJb5?QO9%6zF(=B>nSN*z{bFptaQH=Dvo?MQ#( z53DoH0pLkx{KPQ(ePWnflT^+nYQT<{vTSu*L%FS6$>-m+fjhj*zuTJepkWSt(lF(> zhu`x5oy)Jc-v63+3;BPI)^A}2c54d$LK^+z$JoCIlT?@75B{O=n&`QNe_Xz>^sDgZk;`mbkD(_&;TB7oQ~X zSyjeeJ7ujZ->wem%#kbjUAoZGS~=FYbIn3$tCoJ(PUgisOHZH3dR|VAo_5#HpE7^* zPMK&fKWn0SFZYHE28oMruQQfuY{0j3wY|<;G|@~hOY^Te2N_SjYi9wpm$B|O_uH|2 z6!FU!=ACUnT{G7)4y%q%t0~K$XnLnlH1A`q6ME_nvb2M}46wOpcgwr*1 z#D$tUs^hDT`^($9XEwQKxjGgQWoFz*-Q^YY-Swz`7mq`La~-)^mtc=2>e@%a0R zyPt98m~YwYnjT22Yn(r(wE({Z*8av|E^rAo;!tn=W=J37cAtZLh}`t;L?MJutQA0qpy_%+wv+ z<1zLE?8WyO1Bfl`vDwCs{(V7B6ZSKeu~lU+`^mcNg=LxcjD42<+)^Op21!%(e146m zm;D@#|8KQpqThyXFS>bjs|$LKej`oGw<43e4L`PS{b}$2sk+UVx}k50x=9;;rjV1!_{G{-w#i;`lL7BKD_ZII{bSVEv%qt3vgH6Re2Ry8e`jkK4_^8RvGu}ARbQ#YWqo>K~d!yXJQ@}HtC!Z&e z$BR#EfIY*6e%H;`sD;r-A!nfF5Xr~JN$=SJ5@r1_|4327$rP3qIZ?}tf~NBA4+QpkI$ z+o$}#hv!Du0n!}knMWF_kJPz~-%pWd9N|{#E_Iapf6DKBcy4s{kfx_+IccQs!k6dx zy@fQB2_Ft%$9ONi`jp@I@Z9LyN1A;-!W-d}@bFE33!e%Jn?lMjyc52D%I|x4taI|T zTl(imW(n`6@lALp{1ToDZ$LTh65a}5gtx+1;i>SmFE53U!b9PY@KAUmyc7QP=AZCP z_$53^@JZ^H;Fa)4c+;03!h=GdM4e@fAu`~k?F=65=|QQN)Gxu0gbXEQrj2h7p6%4p zg`K_4+B1E(z>OTwKgnoT$gmyRoty1y_VjZ%=No&QTs*pKZ_i$1Z_hTK0FUrk@?M5N z$yq8~K9qMi@u0{4uTor5(QVP&Y2(-@J&7^MXv3Tt{=?cU!aLSp8Q#A3s_^q`8K-=3 z^Mo7hk4*TnUHry&<2NSy+KJr`#OF_^_Sru@wb$8u`SvV2D)S}>I_ik)XbL(yR;BE4 zprdjg{{rl;=;Jf=T_s;H`39GwDlRrM@RK@1?jxJ6Il!Jep+5kKYwoQYs%*R zD?AgCn=_2B^>Z%Y%6TVp*vR{fnNN#;3eDNPe}!ivGING;;HZ8|UCMYT^4Gxo%S&VW zDfPkw%U9o0|a$vobP z3_r#DOB-VPDSXQ2{VO~Zk-0OBuk};-x14vPpIdle(jL=K;b}JSU*YMipL6*pJQIEi zPZRnnyiMq*@Kty!`q`J4qMyP;(NE!_=%?^b_|uzz!ZYEQ@Fc+}sat|q!XM#HUw&9T zp#F(EC-k#|w)60aeoDQhehGf`)lVIF0`vp3>IXy1V2Kp*`IxW5i z;X;<($a0l|p94>~5$>_O!su(5{K9{uuV?b^DxSnV-I|+sBw2fC4~&_-NcQc^yLD^t zzV{wlOVx-k*X&zS+n`u?PW1(Eno}99MBhqv)|n_2g~1|5~P zRQyAB$U9ljccHUK7)$SA3|-C`%bO>A=)RJ2##-Lh>?iVnw@u$M2fg;LP{De}U*2^3 z?oW$r<}lY8N*^qHgo?XVJgoJ}9L!7Jo(alS(BonKag|a#3}|wuYCEj8=*fI%t*?Uf zke)o~7)ySvlbl0oM2;^ryoc=QF;Lv8IhU zQV*ZtHxSxcqZ!Q_g#!1m_dVxw|BKx7t#J>E#=4*$;LewTtH~BHnvw$UreyAGQTRhA z#ss~?Owx@Zp20e!i}l4pi^yN@H+NANgSv>1o6H|7 z;`av%AC*zm4 z0n(>=Cb0fENIk{^&Ccq{;UxKeKVcHS+IG&gNPKS<`}SkmtH@Jb&pN0x^;bUSzmT<& zBz(P-@%h#{FJQy}U%{Vo{2tGHAHMSPy#nkViBpO1cNMgep< zzH3P{h`jEx(o{5lhEM%C@|_5N+ZSN<3?&@TcLTpWSLl__8v{S>Sr*txTYb!x8AM+F2Uj{HSt674H(+q*sb{_ilV8@)xk%Kltw5pqH~a))s}?-gl7$d(gYB@aa&Vz-8UH)gLCzC&V< z)OQ){sF+O}iEq$Ro5cFM5}RZUwQN$|uEQJW#pgT;yVQ4mGYMN;sFHR#uvKEG_JS{C z*lhlUom%)`v{8f6?+NI0!aikTpECQ{rxd;?>_u<;RMN*j&BQ)k-pf8+*2_Lk|374( zd~y3EvSJiryZhLub=W3Z_cw~BVvnZwh`h=Er`V)P^lOV4vnFhj0~|E5MItX^i#Eq? z(H!oUbcr3}@zD1rY>~*(h4e9n=)pMjAP*gM#`Uh4cT;(nV(I2j8Z*(al+bgXnW2|E zb!4rtY|HOK$Yd6F$w|67oSB(PeuL2I8?gt;Yl}c4LzB}PYG=&er4kg z4}D@6zf~z$%8)do|5BFFAv7)t+|wgAWhrSB_GSTni$*>rXw-lYEx&t(5p)^0)yzP-^8-K|Lya z7RK$&XlN`Tjg&8C3Lcv)o(J?Cw39Z8boS7;&Lr|LwaSXv=a5G^`6r?K0qn|N))2niZWA8%Wq~JdH(W)&MrrfDHbcIb^6hKe z5wja2SHtiZRQNq^6}$26ukFSN_RWsk4ffBJ*o|?qJ(9cLJiPJRe_%I~u^R;{d50%% zH)MR{=w&w^{4db_a&Za-vPXT#=M7^2u!8QW>tI~m`IO)O%3BV#64uklT9`{6i_ z{a9<+kEQ}g(KPJGv>vNZDU8{VWX8GQ)P6V<_M_KW=AUgp2KTZbOVO2Lbb7FiQ_z`X z?MLn3*bj-H(Br>vKWZ)eaYG;bA>*wZNT0ADVoTyL&pxx!v-zJc8Km} zG0x~~Lo{?TGt||&q>l|L4fuQJVn4)gcp0yV9hryD_qHE09_ejA#1{6pA7Y!teh3|6 zKg6DS#Rfpn-`Ee@DG%Gxh7C#Rhx6~)4;k-Zga5{URM3Ao#D0*Mw6)+T>WnwUb_Dq5 zjoS|yi|7GgkLNV873|kyLtb=z-7f`3smEk~vo_u@Jxpj9d&nA3$fx`XTes;le84E@ z!C`9FVCtStyXdrq##vg0olfR_t)26f29169t|Z=JO2+R-ywwA0Y6spPI#OO&9{@!+l<4Gr~{1KeT{N2zzqF>{ru2doe7#x5BhMYGAmi1ONs|q~WK8%y{x77TodmChH&Q=W;I^K>JR9SSLHa$U6JBZ5MR2U= zlO`8l-vIr$QUli;oJXE1GZ0iob)KSLcJg9m~?|9k!y zehncH;kzUBJUsYS&*#t}{46sx{}0F~K))&ctOmbGQ>;X{+;itrr_rlW)$gd2& z6zqTD*BAWW6rWEFhxTdkSNL!_bP5lOn4_GMt%75q96J|^1WH`G7TJ}%-K z#PbmE+|WCn+xa#Tovwg})8V6=-+M?u9vLWvFH%>j;}6k+4bT>VmLH(o!n-#9pT+wy zX&DdoxcDvfOP!|i{&L>!h>sr<^Ao9;%ulG>!F>2-gFiZxOw3VS z%uft-xrsT7FFr>R{pxEA5;mcC7&59F%N((}iAH&vv=e1HDaSz0g^v#C?PQ$tR(zZx zV@+@6v}T!$$aqEUM7vSZD6|^f?Fg=rUB%NHq?Pp&#h#vrwH?n2>;EMlS=YHSw!ha> z^)Fu@J&zFg^L}8=ibcJBy^C1inmXJ#=A7|e|6~jaSD!l~cQ96&&YIit&KZBexaGf# zJuU6<|LgO|@b(|#M-azamoW@$y|Re)`(g*{oveAH`_`HBO$w|CWTE%jtHM5e2h3e9 z->W9}o#mVK?K0Qx?aPMi4gUh*_xv1U+{*uw;u6H-htUvZ{W@&#P}Slb`ju(<4Pah1|J)8*64&tj|>kiklqV z&+O!W=1SJ*?qPjyOt1TyCvZP=b)Wm0rA(P`iT+C2^y3E;SHuMqR)!w$|rV@Akg>?gTd_wL>H-}xuEz1GJL)cl>c-|^pU`xEWY`p18w{nc^)j@iSg zO73+INX5?qCAWOenV{IYM7!l{m^crXIFIPrWtj7HWuAns$w9`peRbr(@&=oA9?^ks zn}>1i?Y=bsm?~SBhch$l_+5aXqJuMtQ#hYE+NO1#%{w^*bP8t<$FP4eW{=i&^5OkE z3ptBec=(H*^QUY(RDi!}flcq4%m3?cYdLfq&-XaP=u}29dGp#s`J72~^M5M;kH$we zpL2;0&M!JRzv$rnqN7aj8f{k(=krt>=lIKvbN!=#a(?rejpsI>&Dq8&%+DutF7a&6 zGEQOMUPRuUEm~j3IYc>IR6x2Wb)MhBS;8>>t`%eTVC89ga2;nhZX1PvQXU~^H+*xo z!v(A%=5zjV3g-_;bN+A&Ylc_67CU?Bu$4sTu=Vpo6|@BYRcc_Kh&6F(Z3hI^)ADAw2VPfk6Y*;Y~?TUq>OU-pD4r1Kh*DU^45K^ zyd~d%5uocENy!o)eyFXF%d zN_cY#XF=I_x{C$*?}`_Ds1BpnNIoberQ zo$>wBt~ld6)H+Lg1bw%B+R?2eN6?WYiZidQ*U{#ZZUlA(zu_f|=(EJfQ*>b^`<@m2 zuO8-X>1>TVMzxl|az9!b@&AHuu5x7feYTm=VmUinb$PT3Khp1U2J~Xie$Ib{Iedfi z*W~M6cVN@5XOHw&?9;j;z01S7(yD%{&d%9VU#hBe-@LiiDEd~^{rw?zMeGfgve)LG zU)Jizwz}bUv78@GH_Sch;Pa>2Yu28A-6`AB>@`jOen0Z|{x6O!KTQQiU#}gjf)VQJ zU8?!N;{WMnA6e@DP0o@YsnWW>!ft&s)6Thd z8+WeStTUuvl=eT?Ku1 z_7;8kcsMFc-k^GZWa7fA?Lu@``$I1xXU=JO`LpetO^mw%~>Dz&UY>4jMDjp zcM#`p&i)d|K^$3Ydus+VGnni6t!u&EqqLwiUbfT6I8|l% zL-$I5GPI@b4$c{k)Pir-Dswuv!qHY;(xKbBcDD~{4OI?lb;BdhRdu~F_snL=LwM^9 zu@~*L`P=jn(cP=hYTmv2?B?B-BcdJp$ms5`CO7Y@%xT@-p3^G4lQgoo?KEuuKj|k$ z+bU0r?sk8xb(j9F*0(CZ72VxFs#WZ|6JE6GqoS`@j%w}Dv!m^mJbG?)w>~7gtui<2 zfVS>DU#-)%p+tDywji(7%kSL_oUIY3ul9`v&S=Ept9_HOEycG}57{^yXr~^7T6eD= z2aV&Kck6@5e^6^%`svM=k>4z(CN8K_8_JM77jhTIH(W;^@!4;ggZzmc`jEkEhN~qa zhqhH!7rwyS+%@>%I#_p*_jeK+tK1pt=G;Ms$fc$xiv0_;wCoJE+;PYemtk#H<%JHV zA-|f)@r5C!&Tt^}5zYeykW~kM=O61TTVy(Xfv;BDTx5D!j&En%0!OQdce@EA(|xs4 z|0|I7*QL(WVsULDyZ?{!d#c5gXrwqE7R5t%JaqYL&qg0Qh%5Q*HGH*Ro;MbZZWa9y zeoDJVrub@$k@-InFOT+#obRjcIoDUaP0BdW;&-c;P~umkXR_w9Z9zd)+I#OgzS_0q z6{^f)?Vc#{@>)v?cN2D>?yLQiyr1B!jg0rzcJO~GAu`b#85fHq`XjOt z`L3_F`&3_Ti2uW<#c3n7c>5j6#~JN8CB|cs%RMLiYWI%u)hcwa5WSOkA@UD@JD!$M z(uT*1>^Y(y;%|o!1=L^aa=O?Q`CjO&l{!niy3xUQ;&vDKYCSx!NF7GU@^PS>Z<2o` zKSpCHFRjb_3bOx0WWTNYYuV?wCHp_{)mn1!ufAHV{byV6qmh4!hu@EfSH(gb_eF%S zgilw*@wyUPb-7IV0*I=SaUU#*56koMc_kviwMmh!F*o)}_>iEGK-HSl{zj1I349p-!Y)xO$2 z-?Q?IhT1c_+K`8n;7Md5b%@)8cG}v@Z;K}j;yk%F&Xf7p`)FidJe(U3%j4mkcvvQM zkq@Ed(_Kovl8|j9$&bB>M!fMhsqEinQ2s1KO`Kh+HYoJgKtVI;>v39Ni-&)V zhp)!NSNiDpPV|lEYyHlb^8pX<=}PE#zNO!LUiQ@{Svs5_-Sh7fA3Y=#J>2_}ueJ&u zm$p8tt1pT?6ZeI9TtZ7{clc_nk^KU6Ty$ld#Q8%!?(gGq39Y!#_tNj@e6_ZOes7m} z=r^GyL!EK`-sY7l={GXlhJHUQa>f6lSR4UXSP={^X*-x58-M#uF# zasd7QljP@&hV)Tg?c_IFcygFJ^zQHZZSmyGI8Xi>=gD7UX(MJljK;$+;^F7<@Uysn z6G}eapZ3x3PvZLBp4)W+{6;}H{k7oq+Z`t-`Q#1<$4>5{ z3|W|8HgL@H1Ks6b6)E?qaCx31T+SMPIcxd+FLwp(<#)K;$6WwQ-8{+*uD}BIAFQzs?<|_v$J%vB+&*;wBo;T{C-#9p@NS7mcvn2UGalB& z!#fi8AurZf-;RCY>1`jRkJ@vauhwq$|M^xwz2{b6Z9&35tdscI2SQ7a*P`>-2eB(+ zA1s}(j_Z6?JT9RXw=!lQreYsN*Q~e|@wmQtTtX}E8ei>5`hOXJi;RU=C&mEC?ky4* zyGdxt?5dc|Mph#GD`Gn8CA4hBa*2cPC2Yja*ob9u8*x)SA3`giAIEIO-lZ`!MeZUGK-)dBy1Oj%=W1b%xA&VD&`K@BJO~7GtYG~&o!FA!vBZ)a35@~|02ecU?{Eb zgR#V%Z#lS2o=Py5z*+JzU-YaaWd68}b=L+kme9%d2AE6R+{}%y1aAqfB`52h2KY+t z;3b7hY(ZIX6`Z9I_)FV<4L;H%nrW|%;VrpY?`&%T3+4$PaF_aGE=m4Q)FNU==9DezjXW8OdOWp;BS;?7LdmL-&Iq;QA`QIT}OL-aoQXq`3h;~mKf&vHzHRL0w3vC@Rpui&6+KHt9itA-g$YhcQ)q$?w+2z zo!?EVOGag-&$DovW{}=ZdSsP)3szm}C^z@1y-=x{Tfk5nXLseEk?I|FW51%@d0;Y) zCC~I*(sOQO-dDFu%Sq8vGX$rpnRN=mOZq-%elv$o&8<(qBKKYJmr}r8+5kq=o_^DF z=dmULHdD<${PzWyY2T;QYFY-Vpx`aNg|Get1K9foZ|Q#4DV*7t<(3!E%I#PX!(D1G z1$Sp1xIrUbxn7=XHI*&5sTST+J$Orv;4KBfTRQabF}x)^c1rM;+TwUiQ{k~-EeXz& z;4O84z0?lg(v~>hQsZgJ8fzGWx72p!*LX{UwZt01`f6W_-+PH+cFu@lEeXa_`_pNU)ZkgVqGr(j4d$tfdaH zmfFEr61*kBTG|5UQfDu$rEPg%V=dWJe1C(rGzWUxCm^S%eT}yy^jEPT*c)qUJ8S#L z!&>S*6FQ&yn$85)(l4M@u$I~DXEGc6O8S%usru$Rh^6~WL+;4PIx zvtTX>-ckZG^%ioF;t5r^-9QFt-cMU@Ucl zwX_+`CBaw{d?mqK+TOyt)~}WM_pp}Qp8|jDHL!5r0Sl)aY#?Ociw{=k6YMPse;+|U z8l*wY2S-81|0f?)1i6$`M-QcuV_)R%~)-yUpJS?vmgu z3EomirOm&+5?a?m>qz~$cuSpkWHl%7mIP->Fqg#cmggCq_d)-b!pl3LbtHH&XHuWZ zy18uyd;@>UqH`$Uz`W{U&F?5KlsnGjLCQS%5_Gb@D_BeRLhOE}?(Zzs{erQy1-zwp zx9;zlOB)U~Ou=3{9@bIE zTaxw{yrp`^Vt)^BY1_0IFMH!HZGyJ{2yaPnmg?UDX9>(D!CPvK<1IC`yUhT2OP%oO zWPB>B@vSK1xfUPOYW&m%Z)v(p-Emi6yd~Z4*XXyOuhpBMqa9giSg)(G?0tZ32`y){ zuD%I975|J*_~k=aHTn(hfUBmEvta3&$rj#{ZA7wl2X24P`_Bazr=7h8xwG^d(z5VA zOKAzbrIe$17P9Bw`%(DV{zv#r#y`Nv$)leW-v=XX^eFrozQ$ilIf}o;onYWEC0Y1O z73@m{kk|hV{?dWbO7NG~!zcDZ&-d%Y~gv2|>*xp_jd*>YvE`4Htjcy+NU zXNno$V>W; z@@_E4xMy%3ciKgeA$(J6_JS2rNjL|(p84#nzl%5Z-pT5piZ}J>#2DVxHh9|`Z|c^G zE^{4tQ)|Bg-c*mZ2Mo>>d-<|QyO;fc!Jpb6$D8`?rT;y=sTbMH>-ZnUo4Odhsr$h( zi=bBtyr~+_DfGsh`rpQva&gv7d_IoduLGx;{kp_noymFbzu@yBdv;&qn{}iLd!`mBmdsE zNB&<-+8^C#n2WwL%eaR@v>! ze1f`3Uq2!hY-{3OwQ6WxZa-yi(!touRA!Q)WY5*C1m082={5{p{15YuGp6iVxTr$}iw~R#!`2L>~6pQpP?&8#mJ4 z@7aco&6Rlcbs^q$@J?w%a`X(fL_2A?h0D{3KJ{(?A6@M-7heKK5B;XhxfWgNGOxqG z!VNyp(lcG=_0wEt)@obbL%$hV*Iy0V;o*+SKToySz3`jNx{uQO*Hm2lomLk(M@z_O zDfwJS`X7;gQ9SKsq`mX$th$BR*zdR{-JrS$(=uxAxc1wv1)QVeKD+VuI95~-#^^}3cc?uMN|*243V^G(~S zmtZn!$Ve0aBTGvn_;{n2|8V``e;OlZ5$6%UF-DB1zcog=6nT0ve(ve-VZ;djL^AUB zk1%2cf8u`;WI- z0QexM_reDm4?f6#&e*GQV22qo{N6FW@IeaW_#hL&@+bhyV>Eaq`4M-I0Y1oB@Ieyg z^~DG21|KBS3m+s5KFA){boPS};wFC=`5NR|M4sGVbqqepbY+~thdF@{a{?dc1U}Hg zZ-Nhmf85{vC47YruS{x|v;DpOgkopy+A zx%iJ1g83n5ujaI;`{&|cqT?eM&f%^)3GtV?N_<7|mFZcXROfk04|>|cH^5IKe3dfi zRi^uYj$ceY=eRxHoa5y@cG*(Rbl}V1eU)LZoQr=7zVmag*UWj#G_w@H75t4#N*mHA z{ddoL>74a)_G=$G3tH~OPp6dob*8_*~&Hwal%|d*Rtid{mcR!dvtG zvo9LH*&cm3_$-5>3V)!R@zotpxx#nhxo3eMG-$sy*Xu!#_yv)t_y&2p?Oox2CC{<^ zUuo;|;7_y$f1#Djpye9g=jmM@e2T(l{EttP2R|YQeD~y~P4X1-jOEGWJ-$T>*-+rJ zct*zmSN;8-QStu`{?DTf&I5@5k*6We|Jx4E2#xmD-YjQ#@_n@{2^HrYB6+^ro8+C- zSGx?%f@NS0?4rzNygO6MuFQ!>9Ml`E0*^kFXBhR))m4;+)_ck z?!<4VY+pri;cEJJ{Cnqfw#B>5Fc-X25iFgIA0B?5*UklxskavkR`MwW6{L^*P~FEhDr^eWrnF^h{c?2V~)9?q_K zsLTFU_QB!nPMWzrRj)}oJCJlTXPOoK8q-frY$&d`?@3jccjGg-hCDOy^J-&mz2;>6 z+myYg2A@7fnskFZ(R?baXi^|4BgEMlrDZw!Kh4mxluyf=!~aux3VD=ju$S?O|5PSv z9pOuR9Q;lrkMWX*eDc}js^XpG;Rw5W0`i@FN6UBe&JVkLI(S!LeJ|=!x}?{#to$j@ z&AIA)@Xzyk@8tio;p%ds`3`)#66Hx8c`s#EkeAeNGvPKKDbq^M%tPMhBZFL25!{F0at}7T2^-xrMFq=|$-UF@-<@KZW!x=12f5u-q|B?8Z3mp_ zDnl;!o+CESwnKcC_ktxe2N~a+Pl$ZKcaCB1UzJw(9%t*CB;}EU9dE_|}?EN#9eaG3{qY{|{mJe6;?c4Rhb7Y0W*<{e#o-QHB5S^Z%k}rZ!jNryVIW%q3?U=2F@qA02DsY}lCLDRrgP zXDUxU{@jH;&-45xHKXPO?j=am(rd=@3|Y9M^|=KrS`+fpH!Q=?x*Fd?H{s9eW10xh zv1Qaa39swOZ9T`-%_$;F z$WIo2woBexnBV%Rg?Z$YT_fM#T3EnuXX|qd3tOk#hSu!28^Pxmp4|G!g{QP$VH;la zIR3zY!KVFjA^wf{B75PHll&}RZZzcoCBpA|{2RUS$@(U3Qy2dxZSo1<;Fa|a8H{X- ze?#t^2anA9v0f6DvB$E?tB_Mq6nY=t!&t*^`5z7eKW%8s3-gX_1bb*_nf`;Qw{muL zZsnEO`5#2f^(&%t^sA!FUdwDQ<6MT=T`%WS1Z&EZOy5OVexKevhjSM?_TB9n@6T!H zY)W^M-&<<;r~QlCAmbW|FKOk>fJf(SfSl3b-f>Akkod|TC<%f0!1`z%$;UGfBEuNv$=cV}HXgj>|NLBW6{Xh?|oC@Yr z>>TP58~98zHk+w4hSR`i(p$d3FZc=igvaO~h9R%Jb+vGT+$E-K3m4HpJwG5cQoX5i ze1ciCDm5pKc1olFL3b9`5YM4v?=WQ9_%LTB;%uRR`Zx4j{JuGul2L#>*Q3h~=&`+i z)5rk&)`Fe5mA(dS%na$rwxaX5E}ovzj2(CgTk&gjY%uq!X6yEh2eB*LR}HL_en|A{ zUHT&T16o}=GRWQB7iRKK8?My_8&A7!6Rzu{I{{VF*NDt$=1%F58StP1|`=hm_^D`R~}IlrrT z)?;6%^GLdvvEk$RU(#D?$>TX}?{mD9{^@1D zl#|bIDGQtKe~x}d%Gl2TZu%jiSNbO@&&hjdt;#cjLZ__f#Z#ZKk?o^$QUEPnZl{2`z$@>qC(Zk$Ne@dDV!F?r4)&%U->eoG!NlE(++FJ)%5eY?g(83uXn=Uz}Lhdd4nzI0J)j2AEV;l;)L zo(nHR+~?|1>hW##aWP&fix=Bej2HNs`{i4a-7t-Q^r7?@w=$O4%L5*5%^GN#XYu0x zg6G*g8I9ljw9&$gfc-g-I_~{hl1BLRo=qFu96F`O3GHnL<0a^pZ^EDEkkfh}iNCLg zKdEv4B**#VrkvyPNAeK<>?ePr+X$g3LuNIBHY;*T|##SR``X=5&{gHxxq zd5)^wnOBUhqD(oQz+-7;hYIk*_Mn=QG-8N#BWDGPQzAb z*CDr$JLyl7?St#YMy}B{>#kgl--Ym1Y$W{4zni~A zTRkRc%w$|GWq&&hK8=-go-sV_Df89AK%QZy9;E%X)EfHrF77a^S;+k(?{k0qzt&&c zWYoLBQcm?>sHOX-vj%b*_{rC?MtH53>@TTzgQ+~VXhL)EH9+4)>S7O1?@8y3?9Hr;o=W|F(9uM`jnJJ! zc{5ovbt^DxHQj$1ac(DcvUV$cUBI~Pm9`NYw?Nx^ z@)cTzwtB<6R%rVTGzl#Vo=aU5b$bdPPNQ56I40in-Y)KPx5hh7_>w>Gdc=k| zKYMs%Ag)7;&SegxvaRt%t{S}XqjQ+g_Iq`t!UiLrH>=%kib^8n@FPq}i=a*NP~e%jHk&7@ht*`Z_VcbZ{d#QX1J*SAjK zjAfx=evH1n)OJnlR&8L-R>EgFTNCCS%YiJ_^%HoOsjHgs64f=3y1XPf4JxB1#Qo|o zk;fq3Emr+6e2IR;uMNEL8u~03cS?U~>pwPkxH@>qHgGI`;H+cYziXt#{ZPBp ziu;g++MtDA(rhSMuwpOB~(mJB6ON%QgS3WOey7D{g81e*XOiZB zWW~}}49w*>l;}BM-F#l_(&gv1UN<2r=LP=%<#5$?-SS&nH>J^sAE!>EsM9-}GyLyR zryHo#>O0P_3H>kE>78pe|4ge+t6O)bY5vEk&ra%7a!IT{H&UOA;`OQJ{^9GEFKyk_ z|JeF`)w_*4GW<`+>vPK;=lx9^UEQmV&X2dzGyh>5jXI`{B+Y-+Mz1W={BJ}5qbqJ` zeW$i70ddd?>|PiVby`GnSoPM7wX&{~VmS@p?cj^t3Y4##EgL+VqC%vtTT zC)Pe5+DF}XKK)lr=AMqr+(q&FM3A{tp=}6q^iaG$j=0Q)HJ>FfcFfx}; zT&pgmlei*t-_j+HzR*h_Ec8g8p(UFC#VpN#C*$|P3Qz0S6^mL2pqF9l@WOaKXAyPs z{WvKn#P2_n=bzELyU@EoYpN!I-hBj~i|F0JUV3*x-l20p(fVJQi_U4t=Qzp|ofBEt zsecyoIbQGQpD@F7Hj5;gsce zW%>BlJ6+P2<6GBTy0+NTwFu|$CI6WH=v9}ze*W{0*5$mTb$KXWmy%v}5nCX2vFrzR zc_?0&J8Ac4kJ^n`T`apHapHBk2-_k&k-7*SUFcW|GWaz0=t9SSL--6by7NLk=kU$r zT9+&z7uT_It#_hhi#Z3II{=xa9^>QnI1q1>L9|JUyPyAu)MF`aQi6^d@izHQydIbJ zs)z7W>hZA1BsBgeUXSrsn`ByTaxmT|64#0ougB$@|7bmgj-BY%D61YzTVF=E9$B%t z^y}Fy<9%Smp zGxVGfk*NT(6(W>5jWzZqU+wuLv#dE3`vZqp7J+FUn?LgrnjKi`?jgM>!{ z2$Co>lLrB;77+2#R=zWn0D{UxYVAuV2?Ge#8nqTJ%H##s(Uwsw3av~a0|u|HTD{G* z{nZH&^h&h^t+lnc%q00HC?W(%Z<=zu&BN);V*&=dt%b=j^l3 zKKq=*oN4~j_y1>?tfl+<_nB`QSC8NG>uaVXAM=*`=F{&Oe}Ie}S@G2tx&L3@F+RbZ zUynTNXK!ceFAEa2W6{-Ra+i?eP6gHw{(|IvG!A6keyf_OaRzz}dofPtapw2nF4ikM zSZ8cPhH4;o5ZdqikaeSZ7KFMY5k+^uHSchLscgVd#jT`K| zo1sGW8=SmF?Btzcg@3Brxu=aZS^PJ6b6Ed?^rUl=ZeaRG^f;%g%k~tLE>1ehD{mFo zqWd{jUA#x)YI7v)*u$H~9e(ih=jaJJ173>^@{#rIi2~{JPB{w|J&le z^WYy3Ushng|JQ}y2ZBFk@rw>f+y0aPb8`K8^bcM3Qg|0vPrbix1-Ei#mAanQpsfX% zyD7&%962Z2&)V7gsdbi$9WtEAhRAq*D)uh&;9*=0na~y#{jfWA|AyorC>N!}QYP{W zvR~YAI+E{)G@JI(-KC$@sdpKpHT7KVO|@5JJZlcmNyk&Jla6ffSpT&JbQ#`bw&*7% zd_wY)&XSkBf4w>rxMPEZ6Tw&F&mmsQs0O#u#5<#MCU`XW1)Q_JmNX9TQKtRZ$$v?s zDS7vK^!7XXrst@sVeVw~Lw6_i*P`5?$lgkVv*Yhu$4q>AmRczHhe^Bmul?4^_lft9 z)e~zryIbxZ%Dn^7;5_t^=uP&pR@$>#?i`@4O3346zHy$Ny;1h&mLmU@r_OY1%PLP4 zMZII^IlNGd+hfo*I!C|*QID& z3w;|ObGOvf&a2$*KS}xL0n?I|D_YSB>R3 z{H!lTpQ(}G$=(g`2Om^>AKhSwhn@K*aB-dz{xUJj8p{IhZ4UneHLKa&_e#TG&YqRq zrsp^8CtUmdy)m%7L1Vr)CE9C?kEyqe@AU3~PGQZ=i|=HKB6sB*ngv)yBJIPPIN zwd67CAL%;ff!90&4|!^V>zFGbds7Z{4izJkaCj+8+EMAx+q$imi2}ot7fS*Sx|%O_ z?_j+rbyv#1lU19evoM0uJR2V!F0D=FbG#^Zvo;-2w~WUztIjTbct$}&c%|d_^f$(x zf5x{G_SWLQ&-AsMN1ODlfSwb9TWBXdGD*MFXOV62%3^dS{sFwQ;S65+U-3sh#UJbb z34ava^#S~Gi^(6m2JpvjJ>+Zb~PRKdpfn%6;uB}4+c6*=dcztY{D3>HCJUdr2fn)FbNFf+|Id^=*c!+lWDU6Ctr^@M zldk_scxxCQ!M!c{!c(1zQ{35m*2EUtQSR&iJ$pEtKAsj~-aayod-iKToEACTF*MkQ zO!f1+!o(Q-N7fXY?@w&Hw=jX-!M;sDDNKBYyJd^{w&{VwgxbGmAF|4kZrrAa3lm{| zXt2RQG}yR-Z)#*<)3p~zHr<4~{NhOMFDdJ{g^7nRyEyXb=E6k7R>BJ|j_{tx5qQdx z_UO=Hks8JuDe6e$GkjZqais1Kg^414Sn%OG%2;!8WW(;l#HPmx|NF&}ICHby(N_Bs zX*W>jKFWWc@H3?Q2kBlRT~9JyCuPdL+vWaY!A|nkb`~aF(VXDJFOlzUV0o8(o#cDJ zFj4y<;Sb6CF>cf)5y>lcxue6-h2{q9E$1ZaGS5kD9DYe;!_adQwZqRzZ28^E^>XK} zq*X7h*;l(@8h0h<1vgzgE#ii5R%r3_3!uqMYxX@d1=yw~=~Fv{@MXBmac^^Y9^H!Ez2>EYL@D1gu?Z4etaA9oH?vjb z1!UG4gH=L3v1VW6D+P%i$7cpM?kGt3qQJJhAaNPvT-r$ea?L(Be68W%lekw|RAR$& z=OvA-73%jDBszY}J(L31xQilc3+?4ZvE4Z)JR_rZxN4ZY|&* zFm=R&EWgx(+_AYJ(XNIE1^$g23KFxhRZ`7s_HBBMaR01;(7SHDO03PpIke!}C*2Qj ze9h8Qe~wE0%t72w3X<@wDM+l@UXXYactp0W1=q8`#2u&$Gh4JvRN}0!a(C%H?v^ap zD;{J%%T)IK*|$Gyl5XBzTEN~!?bQVdoo{EWv-Zdv;M3I@Q~qB&?NhSCQx@cMQ~sx} z6#(eJ`di2gZJW4%?dIVQW(?oYBN+=fASx2~7Kjeqr z4QGW8huy3rJhF}m#lv}gFOS8Iidd(ig*wBQP#0&)yNm^~ZbL&yZVMSouzV%uQ-=a9->kM1{dY_I5f1?%C{PN}cAr-44|ub#GGG!KLa= z*H=c}F6xl_W>Vjodze<>w*Ygs-`opB#yT8U?=q^9r5l+8x0>^NPjY_OjW8;41Q{4?z<=l3iF-gmcxvj)D>z7Fo5EaH9lVq_kt zxo>es`$9{H?lId}_jrtI_?NUVnK=s{Hf0>8&j{tV=t&bFho| zz}}1`*QGMIr{mJ=(%1MF9i^uB(B8sZWANJIQSd8xtjy!uBWuh%wl}>#HR9hlHKHC} zv#ES)&QRRqNO6TXSbYA`IWHznl5umV(4q^cOSP+u3xxr1vjq(1!VT8iD&ljLbHD_qTJi1f4jf9e`g@WmchHCyak%( zU1tAAchUyWGI>{?H7Nc2H1E0!-gWf=-ZdBA<$`zV@GdvJ>;Jv}Z9SuZs{#GHIMu(! z9&up*u7!WukZnZ|RYe~`_NNU$t2+?>uFSDw+70$a_2d}vF$P{R$H2DITFMB~2V`F_ zs#h4&Uq-d6$Q0Vwfv%K3QFDkjuZ!_vVXf_Cek(yY;-Fq-)?4tY{ltNDi-fJwMXjq@ zn^z*+Tm6e#t>`bT*hGC2$9F4wGxjxu3jQm$Cq8&I{c>^%IJ$DRe_DPKWi3jTUqo3& zQkKBQI=&P<|Eu>JJ(qk->_UXj7~BOT1+Pm^Yud3Wv1N-I)k8m z+r*fW`8#>XuKPjlxGPYC%u~zUja|&1X71JXqg(DqR|+lr0^n4Et;tfpi|(zLu@J`2 z(`95?x^aLk!-*%JIRvf}ss-E{syz5eSVDKUGoBOuV#Iys0*6h_<&3)Ty zGn`B_!@*pJjgDfySB`CszVKToE6&jqSD+i-jjjmI#Kz6gXeMjjqCqOKh`zC({`NBc z?IqKun7fEsL$3HI_bbK+=#OMwn8DidygPiR4(Yr*N?R+i--s{seWGKMG!`>WRVqzU zD=-9Rvu>34-z!)*%33>3!!ygzG4n1@<(-KBNDHt=H1$W&A;=re0ccQD%lc4s>z=9K zN>p6=txvtXE;2;3^s$GM_Bi9t=wsss^fCEHdwiykIq731^q~xBS9``=+hT(~lXiWP z?{;1F@y>QIhqtzSu@5=V;9i1)JJH9C>Cjv-@Bi67=1Tg>Q1KBQxYOX6|PvvnFh$cIOf4=2UDc<;K~NS>cF zkWacfKW7+4@gAcK`S1wx;f3*Dbk`bo4TFP|k%< z|4*Htgr+gwm1_T_o=oJ&)9oKFb&*EqPA@hv=6L@S?LY6+bIOhAz+_ITXHKbB>bd%d zw2j&3oMJU?#OeoY8@I6M!#p@r<`wy#9P^KqW}vH;y|E^AwT+DV#v>Jh$I%h4$;;l; zYt5ecB05{)r=qhptX5NJo912Om;6U*AdLPN-8Q=8)B4+PYu23VJXR&7lc*{@gZ%exGe6?Yo3R=-2d(g?dfL|}+?2z!b@=xPAggu1+Kj+R}XUv^X{5R)L z!T*1I{`8Ee{q;|e|ND`t2af;JGx&Y!0Ddpu(rsV+IeKB{hCPlU>RIFg?&{A-$`tVX zE6`1BOO5{n$kifO-~!mjnP+g`;$Hu^ty$ZhO;?2{!vo6T`C>Qcz`m>u8G8z2d>lOB z!ZUb49_bCnw~O&VpYd-aua!J<=6C^iYZ`eiAJ={ceVzEI1$OXSX7>>Ui0JNF>dRKTm2f{*MWq~*>KG-wd`P5JU_WXriYlpZPh zG6PyHCa>57OTIMTXz^&7TDvUVVZ_=!%K5?ePD@9$&O(`^ zDRXpxTh1lGc@}V zDaRsf0LB1gd5>CIdE#v1t-l9W>U$E}l~RX|x-#)K>XtgUkq^7`J!R|%pGuV`;{5Z?iFLP9yRt7fSJ-lJi3(ag%);Pc@blL=+qR^>4 zMW>7uof^(eo{)T~K{~N7^pvxo=<2d-rPlZ>qo6va(YJ z2igTiIpgJJ?4Cv0qT33g)ABMtHCgkb%NM&HN65b+ZEKUZtx@!4RU&pHYHtyHB$j$> zR`wQ+(+zrytu$l7hy_Sgjp_VB2`WI|~?-c$> zOJqFA*@o4eL+Ah0@A(&G)$_j$II!>4Hd0SLZY?fAeLvL_ql>K(+j=eWcWf!74(nH} z5vPAd&_3N7v46uF(SEHZ3bs)0Hqu^Wjb#3cyx+G*DxurR71l_>@3h1@Wh#>OJg^t@ z*88(3*N?f?67c}L%L*{pNX4;n~S>!_Zv&Z{wIs z(Idi_sc6G%lrr~G)RwHE{mZ~& z1*R-qE^ZiZgqFxW&l1Tf)Dl^C;Fvk+Qj5nDv2L^7(Z1n|7W+){e8Upi;YP3F8FVRQ zC&>BEJX0rRE683Q)^QcduF$_b2PsL}^%+6?HZ5X*UM1|S&u+1=9@C<2(IOce3tDVtS(jRWr$w^X zTkmMgnbBf@o^*fGB0I+cTXEKp|RHEyA4hlu~B})vp)>#kQdR)bJMjsSz!spHPV{lp$?l@~a$G z6B-Ne;qB?RtFg0#K5;8={Q$%0m6fg0-(uecPxp?+HVWQx=yJ7iDtJao%a}~mp>LKv zAL3VIv(Yw1Py8J`WSpLrtKhxXJ%Z0SDRcD7s@53klq%TcWnMkR-0(bhZ7F+=bsBW* zLPu`VlW$M`_17oYUjR?x)oXK4OTGg`p9PwTotvJraTB`@54=5!jAB9V=tjO!R^|xw zP)eP)Z4f@D(0|F=9UbTA+PCQ`{g;LO1NmM$oYsGRp8durb)p;FF^WAsbfGWcq#duY zTK0(DqJ$5juhCL=dZOPG-OEI9;B3gAIBW57oYOHl)4HFu-PS?d4C*bV6>s66M&r?|eD>Cgt<`6yf(`GmK(do#!mB^&!q1xsdp}OWubTRWn_04kb zq#7NEk3GDl=wxcn*uNW1-f8GFzD_w)(Zy7TLPm9HvvCdaQ_#iel;=br;|nz#OG8@? zH)R*2iz%n<(vT6Z2|Z=p9{P=;Q_qZ0L$i~8r84v-^FocylhKukYs|!2%NWuo-qy%(64!by9!(z zbn@X`r1OIB3eLKqTMJ^})mIhTVt7MMhS*=UamJ-Q-CuyC*3;M=)4RiA2lFbXiHVat!Ca@yA z2i&B2g>Rb)S5uZ1*abc*rzaFP+JNOqXq$00{{x(F^sd>2|uI;mgkeuntTq>*x^%sKQs z!Cy4SJ{jJpxk;J{VbA;+=~l}dg^e(B$B zz~C0XK^ac+y2va1L%zA-9}X+LpbYso3qHcw75?!R=2YPy(@$wF(@$AirrY`NVUKF2 zc4;l+eEQ5J|8QOYGuu}Fr}@hl?r)J#(m2xkdDd8~)#?4d8~;ao zmoMJ$D>*}FnM>cS_$M^^-^O3D_Ep?{C2M0@*Y%=9_1F~@F8c>j#| zW&~bf4(y?hQ^32(@4%p=XsT$R{g1eQL zBMZEsE$>t*s@0hjnP+eg3Z?TxJ;> zcn5fXKv`1ny_9ns;jQdf$^WO=vkI|iRYhD=JdWOTP+&G`ZsmVp3a^9YpR(hP_8{rM z$G6FZx5PV*$M_#+f3BJRxu?;cw(WeQeH(jovx&ctbTcU9W6F>^1@FClzngDTUX<{^ zvxg`DpJV@SYG=%Nfw+r1FrJ{NX&8bXsPo!F3}8=KtO zZJck(4jy)?4r#09ymKcs5O{<($H^n~`J*;A5Tp#Dfut20NPcN|p~W%M3EhMqw@|0R zEA`GNd@uP0_cY$u5;qZ=b&_WrG!Xp1PTa4-?HTYogdE%#iy6mbapV11r}18_3te%y zk$c8ow6weQDGzzyrmkMUe)JU-fMPug&1mlxoK(k^N==xpzoX z-{Te$wajKX;T`IFGTL0WR`?|IOG;$Qyq`12rtr8*Oi2&R(|kkD2(DZSASCYh~=V ze=>HLtDL}M{vRd%9MVZ&T8gg|Cwbpi)<6~Ezu)x-rzCv~te2+X99q}$^2 z{C@IebsjSA6L>7vzCBF~W+ma|{11jGauz%`nEzf*tMc)=tAXN*RKqi~j=8L14Ir z|Le$iCI4pwUjyOMojr#9AJy4wyvMkyC$66{Beb}Z^f7Q+%J&t>LCcYcI{7bjxFtoS z3GwhIZ?$3u!MIzXG$+Txjzi`DOfmPYpL|A~cY+LIcS!Z7;Mq zZq{oJ2t5Sv!@w^vT|@X@@(b>1yuU%5j0@=xS;Fb?wM;O1y7{Bi^em`LR zzR&pWjeU0fO21l8zv`l#nS^J9zlm=u98bm1P0?jCjRB$c2E(bcGHLRt7 z=25|E+>zG6ePS1T^u*6rl=UA+-e_1cuD^D?f1lUFc}isFLe|RJU)rj72O_6_J{fg55 z>B@Sr_CjoA`G#yVvEe+*9HAoqU)zFpQZMBU|JBL$i?HXd_vrnVQ?P$y|4H7|9S59M zLsg`#SOw$A@N!pJC-$J-=($A46N6WJEqda5c;(MLLr_=&=Y`gwlv6jt8mx6t*EQDQ zL!P1ijXQ_-Z}bf7Z`e7kzkcVC{!Kdv_iyqH?ym#CQPj_Q(UCudULQe^Y0yh>zX)1& zPf;C$pWxc<9%SP9!H(?yki2?oDfqesZ}6=YypLJX7bN%6 z;=GYA`n_)OuCuC#K5$$6OMtQK85NZL@dtSGc^~rI4om+jx269hx2?Z>hpoSJhqeE> zJEOmAM@E0#o!S2;b^cd&c~2ybJ7x9qWS*j_nUvxe5CoO&1s%7(2q6yn}6K?R{Mtb1MTbE-)?`X z{X~1PJ<-0V{r&d(_9N~7_E`J!=C{Jjn%@rJ(R?s`d-FTtTbmDsZ*G1!>}x(8u4;~j zkD#+V*<9Ovs=1E3>zl97c*|Fq@uBZPb3^kbSs(Zk&5g}}&OGjWzj;mbEt!43tjr$Y zk><6{HSo}8TbIvei}}=6fAcTePXfm&;5Y#s2R;MG>gITORdXkBbOA>gTkD%Y&N}JanDwFWoUKVX#%xW(F>32+IP$ixZO%p)SPYL( z!@}G#U+6qh-pqzR>!F40-J_SB{}42}8G2-En#?OTLc1luz_JQBmIA{MsQ-5AyE9e4)Vsd@ z18933+V-_?g4P1x1MNrKH@1J&{#g6R?Rm7<)~w^c#;iVHm+h2qb0)`bGLQPovpxc@ zkA02YspwR@d`j)`RjGEL)v}v#o3E1plT_5V^BnFMWlfqz-_E3O_ac7*cZc-l-Sp*w zeNVzd-(ElKG}d{w&?gF=cB7Zgv&DU-=vceZo5-B?F88~|vfeEvU57)jZ?0{NwJRMv zKtvR0xVRNXW3@5N8!_Eu`VQ;Pd#BA;@kaKpGao)CO-Z)U^f*0r~ zKj!XY*^iX@OWv*j;=8E9qi|NsFWK+jgS!Fzgn#U3eQ+cC(bf3EJ2b}rlBP`?UPLy1 z@%XGj&PmUM+3=ISgLC#=W!(9y$kLLQbBGIHLQguE`$>A3cTW))K=(XYvj*=&XD0Ni zH4YiOX=c0Xk!0APJoE?5RgnNqwR#_k4$Jxup;PricIj30DpF7Qh=)p=XLjqGQT5vrw;9_{D z)Uk%PEm^s>b?nL|Cw@Vi8%0(>OFjFS;_(@_9HG&<+czQ0^;+|{=W>7KAGmAc8q46o z>(*g`P1mWuT%oz;ppbh@czwR;a4|zhdVYK;TJadgxfdwhF`bj1i!VVEBx&(-Qn+`7X9v) zp71xf^oCn0XNmg2SB?K` z&d-q<-vs|k@EA$DDE=>yA@3$`KX~1VyM=TS()}GA--Je!_jWmCThK+pxEA*)%{+76;ahe`N3!#JHE;tMRg0tW#I0+5{b0DSfJ(K>@ z7pic*$`X`2CWY>mxYud72HE?O@^Mv^Q%O0u67NG_`Su3B^2s<7 zd#rzCVe3Uc$s_vRX70I#M?Kp>`Y8Q1&U{n{FO#_~-V-z6TltrwS8Y0wJmZVKWKCNS ze5hXiOLwcvoq}r^mtqehcMFOf^E`BFW-ToKA$Un+YAxJ&ydu!Tm@I`q-NT;tkKr*k z_|HUmNCP>+tPItwXoJ7XE4TzHn{xe}?_de+kz& z-%Z=!#d!M%E%ypM_!{JeZz4M^AZ{;dF4=lGd^>I->B?x|CAgBU@$mSqoyZ?u;mKRO z!;=|{KH`2rTs3j4iPLr;Z(q3er_E~j$@cFe=bW?qX!`=>l)~K~w_lH}Qn34j_HQ7s zjM<%NAF=ybd*1FN?b_P+eX)if-yrgiqt0#H;^9Wy3EwEnc!a#apq%D$du_Iik9-#a z$K%^N!<9XUxsN+$Ncj$6_%-9PX6I;w`br$)~Z#sBLSwiCp&`HXZJ8OT!+;S;& z2}e~>=pnS93Qc7HSo(|5V+!~S9R=rY&}nOm7JmjOp@Gmta24DHZh`TVjAOoOSx0(kft_=FCE=XJn*EwBpw(td(Zx}5|Up}o{6cnCeEtUUvG*)IBM zl)e|%*?-2Bf};mVzc$Y@iQMbLiJrr@yBj=X?OSZ!rcCXjZWncn4znHI-_@LBVr{=L zh>d0)da{z?s^e+=3dUGbk?MeUa_)dVvD5pAe&n;w@G+sW@Cg@TOA$P9`?-LnJ><>i-8+dQjDUZls zHttWgaxbr?<%4RiC9y)a$oj2^^?f6}WH+)`Gdw`fpKOBn-H+@AfA~c9lKXT;Z+``P z{VU$PA}|5@Yxa;qd(JmyueVDj?Tzrux8RExAbY*T{_TF`k0;=B-)G#5E+x(1;>cej zYrO)0j3a-cNyEjA!zupw%6}n${gkqV58g+6iF_4H$zRLik^jcGT6paWY^a~aHK4zd zJImh!$La9P8_{p3@mkJ(LOa3hTKqEjViml;>bN^F4?h0`WUs-};g073g!_(9S~}6|LNYtW|yDdg87^);hwSup(<&khQw3W92Su z>`ijFKY@Pq6=bbN%-yePqXIX9%b(c02(S)42H$;%{`e?kV+sCZ`r<8w@1oB=KzJQv z?k0GF$S75WD;aZh`R2#p#JGEq@fBoztz~>QZtV>}ggkO5@joJd74dfwe+Ti`QC2bI zX-y__0?vZdY#;a@rq1`m$XBdemeAjihmo)N<|qAP`u>B|c{GfCMcih_*O4&t75ReH z-^5ruMmw&hzMe4h74d(geY?ZRSA-jZ;Z54>BzLRU150NZ`HFJRp&Y>%=_ovsbbeqw zm$JC`Gq?#@KMW&Zk?xzovq9u5V4B4L3r&6yGu~jmIUoM;ci`$F|9jN=pOoHAcqVC% zQzw^L1uNize+8~8;*Zkn7Q*iuM7{z(!QHcsIfnm7j85ZE!01N4k~T8ss}wyNkf+=t zUs1o%qniKHu4#G*Erbq&yWlMN3(kV0;3PO)N4_tTuj-+HC-iSXwvxA0h3;|ieTX*Z ztYx3TF0gh|ZgSit8*|;4w&i87VtWsIO5ry?_)ND)1^w`n9h|jx=baVIBJ5{>!tb|Z$E|VKf9Cc^ z_9S{Z`_QQD{p@oF3zd3E>KkYyJg{8vC*^X-KRP$FO!7)Sl3&WMqmHQDMM0hEdZZ4{ z{eP-#;g=s5%f0*77SVfhr`~qqo9}TR^fd3(I(mj-n~bf%!{5QbuX)K zjW4^Qb?^p8;)1FnfxBI4D{_D_my|J0jqUG3FL{YN zw_oyK>>t~IssG%5DKA~VQICF-vYIIC)K2X){pw@%is^p!KW!gRs(qHwK5NbPv3_p* zc$a%mcvJ1ww#<8C68D_Z9~a7cgZBHReWX3*d!D1x{4R8t_BGo_rP_ybq^UwcH?ej%CpHK9}_12DK^o`0o zYs*5~2ppIBO!ZqQo%@R}x^WtCRAaY@>!c_V|~J9X2R-OikSXuMh|dY0?VF3 zci)!LzE5A`9lPX>`1KXI36m;q)sN4x_hc^_>wdh#UNOiww&9W+#x5P~vEQ0qJ$6C1 z+deP5YHaV>Gwinxy~getRbjW}%(E{km}z&9^w`H+X4ubT46eR~JN_6uo$O^SohG{d zIipWUYN^Z8#c-<&F6cX3Z2Z$-?hRQXrds{E^(RQ?g`7Ig1h zY+>AF%NAP${)o+ceTztUG_=iY`i=2Q0%Igg)~ML*B~OR8LX$Et|= zub+BPQJ=tZ3;%z?{~YMyW1sR4(vG1n3$!VsT!H`Zz;F(6LXV6^g4lJA0_;8Z{!f$tdUi-3Pg3WuY_3!aO?VU$^B zmmx3BXq{G*O!Ia2oBsj_c1)159)@{24b`Q?1#oHJ}f z2KEE#d&l_$P*XcxmUuBlXI#KGQ9;u_8xb*tafi9mr`~r`&M${PNv8)578tV`* z_0=)H9gKG?Zl@kMnk-E=CuQg=?o<5t!UsQjXAC~-di~Tw?2>ElXWUOq^3!#<6F=HJ zA$XfbMX*Du8N!;TI%n<#|J`atWhVAwN3v^Jo6h$#zm;;&P5E^r3!VKHyy;~vs!X><)$ekk{Zu~I*8VTbLSo0<>X3ZXl@A*_lUbq8LzwTUe$n@A#uxp>E_~6? z_TY<-_JBoAwNSUr1)_5pM_9_!@uj@Q_)?ymdW07$%5R|Tx>UJaQ{_fet>&Sj&nJr%@^6h^_J+1t){+M_O0IgwuiM$T8HxK zx3~`2)k)7(_P1?%r2J+*0zWkGTzOt;D_%y=2A^^zrHhb!GalDneIkykv( zD+^}KxBD#%?F}}Uy(-&dSLF-rE?c?1CdWHAZ!o21`m3DN!`+w-_@;)Hkp0RIyFF1|@!oy@~h zrW0T4lyX;FL$)yUSvBbrqr0fmMG2g1|^+~xSnGY8deuT7cd>2m2yOjS@&vT?X zn=w5CMNZBLcNNO z3DVs~+;@rlz|7xi2)x-^$aWU_?`B@?mi%7c=VSg&!}@|>^2ZIS#|``f_xoo4Zljp= zQtoK--<6s_&u-f5dnKguS5apr=>MYP#_lqYZsYyyYW?K`9F&B!W3 zv+7hGBC`k`q+BU4IZs;%A13af%NNpzcRS#b;4l4L!qA~6S$E9L@20Ox|8;}E%-QLF zRz>-h)F-lx$QO>3eBokT6*;(*kul|FObzUBXNJ>t!UJnAq%1k#CUr?Y(#|g8((;9F z$`=`dmys{zTsV0;F zJ6@wz;tFidJ*@jG#_Ne0*TGM}qeo_W^~mhS<{5L7ukt3`iu>7HS|N8?-Jj&EWvg;O z#aGKzuE|$L_aWcn!03@P6!1`y6)uMsUU=vr_~9@uD>wV*D{}8wS-Dpd?!aG+%rg8g z+lcD^^1wV~hp#c`4^??{yvQxW!*bQwKn^sWGE_~i7uf+fll!njoD)1sc-)L8+fKq7 zvcqEJ3LVG$ogEFh3|!1Qd}17VqKowuXX66~<@dttgx|e|vkz7^0ptm@Pv|N?3);r% z6At_{+b#Y7RldvoeT?)q@Fpj7>SH zGDWXnZ;F*9gu+Vqr3p~=_1SV52i7)boz$NlVjQQT|pOiuRni%j&c{bpY@`~`K zJm)8}#WOZHWjj;lde10#bE;gCFLYDBI2YMsY`{jFDs-J9U-)UqW}L_uZrZksu)L8d z@`cD1MYJ*d2%jroa6gDqj%?xKP7Rl?8^?Ipd*I%SoY%4uw6 zuCHV5ZnKXgN$v44gCvlSAPt~`D|5Aq=90bnIsdO%2Z6hpcXDM4yU=*0#(9=adD^h#hR@$Zr zSM6tin|`Ti3#T~Y)i`N?X?tDl`Y21vQ}MZm7T2*`vjj8P8}hT4)Xn<5_FhlRnSDUl zJ>e!C{JBrcaiq#|=*hcEGq8nQ%brqf^tMtNi!wg^tlOIO8DTfh!8md0{!j98pReJC zf7y}$US^NA?lQ*hMDB57{;i#%CvM=|z365GlyM(ATW=(1}9e*Cl5-ui8eimdO}CyY`m@^$nguOGgA!rzWfpD=HS zy>+xrMefYjBa=w`7tW^sdAc@%b#?G7#LXS7@&%5)*vHR>2R0DD?v2$G#&FL&I*k0k zj#iN{asRNgr(Az->u$~@uwD=TZRfeI3*0LBrgdy9b866u`?}lSI(axUJUGtgoUp)7 zUk^^sQS;NVhxz{lVE;08RukrYe{gR-We}c@PDtQagkSgATmSO>*CxybNA@Z6r;*1= z{9N$-Q@y?QPweshd8fVg>ztzy9AD?`Efeu)?4XW9FQGAO`~15p;~CNl44WxO>VA&= zQa3Qx9C3|p6_}6Kj%~e}JP(jw;1@WLw2f_@MBMNcd`GUhd_rff-7NRxHhU{;V-vn3 znu;8*Rly4GMsQ@R$>qSbQ~Cq0lD;9jAs>BXG5w;NKCzp=ahQH_6q#;dyQjmw!2dM$ z9%)h>Wcv zoSSc83}hgSWU}5U!N#MO@l=1WyT#!Lrl*qc0S{7(TC>#kt(@bTQ)W>Yofo~nHOqf} z>qO#*5YE;gYyFb{vDRvI4smo1ZhX-{WbsbVJvh(GvJ+J}*UIrHytpjrT&88s>D4If z@zoOsO_@Y@YMVO;Ubalkb0gmYynFqNK=aVO)7b~WEG5gz8Zs3adl))0GMiIaUN zIcu8>KmAlY-CS(8(@NUuZ^#_N_qx#wt(^$3%AC~_u&^cq&I?r5o*_8V3n|tz8uop% z*E5+lP2S-AIbX&O#mG8R`oJ^p7J0kU`j15EL$tG`7n>CqyikV^I#*^Fo;5FP;{g+@}yet=+6uIvtM4xiTR8aJA7t`0Lp@*|_7IOc1aNs_M*fWR2@n^6} zzy>9XO~R39;^Dq$I>VjMbcKy)y2E)l@APFp^@eW>{)k(4`X=LcVJ{lp9t*$lOYFt? zmTrsB^G9H_a29E%N*PbZ!`D(ydF=a!YK@1TPj!ZW!~Z4x@8I%=J-tu=U4O<91!l$~!0?$(ZXOVAVca?D~?i#}C@$T?${AY3I{=-v; z!vgor{%S+k_gVjTI9&P^_F%*{C~NRm;su9l!gANkj1xB*;V5!E{tW8oUX}SmtCx@? zBz!S*uE0BvZ;E`Qn7aiZDQh^mI*GIKP0A2l_cK=K6W5D-ivMB!JaD&!I>S1+R^k?e zhfbcE_)EZ}2ABjMU+gABBi>COop=}V0;8Mw+|-^&oc4>+ezNY8dEx`wP{vaUc`Ud| z)R~WKlQzTlMC^JO18-HgmpafDkVf!u5vLO;x&j~ksx7695FKAVaiasi`v6Hbg>E@_U%JhelFjdB=$IsXzPABXp>_aAT4jC2*jT#nMhc1GA z9Tw{Fe?1NgL(q8)4dmUn)8}%>!zz@_=fGFw=Zr!=`hl8SY*s$+Ow;3Kci#9s>#+2B zyMgBwj#(|dH?Cp-VMQ-&!Nx^v`RG<`=h(yUsvp!6yC%6Fx)B}kChlh0j=nwMU%{n(*4`nY4Z$Ex;(xKDC9Zc7Wtar_C^hD1m?t*}i|8?en=Vy4UjOUyAUYshUlDEf}n*S|knerCd67#>+{IBtU zvH9O-{%_)cwfR3I`Q37lt;+nLY5tG%UEnEJS?2#X{tGI3_W*3 ztE-@$l+7I9x0(M}M!yvBn=~vA2#f>EucZ!|{~J>GWSz+)75zbQby7zIGPqaQ8wD=8 zKdI^L>|AV#o^|ovQ9i#>OTFo)sU?q1&@uz`vA)W~$P?H$s&(x3-|1+L&E+22(8=}B zTGVr*GqX7S3#4Dy(ihdN&9+X$l{?&xre1*g#kIF~gVHVe)1jkxha({Or^QA$m8ujR z4#z!o=OvFJk4L2Jb(DP@Z&7krP@;-C4!K(9$UZl7o9HGge>pYc<*gR)_NmD8$vpMs zSwY|5%^hnO0EfWy^18;zfAIeWTpMl~>-%>6YGk8b_{&ea9$b=`9hg|#7>WH#MWV#* zMvphCp)oRyZ-czVKhzk>PRtEFeQD;#ZMQW>DwQ?&zQv6ZY|)C8DNjEIeiEUf_LFinFJzSnPC$=710eg(IoKfrnW7EaY3dFd}CaUEHV%&cd)rJSK z)xysX#ISjba<(ZpQ~V);828;oIrkLf4xFf#ABdsfb&gb1D@6}8LUnxfpdNYGGpps` z#WP!aFPzcRb6!QuW$>W4I5)d`7`7-s^|TxaxLXddb+s6rsXaJ^Hvx3?9{Rj+9_tmW zJ{w&HcLM8IhHd&4;Y@v2_{=de@P8ipew3@`=j(IBQoioF+W3P@1s}k^Z{eqFdfOHa)6TxUF4tAh98T%Kcj z0!I=zbg;pho@zVnU`9_%Vy_^ja8a(NuZk*6yHvR-$HcoJV1z&LILFr(xp2T@KzN|R~XOVT? zxGZRTm^44a)=ltr5;qfEMUL2LQ&XiKvY>w^I7!<{of&4k%??Z5Qm++!EWj=GOSu~G zE6NpEQf1f71YUt@2CxcD6~LH;Ylb0kd1w=X%?)e%4D_*Y7rI&o zty=Y9Y^I*LfN^7t&=cd}g-*sw4Ey(qjFD2}zbyZ!>xm-qzoI85i+?eC2=On}6JHYl z%X*?j{PWm{7N0&`CO-Cw=ZkOWy;||P``3a0)_OhiW9TCOB<5}Sbq8k#&3$WUrs|OO z4sXDkYaYe7SXN7^*rKiV%nLVo%EOEK*649#uZ)d?XI6L%|LZ+7!*zVyMYtBfnQ!el zzo#NxL0p+@u2Jf88RJ}68YM2bQS9;4Vz}w0pF|N_dp^36IiD9;Mkvnmh`)^X1!e;I^lDl-yBU34eya z7hsnhw7{Dz*l1h{FFKz!b#C6^Iq!^6Q-91}@d3^aO=qogUcOowW&dRQrM!WCLKfwNibM0z-6?!cX&Zjsdh+BeQYbI_fGW85xWylrQabDzh7tV)Xu^d-}K5-uI z)=+tP0j|bhS8~+9req-BNQXtgc^PhmzqZ8PJ=dtljiHW9a6x}#$&3TKF^syG;*X}T zi*Up1f+e-@pfkjcq`qmmg>?^>Gj2#eq%|;fw{&JTqf|8;qvPr zEqV2bZe#%WQT!5o4V|U~_e|aTlCMy90WKpnBV2-eweF#kODQ)C9pTyd1U0 z3W|Qxf7hx96>ElE))KL-CrU}z(d5#@IxY`5T#T0xPR5G&v6Jh)ybGssj%PY@%OUKe zL>?i0a5-}PbT#teRm6#$ zJc+zPWuqTv&<8ZmBUqr91scdcg7iO){%E5=Wzv^2=xcfOku3U<>_*+z~pJ@-F0?lQ>I^eM9uT^1Ynz4$5>;b_wMs_0>(KF481**-fQYq$#4li>R-N z`V8`xlDC>Pndq>`5w0aoG4K`xixXJNh%Y0)ku>uNPa?dPG$r7(1~`4dQbYV?;iwWJX|Ci7izni6vvwZQrSum(f!u)r_pXBWrmyX2R&y`1q7dP@IK z<1RS&PU4(B?;i^7rB9tngD=9nGesxC)k+=3lqI-22}`+k#JdR#EL(^dIGczok}&?9 zFBmuJ@#AHGr?N>8i=9_5`hCeS<$B|DjY{y6dsyXsM<+V`26Rqd;mgd+X{TY+CN^Dy z6S^xiztk)12gjIf?pYGu{q|C`uhGX8>7))t8gI(x_$t=9GC$baqn9yYXU=$XWHK&? zIYY123jNF(4%Q0+OOE;W6zkqk-ky>;76~I|ZJtgeYh4)&$oA`Qn4%{peWya?`gO?W z>vrPiURM#he_lo8dkZTf8vFL}n?9}I6)58Tyw2DWTSJ}qn8$tZoNMGw=2`Mq_vpt< zZ*nsa@y51q2I~)GXUTUzb4rMNfGgQg&VrA0p|h2CUV)DPltcB+;f}!?_Ny0jfBlvh zCx42+1c`r|xP8i&Tb`-rH}l^10!wCYWz=hU@D~v0+~GBzesM~mmbhC|1IalDM=!DBUm8{$k3+#yIzB z@~6X;*O$cUblm6tmpTP!S-*CF!TQxgTP#i0vF*h&^Ne0RT4nY>Yj$Sgyd`EGsg#Rc$|3xlBCl&b99Yw7Y-iyx~H=ll0({$vtZC~21FR{Xf z{zlFzonhNoX1!6~{3_=ipiL>hzDa2ZZ{&P5Z>eqYu1miAHF1^I{ zScCFyH8hq!TnRsS&?g|Us_fEkNr?U@v54fcFknbYg1<$#daxdmv z4Y&!9_mHoee5c^;MZ~WG*XP+s-o#$yQo{5ZaVqV2FY}7v7z0Ns!<1?GCb$)+(u-W87_;g9Wa%3N_mgAbD*MS@;5HDS zG!6p4#hg>Vct5!lJOtLxRJu6uI;mf1b$~fiU=)}-sVh!B2ftt*s;2Gga85t#Tjn1x z?Np0PpI7`>_Lps`{bij#@1f79d5`!?cZHj94QK2xd-ddcQ{=ZO>w+Jfd(17RGHzr{ ziS164u7|5|XYMiUx^5gO^W1pa7R}P}F*=fC*JQRFV{LI<&iJA4cn^K=fo--M-~N^L z#&>>Wx$)iSwHuqzTQT0vcUDE#OUisB4&KjMUB}?pkoQKWClZ&+}!QNv$P0(rr4c}E&W=hY<`|33apJuhn+`OkWn8&C4T)w|S? z`d-j7^WRR@^MaO@|G4)CL+TBAml;yuD_VBG)GzhEsA>7X_bxWF`Tvyn`-YpoFZjs( zm4=1;1v&(0fkR-B`lK!?SIT?>IVRml)>03=5gIHFOPTb$d?|-LXYwyK(~JBwlRmbX zd}$h{^VgA|y$|wKg?s5^A#as=e~;sAm3z>XeV!<7g6@iRj;J@>1pOUeuMy+?=XW=r zT;IgHnf_37ez7V0oAS?eHDbk+MP`2}pg)-F<;uHNp~(OA2Xnn#nW;WmFUvQv)v~A7 z%Vn}AV67aZkEG8tRIpYamzOc8^jtL+gQ58cIkUBhHC8ug6ArRIZ_3dVn}N;BT6q!o ze76Aecx4UDgO9kN@!UzO<4Rq1tUxYP@bg@F_aJz-6<#fGX<3jHEyQQT+wO@zRa%L? zOf9~oa}f3uUe33B@g?5~_p-(*`m)A8*RsZSxLK)uc6Vjt<$7h~Nmpg#&vAurZ{uaU zw=v=JHa>#0x|cT=>B}4AuH}u=1_8?R6CTNZYZpzav0Xdm7TXV}+-jR0(m$!A;lfq6 z@P&8Tc3*h6t@py!HmQ?6rTJ2CHFTR=S#695MuFSzUeQ>8MCD%*a)mF~S2Ql;`$-pZ z^ox?pWro22bN-L~|JZx?IH`(j(ZBjJ510XFcnb>M^WfOvuS} zPfr7aC?oiYqVzl(j15YI2__`R9%dRCFwv-qOwPGKdw>DWn8ZOn=5<2%44cs?Dp4by zi2lB7cejiq=5dqzJNMk5f7EB!-n(kmT2-r7ty)#9YWkhlOQ(O``lac2S?`#Bx3!Y7 zVk|UW2~A5m=dFBNwY3=kJu7FxC8Qk6d-yEn;ky$Oni}3VQzm}DgioZ-N}&HfU|;Q7sb7E{J0DnAfSbq-!T+bJ_T|2`c~Zt$r!OG& zFqCw&lsR;z=A#{bfokx0n5Wdwc-r?1wC`z$oA!1aywJCerEQBmH|x_V^J-76eud{& z-R7y*)9WU}i}m1bg3p9*C$NQ1>BnO8ls!mtx2y195%@Lov`}UNWyUEl%UKhcpw$F) zM@_)bdm~SQFLhpw-s!?d(8wCi4*JKV^p9oeQ_`QIvFjT2sQY-<+f~>77ptzIpS**pRu6t*ps>T zlVeY&^~~5K|By52rN1ne^%fKJB)Jo%fbmE6jk6BhS&*TgaxwOFTQc{old*^T+r>VL z7WPzhNE+5_*?h=3O&P4^etJ(uTDHnF#vXO2hV2-6>?aX2|DQahQCPZU=eAmrWzQv!J~7J?yiu?kZ*c zb}@cC8NVGXKg5>%k%e=rNfc+o5A9(u~y@CI?{n4$z^sZYU z2Asy9bVnBQoX_{UlwU%5-foZHz`hbExCjm}#yt8v{9p5CwSMG{YW+vVH~jcm3-S?-`#LXX;CYGDa5;ta+B~}hBORN}NmbhtX zSwdT_60Trw>r(cbX0eZM347F!U*X@vrk;d8+rPzei%OJwRpPoTm8g7rU~AaqZ*$Vu zJv^`CX+giM{=I5*&0+sN_5#NO_U>~&L_PoIek#p!-l^HFtJeHpYjahqL^b>2&3tz< zSNR70zKHxYv0vHm8Mysw>|T=@+k$J)-G1XGD&Zwh>4vP+?RI2L`rAzY$=bag_!5`B|Ld^xc*6I6XS_}FZTQsQeiM89dt`4v|26)n_x8J3 z1D3t|-TZU1*8FjtIn~E;)}KF)vsNteIO!d%N6VgnBhFg0#AAHdSf7qf@NcQ&eCR69 zfUe@~=&FVhr`*s94aV7bmm_B%rk!u++oeivK8H3b;oIV=s%;(TL=58WVL!GnxkIg- zwY>_~^GshIJGP9qz)~;gH?#ida%XOT72Awsm$_|&%IGYjo--N8wW(U$yqb*d|3%im&RZ}5 zxbw016f1LObd)L?2%i4ZxRpCzjB}FT;tb9=IXnDq<{4A5^*Ai9*7LhnNX``tvR>&# zj&EdL{u#Tf#fA{X#vgRAqMxDDOl2Lwfz51d(_4}Gc9rj?FFNsIneV{Imw1`PJ=n$S zRQ`shICqkDN9OWv3$kMgdBkQcXL8x`-&(+!-FH0hAHSY68^26h+sJ1^u1I-K^4$eY z2QcsCdm&?eDZxyi-NC;Jz^uT(PVm_dK3^i;R`4(*{{$~9K7ih)V+PJ^_0LqoMflu(txjm_j&$HBy`iZmk{R>rUuzPdps;lX^1l}NFYs?k(}~EH z`0H)tTOKlWF>$%8&ct50cFJ?AOz6!FmBdbP_E=`<=g4rOeRezN9kKo;^}Gk&U1${g z^4JIWee`6ZP0lL&IdV;Ce1>sY=u6YOK+eNV)v3@dvX|P%vgd(4RXX=ovmBSS-F* z@P8~zFLqIGDQo7{=y+cGUK#7?j4fSu#scd%nt@m0F>hb71J>++C@ZocomAZ~NVCtmma<$j>&KjB{i>_!ea2i|u}s zJ=LOn=c=IR64w6kQ*twh5FMF)O9}TB-uZ4*s?&oG>c)>M{q8P6#x9byTARB&xexfn zeM$K4#MHSvN<{7eYJo|HBS5yLrcXb%QG^G`vkyk5B*fik$F>u zJ|g8I??XaIy1aBb72qIcETs&wQ|Ek!{niftHqthVjs{$j51emu(nC3J;ESK9*w1#P z=4k1DpMILCE9ut)!zuGLXQ|$((Z89aNgb=vnZaGgJZ)F8oR_6Y7k19l*L+DO7B+B? zxA4dkmGFN^`NlmowodG?UD{&oxbVnA%h*#&aZez3jXAL`b=PSou*JX6pRbmXYBNErrpyJMzNoTa?NOT@sCTXylRg`GTn4VIt3j=*f-@ z@|8r7by)c~G1}Xa56tP&cRDVM{;}gyBY!>lllQESCC}x+xgr`jV2Mw-7g>7_Fs=rM zz!f-47+aPy&Wr(;;2`DXf!nQ&p{p4S@!_PbSjQ#NKX)i_T@%ywYWU{1*l|7Epl1U( z9P22FCV;oT<@Q*wej~iOh_cMkG7mfix67h`>d0&2EZ_KBdZXVIDr7vmnlV6wMR32sH;B)GWfqe5$% zwu$6Xl)H#>WL$Ov*9E+C;8g%)Z_0)&b*_LdJS%)Gyl*G3l;I(-o4nEoI_Lvo`ami9 zr2VDMr4NLijV;JX*3Dxbe&;d0(U!DN^cp6MY@xUQ_>`Av5J5!(R& ztyjQzT60F5)@<&o+Lh7f{({K#ks-$`=EM!ZF(;~yniC%Odpdf|iTA#FdfS&9u0N%j z*msM*=r}xLhDV;ABW5@nR7g88Vut1#HN(cYFF$QgI1U)0%W;@zkGV^$7&Swy95rKM zFYlcMi=`_pcS5^IhO~Fg3GD#-_b>R~JR;=289d(STj8jX6yjI}u-Ez1JDQK715py4fZqMZKbzD)Y`^{1Q-3s2o( z8AUkfl>2K2y{EKc{A(C>%F!_Tl*6*{l+!Zilx7)CU>s~XhcM<;y6@vdv)w&ADGOHO zTjQRM&FHuJ#@YT7H>Jk?s*lcX{c;cR-%9oURfCPb{|NQ?GJW4eTEh-TdXXnG|0$sF z7jW+DHQ2+ZpaV@+13L%c+v^0sNz8+@L{2cLlDX?%WQ}7wGHzD4wU;%c@wMtCdxk^e zJ7ZGkFt1fXdo-(hD919zu+%8JjuI{fAqiL6U5ik$K-tj{cJP+Y@_sXzK7_q z>2h}PUQ8N+AviSiUdDSh@fPCS=-2Z8E&BC0>BB$d+r#m=E_LN3O(yR}#M5+d;N8o+ z&@XlJP`q20de|E0&M1`^+7hQ_GSzXo{C zz+J#o@RM>bAueSL45^zDyi5HHJfS~LyR>~B^b74$?_VNpg|;owRmAs8fnP%Y%gJ*Y z^<}5N`tQR?^HC9bB`$4H*e71lCobjnBCD}&gZl}+0h;Qer;c*4=NtFanN#P@yQIGv zyxU{7rr^r>?FU8?I(IL!&`&;1oqMigR-5D@ttK!=bGH|1MXp7& z{kLkajJ7cHt*QdKw#&@8i;UZAPPma{RgWP{o+MaCgueaI>21!(>f1DQ%F?~{ZC><5 z2Rf*e{w@99)iCVTchO6w-)j}7L|QjofeilY(KBQFqTiqwzLM(WFPv-i@twfFS;qGY z8Q&i+wn)DP&S&X`J5ze$G0VAoo*|w1!1(c*-N6_ydW+~^IqU;c=u2jFJb0HiI`P?O zPaXPQCVHLhr4xNDtsBWRpY+p6r=d?dL|-Fs7Vl2@Tx0Y@C*z=;J6wT&D0*UF{ZPu0@hZZ2Bjw571ED8fUb-C7 zQKgIu%3yx?nfjs7D|C7plSS_o9Z|-}G(9qp6#cO2GxS40b;p`XNc29tp&usqYKwm8 zAA5G)FkbB6;{J-3(70#I{Ux3aLyd7jbD0eNZxC`<&Tgm_9q+|6e6a8r=z=o0Ta~;s zyBHq$p74O{Z`1MIDIM?NXXtpr{{kKFT=bJG&>OCd#yd38f#}boFO5RKy9(W>zkYYl zU)AqE=;*KC4fuq9_kKrOzgq@x-9TBN)bA1<)6nn6r1U!r`rTM$^gp8CrFFVRDIHIA zJJG@ZvVQlzq2D>EkH4hfDeBMEPrtKKp90@aUJvx8^*iBV(eFfO6MZeM-wEF;^87ve zo#=Mji`KTN$iY{vZQ3m|x^@2lZIK1e04MS&Wmf?ner)3SFal;&RwZ)>xWpp{Jcot@KX*t7ZEL>;kYL7d- zd~;=V8Twt2_)>y*D7qbTb}M?>gF|Oj4H-V8Y8UuDD0mGEY1@){RTw>QJ2HDYGCK?X zZV~A>kj9ICXFuLnwPi z!Kt{dPufYuEqSM6lapy3D?F#PhCD+4DbeQ~7M|rveNUTdO8ks-Y8^8jiJ9npG8R;I zo{<4nhgIT+11UN1_B3NGCyr*>>(eFfO6&*+L-9b7t?<|lRWeOb8?*yj6OY3*?-e12f z<(uHVp7d7YXnt&524?EGo{~Mf^4~r{L`tk%Rf`U zOY%-qze~13Qol>allomU{`cs2($8E5zs9Xnm(sRr{jR3Jen;9*>v!aV9!+5M*Y8%R zq(cixJS^D3(e^vkc)2H;mPulm+=zn70`!X`@lltEWpR(^=^$+TQ|2yq_e~KA!4s$Q|QX%oSxIWMGLl+ypi z&Nn@!|6Oivt9r|ns2We2D)hgefg$a3;;#JAT>4(D#J?pz!@tFguI5B{bKtjq>@xqB zb?94O^g<_V^|9&DCeKU!Ta5RM{ad~)@6-HST-@i}bE&)+p6a~UB{pIEb4>4}2kt#1BdT_x2R5hee!~no(L^1;@;B;%H)8V>I{NB? z6R`Qo{r1kOq6fx5w)vGROK62*^E;ylni+3JFVuL-7%uvTiMWfn=t%_xJMUKBMSl{# zNAwU$KcP>0(E}}fw;6fP*! z1MF}AD?zqiD*EMLwEv9`?nl=b{ZIp*L+Z>ZGpQ?!uI=Ev)aBozA6ioOKPSBHF!;Fp zWBt(kS@u8Dex`mXF#79<&6cFh+l5?t#gw%F{f70s`RIp7MSc((28X`=Ao}6e{q)0& zl4Jh~#$eG8SDV{{t^@$&C)`_(*vX`fG z7Ph_&d}-6RzNu%i^~w70-(u?%`<~d+()KX1@8$8HwzvHy`<~d|{*rxf?*9k&Jrnqg zZLYt4&w(9L!+w~y@5$JBHvO+IW#6*_L&nLlv#)(GJGj$W2isYEX6?5^k6+VA_xnOW z-EV5D{rl>EThFxr!Ut1rziNun_UF^~Ez3$-= z#r}8YS@b_y-@W`S_P?=zRsZ{I_P;ahyJG+Q%BS?dKO6SH(S7WHqy8_^|74D1*#FS! z{+j*oxWU)Qi#0?4+t4EElQzO$V;w}+b*nD7w22P5$UC6RRKOa@bmZZI+>qlD6S@id z)GkwE(Oy$x-2>=QvR_nee_6SP?st9K_Lq}8!%>LtXUUzRH4IAXej5hOxPBeFTu}78 z0bPy$IC4TlsciKvMVnH{#m}Jvm9;?*L^F$(>R4;Gh{*S>W^x z^4L2lq#aJ?HEe&K$ZN6vEw!{&Z6N*Aq*+WjfbRDTo|eI(F7S3QVeM7PKA+?>R_Wj3 zLFb#5r6qdH{D$rCSh;^o_bmUGa_0X%75*){)4$~g(e*U{mRTz%p6V@?bVa9*qAzN^ z$6TWC6`bn+qNKB(in1;nzt+E{bVc>4Zbwot9L^e1DQO(+2gR5Cqyu;hCz=u`#5Opw zk4_joBRi@#Fm^PgKes=wDgkeV%{ZHs>B7Y%4=oi}D#7l{9LI0EYZP?Ks zLblA~+tzqoZ{eGnG-4ktBA%vq1MgnmMHiO3_?DsnjR-!R(*M4B7W-fmbr9y>YN;F1 z|C*_v9l-u9{cjCvlKS6>;B?|?{ZH(F(uQ`*|Fr%$;#2yc*ax@vu@C-r{cl7c{cnWP zW}@>IP@a@4b!Q^31P9`M*MEf;SGZaR zg{Fk`-A(w_YlV&kd#jD}*sIo^>9aQ3vo+Uh^wo>W^BR2>d1Kh|Gmx>#^<1an!!(J$ znw6W~dEYtesmuZDWDRq*(g(|0Ie+t{qoK6b$+=ATvle-ytVa@LuU{!a`swwuPg(ZX zHg!jAg!xUe$i;+=a4b?lFoolhBErHZ{9FjL+4C!RxQ`6K6}g&w1O>mgrZ<`G{S_73ZQUy=2o@9UW_`2=n>^A(@KPQz>(__A+A z)~|iO>;t~SoL~7&D(34y&l>=4Um%pJZr=?&*Ab%GhkV`E7km>a>#N{=H{l-27|3%5 z;U~bYgD=`CFCe_(@A0Ma)_^k~{A&pvz$wW1o$q)SXNW?Jm#`38R}+N3+p>P^6B<$c zKCTDhv*w)t^vV8%(u`mE{P3XN|0mxe_I61-+|S;xu_=57&)KXWU&(tKUrDzbTm?UY zEAK+r*9lL7x8Qmsd4@tqJx`(GV&a0o;3RpZ{sk`?PYn8q3td8wci@Y@YU;EU_;&xh zz6sD)n%U*kVlh2Noe4~-ODTUp=^NCsWE}y+O#RDVYA0zChK4P)g0?Lnh+hrork*T? zXC@HD4`(*P1l~4626a|Qu#-;K(4E%9zJs*A%^LMJTMzi0+53HU*#~{qs>f*OGy67J zUuWOv0d$jt?BOikRo1F)Nb<7q!g~Dgrf@FAe#&rA?iAiL2^#SOd@Cm|zIxKP?eLqT zEPHmlQARs-WUzK`;@r7rSwzRUT2&0F=v}&j^lLc94#@s+1WNp{4y%Jvy=VG6$I8Z=0TTno^j^F%&{!`1A?sKqD+R2?)9;*x27xt0on#XDut!=t;j-N6~jn$TdW0uyIOP-nM52~HY z9QC@plQOHDJ1ENUP>HlZh;`%XZT~Z=Ul_h1Hhe+SXExjM1pOP=bNjHjg zw`$0$W4GvKgpuU=CEseb!@eTUA1)&(${GQTTeU9Ic}VBcGbvljs?}a09cQ`_^1x+- zk?xnI^ODZ13vNTft&8t+ZgH*lGU;n{d@0#;f)5{YIkz~1&z;b@oU;NH;frTQ-uP|o zm4$EXQ|+(O{?+(zdO1^B(f0kv26>mVjj;}Y3@I<4vPuOu`+0mkW!^9QccP;Q1=~jq z3RW2Y%Du&A$`ZcwQx^M!f)>iM!IL)1ck(n*uA-(v@ z^`ze$J{kBPDEwsI;{VWX#B1H%++TC&hYQ6Y!uTgX7x-fkuXW=a7r*U87PyU(cqh)U9IQaL-9)h1Lm2*ugGE97QOSHr#Dl3?SkJqfL z@hj6f?|DsS&gNWGu;w1iupg)aok4uQ?#VU?KwD;xPJXR@o( zxYZBu#_`!5Z}k14dvwcrhW}S7zQPO6)e>3wfR*FR`x3ICb+rl|$1kTBSd;O|L|E1S zs~R4xF%J*sV8<}iPCfA7F#K}frk#d6RQ^(Yt%iA2{x5k?&}VPs{T<7=Jx9Xbk#^Fq z=lxyInEMc!@EpO=C+m_vU7}0&=drHlSY#OGyi4ACd`L4X3t?a_K!-Yje_Ih_$#%oSmZF@uS6fZwYyu# zFPeRn-FjVjweI16O?O;>DAuEAg4^5Reu%UQWJ_JQSI=z1=Z$hW<2ZB)&zT`_RE4%dZ+5%NH++DpTk-!A z8jq2F0%Not7FEx`uP77<=(qHMuWa1$I03|!E!Q~qD=lqG(~)lxS+dyoyi)KQt}9b@u?+Ti?P z^QipbO~{=x`aluoiC?@Im|^-uEbEQp0A)MDsgd$U{sFto3m!WttB&A?&H^o_I|y#z z_xJzpdxrZb&Th}bzqG;B70#zt`_GW))?Y)8UnL-)wVo;XA$*3p*n24`#cFqOa` zZs9s)$8sf4wc=;^lU8%S9sk-K8%<-|IpeN?z8oKh{K__s1!mh|W4>Zq(Mg^HWMAKZ zS^SfC`EDnlz)@DSkuL@=vTrqGA#<-Aw8ZFHT4MMYwS;vUXS~#K@8?&MJ*%|DljtXx ziH>3!9^8aq+D(MnYItW3&!gyH(H)|1ScaKaIdc97XUH_&a_)j@^oM+9s(ftSU7REE z!(u5*d}qJOe9CmSmdHS!#i^ThDoN@Wpkz@0&8oK>|4pk)uWlh#7b`%r- zg;vgQvN4_%GM-GJt>c#Sru@k=cFN3iIR_RwCg)HDurJqPTko}unR1+e{;)G5cP2FK zj#%ZN>@ls|-DKUVxdJ`lvP*LW+IjkShpqi(R^Rs!d7sd9C!W*Q4y%Ls z8lD0_Gp6Aqqv;C?Tfsrf__bf~kbZs&U%|n}yWlB!M1Wx;r0Fl?dzpEMRdDhU z7rdk{%c*0Zf!_{mJ~#`Wf`{lAvi@NMhKJzhoAh-DPlqLW4s_o-?;H11{~qv?_Pg7a ztkbXXgq~WVQ|Oa66#NC|0iGgH!qBRSOWAR`Z-VhpnTG^Va)zr7-YS4E#g~!2(gtri zTC_+3{AGu~xFXJ~9n*9hL3k!y>If*}GqO0>owEYt+_5A4j-1JtJ{*(&3_daXr-$hEIBjm_4|>U?L25zPt{Wg z-0!fbigcoz3hq0VB@{cluUOp#9oUWfwnzWCie0PA*yiLc043{D(*8!hTSLX{;Vw^| z>nL#3F#EzVGe;EtSd(^R4jLd&c(j!}FctI7=HhrNpB-Fm*zW{3GTFF;`4i_fB5(Sh z(^z^+?p{V#e;{);L$`ZuNJ>NK6EoO$9$sXC2ecTS(fJB2!(#rmQ6kj`drna28I9Jw@}wB6LN>@Rx`I``5h zlTDVO_(QMc9Q^TG^8C=((W&0B4BE4b^Nwnp9FdjiCO6`f;^urIZ<8ysw8vu|P4O=kJjK6M%8@lc#W*bG+1cMI zG^Wc-m(v6en}99l)KN}Ozj;rZ20QrMNGtOV(NR+8lbmd#oG|dej~*rS5BU15>x+|> z#o!--L7J0(4OxlaBmM)?(F21fY#+M}UfNZRJTm-C{hC9U^L@(R=04e3=>G2-_azwo zaa8yNyWjyi$Ma$Q$l#B^?Htcv7P}38NZK0h*cvCIA7!ho&L-9r?d&z|;p|TM>trYV zcMbZA-2Xar8T|&@GqFQxtRslL!uK;c*{-@oM?V1%{ae$6Ep1J8EqhJY(4(e|(7&_4 zzNM+5MuUXjFwPe)7oPl>9&#Qe%2Rl?eBJ6-2Q&YOTZe6 zt~gqBHr5v}ZSU<6*oWCaZ$e)k8SB;$u)ZkeNEyEs-&S<+40P#N!U4*Am-4zhUc!HL z4EtdR!8^lZ$MxrtAHTu(wHSC;g45yf`j)&{ubu-BhU1(MfdA;Ppl3R8r-A2p!K0S- zMX%o!a#IJlk>(Kn$v#bWNqvg{sNk6^ek;Hbd?l^?7d%A=w(aoHoU!{g!aCVAYxHea)Poy9^d?+jr$Kaw;$=qZ`qk!=i@#l#PoIjFBU=9I?oy3>M-_%d=?h*c@-5=+h zo3{TM-`*m9g!c!Czd?Kx;UMpV-w%k70QPEl{LE!C^CTq5F>baea{461+X$t7pPLKjhnJ__~ucgUthit9gGtm0xJB<~_)} z(7c9t27E8@h3^~L(>{X!nL}U6cF<-i|Hl!ODRpu_b!`Rj81VCC} z!Bgr*U_;+g#K^w?Q?HY2HJek6*R_<82+7c zeH-~UlkZ!k&*?MwmHv@S-74Cqp8V-}U7xtWPrQM+%%R2qu^JjY;OtJd;|gSJ1U)f3 zwg0ISUKRKXUQNSA_dDrtkAg2YWBRi6{|v^N82qlR8QUG_U|ToVz>c#9hSngsMWY=W zu#oG<8kmebr7xkIl%kvb65ZstM!))4H^lO#KVGiR^#>U)4>d{yx`F z{sH~udE~Z+e)7WS`pM_|$ua%^I{hSyesVSZeGoo>_8-(wa{meX$@!n_C!gyl|4sB0 zc=eyAp8)F<`pHx1Cs&}K>_b2K_s{i{&+R8-i#v<`Cb9E38SA(gTGtg^WFcTevnESIA?EekNBGa2<`1`~om-8+@KH}H(5b0Nu{wCJ0Wv}aZNLNj|4dh=U`AH{h zYIl-u2I+3KcKH4yGwN%!w)=dUFZ%>;4}LXi*#68Hd;;H@wcnS9?HG8(cM1MCk?ani z7au1R{v*<6eZ#*3=j)VPrn-HP@cd8SqXYi~|E5E}+bQR}zK0|4|#SiG4;Qu0YbO2|6)~|d&&N}Lo`z{VaQwUmKfhM7EXvS}SLZj?~ zPU9?oU*4SG_)6m^bZgdgK8-a-@o$o|tEDZ(zv*Fc6nq6w*+YF7c&G7|bnk(y;3sh9 z{oDNi4SD8+x8T}9eQ$-9a-Kp%Ei?)Kf|KNt`WL)}AA~-^$?$KYyk>l)%=kAQWbc99 z{|Ddg&{sow(O3-srb9k~DY!}b`$;eUO=%cr>i+=w_LDa4-?Wsvuu~_pw-~>Qll9=~ z2Hzz-i+IX@9yvcTKsqn!HU)PZ{!gzKmr=fh@-@mYrF*|U$OW<1@K7-Z&qWG z9hchHW{gek*)Z;mw5bf^&Peub>w~WjWV<5uJkl!cwmR(r;zo=)5b~Tg~3Kzb?B;OStdN8vB4Yczcm4zf(0j$J@F0;jx)nV_Qw8 z&ixis=hEzK@f+)WHa9ys=<3|DnrU!Q!RKG(-kl|bhE~pA=H6$`4u-U>{x52WmjjOuP4&4f1ZIY}tPb45Q4s zv!Xtaz~;UlS1joVCHoIe=i~-s!*he>hX2#?;sVM#2+w&^d{&76llVOeABTCGC|mZW zIOzZ4|76E^a~1wi1;A8UF5 z%6BX(v~2EltK3Jn=b{-aZzO(uw9fTBR=j7GJ{j&jz_*T!OmTP@XR1pJ^^ZtF#-hSlxpp$#quO#;qndnD7mXUj2`dUfiH(x19{On65r++=a zBoUomlKAa)^a(cko3(MqxdDauoZc24^A+Q+2UGM^@pv`-b@jqS#(hJo-=1CzI=2a3 zK-v69y4l+(XWhHGL+Na?MZTHY|D}`-e{OhL;ls^-G208by;#UTF%vLUt`>@o>S4cF z+^VQMrA8Wi#!UXG&&GYWHdTZyX-~xqXs+~kd&Wh?FJjN8%nbzZAAy(us#r$1WyGEx zmHvQH543m8GIq~r;b&1}5INkx${tn0(eh}IwJ>^s^DDZ2c5rpCceTQo!8-8u6v#Yh zOt79ZVx!{t6!=?=yPzmTdo*ShT4~dOiM)Rc?$V|w7>lLdIyq0v&0SWebi0+)Zcf_m z3$)vnwA&@L+hwVC^A{TJ_M^458*QDY|F5;10~%D{cAG*!{EYUoq}wN|&a}_p(KeH4 zn`wR8=H>ovBeedNwvjgbd)miD+qh{X;eptwSh3V+0d1rxM?Kp8ceRh;uU>xRUX{IK zT%PUbaT)C27n$0=+`Z3^e%X$^EI^*Sx!(-`_n@1z+lDN&e<1SBeW8|UU+&qbvdzIb z>CRapvQ;}BdpQQY8$X8U?+4E&V+nUa6v%yQz?-zJ-~$i$$k_0?5V!(UU!BvFOCMx+32RgoCAKI^0UK>z5M%6;s&g~aAfR~Gic51eHL1?!Ogh044>Wp zxQU;T`-!AakjS#8UvZZK_(!Qb6LpuAUC{93R2t-A`zz=%lQtcBZ+v)u4dcKF&V{Py zJ$|A8$ji`MLcch=ykMV&I$JOGwzDLW1&#s2f#u$Priq)5m?vyHa%lOIeTSDX-S^U- zlEl#;lrVme49+5SEcflZ3i;X?9T{qWq9kD|-gLyPGIQiVcj)Cj`(x=_BZEGbk>h2o zYX1rSZ+XEL2ftO4h^*y)P|j@n33X6qQ76CL%srsoOXsnwM8OA+t@cyS;DLXoEE%WJ z6<)mi^fona(~&yDGV%%j=8FV>`@a46mL$yQZaQ))^8KaylEgE}fCB^Jq4PE!DW&{_ z50oTY7#9VvMs$Lu{QEYv`>2!kl(qg;d9eL{@E;4UlowH>&>Kevm!M}HU0;$o&b%ON zfHG(q{+g-vSFf5|Yryls?MZq%ZZ1i*Zz)Oa0mmq?tD)6I+n{sQmNF+QppL5XF>k;p zvR>l&m^Z9)<<$I6wcU+>1O|1guG@43e@O0}Q^DbPdiEg~Yp=z3 z^lHlYue*1vz_D3O+r?kay#yJ&%(E}L{L+1H&eY1}9zM}6L~p;AJE?`Y4w@M^hjJG; zWeLw680TnZF4SqFtm{-pXLZuIe%=Y4cI*X90RB z<%zs7Nf~lpkAIROzsqO?Is3x%JFP8-kD5c7a?H>yX@A3c7n$Wv)@3$t^Rv~YpGaOgJNzl)25w=EyrsGZZV|sJbZZQMF47(%Y{l=+={Myc zAiwypKZH+S693FlHg}UsUC8~^g7d}7ijL7_mG44F1Y8B4i*Eu;=sCtWfl~s_La!4# zrSARYSK!k?nnIpF@Hg|{&$9;n8wi3^8F;uQ9l;4KA9(x0u>riQ!5g^~O7G*BJ|k@- z?NmtHh@Y^Tcm$n9eAO?eoy4}3&7GwRSVET*T)hN0c+`NC*q7>wHxL)wl8=4-iu+1i z;L$jJ<^Vx#6JB_uzaHeIJU4YKG|C)QF%J}+rH%@KCwvuil<72nD8f9@X5x(1{4v35 zp0D6bYJo>%Sx*-`DWj>vAE<{~Zv~ z&p6k@e)J>bT#K`vX|d;`udjUc@;g`lVCEewpJ85j`fjat-Q1a0@hxzDaZSRtaLwt8 zS!)tyUtN=!J$Fr_^oBLu$r+RLVm|gW5dTuKL;J8p`;_{Tk8^Rd4F8{u*H>U~@(ni` z{y$#)f8?Lok!qL=tz&K``qq8f89}i}EA-A90Y5Lb^?Ly~h2;BCq?mN#FNQ?9+$f1uuSClkvZBp`SLRpSo4t z&`+%+tU=M$M2Bu5trvZ#2iQ*1RY&)C*w95y=+P$h=)za;e$jjGn2-(KCi$(Pk8W+x zknh@^g&#Pm4{h|Agi)U*)aTXI=QQfGl={4a`qVyMpDX_h>+=}&e^!0|)9Y`v`rGPn zIP*UE@gs{FyJlAFI}0*f-&>r~`kuwS=Y6lWl|vyD8H^J<3)Up+88@tir7&~L;Avxb?>^zAM z@F??78JkY7nwPW3GBBr_@#Yt%AvsqtZrbm)4!efAcpi6#KcI$oo_BBd*c$AO7vFU5 z0&I%G%fNq&X;A0y2n(>AjzZ7URet69jHxotHH}au-T0zkDE2tUxCnmkN5QF=F)mKu zc%3oMj}Eki@of@8A&at2<5;s98qDNO=cCB=*HdF$1#--VFRjSWdHBM9+0S_eQ3C$J zjwbFOX`$G|rfZ%p8uN zZWnTGHsu`x)&b;j9%lpCNh{-KGycbl_r|LlxcS@<){cqQZ1%c=2iK5+6lqvasu%tOSp zf%S97IjJWZ{{-hftc3_o^8HEZ5S#_xt&}6MgdV|N;0Vo9uQE0WO+u&8B5ia8I)xUY zLG%itM`#e7jsw#}8GgYXoaKyyc5sY>mj%29ufF47DRfF*x}ebnEHiOCGEc@mIU`Q) z692g|{z<*=U<{OV9U@i*t|n;8Ce1%O^ttl{NrHU2p$ zFP0krWF17tKPf}#Y&YQX&E?STsqwFlv*7%BxtvovfHjYtU1v)E#GP zYkl8aimVV@X+6o0^6>|EwyG9PmvFoisptkBvQO>Nb{c3tT|!kH*X*1ckCYXd&#`Oc3~mfMvT zs?HkU>U~Qk8njWNnx4#%%~Cz?j(4z?U9Kh8y{{5?TC!$%kE%qC#gy>$s)Us>(Le1M zzB=0x*1)1ZjbO38U@Z)H`#g+uZr0rjY%!mMxMsv(uoi@m@gDQ}55^h8?i^PzqeJ4xhy0_c>!GJSoY}j2u}Zvlm6p(Rw8Wha88epbQi-Lci@P|ZFFGo;jCi(b zbjVkQUHNHjoHI$cA!A1ME2P`2605x`;maD;dS@_W#8zj6d87`gQK0{nJIz-8-Z8j^A9_dKY(6$ERwE+qs*3 z?a@nGZ?_BwPttRL+3h^z+;JA;{~e1jZM|#pWvy=Rtch`#nZUe##Wd2xYkyW^3$Fdy zu;kf?)2UDQNAM+cqmg-6gl?Oz+MeP61>6}CzE=$!|3X&n>+}s1>AIO~CC?5VyXU<- zPH(%9v2DrplN6IKk~PEt2m2zk(Q{T{*E#~tTvlF4>8Bx#k~JH#3_hd=RQBeok{zW@)*i;GZuB*Dz}ilH zMop~0teYhA!WyhZ|53=20m!Z#Ke{}52Simqdl2$H#B-3_%5Tb-GYsYI!X*UJiA6T{ zA9MP?=L6G*Y_pM0U{5380D+GzY2cfkcN=myEdMD_;18h8LgexRz7-q)UAhhVJpddg z@Gf}Bnpz?A5)0pD&gEr|OlY~EGcMBQNgDYsWz_*o=x*kDkRWB+DWj12Oc8Jd#?-T% zaUpf0z+2X}M7B%ZE9+ap5IHMl*?})>UoyY&u$EQR=N=`=@1lN_Fjym#bt>|?$s^~h z#Ma)mRnB@mq*O_mHi~8KEasfkV2m@b6lvTaX>BssP_(V^nEk{@3#owlZi}NWR+&6o za}#Gc-P17F;L{%X|6=(sck&@)z1+1@0N>TXN44bdDO8EfwdZa3a`%cG{_?yXnx!^AKl4Nqvic)Rz{azb`#P|6pkC1!tkj z0=+`x@H{2wx`l++bY10w6MI1ny50P{-k@#LzRA!e^l=XEJfZP8YpGI>z(z-*E~f8e z?i_lEZ-U#8c;c%c61nt^{m??WPwcE*%Blyjacap$mx#d)>k;c>ZxNUcSNFU+Xr zV0Ss|_K4(luT}{^Pl4~gMeLQpns&YcYaOuu1G(9s-ATsE^NSn~EKBU|vq; zUTkDF^rcnw3yaobEsyRi_DoFnn_}XxS#qXO#(Xd1(FWdU=BwI98#tS^?j zlJr{G5fR)DlfI6+sG+Phd`bTe>t8-UP1-q&I?JF=CQweEabGp#@Uz9irM&xiO8Z6o zw7CYob-W(}Hz~^x9yaQN{#P60o6zc{J~mK(8kaEfCdN+pJ!`jmd}9_AmYc^KU1{c>L4Cl zN+0D+)oS`^wMDg6Ngrj;q>P6i@N&{utKQ9!@p7JRtr{!y=}+|A6@B{c(p0}yR~h{_ zbld4|P10{IXYaR@=(hv%vMcW!tV(>8C*zyci4VG^-+HO13B-FX*+##up-w)^Rkb_7 zLGB=Oz^@scDLSD~n^~wATT6Y>U}WkA&t4d8g4Z?r&#Ff`&(7aatY}-#dd$BmU(K5W zZ!M*59i+)Kw^#$f>3H6&KTZgccjt3neHZOp2uuacmGJgd`iGnJ!h=%&D*BumxWY5S z|7m=d?si0khXn3M$|<9dZ6@4L{w2T_8*K$o&e@(PG|groq?vMZco$w08m2rul|E(4 z@1^bqHxIaKl-&VNcGY5S;u(-Ml<$TI#a>%ZzYyN*{fu)21?NoaOv;(^>;&%1U_MJ3 z#lTt5dyuElBIO7^f`^nVGO!GMrQCMPl`_GrHeK#c%5+nvVyeY-=li~U9tkz-= zZ7V#lXx}o*uclp>(B?I?u@hVhc^A2CpOxhILk7PW82z#O*@B?$zB>AXJJ1YH_TB4? z+_O}1LDa3+!_)1hZrY>8x`TIHBW*m(R9wgR1H3y3${L;@&Gz5w&M~!VrOZ)>FsBP9 z`PTg)Iv8`Obz2$Fwh^Dn*teZ0x|;hDp6FBVX8sjgLv3qLZ(}a~>9h7$Yps3H+LQgx zAENKQv%uW?F800m7Moh%&r*qPmuPL@`jgf+f-&f$l#YS0I?a9MoR5h8rIB^T!)9}i1KZtt)@5zj?!-MV#W5+$v%?^Z5BqKf7FjYB=M-q|317WYXFaG#yU-Y zrhMnUk?=U{080t!u~VJ`V>5GrxqKH`1{~mRh-vy^zL|~x4n0r)1K)s085?3weFNWQ zey};_(gk*yGDTjoo@2~!HZU)d@?=dWy$&Sv8!6ApcbVVFcPZ-t??R`ndo&X2ncp-} zh9B6Cz!4Z{o8O3R61+t|2re1KWvxcw3oKce@dIDhWn_M%uuIkSncsxTQ%ZeC3>ZoK zljM^;GQY7I^P7R#u99sM%i4w984z^KJWk3Wo!FAh@ai+nbLyBUe}pZ`!Sh>xQf+e9 z?|X|K@S~Rakof|dS@8Bzv&mR*Fn)1)7WwCoJzT7h-b(2tYIyT zv&^RmetCS?<}t_doWb4a;A~O;Epg1!Uxlto?UM|=9knWSZ5{IkhZcAh+?P7$=<;uk zqk?f@(3FYo6N6U%%?dHsYU2EQV9S`g+A&*~f3=Qs{kUbwlnLN?oPQNRWWLm{LWhYT zw`5JZ)#20&__xYYstdgvFIHVr=W@RH1n?I6HcnPurFIn(8XsZb;ym&?^I4~Ywik#` zfNr5rXb}9{`6hVQg5xUi@KA>671;Tw_?fo|og2B6M%qQ%QrfSY@~!;yP(}xR$Dffr z12YaEq-97q`GqIoo0HOZ8u@G*{gr%%eSp4k)oSihWW8f1Yj>Oa@#P@iZGR_U_OK=* zd^rHVtbs3oKSB7i**cRtlDWm3244=I@;voZx8D|wQZL<>+$o)oGj03qJo#r2{>($Y z*D{~0Q=$6(Nxp2q_zYh*@~xYBjQs1%m&xygjPFUl%>0-yC2hKX8uuspvxEBB&)ik` z(?J_G?nkerUj3xq!ncFdROsi}xbum-9AD&nQLxnD&%sj!PvOt#ToroWeTIfIN2M@;LrVe z)GM?-4x9jV3w=U^;NQeI!E+us&IJ!gKmHUtnd=z*DQznJ=}hsbBgLP#G=IVm>H1Id zXS2bd(k`Fk&vEQO!G2C3sy$K2I)G_Ja*fY4a>YvC>ju3%#`gFK!`~r#ugUOtIEpT@ z0{I>_n+$&kJL9+fQ)}%gtDHG%IPwDB`@+0ImE7x4(nJ60zKnH0 z>R4ptG4{-@yOc4Db&D0u*C#N(77thR4iO^Qr6!{1u8I00hluy`ZEbW(WRkMv_wt@S zLd{ziT^gCJtogG4nR7GqC-bc)x-2r8_bH@b6}>SsoA{m4i@Fnfu!1dZafrZ-IK$W&4@HK6D;9s;G17Fpa1y-D==3N9nf?tKUH1HO%%e5te zw}4ls`2xEZ)$2PK*Xxn0dfgYjB~q%@1pIEFUJTBfwmJ}@{M~aJ^j(z=`p$|5J>qK6 zTU-G>ToFJl-Wm}4!j%%Q4cr8c;W-jt6?n+KM4teS;RW)3cR=bQyh!4A1;UF1dh?uy zz>dm>KvP9SAna-gNZmA7uGe=|tk;`d>-BJzr2TpzJZHV`roNi1__vsUi}<%-J^$_u zeAm5{_lno5`8#au|6Pe zFk9j-;*@(0ad&iSq}dfD&;8`NpFD)BKma%a-~@mZm?e1@-ADZ_qufBCX-)tdNK+9A zOrqVIU7K{5b_?k@>e8-Fi#O^{?Pl_9)OS^_5A0mLJ`h>7KG3pYeL&jUp{)$;ay_W; zta?C?EPg<5S@eJ|?XGDz1)g+m3OrG@G4R918v~Co+8EgEzEOXC!F_=r&RHLLVsRkw z0Z86LTKae^~jT{&)q!^&okJHQye!XRZU$1~4%i*~)c&$`uS>UHW{DCLfGyG(Q zpE_EmH&Rc2aNNtfqR0^Ghf=oi=?d%*Zg{j@V{WEZ1H%(=(WVV)~j%X$M$+%+De~E(?ns>ej(xCe0(pzcTSVSM^2X`=g>JY0C3Lbk2CB9v7p!YF_S`i5 z%c0eL$I6BQ6 z$i1U^N!voNGRb+S!A|xP#KT%7z1d1h2=hp$zOC ze(YxE`#)KR;4V0)%Md)JjHy4J8tge(qkB4P@FBwf*Q7-z{&Z5X{78*4KZ#M6*rugk z#Qqnj+zrqrv`E=v7x@FWiPy1Noqq0;;9=&2lKxd__G4!d8Xlih6A;`DyBK8}HbAMb z6#arz7WfFQ6TqYS#U#x(@Us8(l3*S5NV#^gXOY$qjWT!2B&{9%?9h;gEqT`e75iVh zJ-%)}f8i6o2mjrS8q6qbjmL@b|hq3js7CK-klrbl62!1ySg977$z@Y$}d) z5*8&cppGjeuQyzRPF^dbiDN<_YH%6cyVV(*poro^+RDLRO;t0XzWfb!J+^XuP ziO&4a`F;QT<(xh@Rj-zNKlfJEt>x7lRZIMidUq7ltpwf5&}{*DC0Q)9mwSzZz(VBY`>QsOS>_r_8T_t%T-C=H7jI|JHKo-sw8*BHo^}iiOvtgG-*c&3-EQejn zz_1kdN^5|#V55>)11y1!x)CQAm$kI*wbZ&WH+*xixwaDjJ3z?>%D~swdpsE5UDhhB z@s)!IZFX6U7dFQ*+v_q}5VzGsYk+c*W-DuP2Z5Vd1C;UqiIjO@>2kDH_#fq0pWasA z$C}^@de<`9R{!_AmKkWP#Zqyg1aj>}n^iJ1YPX@ik}q;Z!nfejX1#05dRicp1@b?Q zwu|q(4ZaWS_=Sl37HfjkUfo!iAe=P#yo6O5u)7-l7Ofx60zR}>8b#Zki8VA2_WfG$ zn~SwUFWN2A&3}LINVZn`1oTP$=WeWRZE12^Z-AY)W9_)89PI{ecL&x7o3VDJ0n;_; zUwibC=6|qvRP7Vc?OVv3ZP;o$jIx^F$9sMF9j0~XcbCW0q333lsiDklyodSW-tn~u zk)CXnc-Vn;z}+Z!3(CcsUrvIjC$VlwJW;t{qnX4r5Ve%gOo zAKU<*uLEvW&pTMFq`Ih%y(s59g#Qh?3$n0!z|Su5LG`Ag-U3nY6QEQl_*$E&S3;d{ z;YaI(m8?zlM4RYUnbTLLfiesclBF z2>TDzP@`1{Q?~7l0?5O)lC(Wdt2@89y4Qq?EtJ zd7A%zmZnep!AVl*uQ>anoQw5AocD0yER6?eX}s7AZk&!E&NejSyhbC=aD=hGS-hwv zlsH3ExoA@d&hFQ3=%Ix0{z1rHlBG5_8UmieES1j38PN8^IAfeDYb?Fm1}(st?0Q=c+;$hEuFbh3JvX# zUMh7qERj0ByYcOft(mI(Y`OE1rBY`#$~lZRuxe?rO6P9OIDg|ABX@dAGSx?_aaO6P z+>}9(15&vZ7v<=fy=9x&3y-sH#;-1c&c3&>)oGEwC0S;lDHF$*1 z&fu&~15uoz*+dj)XdWesb2FRV1NBYrLHZ_~v)N?qr_*y<%YDQ>K!3!TtAC3B8*oPF zQR5)+H@&rf)%mRrIM?$i&h<1Ln$lW-=$zJuRpSvqp|$aKIk0J`%+A^59UZ5x#~GVv zaRz78ZaMH1zD@Pebbc=9I;>ACbnd1uE#=%zo;Y_iWP2WXzYlA78>Yi{(Z5UJ;hr08 zo%gP?b=G1X-L=~pxDRI|oI9NX_v^(0IPsmHS^Nyn+ZYqZJe%2Y5aWRz-%LKZro87h zI2XDH($Zw>*>8aE;Nl?{2JdE{CmIGBX(geeAzLv1(E4=s@0`CWrgyo;`ZS)i^EZ@-*4KjK{LR}~pH|rU z8(N=EOP;?`b{7Xe5$A8vw*@quKTviS2L@!I9OzboJ?_H%N-@sY=`39gZNX`rryF2X z!_lt2IDZpHKWj#q(gs1p%Wy`eX1VSbb`>5Yb-pQ?_JwhNW(2((OST7FJTyY;d_l_C zw*uo#I3N83Y&6^x6gGOOC*}kA?$IHfeZV&+JFAt9h9>+l_U((FDd9YVyf2(9b^hgT z_%lYFMZ@}#R1G=)?O#hvz4I#j$v=>F!*^8^3TNilCM$E zhQ_ki$07R)@Ji==q9gEb80IrS;CC<==Zo-8fgAn#3iPex44L@;MP}_`_-d>0Jer4l zHq1R5sLXE>{}kp!@iT3myRW|5pDw4@ZUarj*=suAgLU!I?_&OS1m}F71^pWLLmbBW zp4~Wiqu_kc-B>4|fZsNRTd*d!2fq)nMwwW%N~QBwPw*ebvx{*?=c3i){n$rU=ir>q z44ik##Sdq6a*p79&t#PM9?JU|&v$@cjPp6)Vg0id=XK`bJkViw z^D*Dxe9siD-M>rcd+_{OP)h&(1gw=KKi2h-=WKS)=c3hP{C1r0nSnDsbpD6V{N&PE zAH=mF9L8Cg30TkHga3C!<`3|E8z|m;oKN`E`JPl+Nd8oLNdAi<>-XS;WGaQcB;yaj zrUr2&YXYk|;0b$}OzshQ)(^iD@CUyohvXw4j%3tuzK80evcJc#6y?)7A3EPdywUld z8pPYF9pGFKwTBl$sUGsBPC_Q)gD@bONKaG`o$sM`^|wSDqIN}X2)0FKP&)}P6K8(V zR_J?e4;d?T@?AE$m*_5>`Eg*(io#bhHDNqtXMXx^Z`#|nITvltZM;%z&R%jE>0lCpOqQ)WHooGjNPDsh1u{?LXx53crL3=Ua45vLjO?}|H6PuOl zG}Re3s_RVBL*y4xdde%o=TUI>0B#u0{LuNK-0d!;Pwd+&IAg5jDxpT4Empoqdj(I* zanyq`w()0#f5HDVZJkONDB7}ubHuc7t7OQX3eF$TMOj_$KL4NhZ67|*7TEM!aUc)v zoz_}cW33hYR5kBoTx_FvEgzCGjK2VY?q;* zc*c;{Gl+GjyRXN%xDt2yU`)K{@6JFi_HEz7xY#BedeXRh-(p+m{n+n)3-c!UU-LJ~ zcwcp0kA@bEl{kA{(TuUu^GrrVE%t{csrNpd>6x36meC;NS*hBi0q;1~;@rz*2hOKI z37h=J*n4{y>i-t=r6$bXyKvr<&Pvu`ytHDx9Em=D6vj&f#>0_8DQ7IkOFCaV3gac- z5y(l$|6cs)Y-^p=WSWH^<;%txG9Ld^ewG(yWMF)F8*wtyW@9gP2R%obRK`e@n-R8S zZ??&l#-5kNsl1V>$A~c1H3#nqWMJQw>X5MadI;xGiC@~krTQ$0r!*8#b+sW(vTXyc z#!p6_2Gn5+m&A=IhsyZ9{o4ZYkF))#&!DooDgMV9jkR`^L3J2VmyGfyF+PU7jgORP z7QTnW%i#OBlur}mV-p)6d)FSs_*lu_6L5P=*8UjQaLsgxz%CTphn}t}^+aAOFr*rF7~&KYCVb!h6iU z;2Qu3DsKbB;fW&nOvgOnmDVJr*{8mlN@+;`L)eFXGB~1Ev)R16Y{hX4`f7Sc@;@20 zoEA@Ik^JzbnEZB>nUJ?Tr7}qVgD9WseIhu#Hi$ZGq7Ib7mwo)y{d+p2 z(tQu#Ww2omAdUVJ^(;d>x*vN_%cTA_)b}lu`qlJCxVYCRgUt8z7i+iu*xKz*u@}{p zvKM7u*YAJsMO}pc>#Xcvb2nlysupLgur@JzJ@&tP;+t$9tXsRVR=s|LwAPEYY1)(e z7U#2vV=a5c5xips-|7&4j|5k?JcK=ukyv9Hb;OWE`xQ8c&-S2bJzv2-1nm>hdcFs1 z{|m52Ux79H`B_=TSzRGkt_N3O2uQpwVeS(Lu{{JfW zieACK(#zOix^>c>rkAkSw0P1TrYVzdH{Ch$CR5)@x0$Y(c%y0B#I>dY6W5sPu#fZn z_!Xwm_?4#P<5#h^G7db$f0#cD`&=Z`hv26i`&|n5s>-nERm%3fZo;028~a{2V&B8% z{R8#~p2uF$m2AJm{Z(#3X#1Rwr zIc{M4O6A!5xd#}RVV|cIdpcXOhe7*y&DhVNJ-jX0+n{~Crddjy_VPwb={c`rPvaHr zX}pX*jhALAUeXKg6+H%h__43C1N$kXj--R{TiHGiVP6OR5cY)os|#H5CAJ!r0j#kP z`0`v=e39)Ml;w&q#C{;Yx0yrwCB5DQ9c^=5A8&H3i9ZcpZHKN}p{u8$r#U}#EsRcD zZ)%%#mx<{B`!-u9{mG=D^) z%e_0GFF*9P05(to-Oq>K=RxnYfI&IrFN5rOr`G!vbkGDHY-2cGAFoA!GXk;>hYgX< zlde3_2kDFWufaK^3e+QCJp+JSnvqW-twGgjg3Q4D2nKpXR-jd{?% z;A^t)EOzgA5@D*J_MfPJ_%myRsQ(Gn(*j(!0h6u3!;L!LLVqR==+*Omw*T~Ok+a+W zlk>mqKRLzz6P;mdUk#rT{ZKyopX<(-7UqloCm;RKchhlZoBAK6|6qmg{)3N0eGd6v z)Cb|#yoK0U-7-}?=WtBkNf2yq|c9oXkE?%pqF&s~PR#kl+DB;EtbA0Qn&g7ZMY zd0_?KxvQ`bP#4W{OubQ(vMcVJQfo8hf6|EVWJdqSLHWpckyJM*-(aZO1)Yus9(^JA zM#xJ1ydbNCC~Y5ukENYK)X=M@5@&8s;_MIMMtLX=rKR#t%9O@XQw%JLpHP{sK8*dQ z&3D}B|FN&s{$5;CeRo{zKZ5stH(qWSeCusf{5Re{#lP`()8J?De+O*o+S_mRH^MG0 zkm-n!=|>^cRgmec>H+Fka~)G}flOcBH={Oa3>z80 zV~HC2F`14CnJ5p*L}^K;BQmAoG7&#tT_~$Bga6HU+~xo3Ye{_^^e2QrUQF^#^xt*+ zME^4rNuG)Rj$T5Z-lxlRQpmFi^1SRCpuP+pkvtzmM@>RU33+gN8mpglG(*Vq`2Un= z*lF@mp8qA!Cl|}=$M}}~!*|@`|LQwQWpY8Dua+1F-vSwKg*@*~67t}lT&5qK@7K(y z+gufFj>*%^<#9kB>7FTQR=;m^nAz874O+r7CK@m0w3Y&8Zo6AC4l7;M!(sG-l zGzRwWE7=@93(l9-_m4^HM%bQmhr@sW9oPBKK>Kt+p7$mg244r66xdu7!XKl|M7#Sp z+TCB#?%qcmI|J?Rd$hYC+T90echnX?M4Nj+?md_4m0_RbQ5SD>y+<1$|9t3kLfZg! zBJ{Zy@=v&LVy&6hzF9T z4z@|MJTGLKz+}m0HhE0QLTOnVAxjQ)Ntlo<#K%dru|D9t4sGkCXk+~lUUS=6{|j>r zgYUY1tbbm)Y48q&Q`;EHLHZ{-jtM#DK_}UUfoeA7xC=VjUppS(vFAG3DCC%*A_vt^ za;QR%XM`LZ`;ks^MBCyzp|m8&GeVAD=qnO(5FaPew#I{RmE=I%qP}7Z!aMAS!E0fA z)K~NpeZ?`>w$}P_SL1JNt019|f`O_{=)-m&&Z|<}LjB!sYm2b0+!WhtO4t_34BMhM zMYhG-6v|+2Drs8^lcQ4D7Cj52O(ojXcW7Iu+SCNmrY886Vro+p{BzJwXq}4Ipya(N z_ptoGoC#Sre(@R~9ynC8 z(=-O}w>S}RM?5`Cx9v1ti2eFmb>)GTkCg{XFh}SuDSha9;oid9W=i`|d7u>GIe4!l z4dGrr@XjFiRXt7RfilE9b}f&O+B>@T>22kK8_lkwGWdKMSi^fV2Wu2qn={}}(2RFR z)TZ~Q{|&XKvkarCykfhnD2VdzQ+WBc4o+8L-@h9B>Q0nv+=6#Vuy1-0z8CQ{dtP~f z=p`ObXWh(c$#PCFUC8N0_ml_jzncF~b=6(Q%eLQE9`I}|50oQr&zkZ;i|GlI+$}=zWj0rFZwp)2)dMzKzFNctu87r|QJL9Fu~!Wv(5wyjm} zh4sB`Lo3!3UaG_zo)Pw0`~}@LTNaS#rJq(#R|(#Uz`FhM1xB1dH?(4IiF;4v)=rew zwYztF6x56|Y@?*fKUeosb?o`sz~_&~0iy{ADL7cQoT-F1;XRIY5ATf?-n+;?B0@NKd7}{;% zrOQ6h-xf(z;{}HHm|?IUb`8{b+cQ+H%Fuq?Fh~!#$?aXPK{|B1A2RIsC_`{=b%+`< z4A47Wc~j%A!FtTqUyr&F_T^1IXvotw!w@~6)s^d4P)FQlZ11w?`gb*FsuIP*!@j8lKiJIvA8}`yhCRqG+&2+K-Qm@ES0DQ?Kdi>yBlaQ@ukWqurN&1p zzC#6R?XaW$G3-qO&;8X3>Kmo_4vtlPhgTQrZ?*MS596KEL#wU&n~0CD9_ogdbjh@Tpq36xYFtuy-2z_rPM~xw0>>S8p$Y?)ww&L4m z&sF2oNmi>Kn?mx9&<_=4v`5E*Uy?rv{?Ai<8lLZJ?yJTobGf2ZN!|iIvRj&%Ddnq& zrUA3&jQ03hxF^At4jHXFc=R7ec?VI>V7{6i;ycdU#r_8&YbC-FJK~Vu z4H-#Zt(bTzVDG4t44RGMphufC+qIcU-Z!+3XhAm%> zmxHHBW_#=c;tBbX=7-ef81Ks&*;rn}@i9toHb9@Lxe#S@gH7@>J~-vcKU|_t10H zPkKlT=Bu&!NLQ8B9+?Fm+j_K9dP)}ue+e{ubX?eA6f*x{sDFcyd=r2#vR}veC=)< ztR7s7G|(O7oBB4=Xl*^)!{9rwG3j}etC|qq&>DTb>`PlE19a4J{a5SO*Ly|@Hv{_VRrqpR{!a4+vFD654I(SM` zhE2^-hU&#A&tkKvCh(nBH*Bgb4bzPSq|VSv^v|fX*r3q3v7hSNg8q67`sQZ4q1~id z)Gg?fccRa3Lch$*DNviyXYWKGz15Yc??fNI4Sn-Y^vhe&C+|dGybV~(1D&BJ!xHpK zC=+8##4W3|ch!V3g7(TTBz#JY&_{9WkEDlO=mB^o#?LOd+>TY2&`In||L*-fxTD+l zg|uG^_EBYwfx8|vU>j7az*xH90KBHy`l(I86?>bLk*+Rx&3yrB_J+_8)#h6B#dQ@5 z#=s`nZzIM-1>;_LpV#*w>F+Mv^L^S>ba1K%2RqslP$YAUXk~_ zKBudn-)JjT|4C)F_4C`1-(xVgZ^l?*F}o@hj8%t$L8Bp0UjcvVoUyKoM&LFJal`Rb znhouZZG-)dcTH_|8wTo)z}5rI8&96s>U0hE-vc}w?L+<4uBiQG?kZG0l2vsYhWhUT zu3n7CjcvpH)TfYss&TKe#b#AKhGF`{u3>)nu*t0(Fh)O!cG`&X&x!H*AJ99=VusCW z7^BR^brqCfL7(J6xN)`FAI2E98F*;#dwpSyJyyuo41PU`t5&S4Qe^_)eZcql*2cSV zE(YV~!>&GlmmwE*S#&qX*^{Wp4(v%M)=bAf1rfYk)pZBs+Ll5FpHP#U@ZpB+>momaZXbU5UfhN$r8J4c*xI8=3}G|dkB zZO-9P+eJZ^j`(bQ@0kuuaG=`u-o}mq{0=kHr@?N>)@ZE$p}MFRW!6c`Ky_5pM;)-W zPV@cn%?Ud^C+swg^{e`R)$y9+zCajzuz042Kk)iiW=PZ0O-jYSt?zZL%#)^NjX4~; zu;R&%m4l^ev$WSb#$>(PvHgvAI_iP347|he1)TUljB$QtzBH}X@leNz=kD%UStw0= zdd*)tGEW`~tsEgu+gvR?bAY1ixAM&BgCh z@eKaT$^{57!EY&k%kZnlZxwzu_}zftP59l4-<>><0-t0xbn-QR8AjZPgx|{b(zJUD zq|Uu7a4rkJgQfQ)72x0R!2b*v_zhBDB~&Fdy!7ygUSCpH_yQiRZ)rluwz6 zz5_l9;poJ8ABMlc(qjB)GQ)pj6n+t-?|OZ_uPRcbZ=j6=7wsLd&jlS-f;NIi_96}R zXpzoTsm)J9|CtCoSHstMJMlbQJtz4rTV>DoB%bA{=O&-!@Mmu&p7l|uCZF};&)!Tt z%T=c(pXIV=RCfWU+@Sj{u<2qvkL*sQ@5}SIvGD%$V9%V_e(HJ2a{8r|(_fS`ke9P7 zQBHqV!#N$2f!CME)4`TmeZfS!yp*yAs1|8}x|I0YNmv%>+TXlBgUwk%cvj*6#?=LW znhUyC!%sBG>MuCY6MdcVhMyGh`YgaVg0V018cVCQG14|trRNbpkBhv@%c&AH@`{N6 zyVs{-4#nz)U(4DOojv$P_MuNlz1fDig<{}0%k9UAh31g95pZuyF^-0hJlk~5K#mM%mxZ{!Yi_# zmEm`Qvb1+`ezZRcUZpXNSH<3^{oUo5voum$dWg3r{GY_@ae>!gM7{)8kFhj*xIxf* zK_3wnjX43Z9Sk4O4Bza0$jNL1@vL0TcZ#87W?%cgWM6!I#hi`Bl?mQ3r$c%@j5#8s zc1~%22)o-M*~T(#!Zr~XLvv{2 zwGx!ZC2czC)IvV{j)GvJs-4Hf+BAU`D3fXGss2MdSMUM9kkySjH`)Ncmmtz&u5AHd zBrC}w!#@m97PuDlXrBjM3C|{auV69K!XISq1OKzSFn3Gh*PepkLLt`zmQD|24$5$w zFX%i$F;`{rmk7Q5n@t=q#+QP-t1u@fK9xvT`}N?9wP8nD0PlY@T^C&ZNQJDx zuX>W%zTW}Lczgmj03EaT5aMG#jq6$qx6|-8!NXQTn+4s%sRo~c>$r&P5`Kb%`zd}0 z^BKS|dN2|hzE#>2$_O!x2?csN__pL~|h%YwhapXI1|$!9tI8TFy?*CW|?n*aSQ$e*Mk_7nSX#b$@~J?w4h<;A0R#agD}qUvhtd+u7NYf^uJ>0 z*S@;?#O7SwIbLYAoj7K&oydInP>9ODyTEqBU^wcd_e-|+IUHJnXKnb!P8%tHK1`|BOmqm0-qKOC}Wt{V1cS7V29`MVvXo_w&QWS+6JZRFvQ z+Yu55%B}m^q{jHAjVU3tq?7&aysA|HR0^$!|X6(H1UZgijC+J>T8Q*D2$2XF; zjWl+Smx}Xc$harFG+(;1^aSZ3(`@XtA)llSRwpB^sZV+S%BhvZj)K3I%r(P~zBeyl z`CPjyU6M|)bkZR8k6Dgkz7OzSs;o7`u>UXO2ddaV=KtFUtG28ghaIxb%FnjX%a>-` z@+;<4&^Z#V~2=O~WMQ558BHPxZ*R89TRF^w6%C zKJ6e~?81D@g;rp<40rDjfX8qH1xR=(b1k3|PpZ-zGeC1iu_dO%}k*5XSE@-Qu zPjRXk`nR74dn7p>d4|c6H^~oS>j*pG+xjaJX7iHWSl9Z8m)2c(l%QTW#(SE3N87MA zh&az`_|&^7Eoe~Cor3sV8xG43@=3mV{* z#-f9Mw#K(ZSv}mp68|@X9(on)bQn8YFcxi~_0?AtpBL+E@t3JzE%G}+S^xWz;-mEq zJH{X{mHQ(1P1a#-48NfG3d#3)Tk*MRTtfIU$W?%HS>ETdcDDz-B24|a3*(a;YkSeR z@Gip+)YCkmy&i3vWOhN8ZB=6ZqPJnP79#(ItzUp|=ni2jQ)|bV2>c@ZdH=6{jDF%n zzK&6?oTYkDf8+x$d-#2#2)`%7`*=9^E)SEhQicDO)mDG_9rny`H*j7fdl6qXi1A0d z+9i0iWkSbafw%XuCI!90Z}U44Cf=g|f^I(X`l`Sm&4G+GKl+le0S{mBx+9+p`kA1g za%z#rsnLI8towxQuTa-C9`CjfX^(_~*T;k{{0Cs^23FC3P`UzLJ3#3$-}*>lb8aOv z81_Jz7U=T?&rJsK{5>E4scka5M3~v-zu|9yU#vmxh#wJU{?qG=dFO()+7exWFGhsQB74I3AHWVU2a=7}kp~a#lD%fs;QH zrM%o1rsr<+I5iSMTEnm;{*?**f0ZXke(8ok!VLfa0RK-hKNa{JsC{*^I`oJx`21PW zp9KAp(?Z+Xs`dl$KTi6>eC#BT_eApBqbCsGaSDHCW57n-wqFDP+ zCyKrzjmO7KJk0U8`m1@^A2m9CZvub2<7~7Iq&GOB15nxNvyu)#5$}&mls};ZJnsVj z%@&3~*|MC#|EN4UJizI*!2YS@&s6}D@GoW9tZPS}5;&ifMVpPV7e9Z2b5pS_*j{tF6| z_}3-y{{}pd0?(p9VLT&DJcma*8NZPcPP8ZZ9ba%iB|aSZfdA^?c;2TJQF`ER74;Po z#eP?T2wQmA3j2qB_^VjBz#lPl{F%+X{N!v2A?ozkNn6ca@|un~nmX7c#x3?9$%FZ5Tl zaG^hTfz!7e_Rspv^M&nC7q$<|Z2vsUd&>4p!V}cUG^CA;OyXah!2eUUqVnHwB)Gkd@qjO>ZbI2yp{uc3gXWQuZ z$U@lvg{SPFaF5OAdes(CI<$vb0{^PfN&NRaME?_l{a1Ihe}tL+SD{YuOZ|VuA=|8;EqMVQ(D^}s*u^%)1H z*#C9H{;%cyMQQ|HE$B6zT5OZm$kk3?bQQP5$c+?VsC%l$wMW+iqm_hzfo=zn9@66q zuBXTvN{8@rfxlrK@W-AE;?^Ya-vgc%@QnTkJ_F|&VTS*Dr_TU>qkp3EfRTo=_b#W; z1lzGFlX>5>j`I?|lPGj>hX~&;!ng5oa_nVc^gXvGY#(`U5pw;}=_^FvQwd7rbmV5r zYw^qId#L?IZgSEZd!5BGS*106rC@wJ#XA%D2VqMa(SLFOr;h0wVP^lez(3;k6+j-c zVK)BWCvdt~@OqD+cMH0K(*k9R8ubEakFftgQ@jQ1&J)|U2Vnp1Q}$23V#G!K1NZwy zIZlCp^Ms`RXD9G~4Q=)>9DlS~;17QiVd7bP4Dp121KA?Vi?aT|E>_R&-yWR8#^30p zlpgKw5u#|Hn??9x5#GeZ$^M6h(f>S@&;k0a2f1u9A9OI*Sy2Uwe#swIDQ|(Wf8f>x zEb72d+oYuZTN3!c1Y2tDX8#B?{GS5;G4!9Q_&+J|e}dJaM_L5kCg@g9Ex~itNHgqz zi?EYtC?59TJf&TG8u3l3_7C|Rsa)W-ou`XDF7UTcN#eg_ndpC>1OBgd!yjRWf57Rp zf#2Ax9RF|}{iomQBj3R;oeSR+XANGVv>0n%=5VV0)Ni!A8T$bZ1G2* z$Jm0tpY^{xIKPp<3i}6T_Wv9!>y-UJ+s*!~&Smz$OUPn-3i$8ohCjk2OXMx!f6(i5 zLmnD`nf<>h@ZU{o(7xIP-6d#{(*kL#8r=!||2t3bvQJ|;YJUUv@4)`|3jW_X)ef|` zd0raZBCiYlBU6+3&r9In44(g)9DnPW|Bo=Wd+igH3w|92+llBuL>-5qgO8oQQs_Xk zO+_CBJ%2>$q4yBWr)%vZykCSrgiO+7kSW?t4+t|oM4Y}CAyfEk+WUt;1vw%b)3+W8 zQyS>ufS_Lq`Y%okY|~WjOJM$mz~Ugqqa8%fZ`b08|GZl}_>8C1Vmw{sQ=tdf`AI$e z`zqcJ91o)%{E(anpznmOBFyw~+zDPSdgL3gF9=;|9UTAYG4fG>$x&W@^m~?G*ZwWS z--+-M9!}!V!odGqj=!W#!`>hKkZ*(zz7{$FWjZ)a`BQZ8Ep%{5=%9JVX*xJ5+kgF3BmiXg8m}te>k-$=c%zyV678x zX!k}cvrr$7GNL~d{%HFKm#++C@dlDfcKM<|IkA3${`p5<2H6a)6H`AyeaHQRXWMZ_U^?uIFvwatjkAwkB@QDytt0mykes%EzXgR;`PKvitq>#9?ru>@I_%0{^cxe z^~Z`_zPB(QR7>acIfa$suEz_3G0n$7Jy`pS6;S@fe9Wqsgr}NR`|AYHww2)d>Tb4=FvEV8!2So!0al`X=!Rjxg0L^p4=(3rN2-Zpt+t9N#!yaLV{Y{XAu>X-`&-$Gk1wLyj4eV%*pf?D5J*QS>rm9^B?60NtXeYPw z_(JGDUc<51ZsFLowd6kn`_&@tHIz0L`$9GkJ45j7xB@(TIrfD(kHh*MgcIu%| zWAL4v-`E|Z{|9CL|LrWl@I}%8|BNGoUEvMF?q-ys;5BCaeAL8+3kFk418+b4=24j5iq5r>| z`hVzl1Esb8rvG{7O40vZ0-l?}bLtq3F!3DOLVAFWc49vfdtb38F$OnM*;YONIOikw z7ou2?evH=@YvA$GdLB;B!&n&eut&uhj63|;82pGBgEtEufHECCO!-sB;Qv4en|@yh zZwPssW;wprh4xV-SJ|P|alF|=7!|KwbPYa&63)(8^Q=D2QgQ`6V9Xug) z@O&a3HrXO{u*2n}JpuHcdhD-g3){F{+Ez-N+7_&=EzA`>OLp+QvzrbOW;*!0(7~_R z_azhL@^!*MA$FFukvux58`2e^c5Fdi?-Mdd@cHA&TI4~J_b~R zvh}zZDSwI%PCy4Q{JsvB3VD?2kY`^v9U#nf@UF}E6Y1b&N;`Om)ul)Ga$civ3%W

Y)hjH>n~bg*0K-~%4d`sFsRgV_6g9NqxDwfCTdT|&P>N}H+!zSs55Qr-^2Q^50= zTnAR{?XtFuFw?;oTnFAWY;-=mF8Vp@$DVKGGv3A&33~YyeEpN9*CU@0wdxkdsIva` zV-f!kqJ=uw1=gim82*DA6A|cWR*4^8|53LV@qQCb?_EY|ZF0ei;ZSX}u zL>lx152C(ApG0GWF61(w4Y>|?(*?pz7l&NF{zIS(c>^1l+1PMU=pxQ}jm89x3L4?m zs+d$wgUn%}i*I>6jmyykLKolg_Q3j~uc3>tNG|kG|Dv?1y5M8O-GXOj6nO6By1>}L zb%8L`h0b+BXObg^4L%29|1;_#z5K-6h9ziXK4ttz&Qt6MUSIS$QM8c`9v?l%!^!@M zh0#A9<^2=uo4)7mBKB|5H-WOg={w4s&;`Z^BXn_uw+qq(jS-3QVUv(6SOB@w+^5gc z5N5hCxqau5E=(!9FuJJ?VxNf8fXaeOf_8B^tid!@I|*H!5W2|Z&sn?pRp=ta&HPi= zF4En;_%EVe{D;a&)dg=C)`a~G1<(E6Y<@uPf{oJ%lk8eQH}g+DIM)zK+u+msx_#6Z z$oG!ry4ifKT1tm5EPA{T<$>;Vh@yYYW@YHwnLIvr1`qS`+Ul?5VZYYf&H5?kfAn$# zd(1a`y7^oUl<6Xi&TFhPe3I)qcJg!k+QyM56?lpa1)5szp7>OeQ2D_FTMn7>*GT?}Ay=+Qh%`&(V? zx`Ovn!EEq62|Q!0hAy~&fiPwc0XOZ7TF|uF!*>$CDmn=Wsn} z#R)wC0~_=(h1-`lnbM}}fsfbA1kZ{IJkR58g66@jO(4wL#HGAVXgxRh;+LR&JZFB| z#iRqgr*;vggYPt#=x{wYhu0OqkjKYn^Kf#$%)(ZGd=_s9b|n+zHQGDFeP3 zBdS2zoUN4dC(epn^=e0^8YywJc|5fRnro~Ta@bBvlfzeb!yaLV{ZhB@6~ew(3iekB z>@TM@XakoCxKavE` zO*(kKt{e6UGwiPw*!SMxi`AUMKE9f;x9SJ4;bq6JCW<-RDx%Q+N**6y!Nc7Ci~P%Z z*dJdmun+d&*jEees|5C-4EsvTpMrf;4>jUA9s52)4o3&%xV;|54DJ1-*$=E6#aqHv;>$0{eA5o?*X6V1H){_ICjL8wB>(Q`+BRzvXh# z{~Q6&_i^l#>njK|?C%xWp9#Ca$IaG|Wu##@BP~t3es|cTxV-b)qaa@~6|We^JPx9E2PXcf%fGhW#eD?qf4y684HTeqO~ipW;ZOSG9N z!dpbRNrW4DIO&_RaDo5evW(ltXD)DSpMX>3AeeI z8mZ^_C)Vi}B=G+nvb@+0e}ozSFSvdEhXVgTDfmAx@ZZ6CjQ&;7=LCJ0Q>(4Fsyzez zpBDJP!s8kK+XenFr{Mn*@NX6PKSgPOi+|)YF+cbRcz&}R{s=StcMJS;G2XRt%*pm6 zyZE?!Fi7d(&+jCPcf|ir6m9r#JU;RU4=1r_VPOBdo6QThD!uU@5AwZ6wvV-<03Ua& zK-pT6pOuqbD{?z}tC3evxBVZ498DiUj{O{a3+@|W^Bja3_8-CrCG7jAVE=)@{(a74 z^gTiM3HmOlR^<#;dk5I>71)2oV9ozaUSI4B zqR_+VJU;dr4=3l!JnWBs%G&^&5ByX3KA#BR2bB3fA5-2G-={x#`3LuXy8EE2kjvHv zxxVYB3xt_2j<|h`Nf&us7i`bwTUHm&{c%2{UkiFz&_kSBgJ-JRLFghbba9l&voRnh zbn!jx6l)c1KJahoA}aJ8p|q*G;N!13VLxwx=aal0B-iZ_X6@hvZwJ*l!yFla`M|Gk zHb1jM7tvq1E<92;n-6IJ;XFk-^E!5%g@D+I>O4@H>iVi0(y`UYb>9_aCr4p^Twz{C8|cpjz0IMAOc_HX)$ za9BP|H4pm__VKWNn<`rl^oa2w$HT{iY!920Re`cT=}eaYRG(zdQ6pz~PV+-Q z6msBg;>qC=-LOZPVL#mCdxfwcl7fAaz}`w}fPJB$1%g^Qwc7fqni<&V3+zYpc-9Vv zaqMHGJg4TxBZ2);;vap)5K5bhJ#PnB37#F>!1L5@*dxraKUZKs6xg4Wg8dYM{bWi9 z>?iR$;uA%9f(Vc2;UxAv>_2$6z+UOYu^%U}KTBW_%CH~H@}I)q(MOGpIUV~oLJsre zkfXF4_6RfVOFX_$2>W3v*xLp6#gqov+XS5{=nPJ+O0KG10PN2f*w5ne4EyN<`|=d* z%YglP0{dx{_P5w~E#`KwJOZ8E$38j-*uf840m|0sE@b7L@`IXk z)yVAAvCm1gUmxVC?1nwU410&i_Y+}nPQiYe!2T-EWAqP#UMc8OPOZVds&)mizg%Fy zoX0ai=rWGIR_zgcX27Hh*e?-j7gO3)?71J>B(QJV2%c~3X7>m)?AHqHEwKAFr?8LQ zAng8nN(Z~Yj@J>tR)lLrcr_0v?VgAI@oPNH52}{>!4E3ZBUh81zz>iZa{YsYq zl--B>s*x3^WB-DX!?6K!+|>1NH?Rdp7p26SjFLr2%Gl2ztAqw{dEf z@c#F$!2TA2r<2Ds?EfgRS5mNF5A1IiX>X#mzs0^-@ElaY^Pjt6k1)gj0fBuXu)iO2 ziT*yeQD9$7=`gyKemDQIn}oQ=yQ9Kzn3V)u_y9l-n%RtL`e3Hq?0n>e-F za4*k8!2Usj=i@w{^*KJ#=lmt5&v^{kt3t1Jlr|N6-rq+S3IG3Q@cc}-J_lij{nG;b zBCI=X_xOqg_R&_t9+*AF`8fC_QH(855XBt0g~vy?@%ZGr8w+FIZL8>Wlsvxf*3A2y z*cM^;pv>QCqWp<l^aW0>3hqmK9@y^?*uT!>nV<7lj(zmC6h9{b?4J{U&a;#@6?@_T3!bHGaEFR* zgD?EP$ETma!FMj^Rt96=T6TBJdxQzjYVGs*_$7%}uE5LRp}Vno*9nyMS$|{s{gF2~&UD^}<_nvV_U?rImC)H|-E@X9)7hsU z-z}uGktsU+r_k9alm_kQV?qBR=trDd@y@9hg3j87&c5XF)Lvryxz6HWB-#tsC_eZ2 zVjnWT_2>tb_P6`W{RPjCrQrFSZtVqOhWXb5^HJ!l4g-%wUv)_IRR?+5u{crqrZEwY zig1L7lYJEr`{SC2zh4s^$k&R(WE)s>I>7s?Dp1x}eMR{b?Zv8BH4Rjw|2oxPXnkX( zki)zPa{SZ{dxRPGKSB<|esl`? zoDauc4@}=CFP|3}DINMO15scvi?AfZT~xPKPh!u*{`g6bJ>3Ju*6B`gUgN)taRQWK z{|l4z)S03%_KyB@3VUiJ?+7_;7ebC)@QCwVn3M5&Kf(~p+)oXDm$ z!2V1@&k(dXr&ioir1io+c27zVEc)|!>Z=ZBdHEhqKkupYTz$R1cn_Q0%ZywSoO?f51#>VYB%}F-8pI^~Hzs z_}CC0POg)(u+<+M>}B&ZyKM*`rw7qqGRheU{4h>02W9JY16VnJldOd3J*a9k?tRRo zGl{rQ3SsJdu1Vm30c0894S$3g{%3oAKN0@pQt%%q@IQ;v0RORqjuCV;r&hWHauo0% zDe#}f0Iz!oV0z8Kf(-u8^=F# zHpc0hNF&~XE`!Ww>|1Ixygs@wlKD9ousphUKCdq}U4+jQ;b}aa+^^(ee{8B(tWSXN zbBSl{SDpj?LI;(gY`mVr@}63s7>~KiWbg0pSEdVHgvUd!i@WIpVWx|VyuSYV(8UC< z3+AuR74|xZ(m)p%3OZZRS)5vNm!wt>U6cu3%oFj{7D~A;qL<=bX?Cs!XB#hpE=s)o zY>}PP{#F;8gf47j!1GmH7g&Gbx6E`qDM6X0T^c_iEECoNftCFpgU%~R| z+U1mCT|yLn<6<74Tq|N>i$A(3p$qKKFXZw?7XW9{1t>e;Qo+hPrHe_>#r)sb z#a1DgVuf6*yXgX9ri*L5zH>+ylT+Ho)vPW(x{C7|T`A}aL6>uC#r=_5HFQzMdDX7t z@vL1`igs~rO1r3mE*zp=ETgo))x|`?a~R(+3E$aG7YH+5+#z%^Md;#oq{A4R)WvP! z2lq*`HPl;K9zA*sQDFZ^qOh-%u1FG7o@UcX!hT!b}$%yuQVxi*r+S;T5{@a6Y4ML0y76Ikn=>M@@k))(c(S z$K%=fe3xh!_j*sQq27Zr;!mRNb(HqEW5kCQVtnoco*(I^3xt_2HVa)$6}osB>ENd& zb+L)Jz4${cJ>FyDb!k4L(1Xh3wK^V7>VbtV{`jBqPHG1HV%$~9`qKyK9vAH8-!F6l z%5<@jm2*lL)1Zsm-`B;zgj~U%kZW5vT_DVKvDNFlg>-RViY}T3URyY?(I!C~1$~@T zi>*M7{RO&sjCe)A`XrAhT|^sz`xE556zX*Toz}Fq7O(GMJ(Z2|;!#RF{5R(xuN6F- z)4}u0To*J3v+){Xri+)jF0| zZeaCS@vuMkjF+!xC zF1OTv{1*v#r%K!D|L`P9y#wVJARm3BgvLvoIW4dr_j=BBWCV~#J^qWWl_<-fa+mfG zxZm|S?sug-wehW{lsmPhb{Xf0B-|(Z6Uv{8b95Ar82fKOm;5r^do3BIK-f57`|I-| zn|L-bNZchZIP8V5Oora&`ztHe*ikM27CUw6@_ z-WSX7iG|F#W6^**;SU6kgTICFr#OGP+bzK%DwRw3mOhl^Eq8lA1$TBMPBZq~-e1@i z-IGUnYv4-`n*v=W#LI8*VeK;F{&C#pcYJ{XxEpY1tqjcM)}QI#T0Bd|>Rf54YC)NV z)fC)IMD>LkKY82rBtQMP%kZ!0{_q;aZ2?B4zXV3M?6iOrc^vqmeDGw4%@m_P+z*R; zhA58d@-)7T{4QPa#dHbYex|#7k%n}bke&Ft1a7Y!M-!v z33sz39sOx*x;i;HRF!s|1N{3k8E=P-OxGej06rwy>hXCeHaj2#;gE;>thoK=ZT}bI z72rU)^@yvZ)x&RC28tZ+zChX9>+)}GzoXZ9Kb!gp8|tvSU(8j zKHZOShwg!LiSC%)FX2v@;Apy2xBvD7xKsB4?$kYiJ9R&^OMwH!rOundV-xCgWJ!|` zv<>nrDDzX-Ab${d3)`?xaRB$*262b&N4R77fMJNv%ETQpLEL2dMuwbdU49|w>pYDL``2R_1hKzGC+SdI6%3k0&gY>_il_f2+c5Q<)G&PciK$`u&*M_VQocHx zhxhaR`RZ_lVc+Nn{`c6C_|^jKv@S*F{g8P_c1Eie<`x^&<>A@qDx;u+dm_h%2_ znS=7x%?UX0jW6n-V9PrWpxyM#9B{f$6K&)v{UGjzXp=xEgYC=1?9O>ja z^`R1?bL&G(@Z1SX>6}QPei7%PxMsLMD>z)uytqD;eo1|Ze1KUsBlWxS|B{;F{`5;J z&j^2uG(x4c^1S*`8I?I-lnF{@;yd>txuQOF8J;!ZPEdJ4eP}7ATPV_jG9DMzhlsc3 zwh^jvaeYW$QXeX}K&;~rQlOTN55WG8xsC-6jkAG-Q~EN>TjV!6h|dDu1zG}`jFnWj)o*1u7Wgf}5i0Ry zsHzVYBi$5?JBDiTin15g;En|R51si9%Xv8#oY6C^;AtgkQ0;@T7imm=s9=|;g7j{$ zG5cKzvpi$#LkmgYXVr(8{>QO+-Eg*`;{~0-sZ|=O$`hfNNnBr~e|aQ-M)pvI`b?8a zCsy4wh2lZa5%gRxmj@K_e$!OK%&MW$y4s*xvcXFTlcB(bkL?^2 zgc&Bo1Sa_c6En|iun1ZpXrZ8J*HpFveF4)4D3xOzj`Gu#kVP7$+DU&SPU+-E)Su|P z%!$71SNa7f9l60_>T5`ltceJSsJ;P;@(7_PYp_dzFnPf#J6dCqd(a<_*gBzgL~QF zLFkW^&}Op3yg~Sm_n_?(#zDi;T;|tqLEijH(lPq>w2W^cNgr*lhrfMH#y4=yzm_~` zK5DC#el2~lFk9NE;hU|JL3#=IJXV;@xWj(-Hd8*n2i*Nv>X35mCRRT4=tg?*gMNy(Ck9qzmV5Es|z$G1+#TaVG=57c40z^BZQ9S+b_d(iZW5 zL7D~MSLX4SQ~zh1)69s^lZFo)k4YTKo{&S{dOH6_f`5!LFPXr<{m-^mX?FAP^1l+_ zE+)R)z>g=}(35zt1n)NZ^%i`8+p| zMc>84o#4{F^&$GUh8tAwq1f8GFMUdAoo;g-o^l|FnC^rm$xTJCg6` z{j}+BP<%(vi8#Xp^`YDFjXdgq24+ZVaa3-f3CxTeVB^5cj_+7j;@e5|o$*yjZ+8#T zi+?SCF#XSHpT>cDv0hw@K5Z)5>GWUi4^lr=)d!g1F3MumI}81u9ql_CHl=_s;-7f8 z83*gqdd|NSl-a$4{^vYy_auYCNzV&(*~OmY&UMV!?&AGI6@2polF7}(@}F40J(b0I zMBF;aK>eaLS|$FdJ+bFrj2Z5M7>ft#m$?V&m%9gpM~i;w;uD*VcOWlxD&JWja-`cj zml}ua%iKft%Z$VH%Z>TE4Khi0ZwQq@$0n3XGR<;drmr;EI&JP@x&%C_ENZJZ`(xFzF0mt@#y$u!nR;iJXSR~Rx4tS>2qj>!M8VSRw+*JtIx=GIBM`RC`Zt-*KZ z%#fA(4O=enGnSn>2>0fq-)O>Jx#&wC1b*w#=4@Cypf*QkNcg6`jBnY?Yl?f0!1tch zvoq$d!u$*EEmVkK9De8WENLO;e|5GqZR$=NzOe~^TngvF$CcHm(O<#WLO&;Om$qEm zV%SpLBFmTq$eF5)@2{D*l(ZPP*jv)Kl(nR7DQ)TA?OxqeaF42 zxFrK&JH8KJ61K+;O(iXIlf9)hToNw}m&Q#^Wi7_0(w6dYS$tl&JT6O_YI@VGmb9kw zmTJYI&JWLu+odekga2oRFG17KQt=V$`NaQre4C!?sm434EoNyx)#t(gJAp@{zC=AE zz(X<0rg~M^5ydbOG<5@J&|Mo(+Gj58?f) zI{6khuIk1cdHcQ^{H5QDJ^;2WudNTwM&EH^O|ySE;^`YzhTG~x)Q%U{Sf-YvUofnJ zFL^unzh)zz`kXmvpM`S9KI%8N-d2tG+-#jxPN5_P-1|*|Jr`jty#{_Qe#Dz$wdi}` zKeN83hIoSSb1mmdzPdhCl|}bMr}Q7!iT-63`4bl2=Ugx1R-Wo}lKssM{MnPJdowP| z<8z_Xfcb3r^9R6xv8Mw2H{72`nEFBs`gCKMmqq>PCiwG4jmx?SVPk~Sfkp+52^#0L z6yFyx9;^>dPWtnOy6I4T$c-QQ^9$jp4W{wG2IIzIlnZ};DV6s%^|^(*{0)=M?*t`& zoJec>HsQ-#nJ=Gyq&{T&F5$}$*EisQD%bRH$}?Q}@>X5`Uik7yMVX*f=4Y@6`55=F zOtC4W5Q7vd*NO*>H^nhKwod_DQN$P3EGiXXV&&;0uzk@qLz--ALYe)(rg2ibn* z<;%LzPp2pcl$G-zUXBOpXzZeS3HkNRpN2nAetr5$%7bsMbx|J32YNZiH1gl=uq}hs zz~ttBeW9OhrIhSbZs7KAXrOrjzAMy#{P5?E4akq@CfGUVw&d57?KP5ZzRNJKqwhO- z@IQ_3WDACUqVD&^nD{=~sZ}?8z~s>74~e48{XATW?>Mk`(iY<7E1b;Z(O6x?2bT+oFsF??t*3@ud5-&sjNs(-$10 zv@e-n_me&e7t*B%aq#(ReX7o4qx=}-_wss7|Dtw@Z}h!G6ng)P;tTXE5x0c!c|+g> z|K5ZDllc5iwLp9-d_FlIh5e|A~iU;e(l;!rZWx;=ucM;sI^yX6vw40MF~ z!*jfR`L8_Qunm~)fIXu=SJm|^PRIv+VunYfFIr0E1r@(KY$^B~MK;T9F?jXXgkonZ42YE2Z z(GLG#9>V`8dHyr!#O40Pa_R{yCrP_wS}^_%W&-HG+D6L;=m#Yj;zOo^+Y@?G1)pBG3O*dQo7N7L)}WSxZ=skkV?&CohsrwF$p`IQ;S+ z+39nifL|WWl;&&3wC$8Witj?!!Z)XNzU}ZQ598;7-#4eXO`WUds9E@a^ws!gvPa6Q z&4=GR7ry#8#?0;CV!d=8eDz}Z>ZS12XUm!DEcogr@YQYb)yv?k+q?Pd=}7N^54uLX zG`>o+#j}w&2YD*B;PXu%3-bf+ zpRd$r#s44b{y#pd>e~Ou_xwo0&p<*57!op>1kj)ei2PFFWP)I!T1CX4*GwjW2$c%9 zsHiYWAX;K6Ct9^|uS~)Z8+x@AEY6|tYknZqLZu{HwBB2pnGkHTT7D?bp-Mi_b>@ub zQtfT;{r>Zv$74PAKIg3c+H0@9_u6}}z0aJ*j$VvUPJLcpC#7obbg ztIW?=e=$FI{zLO~{(Iny`FRWTa}RY|pweo4;%|ziH4anE(+k|HP1Cfkmi>|SlvdK& zy&e92A9$+e0~gL3#~zLBNxn?_rms!q?}3rTz$j; z;GgUFzwpnwzQR9;f9Id|&wXL@ZQCyLm%Q+Zan$Kp?3keD{FODZ`n0Bf2)?Z%d}~$H zgY9?jonSaj$JIjf#W&mm%hl@Vk|dN~}?DUtBoR_tzn2 z$2DaEPfss%gK)_MJ&zD=*f}+m23doQn^QHO<75SL}RMv0m~s zFy9B@BHR*cMa{>0QVd~y|c$7JH)isS%@!49>)#bW}dY1p;pNfyxGl26; zjiZ~u!W^@O`j9_Juc3cSh5cW2P(}WO-|fj2$l;T{OTT; zyX{f*u$=O(r7XWlRT)R1Pg9jXI880B|F~<8)MqyJiTzo6A9{{TeImDux{6Y#h1Au9 z^othiwZiGDeVFzh!3XQOPd}|beD3ru!O^TOUA4k5yfWSipNwZ&R$aTO<6!&0_MyJ{ zp6)}m4L|2(y89fv$Gg|RE0aksTtUG@=}|~C+$jOuIoy}`8+oL@f>u9Z|C30<0hW@K@RRVz(aze`AjM2>8A5S28y`Eawk`oIem>&OA8T zkhXa>{oGAh^1x(cAboOm^Jx9{sd?rg`pzw-d8YUc%Vy-6Z=r*-S$U>cuD_LMieFFN z@OXRK&3WduTk{h0wpS(_F0fJ{IbX1)dAMF$k!P0ucCu0S{$%5>U6YMl%ks>-4o)^o z7L)Ef#5;&Tm}g2l*26n0)Cm15d`+UO(ns>l0&Rp|)w|$uoUTTt5KM53e#r2JHV1%TFjizP)+oZMEFCnJ&ZPMfzG%nt5P z$TJ^8R`H2Roy&Jy<$J2yos$eT68Xy}8Mp6B$XT{&l5xu`$o5O93EB(&3Obl;-nMa) zQSv4-znyFT1UwIAHKi@RGSLv*qwSh#r~!|+`?N9o?Pa;lchN!iV& zO#D0017JM}U$Xp#B)HX(91jCmP=v zk;@upqT#!o>+ei7${wF+T*sVq`W2LGF??6$nlq;6n%7ptGb7iWd&M~8y31M9%*r)y zl(r@P_DkQ>dhtDpt}gUFT_a_~?r1mLYnoeG(_D^iSesbW{AhaOIc@oHIb%X{-r{FW zC}0e6;D1v1otm+ETE#dc!aA+&9xx`z+K@TORfNndwNgUnzS<11pQQX#6ZWSZ{C~>F z)Z-4b6yHgAAJd2U9)j4Gf6B+ic(Umq^fB!h9}_;Quk$he!~P{O{;q$i|NqUuBhTk=fXcR9BvXWGu<*GaDF~ zsb+krkz#eF$nt|BYR=TA>{GMY|_1@33BIx@T&c(IE;a}2xdF_qx{EGVvn@86QesT_W zi-lcOTOYZ;b3bWXp-hYKlGD zB6k&W7je;($RK6g$$t4O?8DCo^BsJ6KPUZs@P3ESum^dGF86a!^dowBfw<^lA^f6; zx9}^@bh!05qxclTJc3_wAHKfDC8|y8Y0;-$b3`9f2Xar!Ec~k+>XejS%00)zFRB$; z2O!hJ=1Z)+L=RHNdB`K>oDH9syhU~?Z#CCjD6{BI%KIAE3rO2axQlY_q+DxwUP&HL zgS8s0>PTs46=_E@*G<-2GEBCk>BuqD;m}uuBf1p1M0blbIMYL3lE363a!GsJLisjR zt_I3ePhMMt9_UMcHw`6Hc{zt)yA;JBf*IB{J6_qoRlM#G1`YuxM%Q= z_$3bq!mAuT7uT~_(2uoMPjx%@z7uZboCkG#Qvqi{D)CkKM4#WsZ&S5GGk%tWz1^TS z&H~^2@a5rA4~-1(gSN8A@M4P6pLF!7oteVg@~>TUenGnDoSY$I4S#*MnzLzzyf1|B zfOACKvt+%N*o#P|Jc+#s_M_}GLP2;hW})A_Z+sC|&XUFxE=O_KV70WAI&woJS<`y)Rca+FqYxY)bZJm!jBHjJsl>HP z{GBa4pA<@=UNhzq&fxxf!V0z3?SuBShm+J_7SD>olYJeH@Mib|)c;H{XGLq@QXZKDMJm8h1-8f-1ViNWgFg-Y3i1`q z)r3{tll*2~U}L=CddS0vK1F8^;*zIZ@?*baKU7NmefB(j;EPPFEm`Z`0b4io$W!)Q zstM&h)O_qrjQx-;(g)K^8n?*)Qh(KkEMJUEN&S1krvGq;6nyf>?oby}PxWr4P4C=K z-;(lHQ0}d=&+^!#Pu=Upucjs1jO>e4rIs{$oFR9C)PcsH57djc>Y*Ld#@d796=z`? z_s1$3_jfo)r(5IxA4)%e7Mruf;t`wUFScyX+uU!aU3+}$N!oNBVL~ zv$keCe&R9*XR7KqY`s)zPMvfueWv|nv;k8y5s zJ5}W{UeEIr{mZ6clzK{L6xyjOW~YZ zD5V3Q8qGDVfP0yO|8mJzDeL`&Gr}cXb*TP{>Y{0+8_RRrV1|^Hc1XKua7&ptudgfe z(axmJoqTISXU6aE>6CVN3HC$uxCnnu_j1XZUaJh0OWIlmxIZHlnWcP7A(2ti-}vv^ z*2kf3PgfQNM3?Yxc_LVJit@BjhO{^C@0`A+WNU>Gc~+sflAn}p4MHN5$RTA{zb^0m zwd`*pujCm)FMqM?@DQPk`-=M_o0LoHPvk0)I$IqqY9%b!9K$xFi%YP-BB#`W^n-wv zr$(NfbL4t8l+3e|JJ3XAQ9UQsNHyJKzgY zezkXQT*_Ve(B^OfX&eu6u8VuZb1gO?7k{xEKeb>x2_vK{e8?Xbzj1+|bL?d)hUd;; zdlT=tg?O(`$vcGj$3naVXT^hKco#7%uE1()&4OoOylLgw#-^25i2oSgG5Rm7xL-9e z9;Dn&zU*)l@9xz*v$>ZY-^zP?E_}Q$e8^$m_xoklpl}oK_2D}^yp`_=Z{>Zzdfw{` zRb3R{?97R8w(`j#eQwx+ulSc$IpNLDA@L?(ZWw>p;R-uv{s z{@6~h*eb5;pQtH1CjD^z`l6&A@zNI#gCX{@qMLox=!1g2fUp$1QEAx@y{H7N3^2t$ zN;A zEGiOwo_Dv8e()3aQUAg|o_^<^&eY%C|2OtA9eKp&4=2r1aHO14F43FVMzNP7v)IK_ z?9Tm=*vA=Pl(D8Lp|36Oldn}+w$bs%J)L4J{~7x@oU%!tQSuY}Xyx0@K1%&0Y-GYd zie21H`IGi(^J?2ZqW=mZY@yiA666g+U)aajvB~?&JH`lSRn}YMO0bVkD3bQm zVKO#XBS+Fc7GNhrT#J1yw`^mB+e`i~@-HD2`{-I-Rpi4ymR^^zk0sbg)&yHCUJqFI z5ntU7#rw%(6PqtlZRYBReHuDYc-Q>TFd|oC0 zR;O9LoAQ{%y`kmdWW@9khRf|eOdZMo6{_F&ml3^!BGse5zTqsxnrug;5mWIt-vl*Xy6rZ!@? z48{vne4n2pli2&nY-L2OG?}Cskg)G+9D8`#aSa`fm%YKg**qH*pSo%s`;r3_JbZ^+ z_WL}H7gMVT#wS(_&){%`G*kCpL_8-xwRCVeF8kMIzP41!CEd#Op^3vFGA4E0rag(FV(I>GPq4GKr91|{;~yV#K`%19n( z8Q;3jPi*Y+4dFTO(DQBTuJe-`BhFk)2XUv|&kcvhl3!~s@w|A%=WILY%!}9i^26UG zzfjd}aYfz99HY0J_TufWOFQ;@_zw#!@BZOvRsZ-|#^ea@}{t@FH z--)go5SRZKi8=?`V;%bSskWFiE9@0r__DwlXq`9hY8{9i+3|?e-4^4W{HQZKUW^=r z7}tX2EqiBQ7zfaZJi&xY|$l2x% z4vC-C66KWsP(r?;9ETxg&e!^f9l`$bY?Tqu|7=WS{$~jt7c@`Q9l-%{tDGt;Tp;Dt zvf#~%C-g80J5!amcM zWz80(FRjK-h+Xg<9;^QX`>~pH99vgvPi=nGwegvS6=7NP%_9%Ly@vCovYx|_)C1mp z<{jdT!B;W68XWO+ImyFX-x1E6u9^2L$H59;!gnM7ner*x-|Tbu0&BuU-tZ#mSj}(L=++(;prdW?w#|%bC6SAahXRWA&^{S@5T1us$`)9BGSBC^e^d@b-8wb!Ys0 z56=((6!{lD)@$SVdl!ZGqYocxdNBWQVcZJS-WX3fHWq^q6Z< zvA=q5SoWBU9=bYQ4!(!*70T*&-5f6;rI}YgG&wvNlIsAx1^(dd`RoU++B+n?it`$) zIIrP)XoWS0_E!%Ht8(kNNy3OaR*&IOAx0cqI2{C>euxY}F>~^YhvN zD1~nXJp6Y_gW!~5Gai6k&bEi|zsAktZLfv2+mS>pnLI)PF1eOwe-mmoVAvFEQ+o3)=8cyxH9g@dggNc zS>oq(ifOF;>)q>_Lq}b`x94*{ z#|_^pSHJB)#ou#X56#s2Xy*J+R=#-*5?|lrCl&tl^y2&+wKT<%!Ykfswc`JLo%wN) zIrD4GO=Bwt&8uyf2O)g@MMod2T#hI@P9VA-6bkRd`7|}vPybM zBQlB(lk#b#7ukvkL*UDrVGH>RrsUtjJ<0Dv|EH`slKPagr<0#sgSbDYDskpp^6lS? zcU~z&1-PpT1wVvdI-o7&yA{7rl<<8*@qebICj6fo^*V!ky_h}G9vQ0bebwW?`9LLq z@dq(BEUhG;)#NStSZf|FvA2-GP53`6W$mJR*A}RLwKbdz_uK7C-s3DKuLAIVyx-A{ek+Hl$n|3wXz4 z7<)GRRmwrfVD)k_KF@En$AlmC)G5ZSKk=TyLH1T>^k-%T+u_nb zM2832V_n!XruK11M(>YQpWay|GuFKB=+pZk4e?;Yj-<<366PiiyP zENK~4`#H~EaP?u2b;g?Y?AzS~e>%^P^ZcHc%WD_5TwEI=z6@+9JZ0|a{i%gDrnVpHj=+10drRQ|g!}cpv#?p-g#f>S zz0Hp;-qE!?*xMWpe-G$Q(tHP5GDvrt=cBkM`JUqb7WOtn>}%dno?D~SI)BE#W`AT5 zdA9M+#39m%9-^dMN*-y%T|7Un`t+7GUgEFtUd3+SqqwhSZ0#q=unk-(cN`h6C$E=C zPIaEZgMpSI+Xwa|SX=JuXBy z4#HiOYbWKRedr(47f;#!J{Bp(27UGZs?>w%S9Ep>`>T?V$R&C^h0bQOzuIEuadEBa zLE1|PJPnjj$`V5U&B*^EWs?2XnfCtb4BF}}+OMMR{;_#X?HKZ4-gio|SL-kNM&~8= z{;K@PgopQ(>KRK?t^L()!={l|(gp4PRZVd0{`*z$W=+jfr`FOJwS}yQnIA}B^bp_7 z{KnD8v61o0I*ZR(wZTO{be$}%t)LIiqYp9HHq5?KtN^o8YZwUNU1a<7+N< zi~bim8XndI-H7d~fRbZ}gfcel4=Q3H|8fk>zM>^4g?6-EeWB={FtBL>JhTX^Bve>X7Hq3<$ ztH6d8p&!P78RxC{(~A12jjqHPugkOUx^kc^2R5q^U6rG&6xIVSbX9@9Vh?uvDs&}t zIL)n@kE18qYkpt3bfwb1(2?vf%bp!+zH)!L!rosN3`w8VOEOfpUMlSUWe@FStEHQ* z!%FNl9_;(q>EwUgHWpA`w@S6zhM)3w&^AOj(l)O3B-+KV9t~!SJ&rJLZM~pfB;^lL ze(}jE${%8XUB=81Z9~RoIbWdc^3MQsA9x|Kl4&K3Xo+{ClwJO2+Qw^?-v@sS{EoKa3$`~&*jYFVSH>{|IRv zO*}s+&o`+-i`O!z7aU2K3YMgiJcRF_g$u#~{4{}u!^8J1^n{O*Cdj_M7x~J-D<*9R zV|WVvn)ed z4k7Up2YV{WdIco2mR~YYP82 z>E{0?U5$Sn;k@s}<&OLQoTf$ zGIM(Wad-$?37Df>ia=0Pp@#M>eQJTsB;+eys3I1mZJN8sd}fh-S?C^o_1A! zUKzhT{n(q)ewz7EyE0cDQRcjNmAS&1I;ng=K0DgeB>2X$ZrsHAn@Y~|ZC>fv$Xa%N zfx1dBe--=~=lOiBbLIV`k4tJNV+XS-pTd@|n9iC1naQ(s1GX=}0a<4&bNO8Ixn_z4!B!`>)8oinAm?z`rH?f&(dMlrpp4 zUq6vHWnR%!|L$p*o;~`izu6Z|+K4LOUGdev+vAH<^OdmJ+h|aoIiF%{)com<&yoYU$B3L4{B*8W4QmkX8q4A_HJq4 zo2~!HnO%Xb{&V;fI0w<2e&uA6?m*rkI`MG^yo0{@Ys&PbQ)PVwZ=~a$Vb1o9>}{AC&d~Usc{gd|0QpviAHoKA8UXn>PHEdi^fG^r*{u zu-AFtQy*a8dUC#}=XFu{+kH}IEx<1{7M(1{morpl9LzgAvsV7!C6@N-FvmO5yGM{$ z#4+&Te{_{T^+VP7;9Ph!((?}PSe3a^JyDWh(xZH6bkM0`8yu+z=Q(;EbSf?1)x$s3 z=Pt?jtI~WXjrl6qGfK+T_aZfC!MUK}Y>p4xud)sv1Zz#U8n>PIa*wnAW&XEx7H5X8 z9UX9&KxHLr=`_OG&`nS&Gy^)we%^1Cs@;!`{kN9)_9f&0O8gD(|Aza&B+go>_6Lsa z+IO4Z+xPFpw-NtwH~#0k#h>jKe};InEqzs(%wrpTlE;(a9wm=tey?}S??*Q78_4uD z@on(`JN$3j{F1iWjvprUsXxr$s{U(!f%?z+tJS;nXFGpCe~j~;`4#Hz`R}VE^MyZ| z=O4OZ{8zX5e|C#Y*^_epo_JCZUsZM~w@>XS|D)vpI{E*O{NEz~H_5-5{149;oil&G zN$TbRbNZybGYdFNrV=tsJzgmHPwCG|T_)@6LY*h?Cv_%yiO!Pu*LRCQ)h%ArEgmF} zEK7apYb*LHpbV?kTa@FlU5@>fqj`QOXQ?7;@BBh%`}|7PGT*26&G&P^gt(XRn|Z9& z>C;J>yN8Otc))IdPvVEwTAI;Y^ZaX>yBz1g!uDU9y%E3fxc%@nzy97n=M&BIHU3vX zv;Nbrb-u^?e>-nV0cjHPf)o$&Z__sx(Et5C{X?Z6A9%FS#s$~_|Kj4$eos6VJJF1d zsBvT++?JkNdmsOGe2{siR&a63zw}cthdCecq4<$F=R8vW1CamqJJ?gr*-o4Le~!%B z(w1NE`+-ZC4%X01Q?+WhO`eSzzl zq}A-}ZT7XtzTRSAhwSUk_O+@?q!(EveZ+oVZ(ldt*IT(3IfGn_Y=b$|AZ0s19Zuuf zcAoipCig`i!IC^AF1pZoCV2=(vYa07m2fXa7=-+g26>gTJ!qK!GQ&1@K1^&#s+$KIBGBA2wUMUMWpOqO1r$@7wZ zzuxCr{n~ux*+0K|@ubhB%`9d-=tVoxmQMTp;m7)HyxwjjLE6YQw2>ESBPVDhP4M=X zch1MCQ$MAR+-B>|MO#S5o!#ON;?iDjLx*dKlgHP#5osU2Xk-51zWIWc27jV`B(78K zYmfchZC{7%Ymq_tRaJst`>t_2pg=>*3$hFAzVu5OtawXeGQWm+NEL*ai zq6dw1iLz$aN_r31QiqZ*L|kzFkOq06|EYaQ9(N&+;9drODMO$)jbK){kvJ8P{)e7 zyZ;$@8o0NI(3zq;CNXEX-{0~(9foHa*r{OG*w|~qUI%ZT@VoU-CdwMFC;w?aqw&va z+UK9#Ii2;@wXCnEvA!y0edS|)RdV0wk6g$9k30Y7+ZAW<5y*Ed&hib5Pgrw*THzoq z|5d&>;b#sn(aeSwn)%8y%?vHqOxCogUgST7%51-LnHuoHWn9ZywQKvdY^Z<2v9TPV zP5H_c%V)F7>9Bk@_3iy#Sm;$_w$in{hf(RbC!Lbb-IPshi_zQ-H+oWCEN*z?-t9I*KMq4*W> zCHUC$3RrtytQ)@gZ=t7Wv0mxzgQ|KtXH~K16!>8O5AfN{9zeM zo@uNre!{*ldSl<~onbZ1<6T5p53rL@f-xE&i8ur4X>lRC@o za2%9(OZI`We~=niOxlB-XUFy|{gbQj_T#QT+ZW^Of82rJjIogSbC&)Qy~sOMkE@=w z-*EJ-J=xs6Z-k>)?I?%4_D}pL(QC}XK2q*lxz|PG`O{SUw_)b2>t`&5}thm?;-LVO+1Y> zZ;}2lTz^DoDkJ#CCm3V6KE<=kdFCZPFnYXGuCt== zcbcPeLHcBwQ@FmEXHxbw;-@3A&e2?d8tK4y*CK6Fo?| z(?};}mvSd`ge;U_>Rxmpx^q_o9^A{o@=P&$+USJFNd*?cl$#qwW@D@{n&mX*`riz70@G zUo3N7gxb`chIaAuWpA&V@cFY1?V9lv_OOAmcsocKwup+1*GQ+QwW&-hp}`wTtkcMLfAn~ODb1bL{{zWl-- zfuU`y@)&bY5Bm_G-5dQibGoDdK?gn)Cq9!1XIGl>wH)U^p=%s{4;J((eU<+tS>~i%?{t&#Z99I1@PG23NdEs<|4CARN4n`x^pun>sSlC) zE&KjD;^K4q4LaLTyt^-@yZ=P$FX2Bqg8$@q^TkJz@SnVi|K#xe3j9Ow<6HT^`A<5& z-haaXM*VO7C*n7Gl74X<8zKF-1$(jfu^}79C-dXSayB+EEdDI%JNZGsFMTH~)78uG zurB`0_MOb?lklBMx;x~^v(|FSxUA)paq*ozQ0@_Vs@ITGsUP{5AVJWMA*Kuf;zi&s**5i2c09zHYX!_i=p#_(85E{|o&iNm=B+ z;E7K}@{lybuaQpHr@|-C?;`YYPx1*73a%g0AP@9Et$#&l|7z=Oowd%*v&taYq6fiE z<|AeQ-}pxaSMm`5NQ<@pea&9~X4KYQ;2&||A34FgN!mmS>);0Sck)yVMg!N_ZV7pAocydiI_oW>q?@K$7cz2uEJ)ZE7Nc-sSACdOa z-9I9Akho6xNAfIRg!mQ`{*k;3{3Cf6_($?C@Q+CQNccw%;Rlg&CH*5JzsMr@MQ$m( z__lg+U-A>V68@1q%ReIgBAb*sL>PqpkOq06|EYZ>^(1-lZWWk$wN>~*68@z;%O9EK z5&zktuknu@_&ffQbi2O3Y#;l+rhO#*BPaM~)CaT)Ij5)5M%F&of1@8CiL{yji+|)J z+dp#X@AyYX{U7`zUxlCak9;slGnd?39Ikz=?-%X;>--}heXV~a{R{sHW%x?}$N|ch zeD=@#NB$N+=^r`HHxyShFJx}G^Z-5*N4RTF*IxO~;y>YwsQ&VsgkSwV!qIIJ&J=5M zhMMo3X`G)sbH!+Vl~b|b$NM?VT_dy$>ziZzzu;v<)zjx>U!Q$$70kjF%X<9&#J+cy zHjr;xYI5dyoYqIamo{1tjOM#~r1!K0XIES<-_!GkBZPcQFZ}HCV0&xk@V2+*`+D$H zj0)BjXjkd2Tn8=_9&bEwsU42A!{S6ZkMHeO@cp|MzIocREVb<@X=2QqEBF?k{NGj! z*X4ZE?=4KZoYr5;nXhH{a5hKKk|HMQ9(G$xBcdi4c4{tT{9nkCwRjZ z+zSyeA6?1)Vew}00%L-8tAkhR6?_A*IWx8GO|V7A*Le29xWsoDgM3f0d`hs+Te5z( zl&Mwlud(tEmlM8Cn!RI(x0PQVtP5NftlKN{O-__4Fv*s4qJ2HVz8;^rj$Ik76L~8L z<@<#4|6=81L_Ypky&1X21?xnn=JvEUx!3DT&I_QE4(g$N8Zz|_&fbE~1AH?uS{kfd zMHnEQ$9Dq*zF?gL-S}@D-ZpP)u+Gmte~IvT;(iTT$5tld>wC1VT38e>=XpA127ia@ zf34x?J+4p5=L-HeigF(=pB=1=-4v`lgS_R0T_W#;!FGAKOPG2m>=|Pvn`)`zYtYjD17yd&2?3g2U5{Nt`qPj5=|ut9Ac%$gl|c zXAn*g)|s@q=crTR_j4ViOmUtc3k+|oxHec9ncb@`%ClqW?w6F!?lJuY5l~J zF2_!K5gdLV{Jn=|fy67Vu!zLVGG%P$5 zos>U8y2q1sh%Sgr-a&LCvioc7I$UGjkNa2KVYMAr*p@rCoYv7!ma0C*CFUHQ0K2#Ma9S8}nfslTh>#cqpNdisjfU^dWla z+&R2$!S_TL^v?%vUGQAW6u45_NMXDgIb5U3Gc%*DlkZhW`KBptDx4~9`d`U&qh*s5 zZJM~$RRj94`pO1dA3wG*vh)X|dN%oVic0bu--H(@Vw!;QHthd8Z zA`EN_))g}5M4z|%Za6?FcuE!NlrLWXZ&F_c@yO|{wyos9i!pK)XW^BXZw4%LEWM9; zwv3z2seCIG8(MJ`+3CX`#*q2%1?xNu3&Rn@shodvKg_qJP7ZG?TF97$9_IZaSSRnN z7Gjet{!4fY;}!pDhws|q@9prNL^$tlDOOJVmeg z9c}roU|kWIh1k_XzBwCvQ~15%3c@P-?=kqj@?4E*3$%-@!{VNkL)xwY8~*scl-DZL zhsiQMJ-di9SY`UNU}0AYOBol67;B{5{tp3Re(XxRj@;|A;p7ikDKJKnLSmOnAK3dwyQ>jzkl@6@)>`6PQ>j`i@sbD9esK z%Ha)5`6p10E%@o8gD%z2%D3kSjMh5}NArK=@?Ej)?S(v-I*jyGE{MxFW2g+L2cQ5Yvh|?m50BWLmYPU zeU0cVeCwC6g0TJ}{?F-(5p9yDe79g=(|=(-kC(q}hr8@>ryc%05mxK~7hOevCg}>p z0YbrTq3jOwc4|}g@|TeN#RP5veb&LZH6s5me4cPQq3Fq3I-*UHum7iZ8MdP@=>v`Q zOTNM3pIT|*&gXjGq{_M|;%KxSVjW=**sbSaYs}GT%dQ2kbf4ukG-4JN%U$?oWh)ePYL}W_P?MGVtwXLgt*| zR&*gaqBs9u#_!g|JW_03Gd3X7B7E3p!b*6XXOCzjeZ0I`=E4Q>Kohv=E%K_3>#t1k zbM2p8Njb~o<^K_^`yCj~J1=UJa?2d=Dasq+|HQ?{7WikdCzd$hs(2Sl+My>!jT8GI zbH6}b^s;`o^zkk9J?3uV=%kN ziBSG~JNg%yLk`az4EIn>*k9s2~O1mA5k7~{r&UF%Nwsi{$nDWtJ0dU zNWE1!E9)vnHo{Hdv?8m6I;*1p$($zOsI05_D|#e-xw3fT&n0>C!8jE_n~d0TWvjhOs%ZbxaaRJJhatbcG%Mnd)Q%GBDCs0rLwL>Y%w8e!sS;> zSQOvN_%Y87-r<6_QZTRO-ax5$(c4AzDdZ_cZ$;=x;x2R-8%)0=tRVCva{(Am^cNUZ zS?8wAfo$t}JTTA>v+Qty9cCuNc^QlY=q}cuvWZP46x={R3Hi1WSZZ`(+o>^$HGtze zpUEE0%TiB@Z!>z-)FTnvrn-@H(X5H2Evoxx8u|Q>mxq03YfLCW#y8f?c0UqqXAB9) zJe7&Dh0wcW1Y;aFGQYB}=>DQMp2q`2t>^JTo*m}W9twFbq z7s!$4%*93*waGKauK1J4Eb_=YH!za=MTUyv%DQr~8HB6ow?1SFEF#ZKD(f76)REKRGt;Zg>POF_m>T81E1?cs3^YJ z)?0E7E$eP{cTy>(zcxCdQ>oJ!V~h&&O+z(YuOdzP<%~~?vkqcgMp^lX%L%ndd4CwY z;6FXA?HK9BE_j}En$3K(NT~bS|1Zz{XSZcxH?nB&XREXH3A82hJQ?a6Y`;QN`cd}N z-o_6g-)d%VV!qi+nMbE9!;+KtTbhfNDf@6o&pR5Ao_97L9jeUV`IK>VxH6@D90(qF zv^6K(4Bp%P2TwEq!K3k?!bf?(zM21Jc$5D+IO@!`*8Zv)JpON|IpAnJdj4wgu4(*T z)zI+m;G8)#ka3o8)Mu-wWxWvPeYj7MwxDfBRWHS`e(;OkG7i7LWD605NQmtJ$G9`7*;z&i?!#k-M$w{OHD}sto>@ zC^Ou!Zfs*V`H3D{27ajrDSyfOG$Y7+{8_!#xQ;Q5!^nXRJ{ek681{4Bw21d6MsvSk zu)P#H63>d_;)mHx`;3gTc;b=E?C?@M9BGHeiSXDZV4%Ya!VqhU$i;HMFuWH%3r?x# z)MF!<>kb#(#2l-Ey!~8@46$K}xx+EhJWfB3naRn_RyleG=WzPw4)zv_VVvp)YkGo5|cV(FP7vmazCLnh1}5 zgE>G0+TpkC@CG})9z9`G0)(`iaO9hEpYIV`x@Ya! z?9!vNkgc_srTg1#-S@mu_dCASeMiL?{SSE=>$w)pjsQAAUJf5yekUnstlZLJJm$A} z;;}M2yxR`{#SZUEgvaho%$X|)sk?CO4!QrO?wy)jkKE3h>Na`KSR*!v=YFn5XOUZj zb=BCM7`m5!vL%4-=Tg3^KIk4>f=v0{bRS!i=)<;t!+x#>r{g~EXE3HG`Y^g@Ui58g zzx3h77Ee5~$PVwd!-aNuPa^DCkZAXQ!g^$k&bRJ|BiNtNqJp@unRmnIAzQ4krF--8 zM7w`6%d$CNw)^I8x_|Tn-E(cV`$w1yBX6>wTJ3&?-R>W@c;c~#?C?Q5TyBToON7V1 zOIxAci*IYQ_%R-^?uT2kIZ~HOOVK-)QO8S>nd^k^Y4==P?e%`U-EWrX-gv_@bpIXV z4gJ1o_sx{?3!C%!1vZCku{j+ztkE)AL)h&I-NmD8q`tA^t1X^*wAv1-EXjUf76A!Km4WcV?VmU=5TGb`=`kR zc@^^F=axPZk3E&pL8MN2XfwJUuD8P<+TprH*ztpey$=vddyYIQ_r136J@INSRgcwT z@7E^kRQ@~1vK3rg?e+T!-N!85^Ii6;thQrMfYq95wR`F_Ufx~zp$l}+wWa$_)GuXm zbnnB@TXs7h{Wpsz9{pE4+-Qdz?C{5lu;V#f_k@=2pSA9H(|xKQeFoXQS(fgvLar`X zHhV2T-l;2T{FHt9^X$jS`+zc^VxIQ3KWo0#ZQtdLD|P$Fyc?U?e~~kwPR@XG4wUyV z|M~!DL955MeOjvYE+_x%o}dv72H+#zV8%KTqY#w7`q{3m@+-&Z9wKP4- z+^aZ4JuSRZFYjq{-2qL5pZV?KsvfM}wPM}hi}R8_)TCI?;B1dllY(;HM@?!VWG+6* zlLhguM{j>M$+rqUyMwc5fiaMGuRVMRLFABc#VDq~x zZ<3|}8Gna-%-IfSbLMs;wg8!nuT(taoxU@zO1~p`i5~U!FuJDqFrvJ_8Fd!u8vi#b z-`|N3cblISyUngqZu4X2mS@Jg%}M0(8E5<>PKO?u>^36}1-dzf=RUXj*?714InO(I zheTu>g58hu&3C00qMISx&tLZWvqv~n+%>d^5eazovpGGCcqVydlShu*JTug7n(&-i z$ym{l7~cw-({$Nq;T>2r63f@moOhYgRJR%H1(BEJQ;r@R&^5=HbQijCpyP7UJ-RKB z5Zzazdj~pqqGNBL;A|H6!`F}arNl?8Nv+&>jUzsh zdV|+_H6inA`oyG`6!@m8NwP=hx=u|}-{k#P&bhZzmPkL%cmTaecBUC!yVHzF>rnm7 zdoJ^nn9J-s?lM1SUjOL{m)QX?P7E{RqwJ?$W+afWn`e1`&Sl0wa+xoPUO7uF<&|#& zi9WNm0_Npe+kZmZu61C0hw5k7rWt1rfPV=5c9;3-5tq4z=b9_=|EKqHCU*eqG|vx$ z{FfYQkgaPj;Y;M{%g`e`CCt;$6g$nX-C*p2UWHm+=JViq`aU;X>~L2$X)-0x486md ztGoT7+0k__)4{v5kvf-oJOGw2SMN$qGsGWpZLo(P8#`8y2HZx+GcNO(6MbxOnVqA^ z=XsYIt09jDXo1_ne|K2gY(X$z_XS7jdx?+h!TX;K4V1dO~ zB7FR>Qfx}%d5rzHf}mITH4oJBTOTgud3BKWy3fX$?lgr*uy`k$?`amvJFe^LujV{0 zTaV8CBA=55!C|^j>t*FrB>4n~>(Lt$IA?}C&5qel^Y}KG`5bzRtotVKJM%xHd|y@m zi|r24*^v}kyB!|Scp7a_F$P3>>jP=q=lI{lGpG4)L*iX$o#s2zKP7(7X^vyO>N@YF zP6lD0L~rUaYofzzR3E)U>tl^AovAK!b+C`#m7QvIWTL}Ssm9sNRO6F$mwC20mA*|p zhqObv_Q6B?isn9gY&h+%82-EASq`mBHPHJ>^nLPnzH21)Hc#uV`&3{3>>a5_e5}hf z$Ahs9yeZU~kN8^d&jkAhaJGT*YN}P=rCMLT>j-i*z&n?G?tpg>yaAUfdHDFoQEUNy zc?tL1N%v7A9rbY17wpS=ySE-&M*BZOnicS^beYSf{k5!~-NAn_c8x-p#ZW_*er^N$ zd!BaG0P(+*V*k9&ef1Lb*s+Iu+aUh?vFj!3dM6?O`PlU;)ape36yuWv+$W9b#i!Es zd0IMcS{*)i$VnZi>s{MYC|3$)NipI_oTmA%)BJc(iV<7uG^6XF7+7`G|8b}J4P=yc zXnCsGEc^$1+`Mm^u18{-de^INqwBoeI2SZ0LiSRL|mGDjkXKhC^PFCAzZ5aoh zS>JCzKN9)wQ;vh@axHyG&L2bxr5^?H1*z%Z*CZDiXC)uzkb_bvvPk;d((EXhx2Vk!9OtA-274^ucn=Y&8FSZ zp26lXUL|ZDY&JN3X48J+H$aD=+1#5u*!qrHQ#;p3pm(A7pcr%q&+jG-KntMb&?4vr zv;_JHS_YklmP2Qu70@|oC3GIDf}9tbO*Mq6gzH8dO>2qwy2#wJmiRj2>D;d)%)H3l zMW3yoN&Fco`y%tlQdi@b8`^8?%4YF5QXekreHDJj;D4z(qW4MozR}?h(S0a~xwaGi z)m&yQXB;xBE;A-$<8I>|erSKTS$`ngR6EwRHyz4G7nd1L?Oda~rXyUx3%!?Z?rG)z z@oaN9wj_Ka+uVT+t%4iN(VIqHW*Ehn83TGU_ujguy!ho za8`pk8_c0LrWc;!P%$(L%mA3%}@Z$10#*lM+0dOHYWW&ln&0r zU}FE9P7h4f)meDXLFXYSn7zR4m2FNJ%;h5uzhJ%!rVq?zV79`yd!((;Y&{eMX9<{$ zD^2@t%meTog4&@Y1I;};oPO-pRd zW$-MARzNGkbb?tk&`cA|CB;UwU`_@zc9Cu@0&@y{FBK=suI1>VyTQ30OvcwHpN%;k zo|(`M&}=Zb7aP0o7-*gz31&8F1v4GYRxmTc%!F^QjTs!GhsJ{A19LK%**0blJVPNb zG#t#?V2&DS{y{Kby~I$tV8*g&pJ48}#0VYFqCPLN+h?vGN(E;En9K*7PGlwO{Udlz zLua9LS>~Q|ml(U81I^b3bHOEsM=*DTSp{YQ%sudJvoZN@c<5blE(Mc$M$@Y{W-C1V zp##t%FdM);l4b4^%=AkPO)%Gj833~vnCsxX!Nz1g5PAum0x(B`S!ZKD1J4HNd8h%* znP6_uGM^XB-4`2v!MqzxADBBYHbMdT&R%S{PY?e~4^B3i%$=GR*qDppSpqGCmV_u+Fvr99yp7phpoivy(;H0YWKEN8%qj5rpy|*|FgJiX zJInm8V5Wj0n5keo!E|!nOL%Qe#sB{o3l5lGFwqj zFy9?O`y8wr+ea9o_XaSIjIi5hksdlfz*L{CZr?o=%ouU8&Bx(6A$-v30p^|)BaB_= z2ADGib1rEG^Cd7_!JG}|PWYa&F_}|`+QB&iW)7IUZOlFJyb85K`@yUO^UwhEO2Iro z+)#O7R)N_7=DFcUs0O|%HfHm1J+uv+qhMx(xz@&92TvXJ4735v$zV1NFg=2~ZMfkP z%(-Azf!P4&9q=6=o+!JzSP!iL=PfWZ!MxkX48XGhS_CZtGdA4VwS0itTQF}JZfJs8 z3}yh#nP85BZ=H>)U809>0O!|Wrh_@w#vBjNWM~TH19L5yGY2r22lMPO!!MZUGije- zo*rg|obZjeF@wc=$P3P^VD;l8C^AAT z;TvURYNPbf^Wgj&n5>zas%*>}c-BJepgJ&%!Q7B(HVEc3MMgw0Zve9u%sMbd6U+l(2Ebek<{>Z-725s%3O)1@ zI7`9&2+VdH^9VfeLhnJb40F$cLSxs74D$xT9A9Yo1@n0@ePE6SvjM*4HYWeI6lw)$ z0hlMi+-75Lhvy||C$t;PWnjLVVNMdv_q;|>FqeVp1@m365n2x43TP!X)W+t2+e6QQ zcPH4a#n`(`=%5CkwP5CeS(jlJfhlv+&0tC$H#otp^73ub3A(y*b$e5d*VsHgk+xwb zY4>}LrW*)nLvx`!pu53q^%}btWSF~SPP2YdhM6w1j`AAKB5Mw^#F?8zCXc?pxYyfiwnET;ff)evfX4_efiK<0)2`7&>%h1O zJl5+?%WS;m@T`DVLRDb(0&{JDbE{x3_ZWV`oC2l~%w=Hu;M?u7`}`C=6aXh3Ond`P z({0R|@Z12+hUS8~(_`$qyT7?!Fo$}KpkQW#=>;Y?%AxWL>GW{!0b%uF!r;G1h>23>k+Cpa-M_kj6~jky7y z=b;8@8aLi=DDH9uBv|K2*F%1)bI%AcrdHL41hTqzHK(9O4UPmfb$zLcY-;^#`M869hwQ< z0A>T2bNiW@f|)+l&;+v=m;o?*ftfCRHl~)Qhem;4AupIS!7T1) zett2SyYmdcV7`}5`vh}mo)LS@}vg1n)Ilr-e72IcT1- z>wLQTN5Q;1&j9++$v=W>jf%*Rt_xABoRoCM8KIcp_c_$>0goKirgcl16 ziUAZYnM@EYR9Yh!TiQn^37~~a3wqIu2$L7EKSsC=P*CtOlLy_B0GH|T{?^f_mjNzR` z8ZR&foEyM7BTa7-oS)^{$_-8voXkPmm-6gTJn1II=wuEvG#nf&!M7QFNilqBq{#rX zfLw4+1ZP2-UMVE8+F@`VOGQQp1Y1t?{BEjN4})g|c;4e#e6Oxl+8sCxoKMB? z%(GiArt0QPsrpCYYW8NdvsSP^lQo#IH@)3pEY!T2yz^?96G>%GB#P&iaH?J}WzWd7 zJyM@0%B`S2(Gau;Pd&E$Q*tt&n*{H^iV?SOXHaTRpX)aVv2T3+g(c0>eiZ$=aOP&j?T4PK1{HY& z+?5%upFPNKfd1_-r|9tR6fNuKEzb^$=%B$|ry50l_EHb2&l@SUKX4E@MEb4d?MTtP zSKt>NOVPiMm7{Kt@=$ov&_)?A=h!Cme(nPJwL8aFnKd1Mpv?OFQgno`6)8GS@Xt@t zPZ;cZ5gHbx=qaQT-nJ~F{4D5LLYYfrv@C;>Z_Wct@+U4JPX`3175hY3&Pp*bVRZr+`& zpWB>uZ^pb~9JoGAo;Z z@_6j}9m%?}EZYvhl&p6zF!lB$4!hyyWc_c$qdE~9{smtfO!!)sg{)=-%Z0DAvTXHM zb;lXu>*y$78^*@?IzCy;{oa#>mlKoqFhX?*eolfWZR@ zonTh4u>gIvl<(OV&*>+FMjxsZgP0bBw;OVag8S+e%GtA4@U9#| z#4+|D+GonbBFuy{Y9QH@clFJm^r$FHPn{0 z8{zGZvZk@#?MV&Rr{!ojb!txH`=lFfJ1Ivu7u?90pS7Y~*0&0HpGe%SXdWrsjj!Ux zSF0bMqhBo}?P$`D&Cyx#)V;4ZvUa0>v#O(h!)V*<$qcq^9&MMvCt2s(GXuVKFvnO% zy=Fyu)N*mO-LQ!F*}#231@z7*TmUQqmP$QF+xCiVS$ADe`>t8=UTPI5ytX+oQy}?$jAGN%917mh* zc`ZuA_o3I%da94T%d$ph7P41{x}Rc=Olb3`5449NvvNM6Zoojh0ew_q)-b;_(5`+m zNwYp1ShYS$*UcOlUC&~Dr*0GPPXW&WAz*uwuK9VAuG*EP&rqK9FQOCjkK2Lp)kvn{=mvGdz3Z)h6+=T-^O5brAnZ zlYS3%5qnb5kP&onM!opQ18n!g0k&F08uW3(ZArSII0;{9P(b{q;?g9&3YnF2!I&gn zSVP*IleGJZBt7n4Q{N-)MO|Cdq|aJkR!|eQneIwH$cvhFFho4K-6HfB| zOyql%XAOzE@Z&^1?%Sp=evWcJN!0PNI>}imcf-(jKkM(~8;aW9-%r%0pFUn_`@8Cn z@%NH`PL!sC%0&Gm^10x#(Cj*#VY^B*g6`IV!Q$WW{NqIJV!!6Zh0xm%8Xh8i1b7Ts z3DgiDfDfGcxFwnR5t+7&b8q9Oo7(-4&|R2mkKaa`EtL1YYV5(FfJ^8^7d`m+qO<6v zJ<_2z8OZd!p`5X#?jKdU1Mbw-Weo)xLDNNl{!)LtzNx=$6jXE9I{m_X3A*v!1YO9p z>@x^=CFtr_`iavCdIH~Wp}iW;CPeoHoKMhMtbJR)P+2%W%8Ql@35*x;wJs)TV_bE| zo=XYzsR>&44YZhv%wO`JM7WMHEm4Oz5N7bcnJ_C+H*Y1(<^5U0A%tPV0>T}H!wH)R zM-sk7IGXTf!m)(A3C9!eC7ek32H_;aHbO7qLBc77@%`i!V8&eeq{b#)ZYf7BfLhf6*rALi}01efj!^_=IS`oRw~eGZL8V zOt)W4BOIBIzYk1Fw4*m9Yu>_3_|XLOGKX=#O|_lg>H~xORZ&4e*dx`s9Wg#Dz&Wi*&Pj z-b=a)%AL=12WgK1=cDPRjNbmZc@gQCB(I}xAK5R` z7u#Fm-Lp>G9az^d;`^Abtfhx<4>s)O+YX=!c*&{5FB9$t-T>O1(B02|?T}LofA$NH z&~w=XCC}TBI3s(Yn4hCg{p`KreyqPb_3Q6C^{adP+2J)#UB3?K0@ntoZaD4K3DDR% zta?KxvKwkEY7b3uM*H9yw4pgM_=?x5_e^u@C8Ue=!#mRK6OC0HLgBPXUu@5!F0;XR zA8-w?q*lX&>SlwKl=Mi7Ov5S3~=wMGvR}nsLs@=E)+M9rvfS19$mvY*8-W{)-m!;Y*n^SGEk8bQ|tv@@s{b0Oq z*pO<6kHqUelNhfqb=W&P;&lyl+)DYaG2Xg8Il*waKkHa2_U*#I(lzM65~x)j@9 zlVV%=cA>s+1bQSUX^+PF)x#IQiv8E0$ zir4pmyK{W?hL49=Z!mtZKFC3~2QatRWeyCuWp3@WIOZ$I1j8ozSk}e{<_dPwR%I(geaZa&}mviV_|U5ZfFeO5Df2) zV}Dbeezh%52TAXS#;{j-mTZR#MhEK;#c6v@avug>=A#U;Y4sgRcD>m@IGK6#mSahF7kzw#H!oPfBuN!kA^dz0(gqbhOR0XO@TYuU@#$g}Jp4znk@ zeyOD=%QJgeC0_&&`;iOSgDlS*iIY9Y+u7fWzq+dyKPQsDI{4+%c%cl#=wGCDSw8`pCtdXu_J!#kf@J7a75I$U6gSK zwyt$#lHJ;s9vtS$3mzYxWWVXXE;6V2+uXRwJcii0)**3Pe9hwpagn*V0=^v|9;aKw z*9DJ{jMK+Q$LRxO3CG9jHzyKK0=#j0-Bzl(BDbqFo-3Z_Xa5<8LHV&*8z}b~*I%&l2sn(}ZV%^S}k*B5=u} z-?@}XzYX48Q}2(D(@%r@Ie02^A|7gGjlvE(LT^s7?sa;QJ%JKa75%(&NM`1bh9He zml=`Ktq$Gl9U45oG|@i(EbSY1=r?x|HaYZxmk3`5c02UGC5iUIH+Wu`7~!GFr|>W$ zpKFL~bLjnth~JTDzX|V!kG1e!_;}z5G85+e3Wt8H+M(NyIrPyqQy*Uq-gha-9UC`t z7F+na&l}}uTR6cE)Aw4OEkC{^!EUWC2>x~!Wt>j1_su4}52yg<0}Fsfl+%@9w=D&K z60*6>p)Y`2#@#i@q4Z%VL=Nd=@9+!>78g0~0_IL#H#%*XZ*b6w92P!f>4V5y4d4n{ zdgzVJU(=oiKXKZ{4|7g~J=KM;Te^5V@I3HyV3(zby-GOPY4683^)h!_i9b9d$7v5= zZ|TBK;AypVL5jnkB=oS?{0emZ&3)bs3ybp9sF&b~bWeK5Txi zr=@yuPYY+{_i#qOrEN&F=%mPv=woB+kYG4|!p;WH*uTOVyB0I2r;)Su-WV;Rm@L${ zIorifg{%8FcYVXZL41{#w*Jiy#lFR`)xO)z;2iwG=K5;F6*p6U5ohBE_Ux%1*xX=d zfxDn*dv#XNPrxgD%JhFd=tGy}+)1i~|MJ1NF3xw${R*cF{Ts@;KcbxXl@GX^yWm54 zr?b6+J1x2jxZjGi;lxMI#uMLj!WF$=q`cG7ZlYVA!--evJtsKFypsDId?82sN`HD! z1!?6zx|OPbPnNVl{f>_|iqONHdoMjNLXX@%;Uhc&T_;C#9#H7Ifsnf=DtMQBjcP_R zzo8P^Cv+|ANrgbqo1~HqNfQpvlL(+-FoU3cYb9 zKo30QJo~AeBk?_*<0A1rokh{Gz(>1IlzNeFEO)a+Xyd%6N8+LJR%p9PXy>f5%lY}e z7zg{%CVEf@AM<^jJ+YF$@*E`RJlenNY{!+Ff&6cV^CMPTFqi)q^3(9(T9PQgoNBg~*%5J^E-%;mHZ$81fOMi8G5C7sWtNZMx zopY@IJymA^o{h+49Wq&mOxAICLml@v)UB8R+ydOXvyS^2p03U%&27BjzH`nM@?IGW z+zb@$oKrKf$K^9QXPDPix8fV5nFJIA3NUuoWhgyo<@lX*R!#tJ0d55*Qhr{~oYM5> zI_|ru`^*9yKpYUivu={o;}rR>+(sEv<~M*zK=IBw)N@u%I`kxfKM_a*l7W<+bqkb! z1m64K!-vRJMe+}O`S%|Gv0q%ze+BX_$KrFG@wW7(GOxkG(%?Sc z%~E_y))4alk^IjAEu{ZG`2xz$y+3hhb_2NX<^46@EAcJKFL>P8bvd^sKBjTM(k0Au z7)@}48_V~RbD{C9CB@0MZb=NtG=>TS_|nZr;jIjFXXJ>BvIg`RHGq}hlWz^|F>CUBexJ|S5j!aNAkn@ba2Ho|Iqz~e z*9o_O!vOBu5}PL1xPq$E0sR@x`73YSnZNQTXwT@$tjTCLl5gIbOdU^PYh8>r zxTmYx$Ftnubpku=M|R}yF4f>@{~qPSpONV5-#*J#imn&RIWCKHTqftZdjDk;*RJT7 z#{si}o6X;~->m06fe@E)95SBAef!J|`*DEHvBmO9#RCLCpqs zMeR4*t-!52rQPz;&;0$_&C)g^YoZS_r&h`M%BmUMlU0-5JjnW5^8hOcetwPi$>|wr zrGsZk&oJ=kmu57po1pik)vjtXda|vIW|2AC{R24%8j-u2{yje0%dj$gj7({#^yYkQ zPkw1ub1vIf8l=?e~tWW$l_l^@%(E@Mb4Rj%(-(pYc6N)KH)6+m70R~%MB`6XDM9=-|NPh zx{mdQzYJHep5)xQ{{YL5!eO#&4t-&<|EMF#WxdL+mQJ}rEevC;^xd?-C;|wE+qU7 z=V_A`=+kCm-z|u`S11WO_hAR-_o7PrT_cTbdtPtgwMG_C;H&G zSo6YW_$TnKhPc}ZkxPHE#eYrsUsx&c4TJD8NV}hTMr7PSf^R4L2mPZ63kL-^jOHQ=y6 z#)4Nbi3O zzU&_u-0~V_?Kkxtc#}(8&Ya-y&{poqTfloOZM3me1)m-jXV;B^#)bjGP1{WUR2?)n zn0g!fu<A>L6ULk%DZTNzz?*w<9GtS_2VA*_)mKM*tlE zXzFJ+lHM8+daaKcm~tPX+{dW*N>krJTKbg#mhbS_&;LDd z?)-?p<_kX}v7LLh^h|KdKcCiQshNL|U8fx)c3olDJ(&chu^ZMXU6d%*Z9NY|B6rCXB{u%56fK!ef{A~ z{NY^uIP)5R*us~~hNl0jKfEvE4@29R_`|s|e|ReRI+2&id<1f2Fs?2apIGK1WNt#_ zhq19@USZQ<(#HAAs_=7sCimv7;BLhXb!#hkwUoz4{U2YJx;2D9RG!5BD}=sW?$wd_ zH2f3%BHs{vlmcM53O))xeg-x`c<6+$^8j_@F!rV}7Zln1;zaM{z5r*_i=>VIZ}PwH z_g(v6hfAN|D>S72uh<{P@w$#Vs)3iUY`Mt2bz(d9H<(MnKKa+g*% zeF`GKtE#hu{x%h?UKVc`c!mX6a~`X1MZ7(i@}BluTJ|4|Kqsp%d@Wc#%hIdL=$kkn z?e7{CTs@8cZw4?MxX;qhR1nU`_u*a}^mA8ZYrkOK0`e^4?vV@7$vQ~gMMBm)sxJ|; z-oY4M*RihggvoO?z}dk%)-mdmfHgoGunx!oHUL?`W*`^X3Jd|B1qy&LFdWzcj0Bp1 zW7zf4gfHPIb?`iv=a+%;z-~)#<1VMF^UyGn_q~>01pgxa*8Et%RY9LnJuvw6ZtVG9 z(!D|d)yDlRdGxa@rrI9Xk;L}7*bCY-iS{a~Evp;P{WR3yKh|N7W9%>E{-;=j5S<$g zFMkhj(f7AKtk3+cz|=A(ACHamj|V^NRCTO_)v;Dr$GYN{B@Vl8sYCWc>{8f0zt_}0 za6B`K_;n83KaDhNBJppl)?q>a4BDLdx*f#LGIb;$EqnRC zgnq2T)KAX`SBJxXW)bPmJ7j*2vp&f|{|dgJb=cdM@jV{CL}*D3`q%K?jI*CvZR$u` zY@dI#8JWY_k_)fL14H27v*6zlqXir150h^!aWmqgWnlCCFNv(C2RBcn4{f6VrX48f z?drDF;B5G1sNq4G5Ad(CY=1!-dSKaAU50+@kfDEe#6SmtW5Bz>dxjSNyBX)#oi=p! zS-zbo{bv#a7YyoS+0R_!IX>D}vTvzsFW*h-84oX#=+|@M)sR>`c5&+)hTfV1584b} zm1XL8kb%fPyj;t6;oBmMHhN(DUxuy?(6t%-TMcOg_&7Z1-)(4rMM|*lS-yvX9YB+z zH_x{01nMiYlT%Dze%7#|Q~3P0QX_)?4Dij$XTFT|@jw!g7Qq{pi6KTrCbo<;?Yb$z zXw&u&H}o^Pv9d)jMp8C%vBgXLeZ-HA4E?kh z-mEe0XQq*EhxvtU%;tO8w71RT`x~*m9@=<5-}jQf!uUcqmKagl=%AeQz%lSI1OK8J zEg~B$$aj{wcevA0{RRSAJL}r`c93*CqUq`mG0!A2as=BMHtc7rb9dIg0q>8+@X+S|3*<55f?Kze z?^)9AHSBHk2k+e6Vc1*GGhYZT;#1ZwRrYPjX(xWA*zAq0JNTC<`>FHJopn=`-ZYK( zHY0c;7ax#2y!>A5a~b_SH@fT-+i+kv{ zP6N*(=0wLr+jzw~B0Qzf^-ol`2N`6ZlyuP3r8uW3{%02RPuxrPH|`Q*tS|m(ncS}@ z&%Qp-t$m&qbIzZq>GRwfd+xoTFX73xpWjOq^-1F*cl3SS=YFD3@K3K)UU&Eueq*-s z*tY|hfUd`u>W>i23_IktQd z{h&N&wO$tqbJr)y`u;Alara=e@%^y1$-(dXlY@+l?3JbxdvD9!8Fvla6Ypi6lJtIX zP4HhAl;?^5;lZlF+K#`nZh3++mW-h~$s_j}#X*aNl1{$6S#Nk0dgR^5nzDSmt#x<= zj~iWa?@F>IbYq7Uyy?Ypn)H(Ii?T-q zzsENh<(2@&%-yH~b-6Cebjh0blC>Sw^=-MoO74-Y=3VZa?Bf39@R4!)_SO+WW7*n{ z+vv|kc3Zj*E<|Ti)Zj3phPazsB92a#w51`EfdYVVph?D?gM@ zdH1jFka=*KbFJo?dsLeZ?iH3YtsnCq9;d4atFgbY?-<8=H{~?N%6JLm6F6J=@6B^-#_8wR zLC1ox^FAE^+G96thNi9X02*s!wD}Y8FJkiMpxx?dk00^hd*xZ%Aw0p);%;SEa~1DW zw|&rC9}m5E5>Fevo&+sC&y{tt!k22{%h+++x`%k-%lL8n37#JizDyjazs??)`-DgC=AT!L)5XyAJCl35Ze81P zg8$DO*x72HMLvWFa#n~cl+_JVq<_cwhY`&#FtiM>KOL(>#>bBNjB7Xc@ z_LCOrd4FATwB(+l(q*n~W52TFdT*ZDprC-ZX+Rnnp3{m=b=s)Ey{xko32qk%T8l=k~le&02w%M!H z;pzOl)9kmlqZyi?#@2_%7wMDCgM`KwvCp;$JyE;N8$(!SzR?vXKdo>pO_Q zer*SK{X_d;k)9i_+uCvn`7n+4RmjRv_*&^16>MaEUvP+wh-(JeXnFG-mAJ5z{;lHCq0KESXJL||W;Sy0uNMBr z!T00Jxo`pT2l*yE{U)JFzGB0S>CpL0lD)BOBTtQnz zWF|6)JfKPbGbs6QA@4D4i}ZtP*xHUBWNHGoJqKA5`|?x1%^%?JD1zt4(6t@RA%ED0 zTnwYVry>((;o6Qf_!&ll=(DT2ly&xRsxBR|{MAUiJ=>G{wr>uy4`$f=PlGCm@hr?7*38%{ZcJtKmb z@M~1w+KyV_uh^|s&}t4^+i?+lRM|QzxDxv}m9*v9zU!dZ$XVO*7wlBxrzIONV!K3+ zf66>Tg8pVe=+FApyRn74yc?H9>3el4Hfb3;u%bvmS6!rEUl66Up#nNr7wOxDPS&S8 zSC{PE%-X=F_l=#~SQ`|%I)%Txk$F!SHcxEU4NmrXG#7q29eE6mM%SpH*uCu|r7X4H z{D3)b>|r4|M{)6acCF0yeOH}# zb-TG6!%H63Iip*3ejD&~EA~GOyK-fwCq?~oF7$mB9>1rg+s$3qVjmkxU&9=z*gr|{ z_uSF_nzu*`&;KQ!I(i@0Qr}VFdu8|+^^Me(eVS6&KV*NpWz>ICS4X6-j>E0k_1?Ok z0-w+P^1A+S>*w=+b^Uza$=xbrEq73d%Jwk_9q~VS7yrXO5PLgAY$;(GvVqMMn^-@a zXZqKcS%mi$>7PU~~*$4Jnzx$!caNdui_cyT*ay>sT5e>jf>MNV_Tz^X_uHU{J0)E2NC3mcPvA>nPFH}49pyylNPnM`4QpFZEX`?!2oVyGCm-ElnDf_pUuD7;TD)p zA~v8gVgvAVy1$YqL*a?%YM#9K{{c@buHnhTzrmCLKl$_NV=X()b*no*wYX!yvf%J5 z_Z08^3(vp${v_6)jHW%6-`Hs{yq$aaReKlT=bT!$Aq$^r5q6~SIDSo5q<>#uRkOO| z(F_%Q*fcmBrx??Z2u?&lm&W5Ch(6LE#kYiXt@sRhsx${@wU$Jvf<>Scy@|`Wn z{il!Zd;VG*J6X-vr3nw)D`WlOO8P;uCqDYFJLm`JMf$C!2vjD-O~?L@ zEBw44v?BdrVagZ%pv0|eEsXRV`LTX*uImnMiG0xy#>3C}pG--93w|b~JEu>jzxku( z90^Z9=VvcpdqclxN~74%zWn++eVOnKdLsPojPN%uKz|K?pU1EIkNlOiF8ZU=Yx*E5 zCo;bn3$K)_b~X97---`$f;m^^4s{?GP4eC;@00T)<73iA{vC3qw7C7#$J9=-N1e5ecGOmFK2K-g(mfv=saq7-9Q?)Vpfeotl`3~CnTs{4ld{fsi-;nQNj!}G4 z$^VB)eqBG1@nE0#ldJ`{CCEHQWG@tR`qu}yUz27N?+rktUf2P{cSFP;DE|$?ukpR} zBy^mdDt^j``zSwx|AVRc_2`{ab}Bj`@e2gUo9tQrk~9*3gm|$-QciE3dvVCOPapH_ zgf|f$_3{|Ip+0@=wJ5K~DEmaF(p~V3&+Aodk<2$n`G)=oZC%)(6YOv39OJQPA?HIV z@5;Ba%YD-Kmf1PR&)vnek)&tuq0DP`7834P!G+Ko$qxle35?2GTO&2e|#hJ6}p14nU67#Px$0 z)r_6zAY(FKkUbXW_PX3+Wk$yD6@Ah=NJ~HSd0xTcMn20$Uo2yKxz`B#%HZpgK!+jOOh)e&Cl=x7IPy7$`t#M>{Ui` zr#|t^k+t?|bw``Pe$+?W$a*a;Lii6`jlIFZ^=9U7cIyRCcjTE&gYCS)KupovK~- z&j?>mC7A&qJepT#1l`LAZF9R+dx6RdlrJ%Yzn!f%iO&3Y^8EdkD_f+Eg*IiVasK^t znrZLFFVe=)mmJ{(@doW&YKo;30t!XL&NA$)nod{K1omsCo-i{$H#=iBG`?x5fE&&}C(QvUtmY{2za?J}0=^m<}=Jl!6l zkv2TZe|?0{!sEGPjbH_9PqKfhoBl2Sp+LuQWHKI^j7KIHaF;?AZR;D&JRa@rLRN$q z*QcwQCCZpyh>TPaCwRUr|34^mx(WZ>mXR#yJjyB8`0l`MQg&~-LeF<7M`UPT0pF1a zKV_95N8aVeHj$xn=51Y;N_Kzn_)#BgWNPWvx-;nEK*z1nJqWr7L3cTGCsUA{YIN!? zWTy*TwHhC)99mB^AF_k*(!Pa46aPdyjcq*5T-030z-`8(fetsg3~(9XvX%!r3VFA9 zw|EyDYAy?O6!6XDo5{CY%BrQDPncslMc*|SS^Wgx@7_eUN#v;pxe{5bpv*bw-}THt zh#idThc!L!@j%Bg@Wp{I4t$01*#m9D^GbMjhW6o%^Yo$0Og7;``4EquOS?%qg$dBS z9G*f$C3T614!`(|$_R*!_VT@uaZtI$(@ve#-$j}dpn`Vzgu2WAQiD46t+%EwpGZGU zJrr?$ZB-g}Dk2x?yvT&u37?lbB9mfAN{%zC}p=>mD6<$iBbC0N=Dn{zy*>rLLEmGdQ>^6{;KQwSs+&5qr7uy7J*r|ztEoO+6YGBp zpjGT$F?=nczp1m#h3AM{NqCm96(2E7UnA)((s^Ug1>iR${f#-jJi`q7R&(Bjy2zYr z<+s$P`KB5W`j#43^)1FqwO7~ASben|RF3v&C-NjZBXhf_m=o+qR}M{9n`AvwY~Z)1 zshN~rCVE>w)}-%HcKIac&ZW8{fXeG{TGg=U-lK4!8G{yYh!Toaf5X#Z0&T?be{a(Fo{#GJ;TmeX(Lk{ z^f%Vvkq+W24afAAlvhrlB;lXa)XX^Wk4*V}F8;$tKR(Z@{&9IfRJq$4c)w#+Ufz_) zJsYQ`sG@0!>h4Y}v1yK!h2NCSy4allYH+duFlSG`SwVG%uVM6 zeq7+u)B3Bs3yG6F5-;f`jl>tk^2oRPIMu$-dm@tm7e>FppLyT!{d4z&;P|tV8o?!b z1XrXSx!)&JeonyPn*z5hhNta6!87fXE7;bYfYeLMm$Id9g0q)~dLuh<1ASy0<=>#P z12PBGx31(}+*{wic~YV0MI$E=sZV`pW9UR@x8T_q!_)ogm6_96YpJEL7JLS6C21q{ zFpd&>+%Y;{ga)a{0s8mWl^_6O zbXty)B_D9UjWwY^vF?Pfl!?u+m?1KlMt|bjct+;#$-l#wyDjdgSKB50$K)#Hu>!kb z{-3M+vO>~JzhSJo+73v+(VFH6%*CF3M4xezKBE$O?4qBjKRlI6ME2BAMblYK>hdHiSveui%dHjg!%Z269^i+;1;=&<)zXuDFf z13tzbtHs8UuT`mtZ=8?LvW^n*CvQM^D~K0;ccrxDI%>_lIB>Ue$Bl&_DSmhtc3kv4 zz`CT!*vfRZ_#8e(REF~+^5%-kT0{=pT9x6pV9-4wsKl6r_P2rW_%!P{GY3FS$33;@8aHa`{psB$qP+FiwE2#;1oQqF+8H1%Lt<;0>pX^vSwTZK_cl*HkalC3Thc>Y>?7`MP{B9TX@iInWk9I_^iM!i}-239A zaU#1sNBunHdEXxycOa_+NymKd;un!e(E;{S9o~~fe>6$yK`Qrfh`rHy=+1V=N(S@) zzVYCh#JG>Of%1vy40Z48d-=vHO&=TZNBoO{3mLb~jEo=$n_KEt**^E=bzcF^; z%9 z^%-wZ_*>;=N9Kxm#majo6Wr8W_DM*2vS#k9hMzINPhlVb+deU855Dk&olQ~y*oyea z;s^KOD?hTpqhdq6)i`6*SEu_0={$_Fjm=-3W(R4|`y!d2DMt5SfVUxJNNnIaX=nK!^9f}h;T%4r z$e28zCB73Mw-b6(u+{$9b0W{4*mLCny0K^RiQ#D^eJ4141JpPl_&wZdCuJ(aLEH_a z(8;HzzVuNpp0l61x}67a33S|!ZVpB_2cw(D)~oAhJ$sFQ(szZxCwBT&WNa;WZw`*! zy(xW_dg^Mu)YyZ+qSJCFpojkRpW?W~Fm!bpI!2onzPhY0EhAR`f2FLKD9dWN8s}=> zuj-Gn3DL7o(LIt0&}!<8?g`p(G_&?PcmK`?$JZ}=EkoasvOf-JDhoh_!#xd@EP>0B|Pl+w=|Op9^lu z?*jKWLjHv^eXz<)7N6_E8I%od&|_^Z(!z z8IP7E`=mdipHX*qI<9}*+UACi^7$%aTLhQvHAv+9D8@w+2DQ6*Ll@}ge*u2unTj6Z0k8fPW9K$czhwwIVS4UFb4Enqd?(X}@>euw4mEN?}>(LeTD@&P&*j=F7 zCjh@=9aIC>{?-G(GF9Lvpn&JHc(u5&!QX8H|3JUfV-5=Z8(g6cObNl1^St0py6Qa0WUDxObuiKH}LHy%1Q@Hclf)*!2Sc2MVhuo zo_TNJy$cBQeiA4o&IAgGvw#QTv+!{(doG24clA4zyAWQ!ZKMPi0WbeCDesrG{l9Pz z?F)?O-nY`4q`m$OKhM!`d<32E8;Jq#=?eUc=lyN_;G-k(BHzM1FJv6o5U%R(P1nY= z#P24p@ToVQDx!Gu(mx2k6$p-NShvD(FY!17`706F9OIS-yMO91N#m%0O7`}?n>aG zawb29pC(Hq|sWzR$} zq`y9k-gwZPX+}~2JElD<>F|On9(x+`|4cbgqBlQ(^heEgF}+y?p5veE&Eed2wDpf^ z_jl2m4}cjR$$8)YTyJutdc$021!JkD_@rOxjY4l!Om7V2(D;vfgKyibH=CkkME*s-MW)+$ zeiFUek1q74>yl^UKPIi%7)d8O(*>L)PIO1~W^*6Cd55%rilrC5d6GJd-blHUU-ae} zcJ35dkTbEa{U({-qyrBg4J@)nMdZbZ0I5FQi{Oq5K=zr*!zBiVuuI&ShW9Ocj5)gy%A3 z+=0%C4nCc(`maZ}MGt?OkRFIfKYmXixe{FeLVHYRuHc-NH*)iGYugj-Bl+X)*0zUP zZ(NY;&oG_2%Rj)gU#BDl(vTPT4;Nkb`{!K#gYw%|{`||XACA6! zRh;sC`Uhz5x38|bie+<&KaxVf*qhhk`82^GuOk|FRo(>8r)StRA?11fDp-}EKCLBG zw3Xm-Gxs4hH8J-g`GgKP^B-RF2yH^s8J7wQjf_2m#n@Fzmq1)Et?nN_aM=%yLR&5Q zTtB?-vW%M|W%4fhs-k!opO4||#c?DhE#M-*)WuKT-Q=wTmrHmO!{>(1M)cRs{KzTB zSRr`njm)Pc1{~B&>O$P&67s#7;t0^r?XDlrz3d@B>7ae+Wtl5M4*N6zxw!rUYnJ%1 z|GTlQ85zrd#M$nP>{;nu$LA8M$XdR}hn4f%;@3VuV&a2W*n>77Ju{xadfXHp$I7_H zYH~8~FZ<3I_m2F5j8mJwI_>2<@W0tJyv!ZIf`DS9p5NubzmEapvo8Zm&snUEiVRHUA zTg!)d$m6Z`n$Y8`V9yY^)K5z&uY8CF4g;K(;B={ye3ej&yP!UmwX848Q}CbUnS&2hLYaBL z40PPa7(9gB8X z=7wkUv3auA)R%X%Rw;Y3u=?Jt?apr-iIRi2R6mOtTqXKRm^Ki8;4kbH>6DA zM{9nwBhvq%AGEu?3vCg8mGKQ-Dlbq$i+c5)+mrgZ;HCSgo_r5HEO3AAIL<3$&4%KI8?nOEMgX=|?{N(I_?Z?3fbh@#vylhIr14_ zPD@M*Oym0x?&@+JOo$I0q;CKItxkv3uc^P984qr$V>0q8^@+T*kIB{g*@5!bD+hd` zmTq_Gjc)ccLvvgJKR=MK;?E^fpCltbLjMi)m-`0%VVLVp^1Ml&?c~}1M)#N1N$Mp$ zJgl6D7ecE`B?l@175ZbN5jxvwhR!uwp+7Y`LVs?I3!QI_553>$gx3l1G%?iGIE{4E zN%t+%-9@??r297MzC*gZNmoX?dq|gLBpz;LPxq{TO`d;Oh^*pMY;M_%gtk z3BD!ZdkB2B_yw{iHOFwAlYU?tJQjKJQBFDKRDiz{{ByxO54`iicR%Gm>

6{y$Nc%o{?#fJ&-KkfuWPc%d<~BES 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 From ddd0d6d9a168c2035434c016997d78414d8c15a4 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 17 May 2021 02:43:10 +0900 Subject: [PATCH 21/98] Fix a bug in setting array storing metric information. --- .../src/mesh/scale_mesh_cubedspheredom3d.F90 | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 index 77c3fcac..8137acc6 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 @@ -184,7 +184,8 @@ subroutine MeshCubedSphereDom3D_generate( this ) use scale_mesh_cubedspheredom2d, only: & MeshCubedSphereDom2D_check_division_params use scale_cubedsphere_cnv, only: & - CubedSphereCnv_CS2LonLatCoord + CubedSphereCnv_CS2LonLatCoord, & + CubedSphereCnv_GetMetric implicit none class(MeshCubedSphereDom3D), intent(inout), target :: this @@ -192,6 +193,8 @@ subroutine MeshCubedSphereDom3D_generate( this ) integer :: n type(LocalMesh3D), pointer :: mesh type(LocalMesh2D), pointer :: lcmesh2D + type(ElementBase3D), pointer :: elem3D + type(ElementBase2D), pointer :: elem2D integer :: tileID_table(this%LOCAL_MESH_NUM, this%PRC_NUM) integer :: panelID_table(this%LOCAL_MESH_NUM*this%PRC_NUM) @@ -202,6 +205,8 @@ subroutine MeshCubedSphereDom3D_generate( this ) integer :: NprcX_lc, NprcY_lc, NprcZ_lc integer :: tileID + real(RP), allocatable :: Gsqrt_tmp(:,:) + integer :: ke, ke2D !----------------------------------------------------------------------------- call MeshCubedSphereDom2D_check_division_params( & @@ -220,6 +225,7 @@ subroutine MeshCubedSphereDom3D_generate( this ) do n=1, this%LOCAL_MESH_NUM mesh => this%lcmesh_list(n) + elem3D => mesh%refElem3D tileID = tileID_table(n, mesh%PRC_myrank+1) call MeshCubedSphereDom3D_setupLocalDom( mesh, & @@ -240,11 +246,24 @@ subroutine MeshCubedSphereDom3D_generate( this ) call mesh%SetLocalMesh2D( this%mesh2D%lcmesh_list(n) ) lcmesh2D => this%mesh2D%lcmesh_list(n) + elem2D => lcmesh2D%refElem2D call CubedSphereCnv_CS2LonLatCoord( & lcmesh2D%panelID, lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), & - lcmesh2D%Ne * lcmesh2D%refElem2D%Np, this%RPlanet, & + lcmesh2D%Ne * elem2D%Np, this%RPlanet, & mesh%lon2D(:,:), mesh%lat2D(:,:) ) + allocate( Gsqrt_tmp(lcmesh2D%refElem2D%Np,lcmesh2D%Ne) ) + call CubedSphereCnv_GetMetric( & + lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), elem2D%Np * lcmesh2D%Ne, this%RPlanet, & ! (in) + mesh%G_ij, mesh%GIJ, Gsqrt_tmp(:,:) ) ! (out) + + !$omp parallel do private(ke2D) + do ke=mesh%NeS, mesh%NeE + ke2D = mesh%EMap3Dto2D(ke) + mesh%Gsqrt(:,ke) = Gsqrt_tmp(elem3D%IndexH2Dto3D(:),ke2D) + end do + deallocate( Gsqrt_tmp ) + !--- ! write(*,*) "** my_rank=", mesh%PRC_myrank ! write(*,*) " tileID:", mesh%tileID @@ -280,9 +299,6 @@ subroutine MeshCubedSphereDom3D_setupLocalDom( lcmesh, & MeshUtilCubedSphere3D_genCubeDomain, & MeshUtilCubedSphere3D_BuildInteriorMap, & MeshUtilCubedSphere3D_genPatchBoundaryMap - - use scale_cubedsphere_cnv, only: & - CubedSphereCnv_GetMetric use scale_localmesh_base, only: BCTYPE_INTERIOR @@ -351,22 +367,15 @@ subroutine MeshCubedSphereDom3D_setupLocalDom( lcmesh, & lcmesh%BCType(:,:) = BCTYPE_INTERIOR !---- - call MeshUtilCubedSphere3D_genCubeDomain( lcmesh%pos_ev, lcmesh%EToV, & ! (out) lcmesh%NeX, lcmesh%xmin, lcmesh%xmax, & ! (in) lcmesh%NeY, lcmesh%ymin, lcmesh%ymax, & ! (in) lcmesh%NeZ, lcmesh%zmin, lcmesh%zmax, FZ=FZ_lc ) ! (in) !--- - call MeshBase3D_setGeometricInfo(lcmesh, MeshCubedSphereDom3D_coord_conv, MeshCubedSphereDom3D_calc_normal ) - call CubedSphereCnv_GetMetric( & - lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, planet_radius, & ! (in) - lcmesh%G_ij, lcmesh%GIJ, lcmesh%Gsqrt ) ! (out) - return !--- - call MeshUtilCubedSphere3D_genConnectivity( lcmesh%EToE, lcmesh%EToF, & ! (out) lcmesh%EToV, lcmesh%Ne, elem%Nfaces ) ! (in) @@ -422,7 +431,6 @@ subroutine MesshCubedSphereDom3D_assignDomID( this, & integer :: is_lc, js_lc, ks_lc, ps_lc integer :: ilc_count, jlc_count, klc_count, plc_count integer :: ilc, jlc, klc, plc - integer :: Npanel_lc type(LocalMesh3D), pointer :: lcmesh !----------------------------------------------------------------------------- From 7245c8b1b1f715498d0184ad5a2f93b53a003be1 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 17 May 2021 02:43:41 +0900 Subject: [PATCH 22/98] Fix some bugs in IO for 3D cubed sphere mesh. --- FElib/src/file/scale_file_common_meshfield.F90 | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/FElib/src/file/scale_file_common_meshfield.F90 b/FElib/src/file/scale_file_common_meshfield.F90 index 869b1c38..cc8c3ed4 100644 --- a/FElib/src/file/scale_file_common_meshfield.F90 +++ b/FElib/src/file/scale_file_common_meshfield.F90 @@ -492,10 +492,8 @@ end subroutine File_common_meshfield_get_axis2D !OCL SERIAL subroutine File_common_meshfield_get_axis2D_cubedsphere( mesh2D, dimsinfo, x, y ) - use scale_const, only: & PI => CONST_PI - use scale_prc implicit none class(MeshCubedSphereDom2D), target, intent(in) :: mesh2D @@ -671,7 +669,6 @@ end subroutine File_common_meshfield_put_field2D_cartesbuf !OCL SERIAL subroutine File_common_meshfield_put_field2D_cubedsphere_cartesbuf( mesh2D, field2D, & buf ) - use scale_prc, only: PRC_abort use scale_polynominal, only: & polynominal_genLegendrePoly implicit none @@ -1051,10 +1048,6 @@ end subroutine File_common_meshfield_get_axis3D !OCL SERIAL subroutine File_common_meshfield_get_axis3D_cubedsphere( mesh3D, dimsinfo, x, y, z ) - - use scale_const, only: & - PI => CONST_PI - use scale_prc implicit none class(MeshCubedSphereDom3D), target, intent(in) :: mesh3D @@ -1109,9 +1102,9 @@ subroutine File_common_meshfield_get_axis3D_cubedsphere( mesh3D, dimsinfo, x, y, end if if ( i==1 .and. ni == 1 .and. j == 1 .and. nj == 1 ) then z_local(:) = lcmesh%pos_en(refElem%Colmask(:,1),kelem,3) & - + ( lcmesh%panelID - 1.0_RP ) * ( mesh3D%zmin_gl - mesh3D%zmin_gl ) + + ( lcmesh%panelID - 1.0_RP ) * ( mesh3D%zmax_gl - mesh3D%zmin_gl ) - ks = kgs + 1 + (j-1)*refElem%Nnode_v + ks = kgs + 1 + (k-1)*refElem%Nnode_v ke = ks + refElem%Nnode_v - 1 z(ks:ke) = z_local(:) end if @@ -1271,9 +1264,6 @@ end subroutine File_common_meshfield_put_field3D_cartesbuf !OCL SERIAL subroutine File_common_meshfield_put_field3D_cubedsphere_cartesbuf( mesh3D, field3D, & buf ) - use scale_prc, only: PRC_abort - use scale_polynominal, only: & - polynominal_genLegendrePoly implicit none class(MeshCubedSphereDom3D), target, intent(in) :: mesh3D class(MeshField3D), intent(in) :: field3d @@ -1451,9 +1441,11 @@ subroutine File_common_meshfield_set_cartesbuf_field3D_local( & end subroutine File_common_meshfield_set_cartesbuf_field3D_local function File_common_meshfield_get_dtype( datatype ) result( dtype ) - use scale_file_h, only: & FILE_REAL8, FILE_REAL4 + use scale_prc, & + only: PRC_abort + implicit none character(*), intent(in) :: datatype From 71a7334380c4f7f1871b531024373871c362dc85 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 17 May 2021 02:45:29 +0900 Subject: [PATCH 23/98] Add unit tests for modules of 3D cubed sphere mesh. --- .github/workflows/FEProject_build.yml | 2 + .../scale_meshfieldcomm_cubedspheredom3d.F90 | 2 +- FElib/test/FE/field_cubedspheredom3d/Makefile | 62 +++ .../test/FE/field_cubedspheredom3d/test.conf | 15 + .../test_field_cubedspheredom3d.f90 | 367 ++++++++++++++++++ .../test_mesh_cubedsphere3d.f90 | 5 +- 6 files changed, 450 insertions(+), 3 deletions(-) create mode 100644 FElib/test/FE/field_cubedspheredom3d/Makefile create mode 100644 FElib/test/FE/field_cubedspheredom3d/test.conf create mode 100644 FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index 7de37a01..80ae43f3 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -85,10 +85,12 @@ jobs: make -C mesh_rectdom2d_quadrilateral make -C mesh_cubedsphere2d make -C mesh_cubedom3d_hexahedral + make -C mesh_cubedsphere3d make -C field_linedom1d make -C field_rectdom2d_quadrilateral make -C field_cubedspheredom2d make -C field_cubedom3d_hexahedral + make -C field_cubedspheredom3d - name: unit test for framework run: | diff --git a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 index 320e86ca..cd5572bf 100644 --- a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 +++ b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 @@ -184,7 +184,7 @@ subroutine MeshFieldCommCubedSphereDom3D_get(this, field_list, varid_s) .and. associated(this%vec_covariant_comp_ptrlist(i)%u2 ) ) then do n=1, this%mesh3d%LOCAL_MESH_NUM - call set_boundary_data2D_u1u2( & + call set_boundary_data3D_u1u2( & this%recv_buf(:,varid_vec_s,n), this%recv_buf(:,varid_vec_s+1,n), & ! (in) lcmesh%refElem3D, lcmesh, lcmesh%G_ij, & ! (in) this%vec_covariant_comp_ptrlist(i)%u1%local(n)%val, & ! (out) diff --git a/FElib/test/FE/field_cubedspheredom3d/Makefile b/FElib/test/FE/field_cubedspheredom3d/Makefile new file mode 100644 index 00000000..e1881fe3 --- /dev/null +++ b/FElib/test/FE/field_cubedspheredom3d/Makefile @@ -0,0 +1,62 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../..) +BUILD_DIR = ./.libs +SYSDEP_DIR = $(TOPDIR)/sysdep + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + +BINNAME = test_field_cubedspheredom3d + +LIBS = $(LIBDIR)/libScaleFECore.a + +OBJS = + +all: + $(MAKE) envlog + $(MAKE) makedir + $(MAKE) makebin + $(MAKE) run + +makedir: + mkdir -p $(BUILD_DIR) + +makebin: $(BINNAME) + @echo "Complete making." + +run: + mpirun -n 1 ./$(BINNAME) test.conf + +vis: + bash ./visualize/visualize.sh + +$(BINNAME): $(BUILD_DIR)/$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) + +$(BUILD_DIR)/$(BINNAME).o: $(BINNAME).f90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) + +distclean: clean + rm -f $(BINNAME) + +clean: + rm -rf $(BUILD_DIR) + rm -f *.nc + +.SUFFIXES: +.SUFFIXES: .o .f90 .mod + +%.mod: %.f90 + $(MAKE) $(patsubst %.f90,%.o,$<) + +$(BUILD_DIR)/%.o: %.f90 + $(FC) $(FFLAGS) $(ADDITIONAL_FFLAGS) -DVERSION_MACRO=\"$(VERSION)\" -I$(BUILD_DIR) -I$(MODDIR) $(CONTRIB_INCLUDE) -I$(SCALEFELIBDIR)/include $(SCALE_NETCDF_INCLUDE) $(MODDIROPT) $(BUILD_DIR) -o $@ -c $< + +.PHONY : clean distclean allclean + +include $(TOPDIR)/utils/make/Make_environments diff --git a/FElib/test/FE/field_cubedspheredom3d/test.conf b/FElib/test/FE/field_cubedspheredom3d/test.conf new file mode 100644 index 00000000..12357b4e --- /dev/null +++ b/FElib/test/FE/field_cubedspheredom3d/test.conf @@ -0,0 +1,15 @@ +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 1.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&PARAM_TIME + TIME_DURATION = 2D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 0.001D0, + TIME_DT_UNIT = 'SEC', +/ +&HISTORY_ITEM name='q' / diff --git a/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 b/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 new file mode 100644 index 00000000..02f1a4a8 --- /dev/null +++ b/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 @@ -0,0 +1,367 @@ +#include "scalelib.h" +program test_field_cubedspheredom3d + use scale_precision + use scale_prc + use scale_io + use scale_file_history + use scale + use scale_const, only: & + RPlanet => CONST_Radius + + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + use scale_meshfieldcomm_base, only: MeshFieldContainer + use scale_meshfieldcomm_cubedspheredom3d, only: & + MeshFieldCommCubedSphereDom3D + + use scale_time_manager, only: & + TIME_manager_Init , TIME_manager_Final, & + TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP, & + TIME_DTSEC, TIME_NSTEP + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_setup, & + FILE_HISTORY_meshfield_put, & + FILE_HISTORY_meshfield_write, & + FILE_HISTORY_meshfield_finalize + + implicit none + + integer, parameter :: PolyOrder_h = 2 + integer, parameter :: PolyOrder_v = 1 + integer, parameter :: NeGX = 3 + integer, parameter :: NeGY = 3 + integer, parameter :: NeGZ = 2 + real(RP), parameter :: dom_zmin = 0.0_RP + real(RP), parameter :: dom_zmax = 100.0_RP + integer, parameter :: NLocalMeshPerPrc = 6 + + type(HexahedralElement) :: refElem + type(MeshCubedSphereDom3D), target :: mesh + + type(MeshField3D), target :: q + character(len=H_short), parameter :: q_VARNAME = "q" + character(len=H_short), parameter :: q_DESC = "q" + character(len=H_short), parameter :: q_UNITS = "K" + integer :: HST_ID(1) + + type(MeshFieldCommCubedSphereDom3D) :: fields_comm + type(MeshFieldContainer) :: field_list(1) + + integer :: n + type(LocalMesh3D), pointer :: lcmesh + + !--------------- + + call init() + + !---- + write(*,*) "* Check data communication.." + call perform_comm() + + do n=1, mesh%LOCAL_MESH_NUM + lcmesh => mesh%lcmesh_list(n) + + write(*,*) "Check interior & halo data.." + write(*,*) "tileID=", lcmesh%tileID + ! call check_interior_data(n, mesh%lcmesh_list(n), q%local(n)%val, q%local(n)%val) + ! call check_halo_data(n, mesh%lcmesh_list(n), q%local(n)%val, q%local(n)%val) + end do + !---- + + call final() + +contains + + elemental function get_field_val(tileID, k, p) result(val) + implicit none + integer, intent(in) :: tileID, k, p + real(RP) :: val + !---------------------------- + val = tileID*1000000 + k*1000 + p + + return + end function get_field_val + + subroutine init() + use scale_calendar, only: CALENDAR_setup + use scale_const, only: CONST_setup + implicit none + + integer :: comm, myrank, nprocs + logical :: ismaster + + integer :: k, p + !--------- + + call PRC_MPIstart( comm ) + + call PRC_SINGLECOM_setup( comm, & ! [IN] + nprocs, myrank, ismaster ) ! [OUT] + + call PRC_ERRHANDLER_setup( .false., ismaster ) ! [IN] + + ! setup scale_io + call IO_setup( "test", allow_noconf = .true. ) + + ! setup log + call IO_LOG_setup( myrank, ismaster ) + + ! setup calendar & initial time + call CALENDAR_setup + call TIME_manager_Init + + ! setup constant + call CONST_setup + + !------ + call refElem%Init(PolyOrder_h, PolyOrder_v, .true.) + + call mesh%Init( & + NeGX, NeGY, NeGZ, RPlanet, & + dom_zmin, dom_zmax, & + refElem, NLocalMeshPerPrc ) + + call mesh%Generate() + + !--- + call q%Init( q_VARNAME, q_UNITS, mesh ) + call fields_comm%Init(1, 0, mesh) + + call FILE_HISTORY_meshfield_setup( meshCubedSphere3D_ = mesh ) + call FILE_HISTORY_reg( q_VARNAME, q_DESC, q_UNITS, HST_ID(1), dim_type='XYZ') + + !--- + + !--- + do n=1, mesh%LOCAL_MESH_NUM + lcmesh => mesh%lcmesh_list(n) + do k=lcmesh%NeS, lcmesh%NeE + do p=1, refElem%Np + q%local(n)%val(p,k) = get_field_val(lcmesh%tileID, k, p) + end do + end do + end do + + call FILE_HISTORY_meshfield_put(HST_ID(1), q) + call FILE_HISTORY_meshfield_write() + + !--- + + return + end subroutine init + + subroutine final() + implicit none + + call FILE_HISTORY_meshfield_finalize() + + call q%Final() + call fields_comm%Final() + call mesh%Final() + call refElem%Final() + + call TIME_manager_Final() + call PRC_MPIfinish() + + return + end subroutine final + + subroutine perform_comm() + type(MeshFieldContainer) :: field_list(1) + !--------------------------- + + field_list(1)%field3d => q + write(*,*) " - Put.." + call fields_comm%Put(field_list, 1) + write(*,*) " - Exchange.." + call fields_comm%Exchange() + write(*,*) " - Get.." + call fields_comm%Get(field_list, 1) + + end subroutine perform_comm + + subroutine check_interior_data(n, lcmesh_, lcfield, lcfield_fl) + implicit none + + integer, intent(in) :: n + type(LocalMesh3D), intent(in) :: lcmesh_ + real(RP), intent(in) :: lcfield(refElem%Np,lcmesh_%NeA) + real(RP), intent(in) :: lcfield_fl(refElem%Np*lcmesh_%NeA) + + integer :: ke, f, p + integer :: iM, iP, fnid + integer :: ans(refElem%Np) + !------------------------------ + + do ke=lcmesh_%NeS, lcmesh_%NeE + do p=1, refElem%Np + ans(p) = get_field_val(lcmesh_%tileID,ke,p) + end do + + call assert(ke, int(lcfield(:,ke)), ans(:), 'check_interior_data', 'q', refElem%Np) + do f=1, refElem%Nfaces_h + do p=1, refElem%Nfp_h + fnid = p + (f-1)*refElem%Nfp_h + iM = lcmesh_%VMapM(fnid,ke) + iP = lcmesh_%VMapP(fnid,ke) + write(*,'(a,3(i3),a,i10,a,i10,a,3i4)') "ke, f, p =", ke,f,p, & + " : q- = ", int(lcfield_fl(iM)), ", q+ =", int(lcfield_fl(iP)), & + ", normal=", int(lcmesh_%normal_fn(fnid,ke,:)) + end do + end do + do f=1, refElem%Nfaces_v + do p=1, refElem%Nfp_v + fnid = p + refElem%Nfaces_h*refElem%Nfp_h + (f-1)*refElem%Nfp_v + iM = lcmesh_%VMapM(fnid,ke) + iP = lcmesh_%VMapP(fnid,ke) + write(*,'(a,3(i3),a,i10,a,i10,a,3i4)') "ke, f, p =", ke,f+refElem%Nfaces_h,p, & + " : q- = ", int(lcfield_fl(iM)), ", q+ =", int(lcfield_fl(iM)), & + ", normal=", int(lcmesh_%normal_fn(fnid,ke,:)) + end do + end do + end do + + return + end subroutine check_interior_data + + subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) + implicit none + + integer, intent(in) :: n + type(LocalMesh3D), intent(in) :: lcmesh_ + real(RP), intent(in) :: lcfield(refElem%Np,lcmesh_%NeA) + real(RP), intent(in) :: lcfield_fl(refElem%Np*lcmesh_%NeA) + + integer :: ans_bx(refElem%Nfp_h,lcmesh_%NeX,lcmesh_%NeZ) + integer :: ans_by(refElem%Nfp_h,lcmesh_%NeY,lcmesh_%NeZ) + integer :: ans_bz(refElem%Nfp_v,lcmesh_%NeX,lcmesh_%NeY) + integer :: haloInd_s, haloInd_e + integer :: ke, f, fp + integer :: i, j, k + integer :: tileID + + integer :: Ne, NeX, NeY, NeZ + integer :: Np, Nfp_h, Nfp_v + + !------------------------------ + + tileID = lcmesh_%tileID + Ne = lcmesh_%Ne + NeX = lcmesh_%NeX + NeY = lcmesh_%NeY + NeZ = lcmesh_%NeZ + Np = refElem%Np + Nfp_h = refElem%Nfp_h + Nfp_v = refElem%Nfp_v + + write(*,*) "Check values in halo.." + write(*,*) "tileID_globalMap=", mesh%tileID_globalMap(:,tileID) + write(*,*) "tileFaceID_globalMap=", mesh%tileFaceID_globalMap(:,tileID) + + + haloInd_s = Np*Ne + 1 + haloInd_e = haloInd_s + Nfp_h*NeX*NeZ - 1 + do k=1, NeZ + do i=1, NeX + ke = i + (NeY-1)*NeX + (k-1)*NeX*NeY + do fp=1, Nfp_h + ans_bx(fp,i,k) = get_field_val(mesh%tileID_globalMap(1,tileID), ke, refElem%Fmask_h(fp,3)) + end do + end do + end do + call assert( -1, int(lcfield_fl(haloInd_s:haloInd_e)), ans_bx(:,:,:), & + 'check_halo_data', 'q_halo_south', Nfp_h*NeX*NeZ ) + + haloInd_s = haloInd_e + 1 + haloInd_e = haloInd_s + Nfp_h*NeY*NeZ - 1 + do k=1, NeZ + do j=1, NeY + ke = 1 + (j-1)*NeX + (k-1)*NeX*NeY + do fp=1, Nfp_h + ans_by(fp,j,k) = get_field_val(mesh%tileID_globalMap(2,tileID), ke, refElem%Fmask_h(fp,4)) + end do + end do + end do + call assert( -1, int(lcfield_fl(haloInd_s:haloInd_e)), ans_by(:,:,:), & + 'check_halo_data', 'q_halo_east', Nfp_h*NeY*NeZ ) + + haloInd_s = haloInd_e + 1 + haloInd_e = haloInd_s + Nfp_h*NeX*NeZ - 1 + do k=1, NeZ + do i=1, NeX + ke = i + (k-1)*NeX*NeY + do fp=1, Nfp_h + ans_bx(fp,i,k) = get_field_val(mesh%tileID_globalMap(3,tileID), ke, refElem%Fmask_h(fp,1)) + end do + end do + end do + call assert( -1, int(lcfield_fl(haloInd_s:haloInd_e)), ans_bx(:,:,:), & + 'check_halo_data', 'q_halo_north', Nfp_h*NeX*NeZ ) + + haloInd_s = haloInd_e + 1 + haloInd_e = haloInd_s + Nfp_h*NeY*NeZ - 1 + do k=1, NeZ + do j=1, NeY + ke = NeX + (j-1)*NeX + (k-1)*NeX*NeY + do fp=1, Nfp_h + ans_by(fp,j,k) = get_field_val(mesh%tileID_globalMap(4,tileID), ke, refElem%Fmask_h(fp,2)) + end do + end do + end do + call assert( -1, int(lcfield_fl(haloInd_s:haloInd_e)), ans_by(:,:,:), & + 'check_halo_data', 'q_halo_west', Nfp_h*NeY*NeZ ) + + haloInd_s = haloInd_e + 1 + haloInd_e = haloInd_s + Nfp_v*NeX*NeY - 1 + do j=1, NeY + do i=1, NeX + ke = i + (j-1)*NeX + (NeZ-1)*NeX*NeY + do fp=1, Nfp_v + ans_bz(fp,i,j) = get_field_val(mesh%tileID_globalMap(5,tileID), ke, refElem%Fmask_v(fp,2)) + end do + end do + end do + call assert( -1, int(lcfield_fl(haloInd_s:haloInd_e)), ans_bz(:,:,:), & + 'check_halo_data', 'q_halo_bottom', Nfp_v*NeX*NeY ) + + haloInd_s = haloInd_e + 1 + haloInd_e = haloInd_s + Nfp_v*NeX*NeY - 1 + do j=1, NeY + do i=1, NeX + ke = i + (j-1)*NeX + do fp=1, Nfp_v + ans_bz(fp,i,j) = get_field_val(mesh%tileID_globalMap(6,tileID), ke, refElem%Fmask_v(fp,1)) + end do + end do + end do + call assert( -1, int(lcfield_fl(haloInd_s:haloInd_e)), ans_bz(:,:,:), & + 'check_halo_data', 'q_halo_top', Nfp_v*NeX*NeY ) + + return + end subroutine check_halo_data + + subroutine assert(k, vals, ans, assert_name, var_name, val_size) + integer, intent(in) :: val_size + integer, intent(in) :: k + integer, intent(in) :: vals(val_size) + integer, intent(in) :: ans(val_size) + character(*), intent(in) :: assert_name + character(*), intent(in) :: var_name + + real(RP), parameter :: EPS = 1.0E-15_RP + !-------------------------------------- + + write(*,*) trim(var_name), "=", vals(:) + if ( sum((vals(:) - ans(:))**2) > EPS ) then + LOG_ERROR(assert_name,*) 'The value of '//trim(var_name)//' is unexcepted!', & + ' k=', k, ": val=", vals(:), " ans=", ans(:) + call PRC_abort + end if + end subroutine assert + +end program test_field_cubedspheredom3d diff --git a/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 b/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 index 87abb788..262c4b29 100644 --- a/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 +++ b/FElib/test/FE/mesh_cubedsphere3d/test_mesh_cubedsphere3d.f90 @@ -27,10 +27,11 @@ program test_mesh_cubedsphere3d !------------------------------------------------- call init() - stop + do n=1, mesh%LOCAL_MESH_NUM call check_connectivity( mesh%lcmesh_list(n), refElem ) end do + call final() contains @@ -59,7 +60,7 @@ subroutine init() call mesh%Init( NeGX, NeGY, NeGZ, RPlanet, dom_zmin, dom_zmax, refElem, NLocalMeshPerPrc ) call mesh%Generate() - stop + return end subroutine init From c6ca37028b591e237f1ab2b18bd10aebf9f9375f Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 19 May 2021 11:23:49 +0900 Subject: [PATCH 24/98] Modify a unit test. --- .../test_field_cubedspheredom3d.f90 | 114 +++++++++++++----- 1 file changed, 87 insertions(+), 27 deletions(-) diff --git a/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 b/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 index 02f1a4a8..75e73aa3 100644 --- a/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 +++ b/FElib/test/FE/field_cubedspheredom3d/test_field_cubedspheredom3d.f90 @@ -63,13 +63,13 @@ program test_field_cubedspheredom3d write(*,*) "* Check data communication.." call perform_comm() - do n=1, mesh%LOCAL_MESH_NUM + do n=1, 1!mesh%LOCAL_MESH_NUM lcmesh => mesh%lcmesh_list(n) write(*,*) "Check interior & halo data.." write(*,*) "tileID=", lcmesh%tileID - ! call check_interior_data(n, mesh%lcmesh_list(n), q%local(n)%val, q%local(n)%val) - ! call check_halo_data(n, mesh%lcmesh_list(n), q%local(n)%val, q%local(n)%val) + call check_interior_data(n, mesh%lcmesh_list(n), q%local(n)%val, q%local(n)%val) + call check_halo_data(n, mesh%lcmesh_list(n), q%local(n)%val, q%local(n)%val) end do !---- @@ -241,12 +241,14 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) integer :: ans_by(refElem%Nfp_h,lcmesh_%NeY,lcmesh_%NeZ) integer :: ans_bz(refElem%Nfp_v,lcmesh_%NeX,lcmesh_%NeY) integer :: haloInd_s, haloInd_e - integer :: ke, f, fp - integer :: i, j, k + integer :: ke, f + integer :: i, j, k, fp, fph, fpv integer :: tileID integer :: Ne, NeX, NeY, NeZ - integer :: Np, Nfp_h, Nfp_v + integer :: Np, Nfp_h, Nfp_v, Nnode_h1D + + integer :: s_face(6) !------------------------------ @@ -258,19 +260,24 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) Np = refElem%Np Nfp_h = refElem%Nfp_h Nfp_v = refElem%Nfp_v + Nnode_h1D = refElem%Nnode_h1D + s_face(:) = mesh%tileFaceID_globalMap(:,tileID) write(*,*) "Check values in halo.." write(*,*) "tileID_globalMap=", mesh%tileID_globalMap(:,tileID) - write(*,*) "tileFaceID_globalMap=", mesh%tileFaceID_globalMap(:,tileID) - + write(*,*) "tileFaceID_globalMap=", s_face(:) haloInd_s = Np*Ne + 1 haloInd_e = haloInd_s + Nfp_h*NeX*NeZ - 1 do k=1, NeZ do i=1, NeX - ke = i + (NeY-1)*NeX + (k-1)*NeX*NeY - do fp=1, Nfp_h - ans_bx(fp,i,k) = get_field_val(mesh%tileID_globalMap(1,tileID), ke, refElem%Fmask_h(fp,3)) + do fpv=1, refElem%Nnode_v + do fph=1, refElem%Nnode_h1D + call get_index( s_face(1), NeX, Nnode_h1D, i, k, fph, fpv, & + ke, fp ) + ans_bx(fph+(fpv-1)*Nnode_h1D,i,k) = & + get_field_val(mesh%tileID_globalMap(1,tileID), ke, refElem%Fmask_h(fp,abs(s_face(1)))) + end do end do end do end do @@ -281,9 +288,13 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) haloInd_e = haloInd_s + Nfp_h*NeY*NeZ - 1 do k=1, NeZ do j=1, NeY - ke = 1 + (j-1)*NeX + (k-1)*NeX*NeY - do fp=1, Nfp_h - ans_by(fp,j,k) = get_field_val(mesh%tileID_globalMap(2,tileID), ke, refElem%Fmask_h(fp,4)) + do fpv=1, refElem%Nnode_v + do fph=1, refElem%Nnode_h1D + call get_index( s_face(2), NeY, Nnode_h1D, j, k, fph, fpv, & + ke, fp ) + ans_by(fph+(fpv-1)*Nnode_h1D,j,k) = & + get_field_val(mesh%tileID_globalMap(2,tileID), ke, refElem%Fmask_h(fp,abs(s_face(2)))) + end do end do end do end do @@ -294,9 +305,13 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) haloInd_e = haloInd_s + Nfp_h*NeX*NeZ - 1 do k=1, NeZ do i=1, NeX - ke = i + (k-1)*NeX*NeY - do fp=1, Nfp_h - ans_bx(fp,i,k) = get_field_val(mesh%tileID_globalMap(3,tileID), ke, refElem%Fmask_h(fp,1)) + do fpv=1, refElem%Nnode_v + do fph=1, refElem%Nnode_h1D + call get_index( s_face(3), NeX, Nnode_h1D, i, k, fph, fpv, & + ke, fp ) + ans_bx(fph+(fpv-1)*Nnode_h1D,i,k) = & + get_field_val(mesh%tileID_globalMap(3,tileID), ke, refElem%Fmask_h(fp,abs(s_face(3)))) + end do end do end do end do @@ -304,12 +319,16 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) 'check_halo_data', 'q_halo_north', Nfp_h*NeX*NeZ ) haloInd_s = haloInd_e + 1 - haloInd_e = haloInd_s + Nfp_h*NeY*NeZ - 1 + haloInd_e = haloInd_s + Nfp_h*NeY*NeZ - 1 do k=1, NeZ do j=1, NeY - ke = NeX + (j-1)*NeX + (k-1)*NeX*NeY - do fp=1, Nfp_h - ans_by(fp,j,k) = get_field_val(mesh%tileID_globalMap(4,tileID), ke, refElem%Fmask_h(fp,2)) + do fpv=1, refElem%Nnode_v + do fph=1, refElem%Nnode_h1D + call get_index( s_face(4), NeY, Nnode_h1D, j, k, fph, fpv, & + ke, fp ) + ans_by(fph+(fpv-1)*Nnode_h1D,j,k) = & + get_field_val(mesh%tileID_globalMap(4,tileID), ke, refElem%Fmask_h(fp,abs(s_face(4)))) + end do end do end do end do @@ -320,9 +339,9 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) haloInd_e = haloInd_s + Nfp_v*NeX*NeY - 1 do j=1, NeY do i=1, NeX - ke = i + (j-1)*NeX + (NeZ-1)*NeX*NeY + ke = i + (j-1)*NeX do fp=1, Nfp_v - ans_bz(fp,i,j) = get_field_val(mesh%tileID_globalMap(5,tileID), ke, refElem%Fmask_v(fp,2)) + ans_bz(fp,i,j) = get_field_val(mesh%tileID_globalMap(5,tileID), ke, refElem%Fmask_v(fp,1)) end do end do end do @@ -333,9 +352,9 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) haloInd_e = haloInd_s + Nfp_v*NeX*NeY - 1 do j=1, NeY do i=1, NeX - ke = i + (j-1)*NeX + ke = i + (j-1)*NeX + (NeZ-1)*NeX*NeY do fp=1, Nfp_v - ans_bz(fp,i,j) = get_field_val(mesh%tileID_globalMap(6,tileID), ke, refElem%Fmask_v(fp,1)) + ans_bz(fp,i,j) = get_field_val(mesh%tileID_globalMap(6,tileID), ke, refElem%Fmask_v(fp,2)) end do end do end do @@ -345,6 +364,48 @@ subroutine check_halo_data(n, lcmesh_, lcfield, lcfield_fl) return end subroutine check_halo_data + subroutine get_index( s_face, Ne1D, Nnode_h1D, & + i1D, k, fph, fpv, & + ke, fp ) + implicit none + integer, intent(in) :: s_face + integer, intent(in) :: Ne1D + integer, intent(in) :: Nnode_h1D + integer, intent(in) ::i1D, k + integer, intent(in) :: fph, fpv + integer, intent(out) :: ke, fp + !----------------------------------- + + select case( s_face ) + case(1) + ke = i1D + (k-1)*Ne1D**2 + fp = fph + (fpv-1)*Nnode_h1D + case(-1) + ke = Ne1D - i1D + 1 + (k-1)*Ne1D**2 + fp = Nnode_h1D - fph + 1 + (fpv-1)*Nnode_h1D + case(2) + ke = Ne1D + (i1D-1)*Ne1D + (k-1)*Ne1D**2 + fp = fph + (fpv-1)*Nnode_h1D + case(-2) + ke = Ne1D + (Ne1D-i1D)*Ne1D + (k-1)*Ne1D**2 + fp = Nnode_h1D - fph + 1 + (fpv-1)*Nnode_h1D + case(3) + ke = i1D + (Ne1D-1)*Ne1D + (k-1)*Ne1D**2 + fp = fph + (fpv-1)*Nnode_h1D + case(-3) + ke = Ne1D - i1D + 1 + (Ne1D-1)*Ne1D + (k-1)*Ne1D**2 + fp = Nnode_h1D - fph + 1 + (fpv-1)*Nnode_h1D + case(4) + ke = 1 + (i1D-1)*Ne1D + (k-1)*Ne1D**2 + fp = fph + (fpv-1)*Nnode_h1D + case(-4) + ke = 1 + (Ne1D-i1D)*Ne1D + (k-1)*Ne1D**2 + fp = Nnode_h1D - fph + 1 + (fpv-1)*Nnode_h1D + end select + + return + end subroutine get_index + subroutine assert(k, vals, ans, assert_name, var_name, val_size) integer, intent(in) :: val_size integer, intent(in) :: k @@ -356,8 +417,7 @@ subroutine assert(k, vals, ans, assert_name, var_name, val_size) real(RP), parameter :: EPS = 1.0E-15_RP !-------------------------------------- - write(*,*) trim(var_name), "=", vals(:) - if ( sum((vals(:) - ans(:))**2) > EPS ) then + if ( sum( abs(vals(:) - ans(:)) ) > EPS ) then LOG_ERROR(assert_name,*) 'The value of '//trim(var_name)//' is unexcepted!', & ' k=', k, ": val=", vals(:), " ans=", ans(:) call PRC_abort From 78177e4e02338ae51cb64660a0b5f53fc80755c4 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 23 May 2021 19:40:44 +0900 Subject: [PATCH 25/98] Add a reference. --- FElib/src/common/scale_timeint_rk_butcher_tab.F90 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/FElib/src/common/scale_timeint_rk_butcher_tab.F90 b/FElib/src/common/scale_timeint_rk_butcher_tab.F90 index c8c0a8ae..374add97 100644 --- a/FElib/src/common/scale_timeint_rk_butcher_tab.F90 +++ b/FElib/src/common/scale_timeint_rk_butcher_tab.F90 @@ -19,7 +19,10 @@ !! @par Reference !! - Vogl et al. 2019: !! Evaluation of implicit-explicit additive Runge-Kutta integrators for the HOMME-NH dynamical core. -!! Journal of Advances in Modeling Earth Systems, 11, 4228–4244. +!! Journal of Advances in Modeling Earth Systems, 11, 4228–4244. +!! - Higueras and Roldan, 2019: +!! New third order low-storage SSP explicit Runge–Kutta methods. +!! Journal of Scientific Computing, 79(3), 1882-1906. !< #include "scaleFElib.h" module scale_timeint_rk_butcher_tab @@ -53,6 +56,7 @@ module scale_timeint_rk_butcher_tab !----------------------------------------------------------------------------- contains +!OCL SERIAL subroutine timeint_rk_butcher_tab_get_info( rk_scheme_name, & nstage, tend_buf_size, low_storage_flag, imex_flag ) implicit none @@ -117,6 +121,7 @@ subroutine timeint_rk_butcher_tab_get_info( rk_scheme_name, & return end subroutine timeint_rk_butcher_tab_get_info +!OCL SERIAL subroutine timeint_rk_butcher_tab_get( & rk_scheme_name, nstage, imex_flag, & ! (in) coef_a_ex, coef_b_ex, coef_c_ex, & ! (in) @@ -316,6 +321,9 @@ end subroutine timeint_rk_butcher_tab_get !- private -------------------------------------------- + !> Convert Shu-Osher matrix to Butcher matrix + !! For detail of the strategy, see Higueras and Roldan (2019). +!OCL SERIAL subroutine ShuOsher2Butcher( & coef_sig, coef_gam, nstage, & coef_a, coef_b ) From 265222fbbd4005d36c7830f920c6115e3d993c52 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 24 May 2021 00:58:18 +0900 Subject: [PATCH 26/98] Fix some bugs. --- .../scale_meshfieldcomm_cubedspheredom3d.F90 | 28 +- .../src/file/scale_file_common_meshfield.F90 | 504 +++++++++--------- FElib/src/mesh/scale_mesh_cubedom3d.F90 | 5 +- 3 files changed, 285 insertions(+), 252 deletions(-) diff --git a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 index cd5572bf..1d798781 100644 --- a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 +++ b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 @@ -156,11 +156,16 @@ subroutine MeshFieldCommCubedSphereDom3D_get(this, field_list, varid_s) integer :: i integer :: n + integer :: ke + integer :: ke2D type(Localmesh3D), pointer :: lcmesh + type(ElementBase3D), pointer :: elem integer :: varnum integer :: varid_e integer :: varid_vec_s + + real(RP), allocatable :: G_ij(:,:,:,:) !----------------------------------------------------------------------------- varnum = size(field_list) @@ -184,9 +189,22 @@ subroutine MeshFieldCommCubedSphereDom3D_get(this, field_list, varid_s) .and. associated(this%vec_covariant_comp_ptrlist(i)%u2 ) ) then do n=1, this%mesh3d%LOCAL_MESH_NUM + lcmesh => this%mesh3d%lcmesh_list(n) + elem => lcmesh%refElem3D + + allocate( G_ij(elem%Np,lcmesh%Ne,2,2) ) + !$omp parallel do private(ke2D) + do ke=lcmesh%NeS, lcmesh%NeE + ke2D = lcmesh%EMap3Dto2D(ke) + G_ij(:,ke,1,1) = lcmesh%G_ij(elem%IndexH2Dto3D(:),ke2D,1,1) + G_ij(:,ke,2,1) = lcmesh%G_ij(elem%IndexH2Dto3D(:),ke2D,2,1) + G_ij(:,ke,1,2) = lcmesh%G_ij(elem%IndexH2Dto3D(:),ke2D,1,2) + G_ij(:,ke,2,2) = lcmesh%G_ij(elem%IndexH2Dto3D(:),ke2D,2,2) + end do + call set_boundary_data3D_u1u2( & this%recv_buf(:,varid_vec_s,n), this%recv_buf(:,varid_vec_s+1,n), & ! (in) - lcmesh%refElem3D, lcmesh, lcmesh%G_ij, & ! (in) + lcmesh%refElem3D, lcmesh, G_ij(:,:,:,:), & ! (in) this%vec_covariant_comp_ptrlist(i)%u1%local(n)%val, & ! (out) this%vec_covariant_comp_ptrlist(i)%u2%local(n)%val ) ! (out) end do @@ -271,13 +289,14 @@ subroutine MeshFieldCommCubedSphereDom3D_exchange( this ) do varid=this%sfield_num+1, this%field_num_tot-1,2 tmp_svec3D(:,1) = commdata%send_buf(:,varid ) tmp_svec3D(:,2) = commdata%send_buf(:,varid+1) + call CubedSphereCnv_CS2LonLatVec( & lcmesh%panelID, lcfpos3D(:,1), lcfpos3D(:,2), Nnode_LCMeshFace(f), & this%mesh3d%RPlanet, & tmp_svec3D(:,1), tmp_svec3D(:,2), & commdata%send_buf(:,varid), commdata%send_buf(:,varid+1) ) - end do + end do deallocate( lcfpos3D, tmp_svec3D ) end if end if @@ -346,6 +365,7 @@ end subroutine MeshFieldCommCubedSphereDom3D_exchange !---------------------------- +!OCL SERIAL subroutine push_localsendbuf( lc_send_buf, send_buf, s_faceID, is, Nnode_LCMeshFace, var_num, & mesh3D, elem3D ) implicit none @@ -400,10 +420,11 @@ subroutine revert_hori( revert, ori, mesh, e3D, mesh2D ) end subroutine revert_hori end subroutine push_localsendbuf +!OCL SERIAL subroutine extract_boundary_data3D( var, elem, mesh, buf ) implicit none - type(elementbase3D), intent(in) :: elem + type(ElementBase3D), intent(in) :: elem type(LocalMesh3D), intent(in) :: mesh real(DP), intent(in) :: var(elem%Np * mesh%Ne) real(DP), intent(inout) :: buf( 2*(mesh%NeX + mesh%NeY)*mesh%NeZ*elem%Nfp_h & @@ -415,6 +436,7 @@ subroutine extract_boundary_data3D( var, elem, mesh, buf ) return end subroutine extract_boundary_data3D +!OCL SERIAL subroutine set_boundary_data3D_u1u2( buf_U, buf_V, & elem, mesh, G_ij, & u1, u2) diff --git a/FElib/src/file/scale_file_common_meshfield.F90 b/FElib/src/file/scale_file_common_meshfield.F90 index cc8c3ed4..7fd8dea4 100644 --- a/FElib/src/file/scale_file_common_meshfield.F90 +++ b/FElib/src/file/scale_file_common_meshfield.F90 @@ -590,77 +590,78 @@ subroutine File_common_meshfield_put_field2D_cartesbuf( mesh2D, field2D, & i0_s = 0; j0_s = 0 do j0=1, size(mesh2D%rcdomIJ2LCMeshID,2) - do i0=1, size(mesh2D%rcdomIJ2LCMeshID,1) - n = mesh2D%rcdomIJ2LCMeshID(i0,j0) - - lcmesh => mesh2D%lcmesh_list(n) - refElem => lcmesh%refElem2D - Nfp = refElem%Nfp - - if ( uniform_grid ) then - allocate( x_local(Nfp), y_local(Nfp) ) - allocate( spectral_coef(refElem%Np) ) - allocate( P1D_ori_x(1,Nfp), P1D_ori_y(1,Nfp) ) - end if - - do j1=1, lcmesh%NeY - do i1=1, lcmesh%NeX - kelem1 = i1 + (j1-1)*lcmesh%NeX + do i0=1, size(mesh2D%rcdomIJ2LCMeshID,1) + n = mesh2D%rcdomIJ2LCMeshID(i0,j0) + lcmesh => mesh2D%lcmesh_list(n) + refElem => lcmesh%refElem2D + Nfp = refElem%Nfp + if ( uniform_grid ) then - x_local(:) = lcmesh%pos_en(refElem%Fmask(1:Nfp,1),kelem1,1) - x_local0 = x_local(1); delx = x_local(Nfp) - x_local0 - y_local(:) = lcmesh%pos_en(refElem%Fmask(1:Nfp,4),kelem1,2) - y_local0 = y_local(1); dely = y_local(Nfp) - y_local0 - call get_uniform_grid1D( x_local, Nfp ) - call get_uniform_grid1D( y_local, Nfp ) - - spectral_coef(:) = matmul(refElem%invV(:,:), field2d%local(n)%val(:,kelem1)) - do j2=1, Nfp - do i2=1, Nfp - ox(1) = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx - oy(1) = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely - - call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, ox, P1D_ori_x(:,:) ) - call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, oy, P1D_ori_y(:,:) ) - - i = i0_s + i2 + (i1-1)*Nfp - j = j0_s + j2 + (j1-1)*Nfp - buf(i,j) = 0.0_RP - do p2=1, Nfp - do p1=1, Nfp - l = p1 + (p2-1)*Nfp - buf(i,j) = buf(i,j) + & - ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) ) & - * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)) & - * spectral_coef(l) + allocate( x_local(Nfp), y_local(Nfp) ) + allocate( spectral_coef(refElem%Np) ) + allocate( P1D_ori_x(1,Nfp), P1D_ori_y(1,Nfp) ) + end if + + do j1=1, lcmesh%NeY + do i1=1, lcmesh%NeX + kelem1 = i1 + (j1-1)*lcmesh%NeX + + if ( uniform_grid ) then + x_local(:) = lcmesh%pos_en(refElem%Fmask(1:Nfp,1),kelem1,1) + x_local0 = x_local(1); delx = x_local(Nfp) - x_local0 + y_local(:) = lcmesh%pos_en(refElem%Fmask(1:Nfp,4),kelem1,2) + y_local0 = y_local(1); dely = y_local(Nfp) - y_local0 + call get_uniform_grid1D( x_local, Nfp ) + call get_uniform_grid1D( y_local, Nfp ) + + spectral_coef(:) = matmul(refElem%invV(:,:), field2d%local(n)%val(:,kelem1)) + do j2=1, Nfp + do i2=1, Nfp + ox(1) = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx + oy(1) = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely + + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, ox, P1D_ori_x(:,:) ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder, oy, P1D_ori_y(:,:) ) + + i = i0_s + i2 + (i1-1)*Nfp + j = j0_s + j2 + (j1-1)*Nfp + buf(i,j) = 0.0_RP + do p2=1, Nfp + do p1=1, Nfp + l = p1 + (p2-1)*Nfp + buf(i,j) = buf(i,j) + & + ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) ) & + * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)) & + * spectral_coef(l) + end do + end do end do end do - end do - end do - - else + + else - do j2=1, Nfp - do i2=1, Nfp - i = i0_s + i2 + (i1-1)*Nfp - j = j0_s + j2 + (j1-1)*Nfp - buf(i,j) = field2d%local(n)%val(i2+(j2-1)*Nfp,kelem1) - end do - end do + do j2=1, Nfp + do i2=1, Nfp + i = i0_s + i2 + (i1-1)*Nfp + j = j0_s + j2 + (j1-1)*Nfp + buf(i,j) = field2d%local(n)%val(i2+(j2-1)*Nfp,kelem1) + end do + end do + + end if + end do + end do + if ( uniform_grid ) then + deallocate( x_local, y_local ) + deallocate( spectral_coef ) + deallocate( P1D_ori_x, P1D_ori_y ) end if + + i0_s = i0_s + lcmesh%NeX * refElem%Nfp end do - end do - - i0_s = i0_s + lcmesh%NeX * refElem%Nfp j0_s = j0_s + lcmesh%NeY * refElem%Nfp - if ( uniform_grid ) then - deallocate( x_local, y_local ) - deallocate( spectral_coef ) - deallocate( P1D_ori_x, P1D_ori_y ) - end if - end do end do return @@ -688,32 +689,32 @@ subroutine File_common_meshfield_put_field2D_cubedsphere_cartesbuf( mesh2D, fiel do p0=1, size(mesh2D%rcdomIJP2LCMeshID,3) do j0=1, size(mesh2D%rcdomIJP2LCMeshID,2) - do i0=1, size(mesh2D%rcdomIJP2LCMeshID,1) - n = mesh2D%rcdomIJP2LCMeshID(i0,j0,p0) - - lcmesh => mesh2D%lcmesh_list(n) - refElem => lcmesh%refElem2D - Nfp = refElem%Nfp + do i0=1, size(mesh2D%rcdomIJP2LCMeshID,1) + n = mesh2D%rcdomIJP2LCMeshID(i0,j0,p0) + + lcmesh => mesh2D%lcmesh_list(n) + refElem => lcmesh%refElem2D + Nfp = refElem%Nfp + + do j1=1, lcmesh%NeY + do i1=1, lcmesh%NeX + kelem1 = i1 + (j1-1)*lcmesh%NeX + + do j2=1, Nfp + do i2=1, Nfp + i = i0_s + i2 + (i1-1)*Nfp + j = j0_s + j2 + (j1-1)*Nfp + buf(i,j) = field2d%local(n)%val(i2+(j2-1)*Nfp,kelem1) + end do + end do - do j1=1, lcmesh%NeY - do i1=1, lcmesh%NeX - kelem1 = i1 + (j1-1)*lcmesh%NeX - - do j2=1, Nfp - do i2=1, Nfp - i = i0_s + i2 + (i1-1)*Nfp - j = j0_s + j2 + (j1-1)*Nfp - buf(i,j) = field2d%local(n)%val(i2+(j2-1)*Nfp,kelem1) end do end do + i0_s = i0_s + lcmesh%NeX * refElem%Nfp end do - end do - - i0_s = i0_s + lcmesh%NeX * refElem%Nfp j0_s = j0_s + lcmesh%NeY * refElem%Nfp end do - end do i0_s = 0 end do @@ -738,18 +739,19 @@ subroutine File_common_meshfield_set_cartesbuf_field2D( mesh2D, buf, & i0_s = 0; j0_s = 0 do j0=1, size(mesh2D%rcdomIJ2LCMeshID,2) - do i0=1, size(mesh2D%rcdomIJ2LCMeshID,1) - n = mesh2D%rcdomIJ2LCMeshID(i0,j0) - lcmesh => mesh2D%lcmesh_list(n) - refElem => lcmesh%refElem2D + do i0=1, size(mesh2D%rcdomIJ2LCMeshID,1) + n = mesh2D%rcdomIJ2LCMeshID(i0,j0) + lcmesh => mesh2D%lcmesh_list(n) + refElem => lcmesh%refElem2D - call File_common_meshfield_set_cartesbuf_field2D_local( & - lcmesh, buf(:,:), i0_s, j0_s, & - field2d%local(n)%val(:,:) ) + call File_common_meshfield_set_cartesbuf_field2D_local( & + lcmesh, buf(:,:), i0_s, j0_s, & + field2d%local(n)%val(:,:) ) - i0_s = i0_s + lcmesh%NeX * refElem%Nfp + i0_s = i0_s + lcmesh%NeX * refElem%Nfp + end do j0_s = j0_s + lcmesh%NeY * refElem%Nfp - end do + i0_s = 0 end do return @@ -809,20 +811,20 @@ subroutine File_common_meshfield_set_cartesbuf_field2D_cubedsphere( mesh2D, buf, do p0=1, size(mesh2D%rcdomIJP2LCMeshID,3) do j0=1, size(mesh2D%rcdomIJP2LCMeshID,2) - do i0=1, size(mesh2D%rcdomIJP2LCMeshID,1) - n = mesh2D%rcdomIJP2LCMeshID(i0,j0,p0) - lcmesh => mesh2D%lcmesh_list(n) - refElem => lcmesh%refElem2D + do i0=1, size(mesh2D%rcdomIJP2LCMeshID,1) + n = mesh2D%rcdomIJP2LCMeshID(i0,j0,p0) + lcmesh => mesh2D%lcmesh_list(n) + refElem => lcmesh%refElem2D - call File_common_meshfield_set_cartesbuf_field2D_local( & - lcmesh, buf(:,:), i0_s, j0_s, & - field2d%local(n)%val(:,:) ) + call File_common_meshfield_set_cartesbuf_field2D_local( & + lcmesh, buf(:,:), i0_s, j0_s, & + field2d%local(n)%val(:,:) ) - i0_s = i0_s + lcmesh%NeX * refElem%Nfp + i0_s = i0_s + lcmesh%NeX * refElem%Nfp + end do j0_s = j0_s + lcmesh%NeY * refElem%Nfp + i0_s = 0 end do - end do - i0_s = 0 end do return @@ -1160,102 +1162,105 @@ subroutine File_common_meshfield_put_field3D_cartesbuf( mesh3D, field3D, & i0_s = 0; j0_s = 0; k0_s = 0 do k0=1, size(mesh3D%rcdomIJK2LCMeshID,3) - do j0=1, size(mesh3D%rcdomIJK2LCMeshID,2) - do i0=1, size(mesh3D%rcdomIJK2LCMeshID,1) - n = mesh3D%rcdomIJK2LCMeshID(i0,j0,k0) - - lcmesh => mesh3D%lcmesh_list(n) - refElem => lcmesh%refElem3D - Nnode_h1D = refElem%Nnode_h1D - Nnode_v = refElem%Nnode_v - - if ( uniform_grid ) then - allocate( x_local(Nnode_h1D), y_local(Nnode_h1D) ) - allocate( z_local(Nnode_v) ) - allocate( spectral_coef(refElem%Np) ) - allocate( P1D_ori_x(1,Nnode_h1D), P1D_ori_y(1,Nnode_h1D) ) - allocate( P1D_ori_z(1,Nnode_v) ) - end if - - !$omp parallel do collapse(2) private( kelem1, & - !$omp i, i1, i2, j, j2, k, k2, indx, & - !$omp x_local, x_local0, y_local, y_local0, z_local, z_local0, & - !$omp delx, dely, delz, ox, oy, oz, & - !$omp spectral_coef, P1D_ori_x, P1D_ori_y, P1D_ori_z, & - !$omp p1, p2, p3, l ) - do k1=1, lcmesh%NeZ - do j1=1, lcmesh%NeY - do i1=1, lcmesh%NeX - kelem1 = i1 + (j1-1)*lcmesh%NeX + (k1-1)*lcmesh%NeX*lcmesh%NeY - - if ( uniform_grid ) then - x_local(:) = lcmesh%pos_en(refElem%Fmask_h(1:Nnode_h1D,1),kelem1,1) - x_local0 = x_local(1); delx = x_local(Nnode_h1D) - x_local0 - y_local(:) = lcmesh%pos_en(refElem%Fmask_h(1:Nnode_h1D,4),kelem1,2) - y_local0 = y_local(1); dely = y_local(Nnode_h1D) - y_local0 - z_local(:) = lcmesh%pos_en(refElem%Colmask(:,1),kelem1,3) - z_local0 = z_local(1); delz = z_local(Nnode_v ) - z_local0 - call get_uniform_grid1D( x_local, Nnode_h1D ) - call get_uniform_grid1D( y_local, Nnode_h1D ) - call get_uniform_grid1D( z_local, Nnode_v ) - - spectral_coef(:) = matmul(refElem%invV(:,:), field3d%local(n)%val(:,kelem1)) - do k2=1, Nnode_v - do j2=1, Nnode_h1D - do i2=1, Nnode_h1D - ox(1) = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx - oy(1) = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely - oz(1) = - 1.0_RP + 2.0_RP * (z_local(k2) - z_local0) / delz - - call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_h, ox, P1D_ori_x ) - call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_h, oy, P1D_ori_y ) - call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_v, oz, P1D_ori_z ) - - i = i0_s + i2 + (i1-1)*Nnode_h1D - j = j0_s + j2 + (j1-1)*Nnode_h1D - k = k0_s + k2 + (k1-1)*Nnode_v - buf(i,j,k) = 0.0_RP - do p3=1, Nnode_v - do p2=1, Nnode_h1D - do p1=1, Nnode_h1D - l = p1 + (p2-1)*Nnode_h1D + (p3-1)*Nnode_h1D**2 - buf(i,j,k) = buf(i,j,k) + & - ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) * P1D_ori_z(1,p3) ) & - * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)*(dble(p3-1) + 0.5_RP)) & - * spectral_coef(l) - end do - end do - end do - end do - end do - end do - else - do k2=1, Nnode_v - do j2=1, Nnode_h1D - do i2=1, Nnode_h1D - i = i0_s + i2 + (i1-1)*Nnode_h1D - j = j0_s + j2 + (j1-1)*Nnode_h1D - k = k0_s + k2 + (k1-1)*Nnode_v - indx = i2 + (j2-1)*Nnode_h1D + (k2-1)*Nnode_h1D**2 - buf(i,j,k) = field3d%local(n)%val(indx,kelem1) + do j0=1, size(mesh3D%rcdomIJK2LCMeshID,2) + do i0=1, size(mesh3D%rcdomIJK2LCMeshID,1) + n = mesh3D%rcdomIJK2LCMeshID(i0,j0,k0) + + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D + Nnode_h1D = refElem%Nnode_h1D + Nnode_v = refElem%Nnode_v + + if ( uniform_grid ) then + allocate( x_local(Nnode_h1D), y_local(Nnode_h1D) ) + allocate( z_local(Nnode_v) ) + allocate( spectral_coef(refElem%Np) ) + allocate( P1D_ori_x(1,Nnode_h1D), P1D_ori_y(1,Nnode_h1D) ) + allocate( P1D_ori_z(1,Nnode_v) ) + end if + + !$omp parallel do collapse(2) private( kelem1, & + !$omp i, i1, i2, j, j2, k, k2, indx, & + !$omp x_local, x_local0, y_local, y_local0, z_local, z_local0, & + !$omp delx, dely, delz, ox, oy, oz, & + !$omp spectral_coef, P1D_ori_x, P1D_ori_y, P1D_ori_z, & + !$omp p1, p2, p3, l ) + do k1=1, lcmesh%NeZ + do j1=1, lcmesh%NeY + do i1=1, lcmesh%NeX + kelem1 = i1 + (j1-1)*lcmesh%NeX + (k1-1)*lcmesh%NeX*lcmesh%NeY + + if ( uniform_grid ) then + x_local(:) = lcmesh%pos_en(refElem%Fmask_h(1:Nnode_h1D,1),kelem1,1) + x_local0 = x_local(1); delx = x_local(Nnode_h1D) - x_local0 + y_local(:) = lcmesh%pos_en(refElem%Fmask_h(1:Nnode_h1D,4),kelem1,2) + y_local0 = y_local(1); dely = y_local(Nnode_h1D) - y_local0 + z_local(:) = lcmesh%pos_en(refElem%Colmask(:,1),kelem1,3) + z_local0 = z_local(1); delz = z_local(Nnode_v ) - z_local0 + call get_uniform_grid1D( x_local, Nnode_h1D ) + call get_uniform_grid1D( y_local, Nnode_h1D ) + call get_uniform_grid1D( z_local, Nnode_v ) + + spectral_coef(:) = matmul(refElem%invV(:,:), field3d%local(n)%val(:,kelem1)) + do k2=1, Nnode_v + do j2=1, Nnode_h1D + do i2=1, Nnode_h1D + ox(1) = - 1.0_RP + 2.0_RP * (x_local(i2) - x_local0) / delx + oy(1) = - 1.0_RP + 2.0_RP * (y_local(j2) - y_local0) / dely + oz(1) = - 1.0_RP + 2.0_RP * (z_local(k2) - z_local0) / delz + + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_h, ox, P1D_ori_x ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_h, oy, P1D_ori_y ) + call Polynominal_GenLegendrePoly_sub( refElem%PolyOrder_v, oz, P1D_ori_z ) + + i = i0_s + i2 + (i1-1)*Nnode_h1D + j = j0_s + j2 + (j1-1)*Nnode_h1D + k = k0_s + k2 + (k1-1)*Nnode_v + buf(i,j,k) = 0.0_RP + do p3=1, Nnode_v + do p2=1, Nnode_h1D + do p1=1, Nnode_h1D + l = p1 + (p2-1)*Nnode_h1D + (p3-1)*Nnode_h1D**2 + buf(i,j,k) = buf(i,j,k) + & + ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) * P1D_ori_z(1,p3) ) & + * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)*(dble(p3-1) + 0.5_RP)) & + * spectral_coef(l) + end do + end do + end do + end do + end do + end do + else + do k2=1, Nnode_v + do j2=1, Nnode_h1D + do i2=1, Nnode_h1D + i = i0_s + i2 + (i1-1)*Nnode_h1D + j = j0_s + j2 + (j1-1)*Nnode_h1D + k = k0_s + k2 + (k1-1)*Nnode_v + indx = i2 + (j2-1)*Nnode_h1D + (k2-1)*Nnode_h1D**2 + buf(i,j,k) = field3d%local(n)%val(indx,kelem1) + end do + end do + end do + end if end do end do end do - end if - end do - end do - end do - i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D - j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + if ( uniform_grid ) then + deallocate( x_local, y_local ) + deallocate( z_local ) + deallocate( spectral_coef ) + end if + + i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D + end do + j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + i0_s = 0 + end do k0_s = k0_s + lcmesh%NeZ * refElem%Nnode_v - if ( uniform_grid ) then - deallocate( x_local, y_local ) - deallocate( z_local ) - deallocate( spectral_coef ) - end if - end do - end do + j0_s = 0 end do return @@ -1283,41 +1288,42 @@ subroutine File_common_meshfield_put_field3D_cubedsphere_cartesbuf( mesh3D, fiel do p0=1, size(mesh3D%rcdomIJKP2LCMeshID,4) do k0=1, size(mesh3D%rcdomIJKP2LCMeshID,3) - do j0=1, size(mesh3D%rcdomIJKP2LCMeshID,2) - do i0=1, size(mesh3D%rcdomIJKP2LCMeshID,1) - n = mesh3D%rcdomIJKP2LCMeshID(i0,j0,k0,p0) - - lcmesh => mesh3D%lcmesh_list(n) - refElem => lcmesh%refElem3D - Nnode_h1D = refElem%Nnode_h1D - Nnode_v = refElem%Nnode_v + do j0=1, size(mesh3D%rcdomIJKP2LCMeshID,2) + do i0=1, size(mesh3D%rcdomIJKP2LCMeshID,1) + n = mesh3D%rcdomIJKP2LCMeshID(i0,j0,k0,p0) + + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D + Nnode_h1D = refElem%Nnode_h1D + Nnode_v = refElem%Nnode_v + + do k1=1, lcmesh%NeZ + do j1=1, lcmesh%NeY + do i1=1, lcmesh%NeX + kelem1 = i1 + (j1-1)*lcmesh%NeX + (k1-1)*lcmesh%NeX*lcmesh%NeY + + do k2=1, Nnode_v + do j2=1, Nnode_h1D + do i2=1, Nnode_h1D + i = i0_s + i2 + (i1-1)*Nnode_h1D + j = j0_s + j2 + (j1-1)*Nnode_h1D + k = k0_s + k2 + (k1-1)*Nnode_v + buf(i,j,k) = field3d%local(n)%val(i2+(j2-1)*Nnode_h1D+(k2-1)*Nnode_h1D**2,kelem1) + end do + end do + end do + end do + end do + end do - do k1=1, lcmesh%NeZ - do j1=1, lcmesh%NeY - do i1=1, lcmesh%NeX - kelem1 = i1 + (j1-1)*lcmesh%NeX + (k1-1)*lcmesh%NeX*lcmesh%NeY - - do k2=1, Nnode_v - do j2=1, Nnode_h1D - do i2=1, Nnode_h1D - i = i0_s + i2 + (i1-1)*Nnode_h1D - j = j0_s + j2 + (j1-1)*Nnode_h1D - k = k0_s + k2 + (k1-1)*Nnode_v - buf(i,j,k) = field3d%local(n)%val(i2+(j2-1)*Nnode_h1D+(k2-1)*Nnode_h1D**2,kelem1) - end do - end do + i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D end do + j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + i0_s = 0 end do - end do - end do - - i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D - j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D k0_s = k0_s + lcmesh%NeZ * refElem%Nnode_v + j0_s = 0 end do - end do - end do - i0_s = 0; j0_s = 0 end do return @@ -1340,21 +1346,23 @@ subroutine File_common_meshfield_set_cartesbuf_field3D( mesh3D, buf, & i0_s = 0; j0_s = 0; k0_s = 0 do k0=1, size(mesh3D%rcdomIJK2LCMeshID,3) - do j0=1, size(mesh3D%rcdomIJK2LCMeshID,2) - do i0=1, size(mesh3D%rcdomIJK2LCMeshID,1) - n = mesh3D%rcdomIJK2LCMeshID(i0,j0,k0) - lcmesh => mesh3D%lcmesh_list(n) - refElem => lcmesh%refElem3D + do j0=1, size(mesh3D%rcdomIJK2LCMeshID,2) + do i0=1, size(mesh3D%rcdomIJK2LCMeshID,1) + n = mesh3D%rcdomIJK2LCMeshID(i0,j0,k0) + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D - call File_common_meshfield_set_cartesbuf_field3D_local( & - lcmesh, buf(:,:,:), i0_s, j0_s, k0_s, & - field3d%local(n)%val(:,:) ) + call File_common_meshfield_set_cartesbuf_field3D_local( & + lcmesh, buf(:,:,:), i0_s, j0_s, k0_s, & + field3d%local(n)%val(:,:) ) - i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D - j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D + end do + j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + i0_s = 0 + end do k0_s = k0_s + lcmesh%NeZ * refElem%Nnode_v - end do - end do + j0_s = 0 end do return @@ -1379,28 +1387,30 @@ subroutine File_common_meshfield_set_cartesbuf_field3D_cubedsphere( mesh3D, buf, do p0=1, size(mesh3D%rcdomIJKP2LCMeshID,4) do k0=1, size(mesh3D%rcdomIJKP2LCMeshID,3) - do j0=1, size(mesh3D%rcdomIJKP2LCMeshID,2) - do i0=1, size(mesh3D%rcdomIJKP2LCMeshID,1) - n = mesh3D%rcdomIJKP2LCMeshID(i0,j0,k0,p0) - lcmesh => mesh3D%lcmesh_list(n) - refElem => lcmesh%refElem3D + do j0=1, size(mesh3D%rcdomIJKP2LCMeshID,2) + do i0=1, size(mesh3D%rcdomIJKP2LCMeshID,1) + n = mesh3D%rcdomIJKP2LCMeshID(i0,j0,k0,p0) + lcmesh => mesh3D%lcmesh_list(n) + refElem => lcmesh%refElem3D - call File_common_meshfield_set_cartesbuf_field3D_local( & - lcmesh, buf(:,:,:), i0_s, j0_s, k0_s, & - field3d%local(n)%val(:,:) ) + call File_common_meshfield_set_cartesbuf_field3D_local( & + lcmesh, buf(:,:,:), i0_s, j0_s, k0_s, & + field3d%local(n)%val(:,:) ) - i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D - j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + i0_s = i0_s + lcmesh%NeX * refElem%Nnode_h1D + end do + j0_s = j0_s + lcmesh%NeY * refElem%Nnode_h1D + i0_s = 0 + end do k0_s = k0_s + lcmesh%NeZ * refElem%Nnode_v + j0_s = 0 end do - end do - end do - i0_s = 0; j0_s = 0 end do return end subroutine File_common_meshfield_set_cartesbuf_field3D_cubedsphere +!OCL SERIAL subroutine File_common_meshfield_set_cartesbuf_field3D_local( & lcmesh, buf, i0_s, j0_s, k0_s, & val ) @@ -1418,6 +1428,8 @@ subroutine File_common_meshfield_set_cartesbuf_field3D_local( & refElem => lcmesh%refElem3D + !$omp parallel do collapse(3) private( & + !$omp kelem1, k2,j2,i2, i,j,k, indx ) do k1=1, lcmesh%NeZ do j1=1, lcmesh%NeY do i1=1, lcmesh%NeX diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 5b3d0a4b..4cc9e535 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -222,8 +222,8 @@ subroutine MeshCubeDom3D_generate( this ) !--- Construct the connectivity of patches (only master node) call MesshCubeDom3D_assignDomID( this, & ! (in) - & tileID_table, panelID_table, & ! (out) - & pi_table, pj_table, pk_table ) ! (out) + tileID_table, panelID_table, & ! (out) + pi_table, pj_table, pk_table ) ! (out) !--- Setup local meshes managed by my process @@ -419,7 +419,6 @@ subroutine MesshCubeDom3D_assignDomID( this, & this%NprcX, this%NprcY, this%NprcZ ) ! (in) !---- - do p=1, this%PRC_NUM do n=1, this%LOCAL_MESH_NUM From cc7f4bec33c91db30541fe693c5e6fe09ac87c22 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 24 May 2021 01:01:49 +0900 Subject: [PATCH 27/98] Add a sample program of 3D global advection with cubed sphere mesh. --- .github/workflows/FEProject_build.yml | 1 + .gitignore | 1 + README.md | 9 +- sample/advect3dGlobal/Makefile | 68 ++ sample/advect3dGlobal/cs2lonlat.cnf | 35 + sample/advect3dGlobal/test.conf | 58 ++ sample/advect3dGlobal/test_advect3dGlobal.f90 | 639 ++++++++++++ sample/auxiliary/mod_fieldutil.f90 | 906 +++++++++++------- 8 files changed, 1370 insertions(+), 347 deletions(-) create mode 100644 sample/advect3dGlobal/Makefile create mode 100644 sample/advect3dGlobal/cs2lonlat.cnf create mode 100644 sample/advect3dGlobal/test.conf create mode 100644 sample/advect3dGlobal/test_advect3dGlobal.f90 diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index 80ae43f3..bf202e8c 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -117,6 +117,7 @@ jobs: make -C advect2dGlobal make -C advect2d_fvm make -C advect3d + make -C advect3dGlobal make -C advect3d_hevi make -C euler3d_hevi diff --git a/.gitignore b/.gitignore index cd8916be..a35d7b91 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ scale-dg LOG.pe* history.pe*.nc restart_*.pe*.nc +*.dat # interp_LOG.pe* diff --git a/README.md b/README.md index 8716c0f7..36337db0 100644 --- a/README.md +++ b/README.md @@ -23,18 +23,19 @@ Futhermore, some dynamical cores of atmospheric and oceanic model with DGM will ## Simple samples for intrduction to DGM. ### 1D problems - - linear advection equation + - Linear advection equation - various profiles of advected quantity - linear advection-diffusion equation ### 2D problems - - linear advection equation in a rectangle domain + - Linear advection equation in a rectangle domain - various profiles of advected quantity and flow - - linear advection equation in a cubed sphere domain + - Linear advection equation in a cubed sphere domain ### 3D problems - - linear advection equation in a cubic domain + - Linear advection equation in a cubic domain - various profiles of advected quantity + - Linear advection equation in a cubed sphere domain - Euler equation in a cubic domain - Test the propagation of sound waves with HEVI temporal methods diff --git a/sample/advect3dGlobal/Makefile b/sample/advect3dGlobal/Makefile new file mode 100644 index 00000000..bf4597ab --- /dev/null +++ b/sample/advect3dGlobal/Makefile @@ -0,0 +1,68 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../..) +BUILD_DIR = ./.libs +SYSDEP_DIR = $(TOPDIR)/sysdep + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + +BINNAME = test_advect3dGlobal +OBJS = + +LIBS = $(LIBDIR)/libScaleFECore.a + +SAMPLE_AUX_DIR = ../auxiliary +SAMPLE_AUX_INCLUDE = $(SAMPLE_AUX_DIR)/.libs +SAMPLE_AUX_LIB = $(SAMPLE_AUX_DIR)/libScaleFESampleAux.a + +all: + $(MAKE) envlog + $(MAKE) makedir + $(MAKE) make_sample_aux + $(MAKE) makebin + +makedir: + mkdir -p $(BUILD_DIR) + +makebin: $(BINNAME) + @echo "Complete making." + +run: + OMP_NUM_THREADS=4 mpirun -n 2 ./$(BINNAME) test.conf +# OMP_NUM_THREADS=1 mpirun -n 6 ./$(BINNAME) test.conf + +vis: + bash ./visualize/visualize.sh + +make_sample_aux: + make -C $(SAMPLE_AUX_DIR) + +$(BINNAME): $(BUILD_DIR)/$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(SAMPLE_AUX_LIB) $(LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) + +$(BUILD_DIR)/$(BINNAME).o: $(BINNAME).f90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) + +distclean: clean + rm -f $(BINNAME) + +clean: + rm -rf $(BUILD_DIR) + +.SUFFIXES: +.SUFFIXES: .o .f90 .mod + +%.mod: %.f90 + $(MAKE) $(patsubst %.f90,%.o,$<) + +$(BUILD_DIR)/%.o: %.f90 + $(FC) $(FFLAGS) $(ADDITIONAL_FFLAGS) -DVERSION_MACRO=\"$(VERSION)\" -I$(BUILD_DIR) -I$(MODDIR) $(CONTRIB_INCLUDE) -I$(SCALEFELIBDIR)/include -I$(SAMPLE_AUX_INCLUDE) $(SCALE_NETCDF_INCLUDE) $(MODDIROPT) $(BUILD_DIR) -o $@ -c $< + +.PHONY : clean distclean allclean + +include $(TOPDIR)/utils/make/Make_environments diff --git a/sample/advect3dGlobal/cs2lonlat.cnf b/sample/advect3dGlobal/cs2lonlat.cnf new file mode 100644 index 00000000..2caad80d --- /dev/null +++ b/sample/advect3dGlobal/cs2lonlat.cnf @@ -0,0 +1,35 @@ +&PARAM_IO + IO_LOG_BASENAME = "cs2lonlat_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="./history", + vars = "q", "Vellon", "Vellat", "W", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_INTERP_MESH + !-- input ---------------- + in_Nprc = 2, + in_NeGX = 7, + in_NeGY = 7, + in_NeGZ = 8, + in_PolyOrder_h = 4, + in_PolyOrder_v = 4, + in_NLocalMeshPerPrc = 3, + dom_zmin = 0.0D0, + dom_zmax = 12.0D3, + !-- output ---------------- + out_NprcX = 2, + out_NeX = 16, + out_NprcY = 2, + out_NeY = 8, + out_NeZ = 8, + out_PolyOrder_h =4, + out_PolyOrder_v =4, +/ \ No newline at end of file diff --git a/sample/advect3dGlobal/test.conf b/sample/advect3dGlobal/test.conf new file mode 100644 index 00000000..e6beafe2 --- /dev/null +++ b/sample/advect3dGlobal/test.conf @@ -0,0 +1,58 @@ +&PARAM_TEST + NeGX = 7, + NeGY = 7, + NeGZ = 8, + PolyOrder_h = 4, + PolyOrder_v = 4, + NLocalMeshPerPrc = 3, + dom_zmin = 0.0D0, + dom_zmax = 12.0D3, + !** Shape of inital q ****************************** + ! InitShapeName = 'constant', + ! InitShapeParams = 1.0D0, 0.0D0, 0.0D0, 0.0D0, + !- + InitShapeName = 'cosine-bell', + InitShapeParams = 0.0D0, 0.0D0, 2.123740D6, 0.0D0, + !- + ! InitShapeName = 'sin', + ! InitShapeParams = 1.0D0, 1.0D0, 0.0D0, 0.0D0, + !- + ! InitShapeName = 'gaussian-hill', + ! InitShapeParams = 0.25D0, 0.25D0, 0.05D0, 0.0D0, + !- + ! InitShapeName = 'top-hat', + ! InitShapeParams = 0.5D0, 0.5D0, 0.15D0, 0.15D0, + !- + InitShapeName = 'DCMIP_Test1-1_q1', + !-- + InitCond_GalerkinProjFlag = .false., + !** Type of advection velocity ********************** + ! VelTypeName = 'rigid-body-rot', + ! VelTypeParams = 38.610682766983714D0, 0.0D0, 0.0D0, 0.0D0, + !- + VelTypeName = 'DCMIP_Test1-1', + !---------------------------------------------------- + TINTEG_SCHEME_TYPE = 'ERK_SSP_3s3o', + nstep_eval_error = 50, +/ +&PARAM_TIME + TIME_DURATION = 12.0D0, + TIME_DURATION_UNIT = 'DAY', + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 28800D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='q' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='Vellon' / +&HISTORY_ITEM name='Vellat' / +&HISTORY_ITEM name='qexact' / diff --git a/sample/advect3dGlobal/test_advect3dGlobal.f90 b/sample/advect3dGlobal/test_advect3dGlobal.f90 new file mode 100644 index 00000000..4208a04c --- /dev/null +++ b/sample/advect3dGlobal/test_advect3dGlobal.f90 @@ -0,0 +1,639 @@ +#include "scaleFElib.h" +program test_advect3dGlobal + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_prc + use scale_io + use scale_prof + use scale_const, only: & + RPlanet => CONST_radius + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d + use scale_mesh_cubedspheredom3d + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatCoord, & + CubedSphereCnv_LonLat2CSVec + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: & + MeshField2D, MeshField3D + use scale_meshfieldcomm_base, only: MeshFieldContainer + use scale_meshfieldcomm_cubedspheredom3d, only: MeshFieldCommCubedSphereDom3D + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_put, & + FILE_HISTORY_meshfield_write + + use scale_file_history, only: & + FILE_HISTORY_set_nowdate + + use scale_time_manager, only: & + TIME_manager_advance, & + TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP, & + TIME_DTSEC, TIME_NSTEP + use scale_timeint_rk, only: & + timeint_rk + + use mod_fieldutil, only: & + get_upwind_pos1d => fieldutil_get_upwind_pos1d, & + get_profile3d_tracer => fieldutil_get_profile3dGlobal_tracer, & + get_profile3d_flow => fieldutil_get_profile3dGlobal_flow + + + !----------------------------------------------------------------------------- + implicit none + + integer :: NeGX + integer :: NeGY + integer :: NeGZ + integer :: NLocalMeshPerPrc + + real(RP) :: dom_zmin + real(RP) :: dom_zmax + + ! The type of initial q (gaussian-hill, cosine-bell, top-hat) + character(len=H_SHORT) :: InitShapeName + real(RP) :: InitShapeParams(4) + ! The type of specified velocify field (rigid-body-rot) + character(len=H_SHORT) :: VelTypeName + real(RP) :: VelTypeParams(4) + + type(HexahedralElement) :: refElem + integer :: PolyOrder_h + integer :: PolyOrder_v + logical, parameter :: LumpedMassMatFlag = .false. + logical :: InitCond_GalerkinProjFlag + integer, parameter :: PolyOrderErrorCheck = 6 + type(sparsemat) :: Dx, Sx, Dy, Sy, Dz, Sz, Lift + + type(MeshCubedSphereDom3D), target :: mesh + type(MeshField3D), target :: q, qexact + type(MeshField3D), target :: U, V, W + type(MeshField3D), target :: Vellon, Vellat + type(MeshFieldCommCubedSphereDom3D) :: prgvars_comm + type(MeshFieldContainer) :: prgvars_comm_vars(1) + type(MeshFieldCommCubedSphereDom3D) :: auxvars_comm + type(MeshFieldContainer) :: auxvars_comm_vars(3) + + integer :: HST_ID(7) + + integer :: n, ke, p + type(LocalMesh3D), pointer :: lcmesh + + character(len=H_SHORT) :: TINTEG_SCHEME_TYPE + type(timeint_rk), allocatable :: tinteg_lc(:) + integer :: nowstep + integer :: rkstage + integer :: tintbuf_ind + integer, parameter :: RKVAR_Q = 1 + real(RP) :: tsec_ + + real(RP), allocatable :: IntrpMat(:,:) + real(RP) :: intw_intrp(PolyOrderErrorCheck**3) + real(RP) :: x_intrp(PolyOrderErrorCheck**3) + real(RP) :: y_intrp(PolyOrderErrorCheck**3) + real(RP) :: z_intrp(PolyOrderErrorCheck**3) + + integer :: nstep_eval_error + !------------------------------------------------------- + + call init() + call set_initcond() + + prgvars_comm_vars(1)%field3d => q + auxvars_comm_vars(1)%field3d => W + auxvars_comm_vars(2)%field3d => U + auxvars_comm_vars(3)%field3d => V + + do nowstep=1, TIME_NSTEP + do rkstage=1, tinteg_lc(1)%nstage + tsec_ = ( dble(nowstep-1) + tinteg_lc(1)%coef_c_ex(rkstage) ) * TIME_DTSEC + + call PROF_rapstart( 'set_velocity', 1) + do n=1, mesh%LOCAL_MESH_NUM + lcmesh => mesh%lcmesh_list(n) + call set_velocity_lc( U%local(n)%val, V%local(n)%val, W%local(n)%val, & + Vellon%local(n)%val, Vellat%local(n)%val, tsec_, & + lcmesh, lcmesh%refElem3D ) + end do + call PROF_rapend( 'set_velocity', 1) + + !* Exchange halo data + call PROF_rapstart( 'exchange_halo', 1) + call prgvars_comm%Put(prgvars_comm_vars, 1) + call prgvars_comm%Exchange() + call prgvars_comm%Get(prgvars_comm_vars, 1) + + call auxvars_comm%Put(auxvars_comm_vars, 1) + call auxvars_comm%Exchange() + call auxvars_comm%Get(auxvars_comm_vars, 1) + call PROF_rapend( 'exchange_halo', 1) + + + !* Update prognostic variables + do n=1, mesh%LOCAL_MESH_NUM + lcmesh => mesh%lcmesh_list(n) + tintbuf_ind = tinteg_lc(n)%tend_buf_indmap(rkstage) + + call PROF_rapstart( 'cal_dyn_tend', 1) + call cal_dyn_tend( & + tinteg_lc(n)%tend_buf2D_ex(:,:,RKVAR_Q,tintbuf_ind), & + q%local(n)%val, U%local(n)%val, V%local(n)%val, W%local(n)%val, & + lcmesh, lcmesh%refElem3D ) + call PROF_rapend( 'cal_dyn_tend', 1) + + call PROF_rapstart( 'update_var', 1) + call tinteg_lc(n)%Advance( rkstage, q%local(n)%val, RKVAR_Q, & + 1, lcmesh%refElem%Np, lcmesh%NeS, lcmesh%NeE ) + call PROF_rapend('update_var', 1) + end do + end do + + !* Advance time + call TIME_manager_advance() + + tsec_ = dble(nowstep) * TIME_DTSEC + if (mod(nowstep,nstep_eval_error) == 0) then + LOG_PROGRESS('(A,F13.5,A)') "t=", real(tsec_), "[s]" + call evaluate_error(tsec_) + end if + call FILE_HISTORY_set_nowdate( TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP ) + + !* Output + call FILE_HISTORY_meshfield_put(HST_ID(1), q) + call FILE_HISTORY_meshfield_put(HST_ID(2), qexact) + call FILE_HISTORY_meshfield_put(HST_ID(3), U) + call FILE_HISTORY_meshfield_put(HST_ID(4), V) + call FILE_HISTORY_meshfield_put(HST_ID(5), W) + call FILE_HISTORY_meshfield_put(HST_ID(6), Vellon) + call FILE_HISTORY_meshfield_put(HST_ID(7), Vellat) + call FILE_HISTORY_meshfield_write() + + end do + + call final() + +contains + subroutine cal_dyn_tend( dqdt, q_, U_, V_, W_, lmesh, elem) + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: dqdt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: q_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: U_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: V_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: W_(elem%Np,lmesh%NeA) + + real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np) + real(RP) :: LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%Ne) + + !------------------------------------------------------------------------ + + call PROF_rapstart( 'cal_dyn_tend_bndflux', 2) + call cal_del_flux_dyn( del_flux, & ! (out) + q_, U_, V_, W_, & ! (in) + lmesh%Gsqrt, lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) + lmesh%vmapM, lmesh%vmapP, & ! (in) + lmesh, elem ) ! (in) + call PROF_rapend( 'cal_dyn_tend_bndflux', 2) + + !----- + call PROF_rapstart( 'cal_dyn_tend_interior', 2) + !$omp parallel do private(Fx, Fy, Fz, LiftDelFlx) + do ke = lmesh%NeS, lmesh%NeE + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * q_(:,ke) * U_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * q_(:,ke) * V_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * q_(:,ke) * W_(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke), LiftDelFlx) + + dqdt(:,ke) = - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx ) / lmesh%Gsqrt(:,ke) + end do + call PROF_rapend( 'cal_dyn_tend_interior', 2) + + return + end subroutine cal_dyn_tend + + subroutine cal_del_flux_dyn( del_flux, q_, U_, V_, W_, Gsqrt_, nx, ny, nz, vmapM, vmapP, lmesh, elem ) + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%Ne) + real(RP), intent(in) :: q_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: U_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: V_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: W_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt_(elem%Np*lmesh%Ne) + real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) + + integer :: i, iP, iM + real(RP) :: VelP, VelM, alpha + !------------------------------------------------------------------------ + + !$omp parallel do private(iM, iP, VelM, VelP, alpha) + do i=1, elem%NfpTot * lmesh%Ne + iM = vmapM(i); iP = vmapP(i) + + VelM = U_(iM) * nx(i) + V_(iM) * ny(i) + W_(iM) * nz(i) + VelP = U_(iP) * nx(i) + V_(iP) * ny(i) + W_(iP) * nz(i) + + alpha = 0.5_RP * abs( VelM + VelP ) + del_flux(i) = 0.5_RP * ( & + ( q_(iP) * VelP - q_(iM) * VelM ) & + - alpha * ( q_(iP) - q_(iM) ) & + ) * Gsqrt_(iM) + end do + + return + end subroutine cal_del_flux_dyn + + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + subroutine evaluate_error(tsec) + + implicit none + + real(DP), intent(in) :: tsec + + real(RP) :: q_intrp(PolyOrderErrorCheck**3) + real(RP) :: qexact_intrp(PolyOrderErrorCheck**3) + real(RP) :: x_uwind(refElem%Np), y_vwind(refElem%Np), z_vwind(refElem%Np) + real(RP) :: x_uwind_intrp(PolyOrderErrorCheck**3) + real(RP) :: y_vwind_intrp(PolyOrderErrorCheck**3) + real(RP) :: z_vwind_intrp(PolyOrderErrorCheck**3) + real(RP) :: pos_intrp(PolyOrderErrorCheck**3,3) + real(RP) vx(6), vy(6), vz(6) + + real(RP) :: l2error + real(RP) :: linferror + real(RP) :: ADV_VELX, ADV_VELY, ADV_VELZ + !------------------------------------------------------------------------ + + l2error = 0.0_RP + linferror = 0.0_RP + ADV_VELX = VelTypeParams(1); ADV_VELY = VelTypeParams(2) + + ! do n=1, mesh%LOCAL_MESH_NUM + ! lcmesh => mesh%lcmesh_list(n) + ! do k=lcmesh%NeS, lcmesh%NeE + + ! x_uwind(:) = get_upwind_pos1d(lcmesh%pos_en(:,k,1), ADV_VELX, tsec, dom_xmin, dom_xmax) + ! y_vwind(:) = get_upwind_pos1d(lcmesh%pos_en(:,k,2), ADV_VELY, tsec, dom_ymin, dom_ymax) + + ! vx(:) = lcmesh%pos_ev(lcmesh%EToV(k,:),1) + ! vy(:) = lcmesh%pos_ev(lcmesh%EToV(k,:),2) + ! pos_intrp(:,1) = vx(1) + 0.5_RP*(x_intrp(:) + 1.0_RP)*(vx(2) - vx(1)) + ! pos_intrp(:,2) = vy(1) + 0.5_RP*(y_intrp(:) + 1.0_RP)*(vy(3) - vy(1)) + ! x_uwind_intrp(:) = get_upwind_pos1d(pos_intrp(:,1), ADV_VELX, tsec, dom_xmin, dom_xmax) + ! y_vwind_intrp(:) = get_upwind_pos1d(pos_intrp(:,2), ADV_VELY, tsec, dom_ymin, dom_ymax) + + ! call get_profile2d_tracer( qexact%local(n)%val(:,k), & ! (out) + ! InitShapeName, x_uwind, y_vwind, InitShapeParams, refElem%Np ) ! (in) + + ! call get_profile2d_tracer( qexact_intrp(:), & ! (out) + ! InitShapeName, x_uwind_intrp, y_vwind_intrp, InitShapeParams, PolyOrderErrorCheck**2 ) ! (in) + + ! q_intrp(:) = matmul(IntrpMat, q%local(n)%val(:,k)) + + ! l2error = l2error & + ! + sum( lcmesh%J(1,k) * intw_intrp(:) * ( q_intrp(:) - qexact_intrp(:) )**2 ) + + ! linferror = max(linferror, maxval(abs(q%local(n)%val(:,k) - qexact%local(n)%val(:,k)))) + ! end do + ! end do + + ! LOG_INFO("evaluate_error_l2",*) sqrt(l2error)/( (dom_xmax - dom_xmin) * (dom_ymax - dom_ymin) ) + ! LOG_INFO("evaluate_error_linf",*) linferror + + return + end subroutine evaluate_error + + subroutine set_velocity_lc( U_, V_, W_, Vellon_, Vellat_, & + tsec, lmesh, elem ) + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: U_(elem%Np,lmesh%NeA) + real(RP), intent(out) :: V_(elem%Np,lmesh%NeA) + real(RP), intent(out) :: W_(elem%Np,lmesh%NeA) + real(RP), intent(out) :: Vellon_(elem%Np,lmesh%NeA) + real(RP), intent(out) :: Vellat_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: tsec + + integer :: ke_ + real(RP) :: svec(elem%Np,lmesh%Ne,2) + real(RP) :: lon3D(elem%Np), lat3D(elem%Np) + + !---------------------------------------- + + VelTypeParams(4) = tsec + + !$omp parallel do private(lon3D, lat3D) + do ke_=lmesh%NeS, lmesh%NeE + lon3D(:) = lmesh%lon2D(elem%IndexH2Dto3D(:),lmesh%EMap3Dto2D(ke_)) + lat3D(:) = lmesh%lat2D(elem%IndexH2Dto3D(:),lmesh%EMap3Dto2D(ke_)) + + call get_profile3d_flow( svec(:,ke_,1), svec(:,ke_,2), W_(:,ke_), & ! (out) + VelTypeName, lon3D(:), lat3D(:), lmesh%pos_en(:,ke_,3), & ! (in) + VelTypeParams, elem%Np ) ! (in) + + Vellon_(:,ke_) = svec(:,ke_,1) + Vellat_(:,ke_) = svec(:,ke_,2) + + svec(:,ke_,1) = svec(:,ke_,1) / cos(lat3D(:)) + end do + + call CubedSphereCnv_LonLat2CSVec( & + lmesh%panelID, lmesh%pos_en(:,:,1), lmesh%pos_en(:,:,2), & + lmesh%Ne * elem%Np, RPlanet, svec(:,:,1), svec(:,:,2), & + U_(:,lmesh%NeS:lmesh%NeE), V_(:,lmesh%NeS:lmesh%NeE) ) + + return + end subroutine set_velocity_lc + + subroutine set_initcond() + use scale_linalgebra, only: linalgebra_inv + use scale_polynominal, only: & + Polynominal_GenLagrangePoly, Polynominal_GenGaussLobattoPt, Polynominal_GenGaussLegendrePt + implicit none + + real(RP) :: q_intrp(PolyOrderErrorCheck**3) + real(RP) :: lgl1D_h(refElem%PolyOrder_h+1), lgl1D_v(refElem%PolyOrder_v+1) + real(RP) :: r_int1D_i(PolyOrderErrorCheck) + real(RP) :: lagrange_intrp1D(PolyOrderErrorCheck,refElem%PolyOrder_h+1) + real(RP) :: lagrange_intrp(PolyOrderErrorCheck**2,refElem%Np) + real(RP) :: pos_intrp(PolyOrderErrorCheck**3,3) + real(RP) vx(6), vy(6), vz(6) + integer :: p1, p2, p3, p1_, p2_, p3_ + integer :: n_, l_ + real(RP) int_gphi(refElem%Np) + + real(RP) :: lon3D(refElem%Np), lat3D(refElem%Np) + integer :: ke_ + type(ElementBase3D), pointer :: elem + !------------------------------------------------------------------------ + + do n=1, mesh%LOCAL_MESH_NUM + lcmesh => mesh%lcmesh_list(n) + elem => lcmesh%refElem3D + + !$omp parallel do private(ke_, lon3D, lat3D) + do ke_=lcmesh%NeS, lcmesh%NeE + lon3D(:) = lcmesh%lon2D(elem%IndexH2Dto3D(:),lcmesh%EMap3Dto2D(ke_)) + lat3D(:) = lcmesh%lat2D(elem%IndexH2Dto3D(:),lcmesh%EMap3Dto2D(ke_)) + + call get_profile3d_tracer( qexact%local(n)%val(:,ke_), & ! (out) + InitShapeName, lon3D(:), lat3D(:), lcmesh%pos_en(:,ke_,3), & ! (in) + RPlanet, InitShapeParams, elem%Np ) ! (in) + + q%local(n)%val(:,ke_) = qexact%local(n)%val(:,ke_) + end do + + call set_velocity_lc( U%local(n)%val, V%local(n)%val, W%local(n)%val, & + Vellon%local(n)%val, Vellat%local(n)%val, & + 0.0_RP, lcmesh, elem ) + end do + + ! if (InitCond_GalerkinProjFlag) then + + ! lgl1D(:) = Polynominal_GenGaussLobattoPt(refElem%PolyOrder) + ! r_int1D_i(:) = Polynominal_GenGaussLegendrePt( PolyOrderErrorCheck ) + ! lagrange_intrp1D(:,:) = Polynominal_GenLagrangePoly(refElem%PolyOrder, lgl1D, r_int1D_i) + ! do p2_=1, PolyOrderErrorCheck + ! do p1_=1, PolyOrderErrorCheck + ! n_= p1_ + (p2_-1)*PolyOrderErrorCheck + ! do p2=1, refElem%Nfp + ! do p1=1, refElem%Nfp + ! l_ = p1 + (p2-1)*refElem%Nfp + ! lagrange_intrp(n_,l_) = lagrange_intrp1D(p1_,p1)*lagrange_intrp1D(p2_,p2) + ! end do + ! end do + ! end do + ! end do + + ! do n=1, mesh%LOCAL_MESH_NUM + ! lcmesh => mesh%lcmesh_list(n) + ! do k=lcmesh%NeS, lcmesh%NeE + ! vx(:) = lcmesh%pos_ev(lcmesh%EToV(k,:),1) + ! vy(:) = lcmesh%pos_ev(lcmesh%EToV(k,:),2) + ! pos_intrp(:,1) = vx(1) + 0.5_RP*(x_intrp(:) + 1.0_RP)*(vx(2) - vx(1)) + ! pos_intrp(:,2) = vy(1) + 0.5_RP*(y_intrp(:) + 1.0_RP)*(vy(3) - vy(1)) + + ! call get_profile2d_tracer( q_intrp(:), & ! (out) + ! InitShapeName, pos_intrp(:,1), pos_intrp(:,2), InitShapeParams, PolyOrderErrorCheck**2 ) ! (in) + + ! do l_=1, refElem%Np + ! int_gphi(l_) = sum(intw_intrp(:)*lagrange_intrp(:,l_)*q_intrp(:)) + ! end do + ! q%local(n)%val(:,k) = matmul(refElem%invM, int_gphi) + ! end do + ! end do + ! end if + + call FILE_HISTORY_meshfield_put(HST_ID(1), q) + call FILE_HISTORY_meshfield_put(HST_ID(2), qexact) + call FILE_HISTORY_meshfield_put(HST_ID(3), U) + call FILE_HISTORY_meshfield_put(HST_ID(4), V) + call FILE_HISTORY_meshfield_put(HST_ID(5), W) + call FILE_HISTORY_meshfield_put(HST_ID(6), Vellon) + call FILE_HISTORY_meshfield_put(HST_ID(7), Vellat) + call FILE_HISTORY_meshfield_write() + + LOG_PROGRESS('(A,F13.5,A)') "t=", real(0.0_RP), "[s]" + call evaluate_error(0.0_RP) + + return + end subroutine set_initcond + + subroutine init() + + use scale_calendar, only: CALENDAR_setup + use scale_time_manager, only: TIME_manager_Init + use scale_file_history_meshfield, only: FILE_HISTORY_meshfield_setup + use scale_file_history, only: FILE_HISTORY_reg + use scale_const, only: & + CONST_setup + + implicit none + + namelist /PARAM_TEST/ & + NeGX, NeGY, NeGZ, NLocalMeshPerPrc, & + PolyOrder_h, PolyOrder_v, & + dom_zmin, dom_zmax, & + TINTEG_SCHEME_TYPE, & + InitShapeName, InitShapeParams, & + InitCond_GalerkinProjFlag, & + VelTypeName, VelTypeParams, & + nstep_eval_error + + integer :: comm, myrank, nprocs + logical :: ismaster + integer :: ierr + !------------------------------------------------------------------------ + + call PRC_MPIstart( comm ) + + call PRC_SINGLECOM_setup( comm, & ! [IN] + nprocs, myrank, ismaster ) ! [OUT] + + call PRC_ERRHANDLER_setup( .false., ismaster ) ! [IN] + + ! setup scale_io + call IO_setup( "test_advect3d", "test.conf" ) + + ! setup log + call IO_LOG_setup( myrank, ismaster ) + + !--- read namelist + + NeGX = 2; NeGY = 2; NeGZ = 2 + PolyOrder_h = 1 + PolyOrder_v = 1 + TINTEG_SCHEME_TYPE = 'ERK_SSP_3s3o' + InitShapeName = 'sin' + InitShapeParams(:) = (/ 1.0_RP, 1.0_RP, 0.0_RP, 0.0_RP /) + VelTypeName = 'const' + InitCond_GalerkinProjFlag = .false. + VelTypeParams(:) = (/ 1.0_RP, 1.0_RP, 0.0_RP, 0.0_RP /) + nstep_eval_error = 5 + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_TEST,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("init",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("init",*) 'Not appropriate names in namelist PARAM_TEST. Check!' + call PRC_abort + endif + LOG_NML(PARAM_TEST) + + ! setup profiler + call PROF_setup + call PROF_rapstart( "total", 0 ) + call PROF_rapstart( "init", 1 ) + + ! setup calendar & initial time + call CALENDAR_setup + call TIME_manager_Init + + ! setup constat + call CONST_setup + + !------ + + call refElem%Init(PolyOrder_h, PolyOrder_v, LumpedMassMatFlag) + call Dx%Init(refElem%Dx1) + call Sx%Init(refElem%Sx1) + call Dy%Init(refElem%Dx2) + call Sy%Init(refElem%Sx2) + call Dz%Init(refElem%Dx3) + call Sz%Init(refElem%Sx3) + call Lift%Init(refElem%Lift) + + call mesh%Init( & + NeGX, NeGY, NeGz, RPlanet, dom_zmin, dom_zmax, & + refElem, NLocalMeshPerPrc ) + + call mesh%Generate() + + ! setup for time integrator + allocate( tinteg_lc(mesh%LOCAL_MESH_NUM) ) + do n=1, mesh%LOCAL_MESH_NUM + lcmesh => mesh%lcmesh_list(n) + call tinteg_lc(n)%Init( TINTEG_SCHEME_TYPE, TIME_DTSEC, 1, & + 2, (/ lcmesh%refElem%Np, lcmesh%NeA /) ) + end do + + !--- + call q%Init( "q", "1", mesh ) + call qexact%Init( "qexact", "1", mesh ) + call U%Init( "U", "s-1", mesh ) + call V%Init( "V", "s-1", mesh ) + call W%Init( "W", "s-1", mesh ) + + call prgvars_comm%Init(1, 0, mesh) + call auxvars_comm%Init(1, 1, mesh) + + call Vellon%Init( "Vellon", "m/s", mesh ) + call Vellat%Init( "Vellat", "m/s", mesh ) + + call FILE_HISTORY_meshfield_setup( meshCubedSphere3d_=mesh ) + + call FILE_HISTORY_reg( q%varname, "q", q%unit, HST_ID(1), dim_type='XYZ') + call FILE_HISTORY_reg( qexact%varname, "qexact", q%unit, HST_ID(2), dim_type='XYZ') + call FILE_HISTORY_reg( U%varname, "U", U%unit, HST_ID(3), dim_type='XYZ') + call FILE_HISTORY_reg( V%varname, "V", V%unit, HST_ID(4), dim_type='XYZ') + call FILE_HISTORY_reg( W%varname, "W", W%unit, HST_ID(5), dim_type='XYZ') + call FILE_HISTORY_reg( Vellon%varname, "Vellon", Vellon%unit, HST_ID(6), dim_type='XYZ') + call FILE_HISTORY_reg( Vellat%varname, "Vellat", Vellat%unit, HST_ID(7), dim_type='XYZ') + + allocate( IntrpMat(PolyOrderErrorCheck**3,(PolyOrder_h+1)**2*(PolyOrder_v+1)) ) + IntrpMat(:,:) = refElem%GenIntGaussLegendreIntrpMat( PolyOrderErrorCheck, & ! (in) + intw_intrp, x_intrp, y_intrp, z_intrp ) ! (out) + + call PROF_rapend( "init", 1 ) + + return + end subroutine init + + subroutine final() + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_finalize + use scale_time_manager, only: TIME_manager_Final + implicit none + !------------------------------------------------------------------------ + + call PROF_rapstart( "final", 1 ) + + call FILE_HISTORY_meshfield_finalize() + + do n=1, mesh%LOCAL_MESH_NUM + call tinteg_lc(n)%Final() + end do + + call q%Final() + call qexact%Final() + call U%Final() + call V%Final() + call W%Final() + + call prgvars_comm%Final() + call auxvars_comm%Final() + call mesh%Final() + + call Dx%Final() + call Sx%Final() + call Dy%Final() + call Sy%Final() + call Dz%Final() + call Sz%Final() + call Lift%Final() + call refElem%Final() + + call TIME_manager_Final + + call PROF_rapend( "final", 1 ) + call PROF_rapend( "total", 0 ) + call PROF_rapreport + call PRC_MPIfinish() + + return + end subroutine final +end program test_advect3dGlobal diff --git a/sample/auxiliary/mod_fieldutil.f90 b/sample/auxiliary/mod_fieldutil.f90 index 8eb89b4f..5aa5eda8 100644 --- a/sample/auxiliary/mod_fieldutil.f90 +++ b/sample/auxiliary/mod_fieldutil.f90 @@ -1,4 +1,15 @@ !------------------------------------------------------------------------------- +!> module sample / auxiliary +!! +!! @par Description +!! A module to provide idealized & analytic profiles for 1D-3D test cases +!! +!! @par Reference +!! - Kent et al. 2014: +!! Dynamical core model intercomparison project: Tracer transport test cases. +!! Quarterly Journal of the Royal Meteorological Society, 140(681), 1279-1293. +!! +!------------------------------------------------------------------------------- #include "scaleFElib.h" module mod_fieldutil !----------------------------------------------------------------------------- @@ -31,6 +42,9 @@ module mod_fieldutil public :: fieldutil_get_profile3d_tracer public :: fieldutil_get_profile3d_flow + public :: fieldutil_get_profile3dGlobal_tracer + public :: fieldutil_get_profile3dGlobal_flow + !----------------------------------------------------------------------------- ! !++ Public parameters & variables @@ -44,352 +58,558 @@ module mod_fieldutil !------------------- contains -!--- 1d ----------------------------------------------------- - -function fieldutil_get_upwind_pos1d(pos, ADV_VEL, nowtime, dom_min, dom_max) result(upos) - real(RP), intent(in) :: pos(:) - real(RP), intent(in) :: ADV_VEL - real(RP), intent(in) :: nowtime - real(RP), intent(in) :: dom_min, dom_max - real(RP) :: upos(size(pos)) - - integer :: period - !------- - - period = ADV_VEL*nowtime/(dom_max - dom_min) - upos(:) = pos(:) - (ADV_VEL*nowtime - dble(period)*(dom_max - dom_min)) - where (upos < dom_min) - upos = dom_max + (upos - dom_min) - end where -end function fieldutil_get_upwind_pos1d - -!> Get 1D data whose value is set based on specified pattern. -! -! Assume that range of domain is 0 <= x <= 1. -! If the profile_name is 'sin', param1 indicates the wavenumber. -! If the profile_name is 'cosbell', param1 indicates the half of width. -! If the profile_name is 'top-hat', param1 indicates the half of width. -! -subroutine fieldutil_get_profile1d_tracer( profile, & - profile_name, x, params, N ) - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: profile(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: x(N) - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - !-------------------------------- - - profile(:) = 0.0_RP - - select case(profile_name) - case ('constant') - profile(:) = params(1) - case ('sin') - profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) - case ('gaussian-hill') - profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2)/params(2)**2 ) - case ('cosine-bell') - dist(:) = abs(x(:) - params(1)) - where( dist <= params(2) ) - profile(:) = (1.0_RP + cos(PI*dist/params(2)))*0.5_RP - end where - case ('top-hat') - where( abs(x - params(1)) <= params(2) ) - profile(:) = 1.0_RP - end where - case default - LOG_ERROR('fieldutil_get_profile2d',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile1d_tracer - -!-- 2d-------------------------------------------------------------- - -!> Get 2D data whose value is set based on specified pattern. -! -! Assume that range of domain is 0 <= x,y <= 1. -! If the profile_name is 'sin', param1 and param2 are the wavenumbers in x- and y- directions, respectively. -! If the profile_name is 'gaussian-hill', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. -! If the profile_name is 'cosine-bell', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. -! If the profile_name is 'top-hat', (param1,param2) is the coordinate of center position, param3 and param4 are the half of width in x- and y- directions, respectively. -! -subroutine fieldutil_get_profile2d_tracer( profile, & - profile_name, x, y, params, N ) - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: profile(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: x(N) - real(RP), intent(in) :: y(N) - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - !------------------------------------------------------------------------ - - profile(:) = 0.0_RP - - select case(profile_name) - case ('constant') - profile(:) = params(1) - case ('sin') - profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) - case ('gaussian-hill') - profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2 + (y(:) - params(2))**2)/params(3)**2 ) - case ('cosine-bell') - dist(:) = sqrt( (x(:) - params(1))**2 + (y(:) - params(2))**2 ) - where( dist <= params(3) ) - profile(:) = (1.0_RP + cos(PI*dist(:)/params(3)))*0.5_RP - end where - case ('top-hat') - where( abs(x-params(1)) <= params(3) .and. abs(y-params(2)) <= params(4) ) - profile(:) = 1.0_RP - end where - case default - LOG_ERROR('fieldutil_get_profile2d',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile2d_tracer + !--- 1d ----------------------------------------------------- -!------------------------------- + function fieldutil_get_upwind_pos1d(pos, ADV_VEL, nowtime, dom_min, dom_max) result(upos) + real(RP), intent(in) :: pos(:) + real(RP), intent(in) :: ADV_VEL + real(RP), intent(in) :: nowtime + real(RP), intent(in) :: dom_min, dom_max + real(RP) :: upos(size(pos)) -subroutine fieldutil_get_profile2d_flow( flow_x, flow_y, & - profile_name, x, y, params, N) + integer :: period + !------- - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: flow_x(N) - real(RP), intent(out) :: flow_y(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: x(N) - real(RP), intent(in) :: y(N) - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - real(RP) :: fac - !------------------------------------------------------------------------ - - flow_x(:) = 0.0_RP - flow_y(:) = 0.0_RP - - select case(profile_name) - case ('constant') - flow_x(:) = params(1) - flow_y(:) = params(2) - case ('rigid-body-rot') - flow_x(:) = - 2.0_RP*PI/params(3)*(y(:) - params(1)) - flow_y(:) = + 2.0_RP*PI/params(3)*(x(:) - params(2)) - case ('swirling') - fac = cos(PI*params(4)/params(3)) - flow_x(:) = + sin(PI*x(:))**2 * sin(2.0_RP*PI*y(:)) * fac - flow_y(:) = - sin(PI*y(:))**2 * sin(2.0_RP*PI*x(:)) * fac - case default - LOG_ERROR('fieldutil_get_flow2d',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile2d_flow - -!-- 2d Global-------------------------------------------------------------- - -!> Get 2D data whose value is set based on specified pattern. -! -! Assume that range of domain is 0 <= x,y <= 1. -! If the profile_name is 'sin', param1 and param2 are the wavenumbers in x- and y- directions, respectively. -! If the profile_name is 'gaussian-hill', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. -! If the profile_name is 'cosine-bell', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. -! If the profile_name is 'top-hat', (param1,param2) is the coordinate of center position, param3 and param4 are the half of width in x- and y- directions, respectively. -! -subroutine fieldutil_get_profile2dGlobal_tracer( profile, & - profile_name, lon, lat, RPlanet, params, N ) - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: profile(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: lon(N) - real(RP), intent(in) :: lat(N) - real(RP), intent(in) :: RPlanet - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - !------------------------------------------------------------------------ - - profile(:) = 0.0_RP - - select case(profile_name) - ! case ('constant') - ! profile(:) = params(1) - ! case ('sin') - ! profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) - ! case ('gaussian-hill') - ! profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2 + (y(:) - params(2))**2)/params(3)**2 ) - case ('cosine-bell') - dist(:) = RPlanet * acos( & - sin(params(2))*sin(lat(:)) + cos(params(2))*cos(lat(:))*cos(lon(:) - params(1)) ) - where( dist <= params(3) ) - profile(:) = (1.0_RP + cos(PI*dist(:)/params(3)))*0.5_RP - end where - ! case ('top-hat') - ! where( abs(x-params(1)) <= params(3) .and. abs(y-params(2)) <= params(4) ) - ! profile(:) = 1.0_RP - ! end where - case default - LOG_ERROR('fieldutil_get_profile2dGlobal',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile2dGlobal_tracer - -!------------------------------- - -subroutine fieldutil_get_profile2dGlobal_flow( flow_lon, flow_lat, & - profile_name, lon, lat, params, N) - - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: flow_lon(N) - real(RP), intent(out) :: flow_lat(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: lon(N) - real(RP), intent(in) :: lat(N) - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - real(RP) :: fac - !------------------------------------------------------------------------ - - flow_lon(:) = 0.0_RP - flow_lat(:) = 0.0_RP - - select case(profile_name) - ! case ('constant') - ! flow_x(:) = params(1) - ! flow_y(:) = params(2) - case ('rigid-body-rot') - flow_lon(:) = params(1) * ( cos(params(2)) * cos(lat(:)) + sin(params(2)) * cos(lon(:)) * sin(lat(:)) ) - flow_lat(:) = - params(1) * sin(params(2)) * sin(lon(:)) - ! case ('swirling') - ! fac = cos(PI*params(4)/params(3)) - ! flow_x(:) = + sin(PI*x(:))**2 * sin(2.0_RP*PI*y(:)) * fac - ! flow_y(:) = - sin(PI*y(:))**2 * sin(2.0_RP*PI*x(:)) * fac - case default - LOG_ERROR('fieldutil_get_flow2dGlobal',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile2dGlobal_flow - -!-- 3d-------------------------------------------------------------- - -!> Get 3D data whose value is set based on specified pattern. -! -! Assume that range of domain is 0 <= x,y,z <= 1. -! If the profile_name is 'sin', param1, param2 and param3 are the wavenumbers in x-, y- and z- directions, respectively. -! If the profile_name is 'gaussian-hill', (param1,param2,param3) is the coordinate of center position, param4 is the half of width. The shape is isotropic about the center of domain. -! If the profile_name is 'cosine-bell', (param1,param2,param3) is the coordinate of center position, param4 is the half of width. The shape is isotropic about the center of domain. -! If the profile_name is 'top-hat', (param1,param2,param3) is the coordinate of center position, param4, param5 and param6 are the half of width in x-, y- and z- directions, respectively. -! -subroutine fieldutil_get_profile3d_tracer( profile, & - profile_name, x, y, z, params, N ) - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: profile(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: x(N) - real(RP), intent(in) :: y(N) - real(RP), intent(in) :: z(N) - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - !------------------------------------------------------------------------ - - profile(:) = 0.0_RP - - select case(profile_name) - case ('constant') - profile(:) = params(1) - case ('sin') - profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) * sin( params(3)*2.0_RP*PI*z(:) ) - case ('gaussian-hill') - dist(:) = ((x(:) - params(1))**2 + (y(:) - params(2))**2 + (z(:) - params(3))**2)/params(4)**2 - profile(:) = exp( - 0.5_RP * dist(:) ) - case ('cosine-bell') - dist(:) = sqrt( (x(:) - params(1))**2 + (y(:) - params(2))**2 + (z(:) - params(3))**2) - where( dist <= params(4) ) - profile(:) = (1.0_RP + cos(PI*dist(:)/params(4)))*0.5_RP + period = ADV_VEL*nowtime/(dom_max - dom_min) + upos(:) = pos(:) - (ADV_VEL*nowtime - dble(period)*(dom_max - dom_min)) + where (upos < dom_min) + upos = dom_max + (upos - dom_min) end where - case ('top-hat') - where( abs(x-params(1)) <= params(4) .and. abs(y-params(2)) <= params(5) .and. abs(y-params(3)) <= params(6)) - profile(:) = 1.0_RP - end where - case default - LOG_ERROR('fieldutil_get_profile2d',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile3d_tracer - -!------------------------------- - -subroutine fieldutil_get_profile3d_flow( flow_x, flow_y, flow_z, & - profile_name, x, y, z, params, N) - - implicit none - !-------------------------------- - integer, intent(in) :: N - real(RP), intent(out) :: flow_x(N) - real(RP), intent(out) :: flow_y(N) - real(RP), intent(out) :: flow_z(N) - character(*), intent(in) :: profile_name - real(RP), intent(in) :: x(N) - real(RP), intent(in) :: y(N) - real(RP), intent(in) :: z(N) - real(RP), intent(in) :: params(:) - - real(RP) :: dist(N) - real(RP) :: fac - !------------------------------------------------------------------------ - - flow_x(:) = 0.0_RP - flow_y(:) = 0.0_RP - flow_z(:) = 0.0_RP - - select case(profile_name) - case ('constant') - flow_x(:) = params(1) - flow_y(:) = params(2) - flow_z(:) = params(3) - ! case ('rigid-body-rot') - ! flow_x(:) = - 2.0_RP*PI/params(4)*(y(:) - params(1)) - ! flow_y(:) = + 2.0_RP*PI/params(4)*(x(:) - params(2)) - ! flow_z(:) = 0.0_RP - ! case ('swirling') - ! fac = cos(PI*params(5)/params(4)) - ! flow_x(:) = + sin(PI*x(:))**2 * sin(2.0_RP*PI*y(:)) * fac - ! flow_y(:) = - sin(PI*y(:))**2 * sin(2.0_RP*PI*x(:)) * fac - ! flow_z(:) = 0.0_RP - case default - LOG_ERROR('fieldutil_get_flow3d',*) trim(profile_name)//' is not supported. Check!' - call PRC_abort - end select - - return -end subroutine fieldutil_get_profile3d_flow + end function fieldutil_get_upwind_pos1d + !> Get 1D data whose value is set based on specified pattern. + ! + ! Assume that range of domain is 0 <= x <= 1. + ! If the profile_name is 'sin', param1 indicates the wavenumber. + ! If the profile_name is 'cosbell', param1 indicates the half of width. + ! If the profile_name is 'top-hat', param1 indicates the half of width. + ! + subroutine fieldutil_get_profile1d_tracer( profile, & + profile_name, x, params, N ) + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: profile(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: x(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + !-------------------------------- + + profile(:) = 0.0_RP + + select case(profile_name) + case ('constant') + profile(:) = params(1) + case ('sin') + profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) + case ('gaussian-hill') + profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2)/params(2)**2 ) + case ('cosine-bell') + dist(:) = abs(x(:) - params(1)) + where( dist <= params(2) ) + profile(:) = (1.0_RP + cos(PI*dist/params(2)))*0.5_RP + end where + case ('top-hat') + where( abs(x - params(1)) <= params(2) ) + profile(:) = 1.0_RP + end where + case default + LOG_ERROR('fieldutil_get_profile2d',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile1d_tracer + + !-- 2d-------------------------------------------------------------- + + !> Get 2D data whose value is set based on specified pattern. + ! + ! Assume that range of domain is 0 <= x,y <= 1. + ! If the profile_name is 'sin', param1 and param2 are the wavenumbers in x- and y- directions, respectively. + ! If the profile_name is 'gaussian-hill', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'cosine-bell', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'top-hat', (param1,param2) is the coordinate of center position, param3 and param4 are the half of width in x- and y- directions, respectively. + ! + subroutine fieldutil_get_profile2d_tracer( profile, & + profile_name, x, y, params, N ) + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: profile(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: x(N) + real(RP), intent(in) :: y(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + !------------------------------------------------------------------------ + + profile(:) = 0.0_RP + + select case(profile_name) + case ('constant') + profile(:) = params(1) + case ('sin') + profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) + case ('gaussian-hill') + profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2 + (y(:) - params(2))**2)/params(3)**2 ) + case ('cosine-bell') + dist(:) = sqrt( (x(:) - params(1))**2 + (y(:) - params(2))**2 ) + where( dist <= params(3) ) + profile(:) = (1.0_RP + cos(PI*dist(:)/params(3)))*0.5_RP + end where + case ('top-hat') + where( abs(x-params(1)) <= params(3) .and. abs(y-params(2)) <= params(4) ) + profile(:) = 1.0_RP + end where + case default + LOG_ERROR('fieldutil_get_profile2d',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile2d_tracer + + !------------------------------- + + !> Get 2D velocity data whose values are set based on specified pattern. + ! + ! Assume that range of domain is 0 <= x,y <= 1. + ! If the profile_name is 'constant', param1 and param2 are the compoent of velocity in x- and y- directions, respectively. + ! If the profile_name is 'rigid-body-rot', (param1,param2) is the coordinate of center position, param3 is the period of rigidlid rotation. + ! If the profile_name is 'swirling', param3 is a parameter of period and the flow reaches the maximum deformation at n x param3/2 where n is a natural number. param4 is the current time. + ! + subroutine fieldutil_get_profile2d_flow( flow_x, flow_y, & + profile_name, x, y, params, N) + + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: flow_x(N) + real(RP), intent(out) :: flow_y(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: x(N) + real(RP), intent(in) :: y(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + real(RP) :: fac + !------------------------------------------------------------------------ + + flow_x(:) = 0.0_RP + flow_y(:) = 0.0_RP + + select case(profile_name) + case ('constant') + flow_x(:) = params(1) + flow_y(:) = params(2) + case ('rigid-body-rot') + flow_x(:) = - 2.0_RP*PI/params(3)*(y(:) - params(1)) + flow_y(:) = + 2.0_RP*PI/params(3)*(x(:) - params(2)) + case ('swirling') + fac = cos(PI*params(4)/params(3)) + flow_x(:) = + sin(PI*x(:))**2 * sin(2.0_RP*PI*y(:)) * fac + flow_y(:) = - sin(PI*y(:))**2 * sin(2.0_RP*PI*x(:)) * fac + case default + LOG_ERROR('fieldutil_get_flow2d',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile2d_flow + + !-- 2d Global-------------------------------------------------------------- + + !> Get 2D data whose value is set based on specified pattern. + ! + ! Assume that range of domain is 0 <= x,y <= 1. + ! If the profile_name is 'sin', param1 and param2 are the wavenumbers in x- and y- directions, respectively. + ! If the profile_name is 'gaussian-hill', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'cosine-bell', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'top-hat', (param1,param2) is the coordinate of center position, param3 and param4 are the half of width in x- and y- directions, respectively. + ! + subroutine fieldutil_get_profile2dGlobal_tracer( profile, & + profile_name, lon, lat, RPlanet, params, N ) + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: profile(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: lon(N) + real(RP), intent(in) :: lat(N) + real(RP), intent(in) :: RPlanet + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + !------------------------------------------------------------------------ + + profile(:) = 0.0_RP + + select case(profile_name) + ! case ('constant') + ! profile(:) = params(1) + ! case ('sin') + ! profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) + ! case ('gaussian-hill') + ! profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2 + (y(:) - params(2))**2)/params(3)**2 ) + case ('cosine-bell') + dist(:) = RPlanet * acos( & + sin(params(2))*sin(lat(:)) + cos(params(2))*cos(lat(:))*cos(lon(:) - params(1)) ) + where( dist <= params(3) ) + profile(:) = (1.0_RP + cos(PI*dist(:)/params(3)))*0.5_RP + end where + ! case ('top-hat') + ! where( abs(x-params(1)) <= params(3) .and. abs(y-params(2)) <= params(4) ) + ! profile(:) = 1.0_RP + ! end where + case default + LOG_ERROR('fieldutil_get_profile2dGlobal',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile2dGlobal_tracer + + !------------------------------- + + subroutine fieldutil_get_profile2dGlobal_flow( flow_lon, flow_lat, & + profile_name, lon, lat, params, N) + + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: flow_lon(N) + real(RP), intent(out) :: flow_lat(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: lon(N) + real(RP), intent(in) :: lat(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + real(RP) :: fac + !------------------------------------------------------------------------ + + flow_lon(:) = 0.0_RP + flow_lat(:) = 0.0_RP + + select case(profile_name) + ! case ('constant') + ! flow_x(:) = params(1) + ! flow_y(:) = params(2) + case ('rigid-body-rot') + flow_lon(:) = params(1) * ( cos(params(2)) * cos(lat(:)) + sin(params(2)) * cos(lon(:)) * sin(lat(:)) ) + flow_lat(:) = - params(1) * sin(params(2)) * sin(lon(:)) + ! case ('swirling') + ! fac = cos(PI*params(4)/params(3)) + ! flow_x(:) = + sin(PI*x(:))**2 * sin(2.0_RP*PI*y(:)) * fac + ! flow_y(:) = - sin(PI*y(:))**2 * sin(2.0_RP*PI*x(:)) * fac + case default + LOG_ERROR('fieldutil_get_flow2dGlobal',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile2dGlobal_flow + + !-- 3d-------------------------------------------------------------- + + !> Get 3D data whose value is set based on specified pattern. + ! + ! Assume that range of domain is 0 <= x,y,z <= 1. + ! If the profile_name is 'sin', param1, param2 and param3 are the wavenumbers in x-, y- and z- directions, respectively. + ! If the profile_name is 'gaussian-hill', (param1,param2,param3) is the coordinate of center position, param4 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'cosine-bell', (param1,param2,param3) is the coordinate of center position, param4 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'top-hat', (param1,param2,param3) is the coordinate of center position, param4, param5 and param6 are the half of width in x-, y- and z- directions, respectively. + ! + subroutine fieldutil_get_profile3d_tracer( profile, & + profile_name, x, y, z, params, N ) + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: profile(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: x(N) + real(RP), intent(in) :: y(N) + real(RP), intent(in) :: z(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + !------------------------------------------------------------------------ + + profile(:) = 0.0_RP + + select case(profile_name) + case ('constant') + profile(:) = params(1) + case ('sin') + profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) * sin( params(3)*2.0_RP*PI*z(:) ) + case ('gaussian-hill') + dist(:) = ((x(:) - params(1))**2 + (y(:) - params(2))**2 + (z(:) - params(3))**2)/params(4)**2 + profile(:) = exp( - 0.5_RP * dist(:) ) + case ('cosine-bell') + dist(:) = sqrt( (x(:) - params(1))**2 + (y(:) - params(2))**2 + (z(:) - params(3))**2) + where( dist <= params(4) ) + profile(:) = (1.0_RP + cos(PI*dist(:)/params(4)))*0.5_RP + end where + case ('top-hat') + where( abs(x-params(1)) <= params(4) .and. abs(y-params(2)) <= params(5) .and. abs(y-params(3)) <= params(6)) + profile(:) = 1.0_RP + end where + case default + LOG_ERROR('fieldutil_get_profile2d',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile3d_tracer + + !------------------------------- + + subroutine fieldutil_get_profile3d_flow( flow_x, flow_y, flow_z, & + profile_name, x, y, z, params, N) + + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: flow_x(N) + real(RP), intent(out) :: flow_y(N) + real(RP), intent(out) :: flow_z(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: x(N) + real(RP), intent(in) :: y(N) + real(RP), intent(in) :: z(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + real(RP) :: fac + !------------------------------------------------------------------------ + + flow_x(:) = 0.0_RP + flow_y(:) = 0.0_RP + flow_z(:) = 0.0_RP + + select case(profile_name) + case ('constant') + flow_x(:) = params(1) + flow_y(:) = params(2) + flow_z(:) = params(3) + ! case ('rigid-body-rot') + ! flow_x(:) = - 2.0_RP*PI/params(4)*(y(:) - params(1)) + ! flow_y(:) = + 2.0_RP*PI/params(4)*(x(:) - params(2)) + ! flow_z(:) = 0.0_RP + ! case ('swirling') + ! fac = cos(PI*params(5)/params(4)) + ! flow_x(:) = + sin(PI*x(:))**2 * sin(2.0_RP*PI*y(:)) * fac + ! flow_y(:) = - sin(PI*y(:))**2 * sin(2.0_RP*PI*x(:)) * fac + ! flow_z(:) = 0.0_RP + case default + LOG_ERROR('fieldutil_get_flow3d',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile3d_flow + + !-- 3d Global-------------------------------------------------------------- + + !> Get 3D data whose value is set based on specified pattern. + ! + ! Assume that range of domain is 0 <= x,y <= 1. + ! If the profile_name is 'sin', param1 and param2 are the wavenumbers in x- and y- directions, respectively. + ! If the profile_name is 'gaussian-hill', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'cosine-bell', (param1,param2) is the coordinate of center position, param3 is the half of width. The shape is isotropic about the center of domain. + ! If the profile_name is 'top-hat', (param1,param2) is the coordinate of center position, param3 and param4 are the half of width in x- and y- directions, respectively. + ! +!OCL SERIAL + subroutine fieldutil_get_profile3dGlobal_tracer( profile, & + profile_name, lon, lat, z, RPlanet, params, N ) + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: profile(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: lon(N) + real(RP), intent(in) :: lat(N) + real(RP), intent(in) :: z(N) + real(RP), intent(in) :: RPlanet + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + character(2) :: DCMIP_TRCNAME + !------------------------------------------------------------------------ + + profile(:) = 0.0_RP + + select case(profile_name) + ! case ('constant') + ! profile(:) = params(1) + ! case ('sin') + ! profile(:) = sin( params(1)*2.0_RP*PI*x(:) ) * sin( params(2)*2.0_RP*PI*y(:) ) + ! case ('gaussian-hill') + ! profile(:) = exp( - 0.5_RP * ((x(:) - params(1))**2 + (y(:) - params(2))**2)/params(3)**2 ) + case ('cosine-bell') + dist(:) = RPlanet * acos( & + sin(params(2))*sin(lat(:)) + cos(params(2))*cos(lat(:))*cos(lon(:) - params(1)) ) + where( dist <= params(3) ) + profile(:) = (1.0_RP + cos(PI*dist(:)/params(3)))*0.5_RP + end where + ! case ('top-hat') + ! where( abs(x-params(1)) <= params(3) .and. abs(y-params(2)) <= params(4) ) + ! profile(:) = 1.0_RP + ! end where + case ('DCMIP_Test1-1_q1', 'DCMIP_Test1-1_q2', 'DCMIP_Test1-1_q3', 'DCMIP_Test1-1_q4') + DCMIP_TRCNAME = profile_name(15:16) + call DCMIP2012_tracer( profile(:), & + DCMIP_TRCNAME, lon(:), lat(:), z(:), N ) + case default + LOG_ERROR('fieldutil_get_profile3dGlobal',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile3dGlobal_tracer + + !------------------------------- + +!OCL SERIAL + subroutine fieldutil_get_profile3dGlobal_flow( flow_lon, flow_lat, flow_w, & + profile_name, lon, lat, z, params, N) + + implicit none + !-------------------------------- + integer, intent(in) :: N + real(RP), intent(out) :: flow_lon(N) + real(RP), intent(out) :: flow_lat(N) + real(RP), intent(out) :: flow_w(N) + character(*), intent(in) :: profile_name + real(RP), intent(in) :: lon(N) + real(RP), intent(in) :: lat(N) + real(RP), intent(in) :: z(N) + real(RP), intent(in) :: params(:) + + real(RP) :: dist(N) + real(RP) :: fac + !------------------------------------------------------------------------ + + flow_lon(:) = 0.0_RP + flow_lat(:) = 0.0_RP + flow_w(:) = 0.0_RP + + select case(profile_name) + case ('rigid-body-rot') + flow_lon(:) = params(1) * ( cos(params(2)) * cos(lat(:)) + sin(params(2)) * cos(lon(:)) * sin(lat(:)) ) + flow_lat(:) = - params(1) * sin(params(2)) * sin(lon(:)) + flow_w(:) = 0.0_RP + case ('DCMIP_Test1-1') ! 3D deformational flow + call DCMIP2012_deformation_flow( flow_lon(:), flow_lat(:), flow_w(:), & + lon(:), lat(:), z(:), params(4), N ) + case default + LOG_ERROR('fieldutil_get_flow3dGlobal',*) trim(profile_name)//' is not supported. Check!' + call PRC_abort + end select + + return + end subroutine fieldutil_get_profile3dGlobal_flow + +!OCL SERIAL + subroutine DCMIP2012_tracer( q, & + qtrcname, lon, lat, z, Np ) + + use scale_const, only: & + RPlanet => CONST_RADIUS + implicit none + + integer, intent(in) :: Np + real(RP), intent(out) :: q(Np) + character(*), intent(in) :: qtrcname + real(RP), intent(in) :: lon(Np) + real(RP), intent(in) :: lat(Np) + real(RP), intent(in) :: z(Np) + + integer :: i + real(RP) :: d(Np,2) + real(RP) :: r(Np) + + real(RP) :: Rt !< Horizontal half-width of tracers + real(RP), parameter :: Zt = 1000.0_RP !< Vertical half-width of tracers + real(RP) :: lon_c(2) !< Initial longitude of first and second tracers + real(RP), parameter :: lat_c = 0.0_RP !< Initial latitude of tracers + real(RP), parameter :: z_c = 5000.0_RP !< Initial altitude of tracers + !---------------------------------------------- + + Rt = 0.5_RP * RPlanet + lon_c(:) = (/ 5.0_RP, 7.0_RP /) * PI / 6.0_RP + + do i=1, 2 + r(:) = RPlanet * acos(sin(lat_c)*sin(lat(:)) + cos(lat_c)*cos(lat(:))*cos(lon(:)-lon_c(i))) + d(:,i) = min( 1.0_RP, (r(:) / Rt)**2 + ((z(:) - z_c) / Zt)**2 ) + end do + + select case(qtrcname) + case('q1') + q(:) = 1.0_RP + 0.5_RP * ( cos(PI * d(:,1)) + cos(PI * d(:,2)) ) + case default + LOG_ERROR('DCMIP2012_tracer',*) trim(qtrcname)//' is not supported. Check!' + call PRC_abort + end select + return + end subroutine DCMIP2012_tracer + +!OCL SERIAL + subroutine DCMIP2012_deformation_flow( U, V, W, & + lon, lat, z, time, Np ) + + use scale_const, only: & + P00 => CONST_PRE00, & + Grav => CONST_GRAV, & + Rdry => CONST_Rdry, & + RPlanet => CONST_RADIUS + implicit none + integer, intent(in) :: Np + real(RP), intent(out) :: U(Np) + real(RP), intent(out) :: V(Np) + real(RP), intent(out) :: W(Np) + real(RP), intent(in) :: lon(Np) + real(RP), intent(in) :: lat(Np) + real(RP), intent(in) :: z(Np) + real(RP), intent(in) :: time + + real(RP) :: lon2(Np) + real(RP) :: omg(Np) + real(RP) :: pres(Np) + real(RP) :: ud(Np), ua(Np) + real(RP) :: vd(Np), va(Np) + + real(RP), parameter :: tau = 1036800.0_RP !> Period of motion [sec] + real(RP) :: OMG0 !> Maximum of the vertical pressure velocity in units Pa/s + real(RP), parameter :: b = 0.2_RP !> Normalized pressure depth of the divergent layer + real(RP), parameter :: ptop = 254.944E2_RP + real(RP), parameter :: T0 = 300.0_RP !> Isothermal atmospheric temperature [K] + !---------------------------------------------- + + lon2(:) = lon(:) - 2.0_RP * PI * time / tau + OMG0 = 23000.0_RP * PI / tau + + pres(:) = P00 * exp(- Grav * z(:) / ( Rdry * T0 ) ) + omg(:) = OMG0 * sin(lon2(:)) * cos(lat(:)) * cos(2.0_RP * PI * time / tau) & + * ( 1.0_RP + exp( (ptop - P00) / (b * ptop) ) - exp( (pres(:) - P00) / (b * ptop) ) & + - exp( (ptop - pres(:)) / (b * ptop) ) ) + + ua(:) = 10.0_RP * RPlanet / tau * sin(lon2(:))**2 * sin(2.0_RP*lat(:)) * cos(PI * time / tau) & + + 2.0_RP * PI * RPlanet / tau * cos(lat(:)) + va(:) = 10.0_RP * RPlanet / tau * sin(2.0_RP * lon2(:)) * cos(lat(:)) * cos(PI * time / tau) + + ud(:) = OMG0 * RPlanet / (b * ptop) * cos(lon2(:)) * cos(lat(:))**2 * cos(2.0_RP * PI * time / tau) & + * ( - exp( (pres(:) - P00) / (b * ptop) ) + exp( (ptop - pres(:)) / (b * ptop) ) ) + vd(:) = 0.0_RP + + U(:) = ua(:) + ud(:) + V(:) = va(:) + vd(:) + W(:) = - omg(:) / (Grav * pres(:) / ( Rdry * T0 ) ) + + return + end subroutine DCMIP2012_deformation_flow end module mod_fieldutil From ceb5707954d1a08814242f0b5089702fd852d2cf Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 24 May 2021 01:06:26 +0900 Subject: [PATCH 28/98] cs2lonlat supports the conversion of 3D data in cubed sphere into that in lon-lat coordinate. --- .../mod_cs2lonlat_interp_field.F90 | 294 +++++++++-- .../mod_cs2lonlat_interp_file.F90 | 57 ++- .../mod_cs2lonlat_interp_mesh.F90 | 461 ++++++++++++++++-- .../prg_convert_cs2lonlat.F90 | 32 +- 4 files changed, 737 insertions(+), 107 deletions(-) diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 index e537817d..9dfcb39a 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 @@ -14,9 +14,12 @@ module mod_cs2lonlat_interp_field use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_localmesh_2d, only: LocalMesh2D - use scale_element_base, only: ElementBase2D - use scale_meshfield_base, only: MeshField2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_meshfield_base, only: MeshField2D, MeshField3D use scale_file_base_meshfield, only: & FILE_base_meshfield @@ -34,6 +37,10 @@ module mod_cs2lonlat_interp_field public :: interp_field_Init public :: interp_field_Final + interface interp_field_Interpolate + module procedure :: interp_field_Interpolate_2D + module procedure :: interp_field_Interpolate_3D + end interface public :: interp_field_Interpolate !----------------------------------------------------------------------------- @@ -41,6 +48,7 @@ module mod_cs2lonlat_interp_field !++ Public parameters & variables ! type(MeshField2D), public :: out_var2D + type(MeshField3D), public :: out_var3D type, public :: OutVarInfo character(FILE_HSHORT) :: varname character(FILE_HSHORT) :: units @@ -49,7 +57,7 @@ module mod_cs2lonlat_interp_field real(DP) :: start_sec integer :: out_tintrv end type OutVarInfo - integer, public :: out_var2D_num + integer, public :: out_var_num type(OutVarInfo), public, allocatable, target :: out_vinfo(:) character(len=H_LONG), public :: in_basename = '' ! Basename of the input file @@ -67,7 +75,8 @@ module mod_cs2lonlat_interp_field integer, private, parameter :: ITEM_MAX_NUM = 128 type :: in_local_val - real(RP), allocatable :: spectral_coef(:,:,:,:) + real(RP), allocatable :: spectral_coef2D(:,:,:,:) + real(RP), allocatable :: spectral_coef3D(:,:,:,:,:) end type in_local_val type :: in_local_file_list @@ -78,10 +87,12 @@ module mod_cs2lonlat_interp_field contains !OCL SERIAL - subroutine interp_field_Init( out_mesh, nodeMap_list ) + subroutine interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D, nodeMap_list ) use scale_file_h implicit none - class(MeshRectDom2D), intent(in) :: out_mesh + class(MeshRectDom2D), intent(in) :: out_mesh2D + class(MeshCubeDom3D), intent(in) :: out_mesh3D + logical, intent(in) :: is_mesh3D type(NodeMappingInfo), intent(in) :: nodeMap_list(:) integer :: nn @@ -114,21 +125,25 @@ subroutine interp_field_Init( out_mesh, nodeMap_list ) endif LOG_NML(PARAM_INTERP_FIELD) - out_var2D_num = 0 + out_var_num = 0 do nn= 1, ITEM_MAX_NUM if ( vars(nn) == '' ) then exit else - out_var2D_num = out_var2D_num + 1 + out_var_num = out_var_num + 1 end if end do - allocate( out_vinfo(out_var2D_num) ) + allocate( out_vinfo(out_var_num) ) !-- - call in_file%Init( out_var2D_num, mesh2D=out_mesh ) + if (is_mesh3D) then + call in_file%Init( out_var_num, mesh3D=out_mesh3D ) + else + call in_file%Init( out_var_num, mesh2D=out_mesh2D ) + end if call in_file%Open( in_basename, myrank=0 ) - do nn = 1, out_var2D_num + do nn = 1, out_var_num out_vinfo(nn)%varname = vars(nn) call in_file%Get_dataInfo( vars(nn), istep=1, & ! (in) units=out_vinfo(nn)%units, & ! (out) @@ -148,22 +163,32 @@ subroutine interp_field_Init( out_mesh, nodeMap_list ) is_cached_in_files = .false. ! - call out_var2D%Init( "tmp", "1", out_mesh ) + if (is_mesh3D) then + call out_var3D%Init( "tmp", "1", out_mesh3D ) + else + call out_var2D%Init( "tmp", "1", out_mesh2D ) + end if return end subroutine interp_field_Init !OCL SERIAL - subroutine interp_field_Final() + subroutine interp_field_Final(is_mesh3D) implicit none + logical, intent(in) :: is_mesh3D + integer :: vid integer :: domID integer :: in_ii type(FILE_base_meshfield), pointer :: in_file_ptr !------------------------------------------- - call out_var2D%Final() + if (is_mesh3D) then + call out_var3D%Final() + else + call out_var2D%Final() + end if if (is_cached_in_files) then do domID=1, size(in_file_list) @@ -181,7 +206,7 @@ subroutine interp_field_Final() end subroutine interp_field_Final !OCL SERIAL - subroutine interp_field_Interpolate( istep, varname, out_mesh, out_field, nodeMap_list ) + subroutine interp_field_Interpolate_2D( istep, varname, out_mesh, out_field, nodeMap_list ) use scale_mesh_rectdom2d, only: MeshRectDom2D implicit none @@ -197,12 +222,11 @@ subroutine interp_field_Interpolate( istep, varname, out_mesh, out_field, nodeMa integer :: domID integer :: in_mesh_num integer :: in_ii - integer :: in_tileID integer :: in_rank type(FILE_base_meshfield), pointer :: in_file_ptr !------------------------------------------- - call PROF_rapstart('INTERP_field_interpolate', 0) + call PROF_rapstart('INTERP_field_interpolate_2D', 0) if (.not. is_cached_in_files) then allocate( in_file_list(out_mesh%LOCAL_MESH_NUM) ) @@ -211,11 +235,9 @@ subroutine interp_field_Interpolate( istep, varname, out_mesh, out_field, nodeMa allocate( in_file_list(domID)%in_files(in_mesh_num) ) do in_ii=1, in_mesh_num in_file_ptr => in_file_list(domID)%in_files(in_ii) - in_tileID = nodeMap_list(domID)%in_tileID_list(in_ii) - in_rank = nodeMap_list(domID)%in_mesh2D_list(in_ii)%PRCrank_globalMap(in_tileID) - - LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, 'Open in_file:', trim(in_basename), in_rank - call in_file_ptr%Init( out_var2D_num, & + in_rank = nodeMap_list(domID)%in_mesh2D_list(in_ii)%lcmesh_list(1)%PRC_myrank + LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank + call in_file_ptr%Init( out_var_num, & meshCubedSphere2D=nodeMap_list(domID)%in_mesh2D_list(in_ii) ) call in_file_ptr%Open( in_basename, in_rank ) end do @@ -225,18 +247,72 @@ subroutine interp_field_Interpolate( istep, varname, out_mesh, out_field, nodeMa do n=1, out_mesh%LOCAL_MESH_NUM lcmesh => out_mesh%lcmesh_list(n) - call interpolate_local( out_field%local(n)%val(:,:), & + call interpolate_local_2D( out_field%local(n)%val(:,:), & n, istep, varname, lcmesh, lcmesh%refElem2D, nodeMap_list(n), & out_mesh ) end do - call PROF_rapend('INTERP_field_interpolate', 0) + call PROF_rapend('INTERP_field_interpolate_2D', 0) + + return + end subroutine interp_field_interpolate_2D + +!OCL SERIAL + subroutine interp_field_Interpolate_3D( istep, varname, out_mesh, out_field, nodeMap_list ) + use scale_mesh_cubedom3d, only: MeshCubeDom3D + implicit none + + integer, intent(in) :: istep + character(*), intent(in) :: varname + class(MeshCubeDom3D), intent(in), target :: out_mesh + class(MeshField3D), intent(inout) :: out_field + type(NodeMappingInfo), intent(in) :: nodeMap_list(:) + + class(LocalMesh3D), pointer :: lcmesh + integer :: n + + integer :: domID + integer :: in_mesh_num + integer :: in_ii + integer :: in_rank + type(FILE_base_meshfield), pointer :: in_file_ptr + !------------------------------------------- + + call PROF_rapstart('INTERP_field_interpolate_3D', 0) + + if (.not. is_cached_in_files) then + allocate( in_file_list(out_mesh%LOCAL_MESH_NUM) ) + do domID=1, out_mesh%LOCAL_MESH_NUM + in_mesh_num = size(nodeMap_list(domID)%in_mesh3D_list) + allocate( in_file_list(domID)%in_files(in_mesh_num) ) + do in_ii=1, in_mesh_num + in_file_ptr => in_file_list(domID)%in_files(in_ii) + in_rank = nodeMap_list(domID)%in_mesh3D_list(in_ii)%lcmesh_list(1)%PRC_myrank + LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank + call in_file_ptr%Init( out_var_num, & + meshCubedSphere3D=nodeMap_list(domID)%in_mesh3D_list(in_ii) ) + call in_file_ptr%Open( in_basename, in_rank ) + end do + end do + is_cached_in_files = .true. + end if + + do n=1, out_mesh%LOCAL_MESH_NUM + lcmesh => out_mesh%lcmesh_list(n) + call interpolate_local_3D( out_field%local(n)%val(:,:), & + n, istep, varname, lcmesh, lcmesh%refElem3D, nodeMap_list(n), & + out_mesh ) + end do + + call PROF_rapend('INTERP_field_interpolate_3D', 0) return - end subroutine interp_field_interpolate + end subroutine interp_field_interpolate_3D + +!------------------------ !OCL SERIAL - subroutine interpolate_local( out_val, & + subroutine interpolate_local_2D( out_val, & out_domID, istep, varname, out_lcmesh, out_elem2D, mappingInfo, out_mesh2D ) use scale_const, only: & @@ -291,7 +367,7 @@ subroutine interpolate_local( out_val, & n = 1 in_lcmesh => in_csmesh%lcmesh_list(n) - allocate( in_val_list(in_prc)%spectral_coef(in_lcmesh%refElem2D%Np,in_lcmesh%NeX,in_lcmesh%NeY,in_csmesh%LOCAL_MESH_NUM) ) + allocate( in_val_list(in_prc)%spectral_coef2D(in_lcmesh%refElem2D%Np,in_lcmesh%NeX,in_lcmesh%NeY,in_csmesh%LOCAL_MESH_NUM) ) call tmp_field2D%Init( varname, "", in_csmesh ) call in_file_list(out_domID)%in_files(in_prc)%Read_Var( & @@ -302,7 +378,7 @@ subroutine interpolate_local( out_val, & do jj=1, in_lcmesh%NeY do ii=1, in_lcmesh%NeX in_ke2D = ii + (jj-1)*in_lcmesh%NeX - in_val_list(in_prc)%spectral_coef(:,ii,jj,in_domID) = & + in_val_list(in_prc)%spectral_coef2D(:,ii,jj,in_domID) = & matmul( in_elem2D%invV, tmp_field2D%local(in_domID)%val(:,in_ke2D) ) end do end do @@ -326,7 +402,7 @@ subroutine interpolate_local( out_val, & do pY=1, out_elem2D%Nfp do pX=1, out_elem2D%Nfp p_h = pX + (pY-1)*out_elem2D%Nfp - p = p_h !+ (pZ-1)*out_elem2D%Nfp**2 + p = p_h out_val(p,ke2D) = UNDEF8 in_domID = mappingInfo%local_domID(p_h,ke_h) @@ -357,7 +433,159 @@ subroutine interpolate_local( out_val, & out_val(p,ke2D) = out_val(p,ke2D) + & ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) ) & * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)) & - * in_val_list(in_prc)%spectral_coef(l,in_ex,in_ey,in_domID) + * in_val_list(in_prc)%spectral_coef2D(l,in_ex,in_ey,in_domID) + end do + end do + end if + end if + + end do + end do + end do + end do + + do in_prc=1, in_Nprc + deallocate( in_val_list(in_prc)%spectral_coef2D ) + end do + + return + end subroutine interpolate_local_2D + + +!OCL SERIAL + subroutine interpolate_local_3D( out_val, & + out_domID, istep, varname, out_lcmesh, out_elem3D, mappingInfo, out_mesh3D ) + + use scale_const, only: & + UNDEF8 => CONST_UNDEF8, & + PI => CONST_PI + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_mesh_base3d, only: & + MF3D_XYZT => MeshBase3D_DIMTYPEID_XYZT + use scale_polynominal, only: & + Polynominal_GenLegendrePoly_sub + use mod_cs2lonlat_interp_mesh, only: & + nodeMap_list, & + in_Nprc, in_elem3D, in_NLocalMeshPerPrc + + implicit none + class(LocalMesh3D), intent(in) :: out_lcmesh + class(ElementBase3D), intent(in) :: out_elem3D + real(DP), intent(out) :: out_val(out_elem3D%Np,out_lcmesh%NeA) + integer, intent(in) :: out_domID + integer, intent(in) :: istep + character(*), intent(in) :: varname + type(NodeMappingInfo), intent(in), target :: mappingInfo + class(MeshCubeDom3D), intent(in) :: out_mesh3D + + integer :: ke3D, ke_h + integer :: p, p_h, pX, pY, pZ + integer :: p1, p2, p3, l + integer :: elem_i, elem_j + integer :: in_ke3D, in_ex, in_ey, in_ez, in_domID, in_prc + integer :: in_rank + type(LocalMesh3D), pointer :: in_lcmesh + integer :: n + integer :: ii, jj, kk, pp, i0_s, j0_s, k0_s, p0_s + + type(in_local_val), allocatable :: in_val_list(:) + type(MeshCubedSphereDom3D), pointer :: in_csmesh + real(RP) :: P1D_ori_x(1,in_elem3D%Nnode_h1D) + real(RP) :: P1D_ori_y(1,in_elem3D%Nnode_h1D) + real(RP) :: P1D_ori_z(1,in_elem3D%Nnode_v) + real(RP) :: ox(1), oy(1), oz(1) + real(RP) :: vx(in_elem3D%Nv), vy(in_elem3D%Nv), vz(in_elem3D%Nv) + integer :: node_ids(in_elem3D%Nv) + type(MeshField3D) :: tmp_field3D + + !--------------------------------------------- + + allocate( in_val_list(in_Nprc) ) + + do in_prc=1, in_Nprc + in_rank = in_prc - 1 + in_csmesh => mappingInfo%in_mesh3D_list(in_prc) + + n = 1 + in_lcmesh => in_csmesh%lcmesh_list(n) + allocate( in_val_list(in_prc)%spectral_coef3D(in_lcmesh%refElem3D%Np,in_lcmesh%NeX,in_lcmesh%NeY,in_lcmesh%NeZ,in_csmesh%LOCAL_MESH_NUM) ) + + call tmp_field3D%Init( varname, "", in_csmesh ) + call in_file_list(out_domID)%in_files(in_prc)%Read_Var( & + MF3D_XYZT, varname, tmp_field3D, step=istep ) + + !$omp parallel do collapse(2) private(in_ke3D,ii,jj,kk) + do in_domID=1, in_csmesh%LOCAL_MESH_NUM + do kk=1, in_lcmesh%NeZ + do jj=1, in_lcmesh%NeY + do ii=1, in_lcmesh%NeX + in_ke3D = ii + (jj-1)*in_lcmesh%NeX + (kk-1)*in_lcmesh%NeX*in_lcmesh%NeY + in_val_list(in_prc)%spectral_coef3D(:,ii,jj,kk,in_domID) = & + matmul( in_elem3D%invV, tmp_field3D%local(in_domID)%val(:,in_ke3D) ) + end do + end do + end do + end do + + call tmp_field3D%Final() + end do + + !$omp parallel do collapse(3) private( ke_h, ke3D, & + !$omp pX, pY, pZ, p_h, p, in_domID, in_prc, & + !$omp in_ex, in_ey, in_ez, in_ke3D, & + !$omp in_lcmesh, node_ids, vx, vy, vz, ox, oy, oz, & + !$omp P1D_ori_x, P1D_ori_y, P1D_ori_z, & + !$omp p1, p2, p3, l ) + do kk=1, out_lcmesh%NeZ + do jj=1, out_lcmesh%NeY + do ii=1, out_lcmesh%NeX + ke_h = ii + (jj-1)*out_lcmesh%NeX + ke3D = ke_h + (kk-1)*out_lcmesh%NeX*out_lcmesh%NeY + + do pZ=1, out_elem3D%Nnode_v + do pY=1, out_elem3D%Nnode_h1D + do pX=1, out_elem3D%Nnode_h1D + p_h = pX + (pY-1)*out_elem3D%Nnode_h1D + p = p_h + (pZ-1)*out_elem3D%Nnode_h1D**2 + out_val(p,ke3D) = UNDEF8 + + in_domID = mappingInfo%local_domID(p_h,ke_h) + in_prc = mappingInfo%lcprc(p_h,ke_h) + + if (in_domID > 0 .and. in_prc > 0) then + in_ex = mappingInfo%elem_i(p_h,ke_h) + in_ey = mappingInfo%elem_j(p_h,ke_h) + in_ez = mappingInfo%elem_k(p ,ke3D) + + if ( in_ex > 0 .and. in_ey > 0 .and. in_ez > 0 ) then + in_lcmesh => mappingInfo%in_mesh3D_list(in_prc)%lcmesh_list(in_domID) + in_ke3D = in_ex + (in_ey - 1)*in_lcmesh%NeX & + + (in_ez - 1)*in_lcmesh%NeX*in_lcmesh%NeY + + node_ids(:) = in_lcmesh%EToV(in_ke3D,:) + vx(:) = in_lcmesh%pos_ev(node_ids(:),1) + vy(:) = in_lcmesh%pos_ev(node_ids(:),2) + vz(:) = in_lcmesh%pos_ev(node_ids(:),3) + + ox(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_x(p_h,ke_h) - vx(1)) / (vx(2) - vx(1)) + oy(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_y(p_h,ke_h) - vy(1)) / (vy(3) - vy(1)) + oz(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_z(p ,ke3D) - vz(1)) / (vz(5) - vz(1)) + + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_h, ox, P1D_ori_x(:,:) ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_h, oy, P1D_ori_y(:,:) ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_v, oz, P1D_ori_z(:,:) ) + + out_val(p,ke3D) = 0.0_RP + do p3=1, in_elem3D%Nnode_v + do p2=1, in_elem3D%Nnode_h1D + do p1=1, in_elem3D%Nnode_h1D + l = p1 + (p2-1)*in_elem3D%Nnode_h1D + (p3-1)*in_elem3D%Nnode_h1D**2 + out_val(p,ke3D) = out_val(p,ke3D) + & + ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) * P1D_ori_z(1,p3) ) & + * sqrt( (dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)*(dble(p3-1) + 0.5_RP) ) & + * in_val_list(in_prc)%spectral_coef3D(l,in_ex,in_ey,in_ez,in_domID) + end do end do end do end if @@ -365,14 +593,16 @@ subroutine interpolate_local( out_val, & end do end do + end do + end do end do end do do in_prc=1, in_Nprc - deallocate( in_val_list(in_prc)%spectral_coef ) + deallocate( in_val_list(in_prc)%spectral_coef3D ) end do return - end subroutine interpolate_local + end subroutine interpolate_local_3D end module mod_cs2lonlat_interp_field \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 index 16246990..a1a26ace 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 @@ -15,8 +15,10 @@ module mod_cs2lonlat_interp_file FILE_base_meshfield use scale_mesh_rectdom2d, only: & MeshRectDom2D + use scale_mesh_cubedom3d, only: & + MeshCubeDom3D use scale_meshfield_base, only: & - MeshField2D + MeshField2D, MeshField3D !----------------------------------------------------------------------------- implicit none @@ -27,6 +29,10 @@ module mod_cs2lonlat_interp_file ! public :: interp_file_Init + interface interp_file_write_var + module procedure interp_file_write_var2D + module procedure interp_file_write_var3D + end interface public :: interp_file_write_var public :: interp_file_Final @@ -50,16 +56,20 @@ module mod_cs2lonlat_interp_file logical, private :: out_UniformGrid = .false. contains - subroutine interp_file_Init( in_basename, out_vinfo, mesh2D ) + subroutine interp_file_Init( in_basename, out_vinfo, mesh2D, mesh3D, is_mesh3D ) use scale_file_h use scale_mesh_base2d, only: & DIMTYPE2D_XYT => MeshBase2D_DIMTYPEID_XYT + use scale_mesh_base3d, only: & + DIMTYPE3D_XYZT => MeshBase3D_DIMTYPEID_XYZT use mod_cs2lonlat_interp_field, only: OutVarInfo implicit none character(*), intent(in) :: in_basename type(OutVarInfo), intent(in) :: out_vinfo(:) class(MeshRectDom2D), intent(in) :: mesh2D + class(MeshCubeDom3D), intent(in) :: mesh3D + logical, intent(in) :: is_mesh3D character(len=H_LONG ) :: out_basename = '' ! Basename of the output file character(len=H_MID) :: out_title = '' !< Title of the output file @@ -78,6 +88,7 @@ subroutine interp_file_Init( in_basename, out_vinfo, mesh2D ) integer :: nn integer :: var_num + integer :: dimtype character(len=FILE_HMID) :: tunits character(len=FILE_HSHORT) :: calendar character(len=FILE_HMID) :: desc @@ -102,7 +113,14 @@ subroutine interp_file_Init( in_basename, out_vinfo, mesh2D ) !-- var_num = size(out_vinfo) - call in_file%Init( var_num, mesh2D=mesh2D ) + if (is_mesh3D) then + call in_file%Init( var_num, mesh3D=mesh3D ) + dimtype = DIMTYPE3D_XYZT + else + call in_file%Init( var_num, mesh2D=mesh2D ) + dimtype = DIMTYPE2D_XYT + end if + call in_file%Open( in_basename, myrank=0 ) if (out_title=='') then call in_file%Get_commonInfo( title=out_title ) ! (out) @@ -111,14 +129,18 @@ subroutine interp_file_Init( in_basename, out_vinfo, mesh2D ) call in_file%Get_dataInfo( out_vinfo(1)%varname, 1, & ! (in) time_units=tunits, calendar=calendar ) ! (out) - call out_file%Init( var_num, mesh2D=mesh2D, force_uniform_grid=out_UniformGrid ) + if (is_mesh3D) then + call out_file%Init( var_num, mesh3D=mesh3D, force_uniform_grid=out_UniformGrid ) + else + call out_file%Init( var_num, mesh2D=mesh2D, force_uniform_grid=out_UniformGrid ) + end if call out_file%Create( out_basename, out_title, out_dtype, & ! (in) fileexisted, & ! (out) myrank=PRC_myrank, calendar=calendar, tunits=tunits ) ! (in) do nn=1, var_num call out_file%Def_Var( out_vinfo(nn)%varname, out_vinfo(nn)%units, & - desc, nn, DIMTYPE2D_XYT, out_dtype, & + desc, nn, dimtype, out_dtype, & standard_name=standard_name, & timeinv=out_vinfo(nn)%dt * dble(out_vinfo(nn)%out_tintrv) ) end do @@ -130,7 +152,7 @@ subroutine interp_file_Init( in_basename, out_vinfo, mesh2D ) return end subroutine interp_file_Init - subroutine interp_file_write_var( vid, field, start_sec, end_sec ) + subroutine interp_file_write_var2D( vid, field, start_sec, end_sec ) implicit none integer, intent(in) :: vid class(MeshField2D), intent(in) :: field @@ -138,13 +160,29 @@ subroutine interp_file_write_var( vid, field, start_sec, end_sec ) real(DP), intent(in) :: end_sec !------------------------------------------- - call PROF_rapstart('INTERP_file_write_var', 0) + call PROF_rapstart('INTERP_file_write_var2D', 0) call out_file%Write_var2D( vid, field, start_sec, end_sec ) - call PROF_rapend('INTERP_file_write_var', 0) + call PROF_rapend('INTERP_file_write_var2D', 0) + return + end subroutine interp_file_write_var2D + + subroutine interp_file_write_var3D( vid, field, start_sec, end_sec ) + implicit none + integer, intent(in) :: vid + class(MeshField3D), intent(in) :: field + real(DP), intent(in) :: start_sec + real(DP), intent(in) :: end_sec + !------------------------------------------- + + call PROF_rapstart('INTERP_file_write_var3D', 0) + + call out_file%Write_var3D( vid, field, start_sec, end_sec ) + + call PROF_rapend('INTERP_file_write_var3D', 0) return - end subroutine interp_file_write_var + end subroutine interp_file_write_var3D subroutine interp_file_Final() implicit none @@ -157,5 +195,4 @@ end subroutine interp_file_Final !-- private ----------------------------------- - end module mod_cs2lonlat_interp_file \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 index b7ce6770..8318ac58 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 @@ -13,14 +13,18 @@ module mod_cs2lonlat_interp_mesh PI => CONST_PI, & RPlanet => CONST_radius - use scale_element_base, only: ElementBase2D + use scale_element_base, only: ElementBase2D, ElementBase3D use scale_element_quadrilateral, only: QuadrilateralElement + use scale_element_hexahedral, only: HexahedralElement use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_mesh_cubedspheredom2d, only: & MeshCubedSphereDom2D, & MeshCubedSphereDom2D_check_division_params - + use scale_mesh_cubedspheredom3d, only: & + MeshCubedSphereDom3D !----------------------------------------------------------------------------- implicit none private @@ -39,10 +43,13 @@ module mod_cs2lonlat_interp_mesh integer, public, parameter :: ATMOS_MESH_NLocalMeshPerPrc = 1 type(MeshRectDom2D), public, target :: out_mesh2D + type(MeshCubeDom3D), public, target :: out_mesh3D type(MeshCubedSphereDom2D), public :: in_csmesh2D + type(MeshCubedSphereDom3D), public :: in_csmesh3D type, public :: NodeMappingInfo - type(LocalMesh2D), pointer :: lcmesh2D + type(LocalMesh2D), pointer :: lcmesh2D => null() + type(LocalMesh3D), pointer :: lcmesh3D => null() integer, allocatable :: local_domID(:,:) integer, allocatable :: lcprc(:,:) integer, allocatable :: inCSPanelID(:,:) @@ -51,11 +58,15 @@ module mod_cs2lonlat_interp_mesh integer, allocatable :: elem_k(:,:) real(RP), allocatable :: elem_x(:,:) real(RP), allocatable :: elem_y(:,:) + real(RP), allocatable :: elem_z(:,:) type(MeshCubedSphereDom2D), allocatable :: in_mesh2D_list(:) + type(MeshCubedSphereDom3D), allocatable :: in_mesh3D_list(:) integer, allocatable :: in_tileID_list(:) contains - procedure :: Init => NodeMappingInfo_Init + procedure :: Init_2D => NodeMappingInfo_Init_2D + procedure :: Init_3D => NodeMappingInfo_Init_3D + generic :: Init => Init_2D, Init_3D procedure :: Final => NodeMappingInfo_Final end type type(NodeMappingInfo), public :: nodeMap_list(ATMOS_MESH_NLocalMeshPerPrc) @@ -63,9 +74,13 @@ module mod_cs2lonlat_interp_mesh integer, public :: in_Nprc = 1 integer, public :: in_NeGX = 1 integer, public :: in_NeGY = 1 + integer, public :: in_NeGZ = 1 integer, public :: in_NLocalMeshPerPrc = 6 type(QuadrilateralElement), public :: in_elem2D + type(HexahedralElement), public :: in_elem3D + logical, public :: is_mesh3D + !----------------------------------------------------------------------------- ! !++ Private procedures @@ -80,38 +95,75 @@ module mod_cs2lonlat_interp_mesh integer, private :: out_NprcX = 1 ! x length of 2D processor topology (output) integer, private :: out_NprcY = 1 ! y length of 2D processor topology (output) type(QuadrilateralElement), private :: out_elem2D + type(HexahedralElement), private :: out_elem3D + + real(RP), private :: dom_zmin = 0.0_RP + real(RP), private :: dom_zmax = 0.0_RP contains subroutine interp_mesh_Init() use scale_mesh_base2d, only: & MeshBase2D_DIMTYPEID_X, MeshBase2D_DIMTYPEID_Y, & MeshBase2D_DIMTYPEID_XY, MeshBase2D_DIMTYPEID_XYT + use scale_mesh_base3d, only: & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_XYZT + use scale_const, only: & + UNDEF => CONST_UNDEF + implicit none - integer :: out_NeX = 1 - integer :: out_NeY = 1 + integer :: out_NeX = 1 + integer :: out_NeY = 1 + integer :: out_NeZ = -1 integer :: in_PolyOrder_h = 1 + integer :: in_PolyOrder_v = 1 integer :: out_PolyOrder_h = 1 + integer :: out_PolyOrder_v = 1 + real(RP) :: out_dom_zmin + real(RP) :: out_dom_zmax + + integer, parameter :: FZ_nmax = 1000 + logical :: is_spec_in_FZ + logical :: is_spec_out_FZ + real(RP) :: in_FZ(FZ_nmax) + real(RP) :: out_FZ(FZ_nmax) namelist / PARAM_INTERP_MESH / & in_Nprc, & in_NeGX, & in_NeGY, & + in_NeGZ, & in_NLocalMeshPerPrc, & in_PolyOrder_h, & + in_PolyOrder_v, & out_NprcX, & out_NeX, & out_NprcY, & out_NeY, & - out_PolyOrder_h + out_NeZ, & + out_PolyOrder_h, & + out_PolyOrder_v, & + dom_zmin, dom_zmax, & + out_dom_zmin, & + out_dom_zmax, & + in_Fz, out_Fz + integer :: ierr + integer :: k !------------------------------------------- LOG_NEWLINE LOG_INFO("interp_mesh",*) 'Setup' + out_dom_zmin = UNDEF + out_dom_zmax = UNDEF + + in_FZ(:) = UNDEF + out_FZ(:) = UNDEF + !--- read namelist rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_INTERP_MESH,iostat=ierr) @@ -123,25 +175,71 @@ subroutine interp_mesh_Init() endif LOG_NML(PARAM_INTERP_MESH) - !- - call in_elem2D%Init( in_PolyOrder_h, .false. ) - call out_elem2D%Init( out_PolyOrder_h, .false. ) + if ( out_dom_zmin == UNDEF ) out_dom_zmin = dom_zmin + if ( out_dom_zmax == UNDEF ) out_dom_zmax = dom_zmax - call out_mesh2D%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, & - 0.0_RP, 360.0_RP, -90.0_RP, 90.0_RP, & - .true., .false., out_elem2D, 1, & - out_NprcX, out_NprcY ) - call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) - call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) - call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XY, 'lonlat', 'degree', 'longitude,latitude' ) - call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, 'lonlatt', 'degree', 'longitude,latitude' ) + is_spec_in_FZ = .true. + do k=1, in_NeGZ+1 + if ( in_FZ(k) == UNDEF ) then + is_spec_in_FZ = .false.; exit + end if + end do + is_spec_out_FZ = .true. + do k=1, out_NeZ+1 + if ( out_FZ(k) == UNDEF ) then + is_spec_out_FZ = .false.; exit + end if + end do + + !- - call out_mesh2D%Generate() + call in_elem2D%Init( in_PolyOrder_h, .false. ) - !- + if (out_NeZ < 0 ) then + is_mesh3D = .false. - call construct_map() + call out_elem2D%Init( out_PolyOrder_h, .false. ) + + call out_mesh2D%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, & + 0.0_RP, 360.0_RP, -90.0_RP, 90.0_RP, & + .true., .false., out_elem2D, 1, & + out_NprcX, out_NprcY ) + + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XY, 'lonlat', 'degree', 'longitude,latitude' ) + call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, 'lonlatt', 'degree', 'longitude,latitude' ) + + call out_mesh2D%Generate() + call construct_map() + else + is_mesh3D = .true. + call in_elem3D%Init( in_PolyOrder_h, in_PolyOrder_v, .false. ) + call out_elem3D%Init( out_PolyOrder_h, out_PolyOrder_v, .false. ) + + if ( is_spec_out_FZ ) then + call out_mesh3D%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, out_NeZ, & + 0.0_RP, 360.0_RP, -90.0_RP, 90.0_RP, out_dom_zmin, out_dom_zmax, & + .true., .false., .false., out_elem3D, ATMOS_MESH_NLocalMeshPerPrc, & + out_NprcX, out_NprcY, & + FZ=out_FZ(1:out_NeZ+1) ) + else + call out_mesh3D%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, out_NeZ, & + 0.0_RP, 360.0_RP, -90.0_RP, 90.0_RP, out_dom_zmin, out_dom_zmax, & + .true., .false., .false., out_elem3D, ATMOS_MESH_NLocalMeshPerPrc, & + out_NprcX, out_NprcY ) + end if + + call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude' ) + call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatz', 'degree', 'longitude,latitude,altitude' ) + call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzt', 'degree', 'longitude,latitude,altitude' ) + + call out_mesh3D%Generate() + call construct_map( in_FZ(1:in_NeGZ+1), is_spec_in_FZ ) + end if return end subroutine interp_mesh_Init @@ -152,11 +250,17 @@ subroutine interp_mesh_Final() integer :: n !------------------------------------------- -! call in_mesh%Final() call in_elem2D%Final() - call out_mesh2D%Final() - call out_elem2D%Final() + if ( is_mesh3D ) then + call in_elem3D%Final() + + call out_mesh3D%Final() + call out_elem3D%Final() + else + call out_mesh2D%Final() + call out_elem2D%Final() + end if do n=1, ATMOS_MESH_NLocalMeshPerPrc call nodeMap_list(n)%Final() @@ -165,31 +269,23 @@ subroutine interp_mesh_Final() return end subroutine interp_mesh_Final - subroutine interp_mesh_Interpolate_field() - implicit none - !------------------------------------------- - - call in_elem2D%Final() - - call out_mesh2D%Final() - call out_elem2D%Final() - - return - end subroutine interp_mesh_Interpolate_field - !- private ------------------------------------- !OCL SERIAL - subroutine construct_map() + subroutine construct_map( in_Fz, is_spec_in_Fz ) implicit none + real(RP), intent(in), optional :: in_Fz(1:in_NeGZ+1) + logical, intent(in), optional :: is_spec_in_Fz + integer :: n integer :: i, j real(RP) :: in_tiles_x(4,in_NLocalMeshPerPrc,in_Nprc) real(RP) :: in_tiles_y(4,in_NLocalMeshPerPrc,in_Nprc) integer :: in_panel(4,in_NLocalMeshPerPrc,in_Nprc) real(RP) :: delx, dely - type(LocalMesh2D), pointer :: lcmesh + type(LocalMesh2D), pointer :: lcmesh2D + type(LocalMesh3D), pointer :: lcmesh3D integer :: NprcX_lc, NprcY_lc integer :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) @@ -203,8 +299,8 @@ subroutine construct_map() !------------------------------------------- !--- - call in_csmesh2D_dummy%Init( in_NeGX, in_NeGY, RPlanet, & - in_elem2D, in_NLocalMeshPerPrc, nproc=in_Nprc ) + call in_csmesh2D_dummy%Init( in_NeGX, in_NeGY, RPlanet, & + in_elem2D, in_NLocalMeshPerPrc, nproc=in_Nprc, myrank=0 ) call MeshCubedSphereDom2D_check_division_params( & NprcX_lc, NprcY_lc, & ! (out) @@ -214,7 +310,6 @@ subroutine construct_map() tileID_table, panelID_table, pi_table, pj_table ) ! (out) call in_csmesh2D_dummy%Final() - !--- delx = 0.5_RP * PI / dble(NprcX_lc) @@ -237,17 +332,25 @@ subroutine construct_map() end do end do - do n=1, out_mesh2D%LOCAL_MESH_NUM - lcmesh => out_mesh2D%lcmesh_list(n) - call nodeMap_list(n)%Init( lcmesh, lcmesh%refElem2D, in_tiles_x, in_tiles_y, & - tileID_table, panelID_table, NprcX_lc, NprcY_lc ) - end do - + if ( is_mesh3D ) then + do n=1, out_mesh3D%LOCAL_MESH_NUM + lcmesh3D => out_mesh3D%lcmesh_list(n) + call nodeMap_list(n)%Init_3D( lcmesh3D, lcmesh3D%refElem3D, in_tiles_x, in_tiles_y, in_Fz, & + tileID_table, panelID_table, NprcX_lc, NprcY_lc, is_spec_in_Fz ) + end do + else + do n=1, out_mesh2D%LOCAL_MESH_NUM + lcmesh2D => out_mesh2D%lcmesh_list(n) + call nodeMap_list(n)%Init_2D( lcmesh2D, lcmesh2D%refElem2D, in_tiles_x, in_tiles_y, & + tileID_table, panelID_table, NprcX_lc, NprcY_lc ) + end do + end if + return end subroutine construct_map !OCL SERIAL - subroutine NodeMappingInfo_Init( this, & + subroutine NodeMappingInfo_Init_2D( this, & lcmesh, elem2D, tile_x, tile_y, tileID_table, panelID_table, & NprcX_lc, NprcY_lc ) use scale_prc @@ -427,7 +530,251 @@ subroutine NodeMappingInfo_Init( this, & end do return - end subroutine NodeMappingInfo_Init + end subroutine NodeMappingInfo_Init_2D + +!OCL SERIAL + subroutine NodeMappingInfo_Init_3D( this, & + lcmesh, elem3D, tile_x, tile_y, in_Fz, & + tileID_table, panelID_table, & + NprcX_lc, NprcY_lc, is_spec_in_FZ ) + use scale_prc + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSPos + implicit none + + class(NodeMappingInfo), intent(inout), target :: this + type(LocalMesh3D), intent(in) :: lcmesh + type(ElementBase3D), intent(in) :: elem3D + real(RP), intent(in) :: tile_x(4,in_NLocalMeshPerPrc,in_Nprc) + real(RP), intent(in) :: tile_y(4,in_NLocalMeshPerPrc,in_Nprc) + real(RP), intent(in) :: in_Fz(1:in_NeGZ+1) + integer, intent(in) :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) + integer, intent(in) :: panelID_table(in_NLocalMeshPerPrc,in_Nprc) + integer, intent(in) :: NprcX_lc, NprcY_lc + logical, intent(in) :: is_spec_in_FZ + + integer :: lc_domID, prcID, in_prc, in_n + integer :: i, j + integer :: p, ke + integer :: ke_h + integer :: p_h, p_h_x, p_h_y + integer :: ke_z, ke_z2, p_z, p_z2 + logical :: is_inside_tile(elem3D%Nnode_h1D**2) + logical :: is_inside_elem + real(RP) :: in_elem_x(4) + real(RP) :: in_elem_y(4) + real(RP) :: delx, dely + logical :: target_tile_flag(in_NLocalMeshPerPrc,in_Nprc) + logical :: target_prc_flag(in_Nprc) + integer :: in_tileID_tmp(in_NLocalMeshPerPrc*in_Nprc) + integer :: in_prc2lcprc_tmp(in_Nprc) + integer :: in_lcprc2prc_tmp(in_Nprc) + integer :: in_tile_num + integer :: in_prc_num + type(LocalMesh3D), pointer :: in_lcmesh + real(RP) :: in_Z0, in_Z1 + integer :: in_ke3D + + real(RP) :: out_lon(1), out_lat(1) + real(RP) :: out_x(1), out_y(1) + integer :: out_cspanel + real(RP) :: out_x0, del_x + real(RP) :: out_y0, del_y + + integer :: in_NeX, in_NeY + + real(RP) :: out_lon2D(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + real(RP) :: out_lat2D(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + !------------------------------------------- + + allocate( this%local_domID(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%lcprc(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%inCSPanelID(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%elem_i(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%elem_j(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%elem_k(elem3D%Np, lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) ) + allocate( this%elem_x(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%elem_y(elem3D%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) + allocate( this%elem_z(elem3D%Np, lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) ) + + target_tile_flag(:,:) = .false. + target_prc_flag(:) = .false. + in_lcprc2prc_tmp(:) = -1 + in_prc2lcprc_tmp(:) = -1 + + !$omp parallel do + do ke_h=1, lcmesh%NeX * lcmesh%NeY + out_lon2D(:,ke_h) = lcmesh%pos_en(elem3D%Hslice(:,1),ke_h,1) * PI / 180.0_RP + out_lat2D(:,ke_h) = lcmesh%pos_en(elem3D%Hslice(:,1),ke_h,2) * PI / 180.0_RP + end do + call get_panelID( this%inCSPanelID(:,:), & + out_lon2D, out_lat2D, & + elem3D%Nnode_h1D**2 * lcmesh%NeX*lcmesh%NeY ) + + in_tile_num = 0 + in_prc_num = 0 + do ke_h=1, lcmesh%NeX * lcmesh%NeY + + do p_h_y=1, elem3D%Nnode_h1D + do p_h_x=1, elem3D%Nnode_h1D + p_h = p_h_x + (p_h_y-1)*elem3D%Nnode_h1D + this%local_domID(p_h,ke_h) = -1 + this%lcprc(p_h,ke_h) = -1 + + out_cspanel = this%inCSPanelID(p_h,ke_h) + out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) * PI / 180.0_RP + out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) * PI / 180.0_RP + call CubedSphereCnv_LonLat2CSPos( & + out_cspanel, out_lon, out_lat, 1, & + out_x, out_y ) + + loop_prc: do in_prc=1, in_Nprc + do in_n=1, in_NLocalMeshPerPrc + + if ( out_cspanel /= panelID_table(in_n,in_prc) ) cycle + + is_inside_tile(p_h) = inpoly( out_x(1), out_y(1), & + 4, tile_x(:,in_n,in_prc), tile_y(:,in_n,in_prc) ) + + if ( is_inside_tile(p_h) ) then + this%local_domID(p_h,ke_h) = in_n + + if ( .not. target_tile_flag(in_n,in_prc) ) then + target_tile_flag(in_n,in_prc) = .true. + in_tile_num = in_tile_num + 1 + in_tileID_tmp(in_tile_num) = tileID_table(in_n,in_prc) + end if + if ( .not. target_prc_flag(in_prc) ) then + target_prc_flag(in_prc) = .true. + in_prc_num = in_prc_num + 1 + in_prc2lcprc_tmp(in_prc) = in_prc_num + in_lcprc2prc_tmp(in_prc_num) = in_prc + end if + this%lcprc(p_h,ke_h) = in_prc2lcprc_tmp(in_prc) + + exit loop_prc + end if + + end do + end do loop_prc + + end do + end do + + end do + + allocate( this%in_tileID_list(in_tile_num) ) + this%in_tileID_list(:) = in_tileID_tmp(1:in_tile_num) + + in_NeX = in_NeGX / NprcX_lc + in_NeY = in_NeGY / NprcY_lc + + do ke_h=1, lcmesh%NeX * lcmesh%NeY + do p_h_y=1, elem3D%Nnode_h1D + do p_h_x=1, elem3D%Nnode_h1D + + p_h = p_h_x + (p_h_y-1)*elem3D%Nnode_h1D + + lc_domID = this%local_domID(p_h,ke_h) + prcID = in_lcprc2prc_tmp( this%lcprc(p_h,ke_h) ) + + out_cspanel = this%inCSPanelID(p_h,ke_h) + out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) * PI / 180.0_RP + out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) * PI / 180.0_RP + call CubedSphereCnv_LonLat2CSPos( & + out_cspanel, out_lon, out_lat, 1, & + out_x, out_y ) + + this%elem_i(p_h,ke_h) = -1 + this%elem_j(p_h,ke_h) = -1 + if ( lc_domID > 0 .and. prcID > 0 ) then + delx = ( tile_x(2,lc_domID,prcID) - tile_x(1,lc_domID,prcID) ) / dble(in_NeX) + dely = ( tile_y(4,lc_domID,prcID) - tile_y(1,lc_domID,prcID) ) / dble(in_NeY) + + loop_ne: do j=1, in_NeY + do i=1, in_NeX + in_elem_x(:) = tile_x(1,lc_domID,prcID) + delx * dble( (/ i-1, i, i, i-1 /) ) + in_elem_y(:) = tile_y(1,lc_domID,prcID) + dely * dble( (/ j-1, j-1, j, j /) ) + is_inside_elem = inpoly( out_x(1), out_y(1), & + 4, in_elem_x(:), in_elem_y(:) ) + + if (is_inside_elem) then + this%elem_i(p_h,ke_h) = i + this%elem_j(p_h,ke_h) = j + this%elem_x(p_h,ke_h) = out_x(1) + this%elem_y(p_h,ke_h) = out_y(1) + exit loop_ne + end if + end do + end do loop_ne + end if + end do + end do + end do + + !-- prepair mesh for input data -------------------------------- + + allocate( this%in_mesh3D_list(in_prc_num) ) + do i=1, in_prc_num + if (is_spec_in_FZ) then + call this%in_mesh3D_list(i)%Init( in_NeGX, in_NeGY, in_NeGZ, & + RPlanet, dom_zmin, dom_zmax, in_elem3D, in_NLocalMeshPerPrc, & + nproc=in_Nprc, myrank=in_lcprc2prc_tmp(i)-1, & + FZ=in_Fz ) + else + call this%in_mesh3D_list(i)%Init( in_NeGX, in_NeGY, in_NeGZ, & + RPlanet, dom_zmin, dom_zmax, in_elem3D, in_NLocalMeshPerPrc, & + nproc=in_Nprc, myrank=in_lcprc2prc_tmp(i)-1 ) + end if + call this%in_mesh3D_list(i)%Generate() + end do + + !-- + !$omp parallel private( & + !$omp ke_h, p_h, in_lcmesh, in_prc, in_n, & + !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) + + !$omp workshare + this%elem_k(:,:) = -1 + !$omp end workshare + + !$omp do collapse(2) + do ke_h=1, lcmesh%NeX * lcmesh%NeY + do p_h=1, elem3D%Nnode_h1D**2 + + in_n = this%local_domID(p_h,ke_h) + in_prc = this%lcprc(p_h,ke_h) + + if ( in_n > 0 .and. in_prc > 0 .and. & + this%elem_i(p_h,ke_h) > 0 .and. this%elem_j(p_h,ke_h) > 0 ) then + + in_lcmesh => this%in_mesh3D_list(in_prc)%lcmesh_list(in_n) + do ke_z=1, lcmesh%NeZ + do p_z=1, out_elem3D%Nnode_v + ke = ke_h + (ke_z-1)*lcmesh%NeX*lcmesh%NeY + p = p_h + (p_z-1)*elem3D%Nnode_h1D**2 + do ke_z2=1, in_NeGZ + in_ke3D = this%elem_i(p_h,ke_h) + (this%elem_j(p_h,ke_h)-1)*in_NeX & + + (ke_z2-1)*in_NeX*in_NeY + in_Z0 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,1),3) + in_Z1 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,5),3) + if ( in_Z0 <= lcmesh%pos_en(p,ke,3) .and. lcmesh%pos_en(p,ke,3) <= in_Z1 ) then + this%elem_k(p,ke) = ke_z2 + this%elem_z(p,ke) = lcmesh%pos_en(p,ke,3) + exit + end if + end do + end do + end do + end if + + end do + end do + !$omp end do + !$omp end parallel + + return + end subroutine NodeMappingInfo_Init_3D !OCL SERIAL subroutine NodeMappingInfo_Final( this ) @@ -441,12 +788,20 @@ subroutine NodeMappingInfo_Final( this ) deallocate( this%local_domID, this%lcprc ) deallocate( this%inCSPanelID ) deallocate( this%elem_i, this%elem_j ) + if ( allocated(this%elem_k) ) deallocate( this%elem_k ) deallocate( this%in_tileID_list ) - do i=1, size(this%in_mesh2D_list) - call this%in_mesh2D_list(i)%Final() - end do - deallocate( this%in_mesh2D_list ) + if (is_mesh3D) then + do i=1, size(this%in_mesh3D_list) + call this%in_mesh3D_list(i)%Final() + end do + deallocate( this%in_mesh3D_list ) + else + do i=1, size(this%in_mesh2D_list) + call this%in_mesh2D_list(i)%Final() + end do + deallocate( this%in_mesh2D_list ) + end if end if return diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 index 4fe4a66a..4dab2682 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 @@ -22,12 +22,14 @@ program convert_cs2lonlat use scale_prc, only: PRC_abort use mod_cs2lonlat_interp_mesh, only: & - out_mesh2D, & + out_mesh2D, out_mesh3D, & + is_mesh3D, & nodeMap_list use mod_cs2lonlat_interp_field, only: & OutVarInfo, & - out_var2D_num, & + out_var_num, & out_var2D, & + out_var3D, & out_vinfo, & interp_field_Interpolate use mod_cs2lonlat_interp_file, only: & @@ -70,17 +72,23 @@ program convert_cs2lonlat LOG_NEWLINE LOG_PROGRESS(*) 'START LOOP' - do vid =1, out_var2D_num + do vid =1, out_var_num vinfo => out_vinfo(vid) do istep=1, vinfo%num_step, vinfo%out_tintrv start_sec = vinfo%start_sec + (istep - 1) * vinfo%dt LOG_INFO("INTERP",'(a,i4)') 'Interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep - call interp_field_Interpolate( istep, vinfo%varname, & - out_mesh2D, out_var2D, nodeMap_list ) - call interp_file_write_var( vid, out_var2D, & - start_sec, start_sec + vinfo%dt ) - + if (is_mesh3D) then + call interp_field_Interpolate( istep, vinfo%varname, & + out_mesh3D, out_var3D, nodeMap_list ) + call interp_file_write_var( vid, out_var3D, & + start_sec, start_sec + vinfo%dt ) + else + call interp_field_Interpolate( istep, vinfo%varname, & + out_mesh2D, out_var2D, nodeMap_list ) + call interp_file_write_var( vid, out_var2D, & + start_sec, start_sec + vinfo%dt ) + end if if( IO_L ) call flush(IO_FID_LOG) end do end do @@ -169,9 +177,9 @@ subroutine initialize() LOG_NML(PARAM_INTERP) ! - call interp_mesh_Init - call interp_field_Init( out_mesh2D, nodeMap_list ) - call interp_file_Init( in_basename, out_vinfo, out_mesh2D ) + call interp_mesh_Init() + call interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D, nodeMap_list ) + call interp_file_Init( in_basename, out_vinfo, out_mesh2D, out_mesh3D, is_mesh3D ) !- do_output = .true. @@ -201,7 +209,7 @@ subroutine finalize call PROF_rapstart ('Finalize', 0) call interp_file_Final - call interp_field_Final + call interp_field_Final(is_mesh3D) call interp_mesh_Final ! From 41272ffbdc9a3dafed7b1e8f6a1df2b7517d9649 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 26 May 2021 00:47:28 +0900 Subject: [PATCH 29/98] Modify some modules of scale-dg to support the 3D cubed sphere mesh. --- .../src/file/scale_file_restart_meshfield.F90 | 14 +- .../model_framework/scale_model_component.F90 | 2 +- .../scale_model_mesh_manager.F90 | 24 ++ .../model_framework/mod_atmos_component.f90 | 2 +- model/atm_nonhydro3d/src/Makefile | 2 + model/atm_nonhydro3d/src/admin/mod_exp.F90 | 59 +++-- .../src/atmos/mod_atmos_component.F90 | 50 +++- .../src/atmos/mod_atmos_dyn.F90 | 50 +++- .../src/atmos/mod_atmos_dyn_vars.F90 | 38 +-- .../src/atmos/mod_atmos_mesh.F90 | 179 ++++++-------- .../src/atmos/mod_atmos_mesh_gm.F90 | 216 +++++++++++++++++ .../src/atmos/mod_atmos_mesh_rm.F90 | 229 ++++++++++++++++++ .../src/atmos/mod_atmos_phy_sfc_vars.F90 | 6 +- .../src/atmos/mod_atmos_phy_tb.F90 | 2 +- .../src/atmos/mod_atmos_phy_tb_vars.F90 | 19 +- .../src/atmos/mod_atmos_vars.F90 | 73 +++--- model/atm_nonhydro3d/src/depend | 8 +- .../src/preprocess/mod_mkinit.F90 | 18 +- 18 files changed, 755 insertions(+), 236 deletions(-) create mode 100644 model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 create mode 100644 model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 diff --git a/FElib/src/file/scale_file_restart_meshfield.F90 b/FElib/src/file/scale_file_restart_meshfield.F90 index 101e8a80..c9eabdc9 100644 --- a/FElib/src/file/scale_file_restart_meshfield.F90 +++ b/FElib/src/file/scale_file_restart_meshfield.F90 @@ -163,7 +163,8 @@ end subroutine FILE_restart_meshfield_setup subroutine FILE_restart_meshfield_component_Init1( this, & comp_name, & - var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D ) + var_num, mesh1D, mesh2D, meshCubedSphere2D, & + mesh3D, meshCubedSphere3D ) use scale_file_common_meshfield, only: & File_common_meshfield_get_dims @@ -177,15 +178,16 @@ subroutine FILE_restart_meshfield_component_Init1( this, & class(MeshRectDom2D), target, optional, intent(in) :: mesh2D class(MeshCubedSphereDom2D), target, optional, intent(in) :: meshCubedSphere2D class(MeshCubeDom3D), target, optional, intent(in) :: mesh3D + class(MeshCubedSphereDom3D), target, optional, intent(in) :: meshCubedSphere3D !-------------------------------------------------- call this%Init2( & - comp_name, & - restart_file%in_basename, restart_file%in_postfix_timelabel, & - restart_file%out_basename, restart_file%out_postfix_timelabel, & - restart_file%out_dtype, restart_file%out_title, & - var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D ) + comp_name, & + restart_file%in_basename, restart_file%in_postfix_timelabel, & + restart_file%out_basename, restart_file%out_postfix_timelabel, & + restart_file%out_dtype, restart_file%out_title, & + var_num, mesh1D, mesh2D, meshCubedSphere2D, mesh3D, meshCubedSphere3D ) return end subroutine FILE_restart_meshfield_component_Init1 diff --git a/FElib/src/model_framework/scale_model_component.F90 b/FElib/src/model_framework/scale_model_component.F90 index b35443e9..cf7bc9c3 100644 --- a/FElib/src/model_framework/scale_model_component.F90 +++ b/FElib/src/model_framework/scale_model_component.F90 @@ -37,7 +37,7 @@ module scale_model_component interface subroutine ModelComponent_setup( this ) import ModelComponent - class(ModelComponent), intent(inout) :: this + class(ModelComponent), intent(inout), target :: this end subroutine ModelComponent_setup subroutine ModelComponent_calc_tendency( this ) diff --git a/FElib/src/model_framework/scale_model_mesh_manager.F90 b/FElib/src/model_framework/scale_model_mesh_manager.F90 index 71e65283..5ad9e103 100644 --- a/FElib/src/model_framework/scale_model_mesh_manager.F90 +++ b/FElib/src/model_framework/scale_model_mesh_manager.F90 @@ -6,6 +6,8 @@ module scale_model_mesh_manager ! use scale_precision use scale_io + use scale_prc, only: & + PRC_abort use scale_mesh_base, only: MeshBase use scale_mesh_base1d, only: MeshBase1D @@ -27,9 +29,12 @@ module scale_model_mesh_manager type(SparseMat), allocatable :: DOptrMat(:) type(SparseMat), allocatable :: SOptrMat(:) type(SparseMat) :: LiftOptrMat + + integer :: communicator_num contains procedure :: ModelMeshBase_Init procedure :: ModelMeshBase_Final + procedure :: Get_communicatorID => ModelMeshBase_get_communicatorID procedure(ModelMeshBase_get_modelmesh), public, deferred :: GetModelMesh end type ModelMeshBase @@ -86,11 +91,30 @@ subroutine ModelMeshBase_Init( this, nDim ) integer :: d !-------------------------------------------- + this%communicator_num = 0 allocate( this%SOptrMat(nDim), this%DOptrMat(nDim) ) return end subroutine ModelMeshBase_Init + function ModelMeshBase_get_communicatorID( this, max_communicator_num ) result(commid) + implicit none + class(ModelMeshBase), intent(inout) :: this + integer, intent(in) :: max_communicator_num + integer :: commid + !-------------------------------------------- + + this%communicator_num = this%communicator_num + 1 + commid = this%communicator_num + + if ( commid > max_communicator_num ) then + LOG_ERROR('ModelMeshBase_get_communicatorID',*) 'The number of communicator exceeds expectation. Check!' + call PRC_abort + end if + + return + end function ModelMeshBase_get_communicatorID + subroutine ModelMeshBase_Final( this ) implicit none class(ModelMeshBase), intent(inout) :: this diff --git a/FElib/test/framework/model_framework/mod_atmos_component.f90 b/FElib/test/framework/model_framework/mod_atmos_component.f90 index fa3ee835..2d3b78fb 100644 --- a/FElib/test/framework/model_framework/mod_atmos_component.f90 +++ b/FElib/test/framework/model_framework/mod_atmos_component.f90 @@ -43,7 +43,7 @@ subroutine Atmos_setup( this ) use scale_const, only: & UNDEF8 => CONST_UNDEF8 implicit none - class(AtmosComponent), intent(inout) :: this + class(AtmosComponent), intent(inout), target :: this integer :: n !-------------------------------------------------- diff --git a/model/atm_nonhydro3d/src/Makefile b/model/atm_nonhydro3d/src/Makefile index 849520ce..66070b0f 100644 --- a/model/atm_nonhydro3d/src/Makefile +++ b/model/atm_nonhydro3d/src/Makefile @@ -45,6 +45,8 @@ OBJS = \ mod_atmos_phy_tb.o \ mod_atmos_phy_tb_vars.o \ mod_atmos_mesh.o \ + mod_atmos_mesh_rm.o \ + mod_atmos_mesh_gm.o \ mod_atmos_vars.o \ mod_user.o \ mod_exp.o \ diff --git a/model/atm_nonhydro3d/src/admin/mod_exp.F90 b/model/atm_nonhydro3d/src/admin/mod_exp.F90 index a264eb33..8805884d 100644 --- a/model/atm_nonhydro3d/src/admin/mod_exp.F90 +++ b/model/atm_nonhydro3d/src/admin/mod_exp.F90 @@ -16,15 +16,18 @@ module mod_exp CPdry => CONST_CPdry, & CVdry => CONST_CVdry, & PRES00 => CONST_PRE00 - - use scale_meshfield_base, only: MeshField3D + + use scale_mesh_base3d, only: MeshBase3D use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + use scale_meshfieldcomm_base, only: MeshFieldCommBase + use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D + use scale_meshfieldcomm_cubedspheredom3d, only: MeshFieldCommCubedSphereDom3D + use scale_meshfield_base, only: MeshField3D use scale_element_base, only: ElementBase3D use scale_element_hexahedral, only: HexahedralElement use scale_localmesh_3d, only: LocalMesh3D - use scale_localmeshfield_base, only: LocalMeshFieldBase - use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D !----------------------------------------------------------------------------- implicit none @@ -154,36 +157,56 @@ subroutine exp_SetInitCond( this, & integer :: n class(LocalMesh3D), pointer :: lcmesh3D - class(MeshCubeDom3D), pointer :: mesh + class(MeshBase3D), pointer :: mesh - type(MeshFieldCommCubeDom3D) :: hydvars_comm + type(MeshFieldCommCubeDom3D), target :: hydvars_comm_rm + type(MeshFieldCommCubedSphereDom3D), target :: hydvars_comm_gm + class(MeshFieldCommBase), pointer :: hydvars_comm type(MeshFieldContainer) :: hydvars_comm_list(1) class(MeshFieldBase), pointer :: field_ptr !---------------------------------------------------------------------- - mesh => model_mesh%mesh + mesh => model_mesh%ptr_mesh do n=1, mesh%LOCAL_MESH_NUM call AtmosVars_GetLocalMeshPrgVars( n, mesh, atm_prgvars_manager, atm_auxvars_manager, & DDENS, MOMX, MOMY, MOMZ, DRHOT, & DENS_hyd, PRES_hyd, lcmesh3D ) - call this%setInitCond_lc( & - DENS_hyd%val, PRES_hyd%val, & ! (out) - DDENS%val, MOMX%val, MOMY%val, MOMZ%val, DRHOT%val, & ! (out) - lcmesh3D%pos_en(:,:,1), lcmesh3D%pos_en(:,:,2), lcmesh3D%pos_en(:,:,3), & ! (in) - mesh%xmin_gl, mesh%xmax_gl, mesh%ymin_gl, mesh%ymax_gl, mesh%zmin_gl, mesh%zmax_gl, & ! (in) - lcmesh3D, lcmesh3D%refElem3D ) ! (in) + select type (mesh) + type is (MeshCubeDom3D) + call this%setInitCond_lc( & + DENS_hyd%val, PRES_hyd%val, & ! (out) + DDENS%val, MOMX%val, MOMY%val, MOMZ%val, DRHOT%val, & ! (out) + lcmesh3D%pos_en(:,:,1), lcmesh3D%pos_en(:,:,2), lcmesh3D%pos_en(:,:,3), & ! (in) + mesh%xmin_gl, mesh%xmax_gl, mesh%ymin_gl, mesh%ymax_gl, mesh%zmin_gl, mesh%zmax_gl, & ! (in) + lcmesh3D, lcmesh3D%refElem3D ) ! (in) + type is (MeshCubedSphereDom3D) + call this%setInitCond_lc( & + DENS_hyd%val, PRES_hyd%val, & ! (out) + DDENS%val, MOMX%val, MOMY%val, MOMZ%val, DRHOT%val, & ! (out) + lcmesh3D%pos_en(:,:,1), lcmesh3D%pos_en(:,:,2), lcmesh3D%pos_en(:,:,3), & ! (in) + mesh%xmin_gl, mesh%xmax_gl, mesh%ymin_gl, mesh%ymax_gl, mesh%zmin_gl, mesh%zmax_gl, & ! (in) + lcmesh3D, lcmesh3D%refElem3D ) ! (in) + end select end do !------------------------------------------------------ - call hydvars_comm%Init(1, 0, mesh) call atm_auxvars_manager%Get(ATMOS_AUXVARS_PRESHYDRO_ID, field_ptr) select type(field_ptr) type is (MeshField3D) hydvars_comm_list(1)%field3d => field_ptr end select + select type (mesh) + type is (MeshCubeDom3D) + call hydvars_comm_rm%Init(1, 0, mesh) + hydvars_comm => hydvars_comm_rm + type is (MeshCubedSphereDom3D) + call hydvars_comm_gm%Init(1, 0, mesh) + hydvars_comm => hydvars_comm_gm + end select + call hydvars_comm%Put(hydvars_comm_list, 1) call hydvars_comm%Exchange() call hydvars_comm%Get(hydvars_comm_list, 1) @@ -208,7 +231,13 @@ subroutine exp_SetInitCond( this, & call hydvars_comm%Put(hydvars_comm_list, 1) call hydvars_comm%Exchange() call hydvars_comm%Get(hydvars_comm_list, 1) - call hydvars_comm%Final() + + select type (mesh) + type is (MeshCubeDom3D) + call hydvars_comm_rm%Final() + type is (MeshCubedSphereDom3D) + call hydvars_comm_gm%Final() + end select return end subroutine exp_SetInitCond diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 index ffb796b3..ef01f8eb 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 @@ -23,9 +23,13 @@ module mod_atmos_component use scale_localmesh_3d, only: LocalMesh3D use scale_localmeshfield_base, only: LocalMeshFieldBase use scale_model_component, only: ModelComponent + use scale_model_mesh_manager, only: ModelMesh3D - use mod_atmos_vars, only: AtmosVars use mod_atmos_mesh, only: AtmosMesh + use mod_atmos_mesh_rm, only: AtmosMeshRM + use mod_atmos_mesh_gm, only: AtmosMeshGM + + use mod_atmos_vars, only: AtmosVars use mod_atmos_dyn, only: AtmosDyn use mod_atmos_phy_sfc, only: AtmosPhySfc @@ -40,11 +44,16 @@ module mod_atmos_component ! type, extends(ModelComponent), public :: AtmosComponent type(AtmosVars) :: vars - type(AtmosMesh) :: mesh + + character(len=H_SHORT) :: mesh_type + class(AtmosMesh), pointer :: mesh + type(AtmosMeshRM) :: mesh_rm + type(AtmosMeshGM) :: mesh_gm type(AtmosDyn) :: dyn_proc type(AtmosPhySfc) :: phy_sfc_proc type(AtmosPhyTb ) :: phy_tb_proc + contains procedure, public :: setup => Atmos_setup procedure, public :: calc_tendency => Atmos_calc_tendency @@ -79,7 +88,7 @@ subroutine Atmos_setup( this ) implicit none - class(AtmosComponent), intent(inout) :: this + class(AtmosComponent), intent(inout), target :: this logical :: ACTIVATE_FLAG = .true. @@ -91,6 +100,7 @@ subroutine Atmos_setup( this ) logical :: ATMOS_DYN_DO = .true. logical :: ATMOS_PHY_SF_DO = .false. logical :: ATMOS_PHY_TB_DO = .false. + character(len=H_SHORT) :: ATMOS_MESH_TYPE = 'REGIONAL' ! 'REGIONAL' or 'GLOBAL' namelist / PARAM_ATMOS / & ACTIVATE_FLAG, & @@ -98,6 +108,7 @@ subroutine Atmos_setup( this ) TIME_DT_UNIT, & TIME_DT_RESTART, & TIME_DT_RESTART_UNIT, & + ATMOS_MESH_TYPE, & ATMOS_DYN_DO, & ATMOS_PHY_SF_DO, & ATMOS_PHY_TB_DO @@ -130,13 +141,22 @@ subroutine Atmos_setup( this ) call TIME_manager_Regist_component( this%time_manager ) - !- Setup mesh - - call this%mesh%Init() - - !- Setup file I/O for atmospheric component - - call FILE_HISTORY_meshfield_setup( mesh3d_=this%mesh%mesh ) + !- Setup mesh & file I/O for atmospheric component + + this%mesh_type = ATMOS_MESH_TYPE + select case( this%mesh_type ) + case('REGIONAL') + call this%mesh_rm%Init() + call FILE_HISTORY_meshfield_setup( mesh3d_=this%mesh_rm%mesh ) + this%mesh => this%mesh_rm + case('GLOBAL') + call this%mesh_gm%Init() + call FILE_HISTORY_meshfield_setup( meshCubedSphere3D_=this%mesh_gm%mesh ) + this%mesh => this%mesh_gm + case default + LOG_ERROR("ATM_setup",*) 'Unsupported type of mesh is specified. Check!', this%mesh_type + call PRC_abort + end select !- Setup variables @@ -302,7 +322,15 @@ subroutine Atmos_finalize( this ) call this%phy_tb_proc%finalize() call this%vars%Final() - call this%mesh%Final() + + select case( this%mesh_type ) + case('REGIONAL') + call this%mesh_rm%Final() + case('GLOBAL') + call this%mesh_gm%Final() + end select + this%mesh => null() + call this%time_manager%Final() return diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 index f3c20a3b..edc9ae74 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 @@ -272,6 +272,8 @@ subroutine AtmosDyn_setup( this, model_mesh, tm_parent_comp ) integer :: n real(DP) :: dtsec + class(MeshBase3D), pointer :: mesh3D + integer :: ierr !-------------------------------------------------- @@ -293,9 +295,10 @@ subroutine AtmosDyn_setup( this, model_mesh, tm_parent_comp ) call model_mesh%GetModelMesh( ptr_mesh ) select type(model_mesh) - type is (AtmosMesh) + class is (AtmosMesh) atm_mesh => model_mesh end select + mesh3D => atm_mesh%ptr_mesh !- Setup the temporal integrator @@ -317,6 +320,7 @@ subroutine AtmosDyn_setup( this, model_mesh, tm_parent_comp ) !- initialize the variables call this%dyn_vars%Init( model_mesh ) + call setup_coriolis_parameter( this%dyn_vars, atm_mesh ) !- Initialize a module for 3D dynamical core @@ -324,22 +328,22 @@ subroutine AtmosDyn_setup( this, model_mesh, tm_parent_comp ) select case(EQS_TYPE) case("NONHYDRO3D_HEVE") this%EQS_TYPEID = EQS_TYPEID_NONHYD3D_HEVE - call atm_dyn_dgm_nonhydro3d_heve_Init( atm_mesh%mesh ) + call atm_dyn_dgm_nonhydro3d_heve_Init( mesh3D ) this%cal_tend_ex => atm_dyn_dgm_nonhydro3d_heve_cal_tend this%cal_vi => null() case("NONHYDRO3D_SPLITFORM_HEVE") this%EQS_TYPEID = EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE - call atm_dyn_dgm_nonhydro3d_heve_splitform_Init( atm_mesh%mesh ) + call atm_dyn_dgm_nonhydro3d_heve_splitform_Init( mesh3D ) this%cal_tend_ex => atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend this%cal_vi => null() case("NONHYDRO3D_HEVI") this%EQS_TYPEID = EQS_TYPEID_NONHYD3D_HEVI - call atm_dyn_dgm_nonhydro3d_hevi_Init( atm_mesh%mesh ) + call atm_dyn_dgm_nonhydro3d_hevi_Init( mesh3D ) this%cal_tend_ex => atm_dyn_dgm_nonhydro3d_hevi_cal_tend this%cal_vi => atm_dyn_dgm_nonhydro3d_hevi_cal_vi case("NONHYDRO3D_SPLITFORM_HEVI") this%EQS_TYPEID = EQS_TYPEID_NONHYD3D_SPLITFORM_HEVI - call atm_dyn_dgm_nonhydro3d_hevi_splitform_Init( atm_mesh%mesh ) + call atm_dyn_dgm_nonhydro3d_hevi_splitform_Init( mesh3D ) this%cal_tend_ex => atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend this%cal_vi => atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi case default @@ -939,7 +943,7 @@ subroutine setup_numdiff( this, atm_mesh ) this%ND_LAPLACIAN_NUM = ND_LAPLACIAN_NUM this%ND_COEF_H = ND_COEF_h this%ND_COEF_v = ND_COEF_v - call atm_dyn_dgm_nonhydro3d_numdiff_Init( atm_mesh%mesh ) + call atm_dyn_dgm_nonhydro3d_numdiff_Init( atm_mesh%ptr_mesh ) return end subroutine setup_numdiff @@ -947,6 +951,8 @@ end subroutine setup_numdiff !-- Setup sponge layer !OCL SERIAL subroutine setup_spongelayer( this, atm_mesh, dtsec ) + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D implicit none class(AtmosDyn), target, intent(inout) :: this @@ -962,9 +968,11 @@ subroutine setup_spongelayer( this, atm_mesh, dtsec ) SL_WDAMP_HEIGHT, & SL_WDAMP_LAYER + class(MeshBase3D), pointer :: mesh3D class(LocalMesh3D), pointer :: lcmesh3D class(ElementBase3D), pointer :: elem3D + integer :: NeGZ integer :: ierr !--------------------------------------------------------------- @@ -981,10 +989,18 @@ subroutine setup_spongelayer( this, atm_mesh, dtsec ) this%wdamp_tau = SL_WDAMP_TAU this%wdamp_height = SL_WDAMP_HEIGHT - lcmesh3D => atm_mesh%mesh%lcmesh_list(1) + mesh3D => atm_mesh%ptr_mesh + lcmesh3D => mesh3D%lcmesh_list(1) elem3D => lcmesh3D%refElem3D - if ( SL_WDAMP_LAYER > atm_mesh%mesh%NeGZ ) then + select type(mesh3D) + type is (MeshCubeDom3D) + NeGZ = mesh3D%NeGZ + type is (MeshCubedSphereDom3D) + NeGZ = mesh3D%NeGZ + end select + + if ( SL_WDAMP_LAYER > NeGZ ) then LOG_ERROR("ATMOS_DYN_setup_spongelayer",*) 'SL_wdamp_layer should be less than total of vertical elements (NeGZ). Check!' call PRC_abort else if( SL_WDAMP_LAYER > 0 ) then @@ -1005,8 +1021,8 @@ end subroutine setup_spongelayer !OCL SERIAL subroutine setup_coriolis_parameter( this, atm_mesh ) - use scale_coriolis_param, only: & - get_coriolis_parameter + use scale_coriolis_param, only: get_coriolis_parameter + use scale_mesh_cubedom3d, only: MeshCubeDom3D implicit none class(AtmosDynVars), target, intent(inout) :: this @@ -1026,11 +1042,19 @@ subroutine setup_coriolis_parameter( this, atm_mesh ) CORIOLIS_type, & CORIOLIS_f0, CORIOLIS_beta, CORIOLIS_y0 + class(MeshBase3D), pointer :: mesh3D + class(MeshCubeDom3D), pointer :: meshCube integer :: ierr !--------------------------------------------------------------- + mesh3D => atm_mesh%ptr_mesh + CORIOLIS_type = 'NONE' - CORIOLIS_y0 = 0.5_RP*(atm_mesh%mesh%ymax_gl + atm_mesh%mesh%ymin_gl) + + select type(mesh3D) + type is (MeshCubeDom3D) + CORIOLIS_y0 = 0.5_RP*(mesh3D%ymax_gl + mesh3D%ymin_gl) + end select rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_ATMOS_DYN_CORIOLIS,iostat=ierr) @@ -1042,8 +1066,8 @@ subroutine setup_coriolis_parameter( this, atm_mesh ) end if LOG_NML(PARAM_ATMOS_DYN_CORIOLIS) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM - call AtmosDynAuxVars_GetLocalMeshFields( n, atm_mesh%mesh, this%AUXVARS2D_manager, & + do n = 1, mesh3D%LOCAL_MESH_NUM + call AtmosDynAuxVars_GetLocalMeshFields( n, mesh3D, this%AUXVARS2D_manager, & coriolis, lcmesh3D ) lcmesh2D => lcmesh3D%lcmesh2D diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 index b139a7a4..f9d99b42 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 @@ -19,7 +19,6 @@ module mod_atmos_dyn_vars use scale_meshfield_base, only: MeshField3D, MeshField2D use scale_localmeshfield_base, only: LocalMeshFieldBase - use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D use scale_meshfieldcomm_base, only: MeshFieldContainer use scale_model_var_manager, only: & @@ -42,11 +41,11 @@ module mod_atmos_dyn_vars type(MeshField3D), allocatable :: NUMDIFF_FLUX_VARS3D(:) type(ModelVarManager) :: NUMDIFF_FLUX_manager - type(MeshFieldCommCubeDom3D) :: NUMDIFF_FLUX_comm + integer :: NUMDIFF_FLUX_commid type(MeshField3D), allocatable :: NUMDIFF_TEND_VARS3D(:) type(ModelVarManager) :: NUMDIFF_TEND_manager - type(MeshFieldCommCubeDom3D) :: NUMDIFF_TEND_comm + integer :: NUMDIFF_TEND_commid type(MeshField3D), allocatable :: ANALYSIS_VARS3D(:) type(ModelVarManager) :: ANALYSISVARS_manager @@ -131,6 +130,8 @@ module mod_atmos_dyn_vars contains subroutine AtmosDynVars_Init( this, model_mesh ) + use mod_atmos_mesh_gm, only: AtmosMeshGM + use mod_atmos_mesh_rm, only: AtmosMeshRM implicit none class(AtmosDynVars), target, intent(inout) :: this class(ModelMeshBase), target, intent(in) :: model_mesh @@ -151,12 +152,12 @@ subroutine AtmosDynVars_Init( this, model_mesh ) nullify( atm_mesh ) select type(model_mesh) - type is (AtmosMesh) + class is (AtmosMesh) atm_mesh => model_mesh end select + mesh3D => atm_mesh%ptr_mesh - mesh3D => atm_mesh%mesh - call atm_mesh%mesh%GetMesh2D( mesh2D ) + call mesh3D%GetMesh2D( mesh2D ) !- call this%AUXVARS2D_manager%Init() @@ -168,7 +169,7 @@ subroutine AtmosDynVars_Init( this, model_mesh ) ATMOS_DYN_AUXVARS2D_VINFO(v), mesh2D, & ! (in) this%AUX_VARS2D(v), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%AUX_VARS2D(v)%local(n)%val(:,:) = 0.0_RP end do end do @@ -183,12 +184,16 @@ subroutine AtmosDynVars_Init( this, model_mesh ) ATMOS_DYN_NUMDIFF_FLUX_VINFO(v), mesh3D, & ! (in) this%NUMDIFF_FLUX_VARS3D(v), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%NUMDIFF_FLUX_VARS3D(v)%local(n)%val(:,:) = 0.0_RP end do end do - call this%NUMDIFF_FLUX_comm%Init( ATMOS_DYN_NUMDIFF_FLUX_NUM, 0, atm_mesh%mesh ) - call this%NUMDIFF_FLUX_manager%MeshFieldComm_Prepair( this%NUMDIFF_FLUX_comm, this%NUMDIFF_FLUX_VARS3D(:) ) + + call atm_mesh%Create_communicator( & + ATMOS_DYN_NUMDIFF_FLUX_NUM, 0, & ! (in) + this%NUMDIFF_FLUX_manager, & ! (inout) + this%NUMDIFF_FLUX_VARS3D(:), & ! (in) + this%NUMDIFF_FLUX_commid ) ! (out) !- call this%NUMDIFF_TEND_manager%Init() @@ -200,13 +205,16 @@ subroutine AtmosDynVars_Init( this, model_mesh ) ATMOS_DYN_NUMDIFF_TEND_VINFO(v), mesh3D, & ! (in) this%NUMDIFF_TEND_VARS3D(v), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%NUMDIFF_TEND_VARS3D(v)%local(n)%val(:,:) = 0.0_RP end do end do - call this%NUMDIFF_TEND_comm%Init( ATMOS_DYN_NUMDIFF_TEND_NUM, 0, atm_mesh%mesh ) - call this%NUMDIFF_TEND_manager%MeshFieldComm_Prepair( this%NUMDIFF_TEND_comm, this%NUMDIFF_TEND_VARS3D(:) ) + call atm_mesh%Create_communicator( & + ATMOS_DYN_NUMDIFF_TEND_NUM, 0, & ! (in) + this%NUMDIFF_TEND_manager, & ! (inout) + this%NUMDIFF_TEND_VARS3D(:), & ! (in) + this%NUMDIFF_TEND_commid ) ! (out) !- ! call this%ANALYSISVARS_manager%Init() @@ -231,11 +239,7 @@ subroutine AtmosDynVars_Final( this ) LOG_INFO('AtmosDynVars_Final',*) call this%AUXVARS2D_manager%Final() - - call this%NUMDIFF_FLUX_comm%Final() call this%NUMDIFF_FLUX_manager%Final() - - call this%NUMDIFF_TEND_comm%Final() call this%NUMDIFF_TEND_manager%Final() !call this%ANALYSISVARS_manager%Final() diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 index a8bcf136..758dfde6 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 @@ -10,14 +10,15 @@ module mod_atmos_mesh use scale_prc use scale_meshfield_base, only: MeshField3D - use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_base3d, only: MeshBase3D use scale_element_base, only: ElementBase3D use scale_element_hexahedral, only: HexahedralElement use scale_localmesh_3d, only: LocalMesh3D - use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D use scale_sparsemat, only: sparsemat - use scale_model_mesh_manager, only: & - ModelMesh3D + + use scale_file_restart_meshfield, only: FILE_restart_meshfield_component + use scale_model_var_manager, only: ModelVarManager + use scale_model_mesh_manager, only: ModelMesh3D !----------------------------------------------------------------------------- implicit none @@ -26,22 +27,67 @@ module mod_atmos_mesh ! !++ Public type & procedures ! - type, extends(ModelMesh3D), public :: AtmosMesh - type(MeshCubeDom3D) :: mesh + type, abstract, extends(ModelMesh3D), public :: AtmosMesh type(HexahedralElement) :: element + contains - procedure :: Init => AtmosMesh_Init - procedure :: Final => AtmosMesh_Final + procedure :: AtmosMesh_Init + procedure :: AtmosMesh_Final + procedure(AtmosMesh_create_communicator), public, deferred :: Create_communicator + procedure(AtmosMesh_setup_restartfile1), public, deferred :: Setup_restartfile1 + procedure(AtmosMesh_setup_restartfile2), public, deferred :: Setup_restartfile2 + generic :: Setup_restartfile => Setup_restartfile1, Setup_restartfile2 procedure :: Construct_ModalFilter3D => AtmosMesh_construct_ModalFilter3D procedure :: Construct_ModalFilterHV => AtmosMesh_construct_ModalFilterHV end type AtmosMesh - + interface + subroutine AtmosMesh_create_communicator( this, sfield_num, hvfield_num, var_manager, field_list, commid ) + import AtmosMesh + import MeshBase3D + import ModelVarManager + import MeshField3D + class(AtmosMesh), target, intent(inout) :: this + integer, intent(in) :: sfield_num + integer, intent(in) :: hvfield_num + class(ModelVarManager), intent(inout) :: var_manager + class(MeshField3D), intent(in) :: field_list(:) + integer, intent(out) :: commid + end subroutine AtmosMesh_create_communicator + end interface + interface + subroutine AtmosMesh_setup_restartfile1( this, restart_file, var_num ) + import AtmosMesh + import FILE_restart_meshfield_component + class(AtmosMesh), target, intent(inout) :: this + class(FILE_restart_meshfield_component), intent(inout) :: restart_file + integer, intent(in) :: var_num + end subroutine AtmosMesh_setup_restartfile1 + end interface + interface + subroutine AtmosMesh_setup_restartfile2( this, restart_file, & + in_basename, in_postfix_timelabel, & + out_basename, out_postfix_timelabel, & + out_dtype, out_title, var_num ) + import AtmosMesh + import FILE_restart_meshfield_component + class(AtmosMesh), target, intent(inout) :: this + class(FILE_restart_meshfield_component), intent(inout) :: restart_file + character(*), intent(in) :: in_basename + logical, intent(in) :: in_postfix_timelabel + character(*), intent(in) :: out_basename + logical, intent(in) :: out_postfix_timelabel + character(*), intent(in) :: out_title + character(*), intent(in) :: out_dtype + integer, intent(in) :: var_num + end subroutine AtmosMesh_setup_restartfile2 + end interface + + integer, parameter, public :: ATM_MESH_MAX_COMMNUICATOR_NUM = 10 + !----------------------------------------------------------------------------- ! !++ Public parameters & variables ! - - integer, public, parameter :: ATMOS_MESH_NLocalMeshPerPrc = 1 !----------------------------------------------------------------------------- ! @@ -55,119 +101,33 @@ module mod_atmos_mesh ! contains - subroutine AtmosMesh_Init( this ) + + subroutine AtmosMesh_Init( this, mesh ) use scale_FILE_monitor_meshfield, only: & FILE_monitor_meshfield_set_dim implicit none class(AtmosMesh), target, intent(inout) :: this + class(MeshBase3D), intent(in) :: mesh - real(RP) :: dom_xmin = 0.0_RP - real(RP) :: dom_xmax = 100.0E3_RP - real(RP) :: dom_ymin = 0.0_RP - real(RP) :: dom_ymax = 100.0E3_RP - real(RP) :: dom_zmin = 0.0_RP - real(RP) :: dom_zmax = 10.0E3_RP - logical :: isPeriodicX = .true. - logical :: isPeriodicY = .true. - logical :: isPeriodicZ = .false. - - integer :: NeX = 2 - integer :: NeY = 2 - integer :: NeZ = 2 - integer :: NprcX = 1 - integer :: NprcY = 1 - integer :: PolyOrder_h = 2 - integer :: PolyOrder_v = 2 - logical :: LumpedMassMatFlag = .false. - - integer, parameter :: FZ_nmax = 1000 - real(RP) :: FZ(FZ_nmax) - - namelist / PARAM_ATMOS_MESH / & - dom_xmin, dom_xmax, & - dom_ymin, dom_ymax, & - dom_zmin, dom_zmax, & - FZ, & - isPeriodicX, isPeriodicY, isPeriodicZ, & - NeX, NeY, NeZ, & - PolyOrder_h, PolyOrder_v, LumpedMassMatFlag, & - NprcX, NprcY - - integer :: n - character(len=H_SHORT) :: dim_type - class(LocalMesh3D), pointer :: lcmesh - - integer :: k - logical :: is_spec_FZ - character(len=H_SHORT) :: SpMV_storage_format = 'ELL' ! CSR or ELL - - integer :: ierr !------------------------------------------- - LOG_NEWLINE - LOG_INFO("ATMOS_MESH_setup",*) 'Setup' - - FZ(:) = -1.0_RP - - rewind(IO_FID_CONF) - read(IO_FID_CONF,nml=PARAM_ATMOS_MESH,iostat=ierr) - if( ierr < 0 ) then !--- missing - LOG_INFO("ATMOS_MESH_setup",*) 'Not found namelist. Default used.' - elseif( ierr > 0 ) then !--- fatal error - LOG_ERROR("ATMOS_MESH_setup",*) 'Not appropriate names in namelist PARAM_ATM_MESH. Check!' - call PRC_abort - endif - LOG_NML(PARAM_ATMOS_MESH) - - !---- - - ! Setup the element - - call this%element%Init( PolyOrder_h, PolyOrder_v, LumpedMassMatFlag ) - - ! Setup the mesh - - is_spec_FZ = .true. - do k=1, NeZ+1 - if (FZ(k) < 0.0_RP) then - is_spec_FZ = .false. - end if - end do - if (is_spec_FZ) then - call this%mesh%Init( & - NprcX*NeX, NprcY*NeY, NeZ, & - dom_xmin, dom_xmax,dom_ymin, dom_ymax, dom_zmin, dom_zmax, & - isPeriodicX, isPeriodicY, isPeriodicZ, & - this%element, ATMOS_MESH_NLocalMeshPerPrc, NprcX, NprcY, & - FZ=FZ(1:NeZ+1) ) - else - call this%mesh%Init( & - NprcX*NeX, NprcY*NeY, NeZ, & - dom_xmin, dom_xmax,dom_ymin, dom_ymax, dom_zmin, dom_zmax, & - isPeriodicX, isPeriodicY, isPeriodicZ, & - this%element, ATMOS_MESH_NLocalMeshPerPrc, NprcX, NprcY ) - end if - - call this%mesh%Generate() - - !- - call this%ModelMesh3D_Init( this%mesh ) + call this%ModelMesh3D_Init( mesh ) - call this%DOptrMat(1)%Init( this%element%Dx1, storage_format=SpMV_storage_format ) - call this%DOptrMat(2)%Init( this%element%Dx2, storage_format=SpMV_storage_format ) - call this%DOptrMat(3)%Init( this%element%Dx3, storage_format=SpMV_storage_format ) + call this%DOptrMat(1)%Init( mesh%refElem3D%Dx1, storage_format=SpMV_storage_format ) + call this%DOptrMat(2)%Init( mesh%refElem3D%Dx2, storage_format=SpMV_storage_format ) + call this%DOptrMat(3)%Init( mesh%refElem3D%Dx3, storage_format=SpMV_storage_format ) - call this%SOptrMat(1)%Init( this%element%Sx1, storage_format=SpMV_storage_format ) - call this%SOptrMat(2)%Init( this%element%Sx2, storage_format=SpMV_storage_format ) - call this%SOptrMat(3)%Init( this%element%Sx3, storage_format=SpMV_storage_format ) + call this%SOptrMat(1)%Init( mesh%refElem3D%Sx1, storage_format=SpMV_storage_format ) + call this%SOptrMat(2)%Init( mesh%refElem3D%Sx2, storage_format=SpMV_storage_format ) + call this%SOptrMat(3)%Init( mesh%refElem3D%Sx3, storage_format=SpMV_storage_format ) - call this%LiftOptrMat%Init( this%element%Lift, storage_format=SpMV_storage_format ) + call this%LiftOptrMat%Init( mesh%refElem3D%Lift, storage_format=SpMV_storage_format ) !- - call FILE_monitor_meshfield_set_dim( this%mesh, 'ATM3D' ) + call FILE_monitor_meshfield_set_dim( mesh, 'ATM3D' ) return end subroutine AtmosMesh_Init @@ -178,7 +138,6 @@ subroutine AtmosMesh_Final(this) class(AtmosMesh), intent(inout) :: this !------------------------------------------- - call this%mesh%Final() call this%ModelMesh3D_Final() return diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 new file mode 100644 index 00000000..430b87aa --- /dev/null +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 @@ -0,0 +1,216 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_atmos_mesh_gm + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + + use scale_meshfield_base, only: MeshField3D + use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfieldcomm_cubedspheredom3d, only: MeshFieldCommCubedSphereDom3D + use scale_sparsemat, only: sparsemat + use scale_file_restart_meshfield, only: FILE_restart_meshfield_component + + use scale_model_var_manager, only: ModelVarManager + use scale_model_mesh_manager, only: ModelMesh3D + + use mod_atmos_mesh, only: & + AtmosMesh, ATM_MESH_MAX_COMMNUICATOR_NUM + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + type, extends(AtmosMesh), public :: AtmosMeshGM + type(MeshCubedSphereDom3D) :: mesh + type(MeshFieldCommCubedSphereDom3D) :: comm_list(ATM_MESH_MAX_COMMNUICATOR_NUM) + contains + procedure :: Init => AtmosMeshGM_Init + procedure :: Final => AtmosMeshGM_Final + procedure :: Create_communicator => AtmosMeshGM_Create_communicator + procedure :: Setup_restartfile1 => AtmosMeshGM_setup_restartfile1 + procedure :: Setup_restartfile2 => AtmosMeshGM_setup_restartfile2 + end type AtmosMeshGM + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + + subroutine AtmosMeshGM_Init( this ) + use scale_const, only: & + RPlanet => CONST_RADIUS + + implicit none + class(AtmosMeshGM), target, intent(inout) :: this + + real(RP) :: dom_zmin = 0.0_RP + real(RP) :: dom_zmax = 10.0E3_RP + logical :: isPeriodicZ = .false. + + integer, parameter :: FZ_nmax = 1000 + real(RP) :: FZ(FZ_nmax) + + !* Global + integer :: NeGX = 2 + integer :: NeGY = 2 + integer :: NeZ = 2 + integer :: NLocalMeshPerPrc = 6 + integer :: Nprc = 1 + integer :: PolyOrder_h = 2 + integer :: PolyOrder_v = 2 + logical :: LumpedMassMatFlag = .false. + + namelist / PARAM_ATMOS_MESH / & + dom_zmin, dom_zmax, & + FZ, isPeriodicZ, & + NeGX, NeGY, NeZ, NLocalMeshPerPrc, Nprc, & + PolyOrder_h, PolyOrder_v, LumpedMassMatFlag + + integer :: k + logical :: is_spec_FZ + + integer :: ierr + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("ATMOS_MESH_setup",*) 'Setup' + + FZ(:) = -1.0_RP + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_ATMOS_MESH,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("ATMOS_MESH_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("ATMOS_MESH_setup",*) 'Not appropriate names in namelist PARAM_ATM_MESH. Check!' + call PRC_abort + endif + LOG_NML(PARAM_ATMOS_MESH) + + !---- + + ! Setup the element + + call this%element%Init( PolyOrder_h, PolyOrder_v, LumpedMassMatFlag ) + + ! Setup the mesh + + is_spec_FZ = .true. + do k=1, NeZ+1 + if (FZ(k) < 0.0_RP) then + is_spec_FZ = .false. + end if + end do + if (is_spec_FZ) then + call this%mesh%Init( & + NeGX, NeGY, NeZ, RPlanet, dom_zmin, dom_zmax, & + this%element, NLocalMeshPerPrc, nproc=Nprc, & + FZ=FZ(1:NeZ+1) ) + else + call this%mesh%Init( & + NeGX, NeGY, NeZ, RPlanet, dom_zmin, dom_zmax, & + this%element, NLocalMeshPerPrc, nproc=Nprc ) + end if + + call this%mesh%Generate() + + !- + call this%AtmosMesh_Init( this%mesh ) + + return + end subroutine AtmosMeshGM_Init + + subroutine AtmosMeshGM_Final(this) + implicit none + + class(AtmosMeshGM), intent(inout) :: this + integer :: commid + !------------------------------------------- + + do commid=1, this%communicator_num + call this%comm_list(commid)%Final() + end do + + call this%mesh%Final() + call this%AtmosMesh_Final() + + return + end subroutine AtmosMeshGM_Final + + subroutine AtmosMeshGM_create_communicator( this, sfield_num, hvfield_num, var_manager, field_list, commid ) + implicit none + class(AtmosMeshGM), target, intent(inout) :: this + integer, intent(in) :: sfield_num + integer, intent(in) :: hvfield_num + class(ModelVarManager), intent(inout) :: var_manager + class(MeshField3D), intent(in) :: field_list(:) + integer, intent(out) :: commid + !----------------------------------------------------- + + commid = this%Get_communicatorID( ATM_MESH_MAX_COMMNUICATOR_NUM ) + call this%comm_list(commid)%Init( hvfield_num, sfield_num, this%mesh ) + call var_manager%MeshFieldComm_Prepair( this%comm_list(commid), field_list ) + + return + end subroutine AtmosMeshGM_create_communicator + + subroutine AtmosMeshGM_setup_restartfile1( this, restart_file, var_num ) + implicit none + class(AtmosMeshGM), target, intent(inout) :: this + class(FILE_restart_meshfield_component), intent(inout) :: restart_file + integer, intent(in) :: var_num + !------------------------------------------------ + + call restart_file%Init('ATMOS', var_num, meshcubedsphere3D=this%mesh ) + return + end subroutine AtmosMeshGM_setup_restartfile1 + + subroutine AtmosMeshGM_setup_restartfile2( this, restart_file, & + in_basename, in_postfix_timelabel, & + out_basename, out_postfix_timelabel, & + out_dtype, out_title, var_num ) + implicit none + class(AtmosMeshGM), target, intent(inout) :: this + class(FILE_restart_meshfield_component), intent(inout) :: restart_file + character(*), intent(in) :: in_basename + logical, intent(in) :: in_postfix_timelabel + character(*), intent(in) :: out_basename + logical, intent(in) :: out_postfix_timelabel + character(*), intent(in) :: out_title + character(*), intent(in) :: out_dtype + integer, intent(in) :: var_num + !----------------------------------------------------------- + + call restart_file%Init('ATMOS', in_basename, in_postfix_timelabel, & + out_basename, out_postfix_timelabel, out_dtype, out_title, var_num, & + meshcubedsphere3D=this%mesh ) + + end subroutine AtmosMeshGM_setup_restartfile2 + +end module mod_atmos_mesh_gm \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 new file mode 100644 index 00000000..bc4ecd6b --- /dev/null +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 @@ -0,0 +1,229 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_atmos_mesh_rm + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + + use scale_meshfield_base, only: MeshField3D + use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D + use scale_sparsemat, only: sparsemat + use scale_file_restart_meshfield, only: FILE_restart_meshfield_component + + use scale_model_var_manager, only: ModelVarManager + use scale_model_mesh_manager, only: ModelMesh3D + + use mod_atmos_mesh, only: & + AtmosMesh, ATM_MESH_MAX_COMMNUICATOR_NUM + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + type, extends(AtmosMesh), public :: AtmosMeshRM + type(MeshCubeDom3D) :: mesh + type(MeshFieldCommCubeDom3D) :: comm_list(ATM_MESH_MAX_COMMNUICATOR_NUM) + contains + procedure :: Init => AtmosMeshRM_Init + procedure :: Final => AtmosMeshRM_Final + procedure :: Create_communicator => AtmosMeshRM_Create_communicator + procedure :: Setup_restartfile1 => AtmosMeshRM_setup_restartfile1 + procedure :: Setup_restartfile2 => AtmosMeshRM_setup_restartfile2 + end type AtmosMeshRM + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + + !- AtmosMesh RM ----------------------------------------- + + subroutine AtmosMeshRM_Init( this ) + implicit none + class(AtmosMeshRM), target, intent(inout) :: this + + real(RP) :: dom_xmin = 0.0_RP + real(RP) :: dom_xmax = 100.0E3_RP + real(RP) :: dom_ymin = 0.0_RP + real(RP) :: dom_ymax = 100.0E3_RP + real(RP) :: dom_zmin = 0.0_RP + real(RP) :: dom_zmax = 10.0E3_RP + logical :: isPeriodicX = .true. + logical :: isPeriodicY = .true. + logical :: isPeriodicZ = .false. + + integer :: NeX = 2 + integer :: NeY = 2 + integer :: NeZ = 2 + integer :: NprcX = 1 + integer :: NprcY = 1 + integer :: PolyOrder_h = 2 + integer :: PolyOrder_v = 2 + logical :: LumpedMassMatFlag = .false. + + integer, parameter :: ATMOS_MESH_NLocalMeshPerPrc = 1 + + integer, parameter :: FZ_nmax = 1000 + real(RP) :: FZ(FZ_nmax) + + namelist / PARAM_ATMOS_MESH / & + dom_xmin, dom_xmax, & + dom_ymin, dom_ymax, & + dom_zmin, dom_zmax, & + FZ, & + isPeriodicX, isPeriodicY, isPeriodicZ, & + NeX, NeY, NeZ, & + PolyOrder_h, PolyOrder_v, LumpedMassMatFlag, & + NprcX, NprcY + + integer :: k + logical :: is_spec_FZ + + integer :: ierr + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("ATMOS_MESH_setup",*) 'Setup' + + FZ(:) = -1.0_RP + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_ATMOS_MESH,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("ATMOS_MESH_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("ATMOS_MESH_setup",*) 'Not appropriate names in namelist PARAM_ATM_MESH. Check!' + call PRC_abort + endif + LOG_NML(PARAM_ATMOS_MESH) + + !---- + + ! Setup the element + + call this%element%Init( PolyOrder_h, PolyOrder_v, LumpedMassMatFlag ) + + ! Setup the mesh + + is_spec_FZ = .true. + do k=1, NeZ+1 + if (FZ(k) < 0.0_RP) then + is_spec_FZ = .false. + end if + end do + if (is_spec_FZ) then + call this%mesh%Init( & + NprcX*NeX, NprcY*NeY, NeZ, & + dom_xmin, dom_xmax,dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + isPeriodicX, isPeriodicY, isPeriodicZ, & + this%element, ATMOS_MESH_NLocalMeshPerPrc, NprcX, NprcY, & + FZ=FZ(1:NeZ+1) ) + else + call this%mesh%Init( & + NprcX*NeX, NprcY*NeY, NeZ, & + dom_xmin, dom_xmax,dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + isPeriodicX, isPeriodicY, isPeriodicZ, & + this%element, ATMOS_MESH_NLocalMeshPerPrc, NprcX, NprcY ) + end if + + call this%mesh%Generate() + + !- + call this%AtmosMesh_Init( this%mesh ) + + return + end subroutine AtmosMeshRM_Init + + subroutine AtmosMeshRM_Final(this) + implicit none + + class(AtmosMeshRM), intent(inout) :: this + integer :: commid + !------------------------------------------- + + do commid=1, this%communicator_num + call this%comm_list(commid)%Final() + end do + + call this%mesh%Final() + call this%AtmosMesh_Final() + + return + end subroutine AtmosMeshRM_Final + + subroutine AtmosMeshRM_create_communicator( this, sfield_num, hvfield_num, var_manager, field_list, commid ) + implicit none + class(AtmosMeshRM), target, intent(inout) :: this + integer, intent(in) :: sfield_num + integer, intent(in) :: hvfield_num + class(ModelVarManager), intent(inout) :: var_manager + class(MeshField3D), intent(in) :: field_list(:) + integer, intent(out) :: commid + !----------------------------------------------------- + + commid = this%Get_communicatorID( ATM_MESH_MAX_COMMNUICATOR_NUM ) + call this%comm_list(commid)%Init( hvfield_num, sfield_num, this%mesh ) + call var_manager%MeshFieldComm_Prepair( this%comm_list(commid), field_list ) + + return + end subroutine AtmosMeshRM_create_communicator + + subroutine AtmosMeshRM_setup_restartfile1( this, restart_file, var_num ) + implicit none + class(AtmosMeshRM), target, intent(inout) :: this + class(FILE_restart_meshfield_component), intent(inout) :: restart_file + integer, intent(in) :: var_num + !------------------------------------------------ + + call restart_file%Init('ATMOS', var_num, mesh3D=this%mesh ) + return + end subroutine AtmosMeshRM_setup_restartfile1 + + subroutine AtmosMeshRM_setup_restartfile2( this, restart_file, & + in_basename, in_postfix_timelabel, & + out_basename, out_postfix_timelabel, & + out_dtype, out_title, var_num ) + implicit none + class(AtmosMeshRM), target, intent(inout) :: this + class(FILE_restart_meshfield_component), intent(inout) :: restart_file + character(*), intent(in) :: in_basename + logical, intent(in) :: in_postfix_timelabel + character(*), intent(in) :: out_basename + logical, intent(in) :: out_postfix_timelabel + character(*), intent(in) :: out_title + character(*), intent(in) :: out_dtype + integer, intent(in) :: var_num + !----------------------------------------------------------- + + call restart_file%Init('ATMOS', in_basename, in_postfix_timelabel, & + out_basename, out_postfix_timelabel, out_dtype, out_title, var_num, & + mesh3D=this%mesh ) + + end subroutine AtmosMeshRM_setup_restartfile2 + +end module mod_atmos_mesh_rm \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 index 6a879777..20681582 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 @@ -100,8 +100,8 @@ subroutine AtmosPhySfcVars_Init( this, model_mesh ) atm_mesh => model_mesh end select - mesh3D => atm_mesh%mesh - call atm_mesh%mesh%GetMesh2D( mesh2D ) + mesh3D => atm_mesh%ptr_mesh + call mesh3D%GetMesh2D( mesh2D ) !---- call this%SFCFLX_manager%Init() @@ -113,7 +113,7 @@ subroutine AtmosPhySfcVars_Init( this, model_mesh ) ATMOS_PHY_SF_SFLX_VINFO(v), mesh2D, & ! (in) this%SFC_FLX(v), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%SFC_FLX(v)%local(n)%val(:,:) = 0.0_RP end do end do diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 index baeef5df..b3c5b23e 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 @@ -144,7 +144,7 @@ subroutine AtmosPhyTb_setup( this, model_mesh, tm_parent_comp ) select case( TB_TYPE ) case ('SMAGORINSKY') this%TB_TYPEID = TB_TYPEID_SMAGORINSKY - call atm_phy_tb_dgm_smg_Init( atm_mesh%mesh ) + call atm_phy_tb_dgm_smg_Init( atm_mesh%ptr_mesh ) case default LOG_ERROR("ATMOS_PHY_TB_setup",*) 'Not appropriate names of TB_TYPE in namelist PARAM_ATMOS_PHY_TB. Check!' call PRC_abort diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 index a4625b72..1e02d0ad 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 @@ -24,7 +24,6 @@ module mod_atmos_phy_tb_vars use scale_file_restart_meshfield, only: & FILE_restart_meshfield_component - use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D use scale_meshfieldcomm_base, only: MeshFieldContainer use scale_model_var_manager, only: & @@ -48,7 +47,7 @@ module mod_atmos_phy_tb_vars type(MeshField3D), allocatable :: auxvars(:) type(ModelVarManager) :: auxvars_manager - type(MeshFieldCommCubeDom3D) :: auxvars_comm + integer :: auxvars_commid contains procedure :: Init => AtmosPhyTbVars_Init @@ -151,8 +150,8 @@ subroutine AtmosPhyTbVars_Init( this, model_mesh ) atm_mesh => model_mesh end select - mesh3D => atm_mesh%mesh - call atm_mesh%mesh%GetMesh2D( mesh2D ) + mesh3D => atm_mesh%ptr_mesh + call mesh3D%GetMesh2D( mesh2D ) !---- call this%tends_manager%Init() @@ -166,7 +165,7 @@ subroutine AtmosPhyTbVars_Init( this, model_mesh ) ATMOS_PHY_TB_TEND_VINFO(v), mesh3D, & ! (in) this%tends(v), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%tends(v)%local(n)%val(:,:) = 0.0_RP end do end do @@ -180,13 +179,16 @@ subroutine AtmosPhyTbVars_Init( this, model_mesh ) ATMOS_PHY_TB_AUX_VINFO(v), mesh3D, & ! (in) this%auxvars(v), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%auxvars(v)%local(n)%val(:,:) = 0.0_RP end do end do - call this%auxvars_comm%Init( ATMOS_PHY_TB_AUX_NUM, 0, atm_mesh%mesh ) - call this%auxvars_manager%MeshFieldComm_Prepair( this%auxvars_comm, this%auxvars ) + call atm_mesh%Create_communicator( & + ATMOS_PHY_TB_AUX_NUM, 0, & ! (in) + this%auxvars_manager, & ! (inout) + this%auxvars(:), & ! (in) + this%auxvars_commid ) ! (out) return end subroutine AtmosPhyTbVars_Init @@ -199,7 +201,6 @@ subroutine AtmosPhyTbVars_Final( this ) LOG_INFO('AtmosPhyTbVars_Final',*) - call this%auxvars_comm%Final() call this%tends_manager%Final() call this%auxvars_manager%Final() diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 index d82741c8..fd34fb7b 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 @@ -25,7 +25,6 @@ module mod_atmos_vars use scale_file_restart_meshfield, only: & FILE_restart_meshfield_component - use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D use scale_meshfieldcomm_base, only: MeshFieldContainer use scale_model_var_manager, only: & @@ -44,14 +43,15 @@ module mod_atmos_vars type, public :: AtmosVars type(MeshField3D), allocatable :: PROG_VARS(:) type(ModelVarManager) :: PROGVARS_manager - type(MeshFieldCommCubeDom3D) :: PROGVARS_comm + integer :: PROG_VARS_commID type(MeshField3D), allocatable :: AUX_VARS(:) type(ModelVarManager) :: AUXVARS_manager - type(MeshFieldCommCubeDom3D) :: AUXVARS_comm + integer :: AUX_VARS_commID type(MeshField3D), allocatable :: PHY_TEND(:) type(ModelVarManager) :: PHYTENDS_manager + integer :: PHYTENDS_commID type(ModelVarManager) :: DIAGVARS_manager integer, allocatable :: DIAGVARS_HISTID(:) @@ -200,7 +200,7 @@ subroutine AtmosVars_Init( this, atm_mesh ) implicit none class(AtmosVars), target, intent(inout) :: this - class(AtmosMesh), intent(in) :: atm_mesh + class(AtmosMesh), intent(inout) :: atm_mesh integer :: iv integer :: n @@ -234,6 +234,8 @@ subroutine AtmosVars_Init( this, atm_mesh ) logical :: is_specified integer :: DV_id + + class(MeshBase3D), pointer :: mesh3D !-------------------------------------------------- LOG_INFO('AtmosVars_Init',*) @@ -249,6 +251,9 @@ subroutine AtmosVars_Init( this, atm_mesh ) endif LOG_NML(PARAM_ATMOS_VARS) + !- Set the pointer of mesh + mesh3D => atm_mesh%ptr_mesh + !- Initialize prognostic variables call this%PROGVARS_manager%Init() @@ -257,18 +262,21 @@ subroutine AtmosVars_Init( this, atm_mesh ) reg_file_hist = .true. do iv = 1, ATMOS_PROGVARS_NUM - call this%PROGVARS_manager%Regist( & - ATMOS_PROGVARS_VINFO(iv), atm_mesh%mesh, & ! (in) - this%PROG_VARS(iv), & ! (inout) - reg_file_hist, monitor_flag=.true. ) ! (out) + call this%PROGVARS_manager%Regist( & + ATMOS_PROGVARS_VINFO(iv), mesh3D, & ! (in) + this%PROG_VARS(iv), & ! (inout) + reg_file_hist, monitor_flag=.true. ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + do n = 1, mesh3D%LOCAL_MESH_NUM this%PROG_VARS(iv)%local(n)%val(:,:) = 0.0_RP end do end do - call this%PROGVARS_comm%Init(ATMOS_PROGVARS_NUM, 0, atm_mesh%mesh) - call this%PROGVARS_manager%MeshFieldComm_Prepair( this%PROGVARS_comm, this%PROG_VARS(:) ) + call atm_mesh%Create_communicator( & + ATMOS_PROGVARS_NUM, 0, & ! (in) + this%PROGVARS_manager, & ! (inout) + this%PROG_VARS(:), & ! (in) + this%PROG_VARS_commID ) ! (out) LOG_NEWLINE LOG_INFO("ATMOS_vars_setup",*) 'List of prognostic variables (ATMOS) ' @@ -287,17 +295,21 @@ subroutine AtmosVars_Init( this, atm_mesh ) reg_file_hist = .true. do iv = 1, ATMOS_AUXVARS_NUM - call this%AUXVARS_manager%Regist( & - ATMOS_AUXVARS_VINFO(iv), atm_mesh%mesh, & ! (in) - this%AUX_VARS(iv), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + call this%AUXVARS_manager%Regist( & + ATMOS_AUXVARS_VINFO(iv), mesh3D, & ! (in) + this%AUX_VARS(iv), reg_file_hist ) ! (out) + do n = 1, mesh3D%LOCAL_MESH_NUM this%AUX_VARS(iv)%local(n)%val(:,:) = 1.0_RP end do end do - call this%AUXVARS_comm%Init(ATMOS_AUXVARS_NUM, 0, atm_mesh%mesh) - call this%AUXVARS_manager%MeshFieldComm_Prepair( this%AUXVARS_comm, this%AUX_VARS(:) ) + call atm_mesh%Create_communicator( & + ATMOS_AUXVARS_NUM, 0, & ! (in) + this%AUXVARS_manager, & ! (inout) + this%AUX_VARS(:), & ! (in) + this%AUX_VARS_commID ) ! (out) + !- Initialize the tendency of physical processes call this%PHYTENDS_manager%Init() @@ -305,10 +317,10 @@ subroutine AtmosVars_Init( this, atm_mesh ) reg_file_hist = .true. do iv = 1, ATMOS_PHYTEND_NUM - call this%PHYTENDS_manager%Regist( & - ATMOS_PHYTEND_VINFO(iv), atm_mesh%mesh, & ! (in) - this%PHY_TEND(iv), reg_file_hist ) ! (out) - do n = 1, atm_mesh%mesh%LOCAL_MESH_NUM + call this%PHYTENDS_manager%Regist( & + ATMOS_PHYTEND_VINFO(iv), mesh3D, & ! (in) + this%PHY_TEND(iv), reg_file_hist ) ! (out) + do n = 1, mesh3D%LOCAL_MESH_NUM this%PHY_TEND(iv)%local(n)%val(:,:) = 0.0_RP end do end do @@ -319,9 +331,9 @@ subroutine AtmosVars_Init( this, atm_mesh ) reg_file_hist = .true. do iv = 1, ATMOS_DIAGVARS_NUM - call this%DIAGVARS_manager%Regist( & - ATMOS_DIAGVARS_VINFO(iv), atm_mesh%mesh, & ! (in) - diag_vars(iv), reg_file_hist ) ! (out) + call this%DIAGVARS_manager%Regist( & + ATMOS_DIAGVARS_VINFO(iv), atm_mesh%ptr_mesh, & ! (in) + diag_vars(iv), reg_file_hist ) ! (out) this%DIAGVARS_HISTID(iv) = diag_vars(iv)%hist_id end do @@ -343,15 +355,13 @@ subroutine AtmosVars_Init( this, atm_mesh ) LOG_NML(PARAM_ATMOS_VARS_RESTART) if (is_specified) then - call this%restart_file%Init('ATMOS', & + call atm_mesh%Setup_restartfile( this%restart_file, & IN_BASENAME, IN_POSTFIX_TIMELABEL, & OUT_BASENAME, OUT_POSTFIX_TIMELABEL, OUT_DTYPE, OUT_TITLE, & - ATMOS_PROGVARS_NUM + ATMOS_AUXVARS_NUM, & - mesh3D=atm_mesh%mesh ) + ATMOS_PROGVARS_NUM + ATMOS_AUXVARS_NUM ) else - call this%restart_file%Init('ATMOS', & - ATMOS_PROGVARS_NUM + ATMOS_AUXVARS_NUM, & - mesh3D=atm_mesh%mesh ) + call atm_mesh%Setup_restartfile( this%restart_file, & + ATMOS_PROGVARS_NUM + ATMOS_AUXVARS_NUM ) end if !-----< monitor output setup >----- @@ -394,9 +404,6 @@ subroutine AtmosVars_Final( this ) call this%restart_file%Final() - call this%PROGVARS_comm%Final() - call this%AUXVARS_comm%Final() - call this%PROGVARS_manager%Final() call this%AUXVARS_manager%Final() call this%PHYTENDS_manager%Final() diff --git a/model/atm_nonhydro3d/src/depend b/model/atm_nonhydro3d/src/depend index 349b1ea8..a1aee831 100644 --- a/model/atm_nonhydro3d/src/depend +++ b/model/atm_nonhydro3d/src/depend @@ -1,8 +1,10 @@ -$(BUILD_DIR)/mod_atmos_component.o: atmos/mod_atmos_component.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_dyn.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_phy_sfc.o $(BUILD_DIR)/mod_atmos_phy_tb.o $(BUILD_DIR)/mod_atmos_vars.o +$(BUILD_DIR)/mod_atmos_component.o: atmos/mod_atmos_component.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_dyn.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_mesh_gm.o $(BUILD_DIR)/mod_atmos_mesh_rm.o $(BUILD_DIR)/mod_atmos_phy_sfc.o $(BUILD_DIR)/mod_atmos_phy_tb.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_atmos_dyn.o: atmos/mod_atmos_dyn.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_dyn_bnd.o $(BUILD_DIR)/mod_atmos_dyn_vars.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_atmos_dyn_bnd.o: atmos/mod_atmos_dyn_bnd.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_atmos_dyn_vars.o: atmos/mod_atmos_dyn_vars.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_mesh.o: atmos/mod_atmos_mesh.F90 $(DEPENDLIB) +$(BUILD_DIR)/mod_atmos_mesh_gm.o: atmos/mod_atmos_mesh_gm.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o +$(BUILD_DIR)/mod_atmos_mesh_rm.o: atmos/mod_atmos_mesh_rm.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_phy_sfc.o: atmos/mod_atmos_phy_sfc.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_phy_sfc_vars.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_atmos_phy_sfc_vars.o: atmos/mod_atmos_phy_sfc_vars.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_phy_tb.o: atmos/mod_atmos_phy_tb.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_dyn_bnd.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_phy_tb_vars.o $(BUILD_DIR)/mod_atmos_vars.o @@ -12,7 +14,7 @@ $(BUILD_DIR)/mod_dg_driver.o: admin/mod_dg_driver.F90 $(DEPENDLIB) $(BUILD_DIR)/ $(BUILD_DIR)/mod_dg_launcher.o: admin/mod_dg_launcher.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_dg_driver.o $(BUILD_DIR)/mod_dg_prep.o $(BUILD_DIR)/mod_dg_prep.o: admin/mod_dg_prep.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_mkinit.o $(BUILD_DIR)/mod_user.o $(BUILD_DIR)/mod_exp.o: admin/mod_exp.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_vars.o -$(BUILD_DIR)/mod_mkinit.o: preprocess/mod_mkinit.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_mkinit_util.o +$(BUILD_DIR)/mod_mkinit.o: preprocess/mod_mkinit.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_mkinit_util.o: preprocess/mod_mkinit_util.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_user.o: user/mod_user.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o @@ -22,6 +24,8 @@ MODS = \ mod_atmos_dyn_bnd.mod \ mod_atmos_dyn_vars.mod \ mod_atmos_mesh.mod \ + mod_atmos_mesh_gm.mod \ + mod_atmos_mesh_rm.mod \ mod_atmos_phy_sfc.mod \ mod_atmos_phy_sfc_vars.mod \ mod_atmos_phy_tb.mod \ diff --git a/model/atm_nonhydro3d/src/preprocess/mod_mkinit.F90 b/model/atm_nonhydro3d/src/preprocess/mod_mkinit.F90 index 43e9b5c2..0a0015d4 100644 --- a/model/atm_nonhydro3d/src/preprocess/mod_mkinit.F90 +++ b/model/atm_nonhydro3d/src/preprocess/mod_mkinit.F90 @@ -34,24 +34,14 @@ module mod_mkinit use scale_element_base, only: ElementBase3D use scale_element_hexahedral, only: HexahedralElement use scale_localmesh_3d, only: LocalMesh3D - use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_base3d, only: MeshBase3D use scale_localmeshfield_base, only: LocalMeshFieldBase use scale_atm_dyn_dgm_hydrostatic, only: & hydrostaic_build_rho_XYZ use mod_atmos_component, only: & AtmosComponent - - use mod_mkinit_util, only: & - gen_GPMat => mkinitutil_gen_GPMat, & - gen_Vm1Mat => mkinitutil_gen_Vm1Mat, & - calc_cosinebell => mkinitutil_calc_cosinebell - - use scale_atm_dyn_dgm_hydrostatic, only: & - calc_basicstate_constPT => hydrostatic_calc_basicstate_constPT, & - calc_basicstate_constBVFreq => hydrostatic_calc_basicstate_constBVFreq, & - calc_basicstate_constPTLAPS => hydrostatic_calc_basicstate_constPTLAPS - + !----------------------------------------------------------------------------- implicit none private @@ -135,10 +125,10 @@ subroutine MKINIT( output, & integer :: n integer :: ke class(LocalMesh3D), pointer :: lcmesh3D - class(MeshCubeDom3D), pointer :: mesh + class(MeshBase3D), pointer :: mesh !--------------------------------------------------------------------------- - mesh => model_mesh%mesh + mesh => model_mesh%ptr_mesh if ( MKINIT_TYPE == I_IGNORE ) then LOG_NEWLINE From a0284452048c003e449833bcaca5e61ea28b7081 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 26 May 2021 19:49:39 +0900 Subject: [PATCH 30/98] Add a module to provide 3D global dynamical core. --- FElib/src/Makefile | 1 + FElib/src/depend | 2 + ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 479 ++++++++++++++++++ 3 files changed, 482 insertions(+) create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 diff --git a/FElib/src/Makefile b/FElib/src/Makefile index f51bedb1..d65e0235 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -94,6 +94,7 @@ OBJS_NAME_FLUID_DYN_SOLVER = \ scale_atm_dyn_dgm_hydrostatic.o \ scale_atm_dyn_dgm_nonhydro3d_numdiff.o \ scale_atm_dyn_dgm_nonhydro2d.o \ + scale_atm_dyn_dgm_globalnonhydro3d_heve.o \ scale_atm_dyn_dgm_nonhydro3d_heve.o \ scale_atm_dyn_dgm_nonhydro3d_hevi.o \ scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o \ diff --git a/FElib/src/depend b/FElib/src/depend index cac3672a..e5eda0b0 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -1,3 +1,4 @@ +$(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.o: fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_gmres.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.o: fluid_dyn_solver/scale_atm_dyn_dgm_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_base.o @@ -66,6 +67,7 @@ $(OBJ_DIR)/scale_timeint_rk_butcher_tab.o: common/scale_timeint_rk_butcher_tab.F $(OBJ_DIR)/scale_variableinfo.o: data/scale_variableinfo.F90 $(DEPENDLIB) MODS = \ + $(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_heve.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.mod \ diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 new file mode 100644 index 00000000..f8efff4f --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -0,0 +1,479 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / Dynamics HEVE +!! +!! @par Description +!! HEVE DGM scheme for Atmospheric dynamical process. +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_globalnonhydro3d_heve + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_globalnonhydro3d_heve_Init + public :: atm_dyn_dgm_globalnonhydro3d_heve_Final + public :: atm_dyn_dgm_globalnonhydro3d_heve_cal_tend + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + integer, private, parameter :: VARS_DDENS_ID = 1 + integer, private, parameter :: VARS_MOMX_ID = 2 + integer, private, parameter :: VARS_MOMY_ID = 3 + integer, private, parameter :: VARS_MOMZ_ID = 4 + integer, private, parameter :: VARS_DRHOT_ID = 5 + integer, private, parameter :: PROG_VARS_NUM = 5 + + real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) + integer, private, allocatable :: iM2Dto3D(:) + + + private :: cal_del_flux_dyn + +contains + subroutine atm_dyn_dgm_globalnonhydro3d_heve_Init( mesh ) + + implicit none + class(MeshBase3D), intent(in) :: mesh + + integer :: p1, p2, p_ + type(ElementBase3D), pointer :: elem + real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) + + integer :: f_h, f_v + integer :: fp, fp_h1, fp_h2, fp_v + type(ElementBase2D), pointer :: elem2D + class(MeshBase2D), pointer :: mesh2D + !-------------------------------------------- + + elem => mesh%refElem3D + allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) + + InvV_VPOrdM1(:,:) = elem%invV + do p2=1, elem%Nnode_h1D + do p1=1, elem%Nnode_h1D + p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 + InvV_VPOrdM1(p_,:) = 0.0_RP + end do + end do + IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) + + !-- + + allocate( iM2Dto3D(elem%NfpTot) ) + call mesh%GetMesh2D( mesh2D ) + elem2D => mesh2D%refElem2D + + do f_h=1, 4 + do fp_v=1, elem%Nnode_v + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_v)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h + iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) + end do + end do + end do + do f_v=1, 2 + do fp_h2=1, elem%Nnode_h1D + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_h2)*elem%Nnode_h1D & + + (f_v-1) * elem%Nnode_h1D**2 & + + 4 * elem%Nnode_h1D * elem%Nnode_v + iM2Dto3D(fp) = fp_h1 + (fp_h2)*elem%Nnode_h1D + end do + end do + end do + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_heve_Init + + + subroutine atm_dyn_dgm_globalnonhydro3d_heve_Final() + implicit none + !-------------------------------------------- + + deallocate( IntrpMat_VPOrdM1 ) + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_heve_Final + + !------------------------------- + +!OCL SERIAL + subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & + DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) + SL_flag, wdamp_tau, wdamp_height, & ! (in) + Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + + use scale_atm_dyn_dgm_spongelayer, only: & + atm_dyn_dgm_spongelayer_add_tend + use scale_const, only: & + OHM => CONST_OHM + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + type(SparseMat), intent(in) :: Dx, Dy, Dz, Sx, Sy, Sz, Lift + real(RP), intent(out) :: DENS_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMX_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMY_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMZ_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: RHOT_dt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DDENS_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeA) + real(RP), intent(in) :: CORIOLIS(elem2D%Np,lmesh2D%NeA) + logical, intent(in) :: SL_flag + real(RP), intent(in) :: wdamp_tau + real(RP), intent(in) :: wdamp_height + + real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP) :: PRES_(elem%Np) + real(RP) :: RHOT_(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) + real(RP) :: drho(elem%Np) + + integer :: ke, ke2d + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + real(RP) :: GIJ(elem%Np,2,2) + real(RP) :: X(elem%Np), Y(elem%Np), twordel2(elem%Np) + real(RP) :: CORI(elem%Np,2) + real(RP) :: s + logical :: is_panel1to4 + + !------------------------------------------------------------------------ + + call PROF_rapstart('cal_dyn_tend_bndflux', 3) + call cal_del_flux_dyn( del_flux, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) + lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) + lmesh%vmapM, lmesh%vmapP, lmesh, elem, & ! (in) + lmesh2D%vmapM, lmesh2D%vmapP, lmesh2D, elem2D ) ! (in) + call PROF_rapend('cal_dyn_tend_bndflux', 3) + + !----- + call PROF_rapstart('cal_dyn_tend_interior', 3) + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + s = 1.0_RP + is_panel1to4 = .true. + if (lmesh%panelID == 5) then + is_panel1to4 = .false. + else if (lmesh%panelID == 6) then + is_panel1to4 = .false. + s = - 1.0_RP + else + end if + + !$omp parallel private( & + !$omp RHOT_, PRES_, rdens_, u_, v_, w_, ke2d, drho, & + !$omp Fx, Fy, Fz, LiftDelFlx, & + !$omp GIJ, X, Y, twordel2, CORI ) + !$omp do + do ke = lmesh%NeS, lmesh%NeE + !-- + X(:) = lmesh%pos_en(:,ke,1) + Y(:) = lmesh%pos_en(:,ke,2) + twordel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) + + RHOT_(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT_(:,ke) + PRES_(:) = PRES00 * (RovP0 * RHOT_(:))**gamm + + rdens_(:) = 1.0_RP / (DDENS_(:,ke) + DENS_hyd(:,ke)) + u_ (:) = MOMX_(:,ke) * rdens_(:) + v_ (:) = MOMY_(:,ke) * rdens_(:) + w_ (:) = MOMZ_(:,ke) * rdens_(:) + + ke2d = lmesh%EMap3Dto2D(ke) + GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) + GIJ(:,2,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,1) + GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) + GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + + CORI(:,1) = s * OHM * twordel2(:) * ( - X(:) * Y(:) * MOMX_(:,ke) + (1.0_RP + Y(:)**2) * MOMY_(:,ke) ) + CORI(:,2) = s * OHM * twordel2(:) * ( - (1.0_RP + X(:)**2) * MOMX_(:,ke) + X(:) * Y(:) * MOMY_(:,ke) ) + if ( is_panel1to4 ) then + CORI(:,1) = Y(:); CORI(:,2) = Y(:) + end if + + drho(:) = matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) + + !-- DENS + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * MOMZ_(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DDENS_ID), LiftDelFlx) + + DENS_dt(:,ke) = - ( & + lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + + !-- MOMX + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * PRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * PRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMX_ID), LiftDelFlx) + + MOMX_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twordel2 * Y(:) * & + ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2)*v_(:) ) * MOMX_(:,ke) & + + CORI(:,1) + + !-- MOMY + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * PRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * PRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMY_ID), LiftDelFlx) + + MOMY_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twordel2 * X(:) * & + ( (1.0_RP + X(:)**2)*u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + + CORI(:,2) + + !-- MOMZ + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( w_(:) * MOMZ_(:,ke) + PRES_(:) - PRES_hyd(:,ke) ), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMZ_ID), LiftDelFlx) + + MOMZ_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - Grav * drho(:) + + !-- RHOT + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * RHOT_(:), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * RHOT_(:), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * RHOT_(:), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DRHOT_ID), LiftDelFlx) + + RHOT_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + end do + !$omp end do + !$omp end parallel + call PROF_rapend('cal_dyn_tend_interior', 3) + + !- Sponge layer + if (SL_flag) then + call PROF_rapstart('cal_dyn_tend_sponge', 3) + call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & + MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call PROF_rapend('cal_dyn_tend_sponge', 3) + end if + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend + + !------ + +!OCL SERIAL + subroutine cal_del_flux_dyn( del_flux, & + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & + Gsqrt, G11, G12, G22, nx, ny, nz, & + vmapM, vmapP, lmesh, elem, vmapM_2d, vmapP_2d, lmesh2D, elem2D ) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) + real(RP), intent(in) :: G11(elem2D%Np*lmesh2D%Ne) + real(RP), intent(in) :: G12(elem2D%Np*lmesh2D%Ne) + real(RP), intent(in) :: G22(elem2D%Np*lmesh2D%Ne) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM_2d(elem2D%NfpTot,lmesh2D%Ne) + integer, intent(in) :: vmapP_2d(elem2D%NfpTot,lmesh2D%Ne) + + integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) + integer :: ke2D, iM_2d(elem%NfpTot) + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: dpres(elem%NfpTot), presM(elem%NfpTot), presP(elem%NfpTot) + real(RP) :: densM(elem%NfpTot), densP(elem%NfpTot) + real(RP) :: rhotM(elem%NfpTot), rhotP(elem%NfpTot) + real(RP) :: DDENS_P(elem%NfpTot), DDENS_M(elem%NfpTot) + real(RP) :: MOMX_P(elem%NfpTot), MOMX_M(elem%NfpTot) + real(RP) :: MOMY_P(elem%NfpTot), MOMY_M(elem%NfpTot) + real(RP) :: MOMZ_P(elem%NfpTot), MOMZ_M(elem%NfpTot) + real(RP) :: DRHOT_P(elem%NfpTot), DRHOT_M(elem%NfpTot) + real(RP) :: PRES_hyd_P(elem%NfpTot), PRES_hyd_M(elem%NfpTot) + real(RP) :: Gsqrt_M(elem%NfpTot) + real(RP) :: G11_2D(elem2D%NfpTot), G12_2D(elem2D%NfpTot), G22_2D(elem2D%NfpTot) + real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) , Gnn_M(elem%NfpTot) + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + !------------------------------------------------------------------------ + + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( & + !$omp ke, iM, iP, ke2d, iM_2d, & + !$omp alpha, VelM, VelP, & + !$omp dpres, presM, presP, densM, densP, rhotM, rhotP, & + !$omp MOMX_M, MOMX_P, MOMY_M, MOMY_P, MOMZ_M, MOMZ_P, & + !$omp DDENS_M, DDENS_P, DRHOT_M, DRHOT_P, & + !$omp PRES_hyd_M, PRES_hyd_P, & + !$omp Gsqrt_M, G1n_M, G2n_M, Gnn_M, G11_2D, G12_2D, G22_2D ) + do ke=lmesh%NeS, lmesh%NeE + + ke2D = lmesh%EMap3Dto2D(ke) + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + iM_2d(:) = vmapM_2d(:,ke2D) + + DDENS_M(:) = DDENS_(iM) + DDENS_P(:) = DDENS_(iP) + MOMX_M(:) = MOMX_(iM) + MOMX_P(:) = MOMX_(iP) + MOMY_M(:) = MOMY_(iM) + MOMY_P(:) = MOMY_(iP) + MOMZ_M(:) = MOMZ_(iM) + MOMZ_P(:) = MOMZ_(iP) + DRHOT_M(:) = DRHOT_(iM) + DRHOT_P(:) = DRHOT_(iP) + PRES_hyd_M(:) = PRES_hyd(iM) + PRES_hyd_P(:) = PRES_hyd(iP) + + Gsqrt_M(:) = Gsqrt(iM) + G11_2D(:) = G11(iM_2d(:)) + G12_2D(:) = G12(iM_2d(:)) + G22_2D(:) = G22(iM_2d(:)) + G1n_M(:) = G11_2D(iM2Dto3D(:)) * nx(:,ke) + G12(iM2Dto3D(:)) * ny(:,ke) + G2n_M(:) = G12_2D(iM2Dto3D(:)) * nx(:,ke) + G22(iM2Dto3D(:)) * ny(:,ke) + Gnn_M(:) = G11_2D(iM2Dto3D(:)) * abs(nx(:,ke)) + G22(iM2Dto3D(:)) * abs(ny(:,ke)) + + densM(:) = DDENS_M(:) + DENS_hyd(iM) + densP(:) = DDENS_P(:) + DENS_hyd(iP) + + VelM(:) = ( MOMX_M(:) * nx(:,ke) + MOMY_M(:) * ny(:,ke) + MOMZ_M(:) * nz(:,ke) ) / densM(:) + VelP(:) = ( MOMX_P(:) * nx(:,ke) + MOMY_P(:) * ny(:,ke) + MOMZ_P(:) * nz(:,ke) ) / densP(:) + + rhotM(:) = P0ovR * (PRES_hyd_M(:) * rP0)**rgamm + DRHOT_M(:) + rhotP(:) = P0ovR * (PRES_hyd_P(:) * rP0)**rgamm + DRHOT_P(:) + + presM(:) = PRES00 * (RovP0 * rhotM(:))**gamm + presP(:) = PRES00 * (RovP0 * rhotP(:))**gamm + + dpres(:) = presP(:) - presM(:) & + - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * abs( nz(:,ke) ) + + alpha(:) = max( sqrt( Gnn_M(:) * gamm * presM(:) / densM(:) ) + abs(VelM(:)), & + sqrt( Gnn_M(:) * gamm * presP(:) / densP(:) ) + abs(VelP(:)) ) + + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * Gsqrt_M(:) * ( & + ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & + - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) + + del_flux(:,ke,VARS_MOMX_ID) = 0.5_RP * Gsqrt_M(:) * ( & + ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & + + G1n_M(:) * dpres(:) & + - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) + + del_flux(:,ke,VARS_MOMY_ID) = 0.5_RP * Gsqrt_M(:) * ( & + ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & + + G2n_M(:) * dpres(:) & + - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) + + del_flux(:,ke,VARS_MOMZ_ID) = 0.5_RP * Gsqrt_M(:) * ( & + ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:)) & + + dpres(:) * nz(:,ke) & + - alpha(:) * ( MOMZ_P(:) - MOMZ_M(:) ) ) + + del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * Gsqrt_M(:) * ( & + ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & + - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) + end do + + return + end subroutine cal_del_flux_dyn + +end module scale_atm_dyn_dgm_globalnonhydro3d_heve From e95dc17d96f5193a8c585d83d3c25fe2395b197d Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 26 May 2021 19:50:25 +0900 Subject: [PATCH 31/98] Modify some modules of scale-dg to call 3D global dynamical core. --- .../src/atmos/mod_atmos_dyn.F90 | 20 +++++++++++++------ .../src/atmos/mod_atmos_dyn_vars.F90 | 7 +++---- .../src/atmos/mod_atmos_phy_sfc.F90 | 1 - .../src/atmos/mod_atmos_phy_sfc_vars.F90 | 4 ++-- .../src/atmos/mod_atmos_phy_tb.F90 | 9 ++++----- .../src/atmos/mod_atmos_phy_tb_vars.F90 | 4 ++-- .../src/atmos/mod_atmos_vars.F90 | 9 ++------- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 index edc9ae74..fdcada1c 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 @@ -46,6 +46,11 @@ module mod_atmos_dyn atm_dyn_dgm_nonhydro3d_heve_Final, & atm_dyn_dgm_nonhydro3d_heve_cal_tend + use scale_atm_dyn_dgm_globalnonhydro3d_heve, only: & + atm_dyn_dgm_globalnonhydro3d_heve_Init, & + atm_dyn_dgm_globalnonhydro3d_heve_Final, & + atm_dyn_dgm_globalnonhydro3d_heve_cal_tend + use scale_atm_dyn_dgm_nonhydro3d_hevi, only: & atm_dyn_dgm_nonhydro3d_hevi_Init, & atm_dyn_dgm_nonhydro3d_hevi_Final, & @@ -211,9 +216,10 @@ end subroutine atm_dyn_nonhydro3d_cal_vi !----------------------------------------------------------------------------- integer, public, parameter :: EQS_TYPEID_NONHYD3D_HEVE = 1 - integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE = 2 - integer, public, parameter :: EQS_TYPEID_NONHYD3D_HEVI = 3 - integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVI = 4 + integer, public, parameter :: EQS_TYPEID_GLOBALNONHYD3D_HEVE = 2 + integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE = 3 + integer, public, parameter :: EQS_TYPEID_NONHYD3D_HEVI = 4 + integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVI = 5 !----------------------------------------------------------------------------- @@ -331,6 +337,11 @@ subroutine AtmosDyn_setup( this, model_mesh, tm_parent_comp ) call atm_dyn_dgm_nonhydro3d_heve_Init( mesh3D ) this%cal_tend_ex => atm_dyn_dgm_nonhydro3d_heve_cal_tend this%cal_vi => null() + case("GLOBALNONHYDRO3D_HEVE") + this%EQS_TYPEID = EQS_TYPEID_GLOBALNONHYD3D_HEVE + call atm_dyn_dgm_globalnonhydro3d_heve_Init( mesh3D ) + this%cal_tend_ex => atm_dyn_dgm_globalnonhydro3d_heve_cal_tend + this%cal_vi => null() case("NONHYDRO3D_SPLITFORM_HEVE") this%EQS_TYPEID = EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE call atm_dyn_dgm_nonhydro3d_heve_splitform_Init( mesh3D ) @@ -401,7 +412,6 @@ subroutine AtmosDyn_update( this, model_mesh, prgvars_list, auxvars_list, forcin integer :: tintbuf_ind class(MeshBase), pointer :: mesh - class(MeshBase2D), pointer :: mesh2D class(LocalMesh3D), pointer :: lcmesh integer :: n integer :: ke @@ -414,7 +424,6 @@ subroutine AtmosDyn_update( this, model_mesh, prgvars_list, auxvars_list, forcin integer :: v real(RP) :: implicit_fac real(RP) :: dt - character(len=H_SHORT) :: labl !-------------------------------------------------- call PROF_rapstart( 'ATM_DYN_update', 1) @@ -742,7 +751,6 @@ subroutine cal_numfilter_tend( this, model_mesh, prgvars_list, auxvars_list, var class(MeshBase), pointer :: mesh class(LocalMesh3D), pointer :: lcmesh integer :: n - integer :: ke integer :: nd_itr real(RP) :: nd_sign logical :: dens_weight_flag diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 index f9d99b42..083f7803 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_vars.F90 @@ -13,6 +13,7 @@ module mod_atmos_dyn_vars use scale_localmesh_base, only: LocalMeshBase use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base, only: MeshBase use scale_mesh_base2d, only: MeshBase2D use scale_mesh_base3d, only: MeshBase3D @@ -130,8 +131,6 @@ module mod_atmos_dyn_vars contains subroutine AtmosDynVars_Init( this, model_mesh ) - use mod_atmos_mesh_gm, only: AtmosMeshGM - use mod_atmos_mesh_rm, only: AtmosMeshRM implicit none class(AtmosDynVars), target, intent(inout) :: this class(ModelMeshBase), target, intent(in) :: model_mesh @@ -252,8 +251,8 @@ subroutine AtmosDynVars_History( this ) implicit none class(AtmosDynVars), intent(in) :: this - integer :: v - integer :: hst_id + ! integer :: v + ! integer :: hst_id !------------------------------------------------------------------------- ! do v = 1, ATMOS_DYN_ANALYSISVARS_NUM diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc.F90 index c5ef2298..690c0903 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc.F90 @@ -158,7 +158,6 @@ subroutine AtmosPhySfc_calc_tendency( & logical, intent(in) :: is_update class(MeshBase), pointer :: mesh - class(MeshBase2D), pointer :: mesh2D class(LocalMesh3D), pointer :: lcmesh class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 index 20681582..473bc383 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_sfc_vars.F90 @@ -96,11 +96,11 @@ subroutine AtmosPhySfcVars_Init( this, model_mesh ) nullify( atm_mesh ) select type(model_mesh) - type is (AtmosMesh) + class is (AtmosMesh) atm_mesh => model_mesh end select - mesh3D => atm_mesh%ptr_mesh + call mesh3D%GetMesh2D( mesh2D ) !---- diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 index b3c5b23e..dd77170d 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 @@ -126,10 +126,10 @@ subroutine AtmosPhyTb_setup( this, model_mesh, tm_parent_comp ) !- get mesh -------------------------------------------------- call model_mesh%GetModelMesh( ptr_mesh ) - select type(model_mesh) - type is (AtmosMesh) - atm_mesh => model_mesh - end select + ! select type(model_mesh) + ! class is (AtmosMesh) + ! atm_mesh => model_mesh + ! end select !--- Regist this compoent in the time manager @@ -179,7 +179,6 @@ subroutine AtmosPhyTb_calc_tendency( & logical, intent(in) :: is_update class(MeshBase), pointer :: mesh - class(MeshBase2D), pointer :: mesh2D class(LocalMesh3D), pointer :: lcmesh class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 index 1e02d0ad..610ff7dc 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb_vars.F90 @@ -146,11 +146,11 @@ subroutine AtmosPhyTbVars_Init( this, model_mesh ) nullify( atm_mesh ) select type(model_mesh) - type is (AtmosMesh) + class is (AtmosMesh) atm_mesh => model_mesh end select - mesh3D => atm_mesh%ptr_mesh + call mesh3D%GetMesh2D( mesh2D ) !---- diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 index fd34fb7b..167488f8 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 @@ -233,8 +233,6 @@ subroutine AtmosVars_Init( this, atm_mesh ) integer :: ierr logical :: is_specified - integer :: DV_id - class(MeshBase3D), pointer :: mesh3D !-------------------------------------------------- @@ -418,13 +416,10 @@ subroutine AtmosVars_history( this ) implicit none class(AtmosVars), intent(inout) :: this - integer :: n integer :: v - class(MeshBase3D), pointer :: mesh3D - class(LocalMesh3D), pointer :: lcmesh integer :: hst_id - type(MeshField3D) :: tmp_field + class(MeshBase3D), pointer :: mesh3D !------------------------------------------------------------------------- mesh3D => this%PROG_VARS(1)%mesh @@ -953,7 +948,7 @@ subroutine vars_calc_diagnoseVar( field_name, var_out, & real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) integer :: ke - real(RP) :: RHOT(elem%Np), DENS(elem%Np), PRES(elem%Np), THETA(elem%Np), TEMP(elem%Np) + real(RP) :: RHOT(elem%Np), DENS(elem%Np), PRES(elem%Np) !------------------------------------------------------------------------- From e021af1e8f73345518d5565512d932168c272959 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 26 May 2021 19:51:07 +0900 Subject: [PATCH 32/98] Add a test case of sound wave for a 3D global model. --- .../test/case/sound_wave_global/Makefile | 28 ++ .../test/case/sound_wave_global/init.conf | 51 ++++ .../test/case/sound_wave_global/mod_user.F90 | 248 ++++++++++++++++++ .../test/case/sound_wave_global/run.conf | 85 ++++++ 4 files changed, 412 insertions(+) create mode 100644 model/atm_nonhydro3d/test/case/sound_wave_global/Makefile create mode 100644 model/atm_nonhydro3d/test/case/sound_wave_global/init.conf create mode 100644 model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/sound_wave_global/run.conf diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/Makefile b/model/atm_nonhydro3d/test/case/sound_wave_global/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf b/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf new file mode 100644 index 00000000..225ac462 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf @@ -0,0 +1,51 @@ +#--- Configuration file for a test case of sound wave ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'sound_wave', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_CONST + CONST_GRAV = 0D0, +/ +&PARAM_EXP + TEMP0 = 300.0D0, + DPRES = 0.1D0, + x_c = 0.0D3, + y_c = 0.0D3, + z_c = 5.0D3, + r_x = 1.0D20, + r_y = 1.0D20, + r_z = 1.0D3, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshNum = 6, + Nprc = 1, + NeGX = 1, + NeGY = 1, + NeZ = 30, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 1, + PolyOrder_v = 1, +! LumpedMassMatFlag = .true., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 new file mode 100644 index 00000000..94563683 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 @@ -0,0 +1,248 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d, only: LocalMesh3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_sound_wave_global + contains + procedure :: setInitCond_lc => exp_SetInitCond_sound_wave + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_sound_wave_global), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + call exp_manager%Init('sound_wave_global') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + return + end subroutine USER_setup + + subroutine USER_calc_tendency + implicit none + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update + implicit none + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_sound_wave( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_atm_dyn_dgm_hydrostatic, only: & + hydrostatic_calc_basicstate_constPT + use mod_mkinit_util, only: & + mkinitutil_calc_cosinebell + + implicit none + + class(Exp_sound_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + real(RP) :: TEMP0 = 300.0_RP + real(RP) :: DPRES = 1.0_RP + real(RP) :: x_c, y_c, z_c + real(RP) :: r_x, r_y, r_z + + namelist /PARAM_EXP/ & + TEMP0, DPRES, & + x_c, y_c, z_c, & + r_x, r_y, r_z + + integer, parameter :: IntrpPolyOrder_h = 6 + integer, parameter :: IntrpPolyOrder_v = 6 + real(RP), allocatable :: PRES_purtub(:,:) + + real(RP) :: rgamm + + integer :: ke + integer :: ierr + !----------------------------------------------------------------------------- + + x_c = 0.5_RP * (dom_xmax + dom_xmin) + y_c = 0.5_RP * (dom_ymax + dom_ymin) + z_c = 0.5_RP * (dom_zmax + dom_zmin) + + r_x = 0.1_RP * (dom_xmax - dom_xmin) + r_y = 0.1_RP * (dom_ymax - dom_ymin) + r_z = 0.1_RP * (dom_zmax - dom_zmin) + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("SOUND_WAVE_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("SOUND_WAVE_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + allocate( PRES_purtub(elem%Np,lcmesh%NeA) ) + ! call mkinitutil_calc_cosinebell( & + ! PRES_purtub, & + ! DPRES, r_x, r_y, r_z, x_c, y_c, z_c, & + ! x, y, z, lcmesh, elem, & + ! IntrpPolyOrder_h, IntrpPolyOrder_v ) + + call hydrostatic_calc_basicstate_constPT( DENS_hyd, PRES_hyd, & + TEMP0, PRES00, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), lcmesh%pos_en(:,:,3), & + lcmesh, elem ) + + !--- + rgamm = CvDry / CpDry + + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + DRHOT(:,ke) = 0.0_RP!PRES00/Rdry * ( & +! ( ( PRES_hyd(:,ke) + PRES_purtub(:,ke) ) / PRES00 )**rgamm & +! - ( PRES_hyd(:,ke) / PRES00 )*rgamm ) + end do + + return + end subroutine exp_SetInitCond_sound_wave + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_sound_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + !--------------------------------------------------- + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf b/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf new file mode 100644 index 00000000..010014f3 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf @@ -0,0 +1,85 @@ +#--- Configuration file for a test case of sound wave ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 0.25D0, + TIME_DURATION_UNIT = 'SEC', + TIME_DT = 0.25D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_GRAV = 0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 0.25D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshNum = 6, + Nprc = 1, + NeGX = 1, + NeGY = 1, + NeZ = 30, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 1, + PolyOrder_v = 1, +! LumpedMassMatFlag = .true., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 0.25D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .false., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + north_vel_bc = 'PERIODIC', + south_vel_bc = 'PERIODIC', + east_vel_bc = 'PERIODIC', + west_vel_bc = 'PERIODIC', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', + north_thermal_bc = 'PERIODIC', + south_thermal_bc = 'PERIODIC', + west_thermal_bc = 'PERIODIC', + east_thermal_bc = 'PERIODIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 0.25D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='DDENS' / +&HISTORY_ITEM name='MOMX' / +&HISTORY_ITEM name='MOMY' / +&HISTORY_ITEM name='MOMZ' / +&HISTORY_ITEM name='DRHOT' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='W' / +!&HISTORY_ITEM name='DPRES' / +&HISTORY_ITEM name='DENS_hyd' / +&HISTORY_ITEM name='PRES_hyd' / +!&HISTORY_ITEM name='DTHETA' / + + From 8562c3acd254dbb4895b3f251d7a26f9d225fb79 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:24:42 +0900 Subject: [PATCH 33/98] Allocate array storing the coefficients of IMEX even when full explicit scheme is used. --- FElib/src/common/scale_timeint_rk.F90 | 8 ++++---- FElib/src/common/scale_timeint_rk.F90.erb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/FElib/src/common/scale_timeint_rk.F90 b/FElib/src/common/scale_timeint_rk.F90 index 676d2969..e0c8ff7e 100644 --- a/FElib/src/common/scale_timeint_rk.F90 +++ b/FElib/src/common/scale_timeint_rk.F90 @@ -131,9 +131,9 @@ subroutine timeint_rk_Init( this, & allocate ( this%coef_a_ex(this%nstage,this%nstage), this%coef_b_ex(this%nstage), this%coef_c_ex(this%nstage) ) allocate ( this%coef_sig_ex(this%nstage+1,this%nstage), this%coef_gam_ex(this%nstage+1,this%nstage) ) - if (this%imex_flag) then +! if (this%imex_flag) then allocate ( this%coef_a_im(this%nstage,this%nstage), this%coef_b_im(this%nstage), this%coef_c_im(this%nstage) ) - end if +! end if select case(this%ndim) case(1) @@ -176,9 +176,9 @@ subroutine timeint_rk_Final( this ) !---------------------------------------- deallocate( this%coef_a_ex, this%coef_b_ex, this%coef_c_ex ) - if (this%imex_flag) then +! if (this%imex_flag) then deallocate( this%coef_a_im, this%coef_b_im, this%coef_c_im ) - end if +! end if select case(this%ndim) case(1) diff --git a/FElib/src/common/scale_timeint_rk.F90.erb b/FElib/src/common/scale_timeint_rk.F90.erb index 24e1b61d..1ad59fab 100644 --- a/FElib/src/common/scale_timeint_rk.F90.erb +++ b/FElib/src/common/scale_timeint_rk.F90.erb @@ -121,9 +121,9 @@ contains allocate ( this%coef_a_ex(this%nstage,this%nstage), this%coef_b_ex(this%nstage), this%coef_c_ex(this%nstage) ) allocate ( this%coef_sig_ex(this%nstage+1,this%nstage), this%coef_gam_ex(this%nstage+1,this%nstage) ) - if (this%imex_flag) then +! if (this%imex_flag) then allocate ( this%coef_a_im(this%nstage,this%nstage), this%coef_b_im(this%nstage), this%coef_c_im(this%nstage) ) - end if +! end if select case(this%ndim) % for d in 1..3 @@ -159,9 +159,9 @@ contains !---------------------------------------- deallocate( this%coef_a_ex, this%coef_b_ex, this%coef_c_ex ) - if (this%imex_flag) then +! if (this%imex_flag) then deallocate( this%coef_a_im, this%coef_b_im, this%coef_c_im ) - end if +! end if select case(this%ndim) % for d in 1..3 From 7804195b4fb818c82be5badf2c1b0da638f03631 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:28:32 +0900 Subject: [PATCH 34/98] Modify the codes for generating the 3D mesh connectivity to treat the larger number of elements. --- FElib/src/common/scale_quicksort.F90 | 240 ++++++++++++++++++++--- FElib/src/common/scale_quicksort.F90.erb | 37 ++-- FElib/src/mesh/scale_mesh_cubedom3d.F90 | 10 +- FElib/src/mesh/scale_meshutil_3d.F90 | 36 ++-- 4 files changed, 258 insertions(+), 65 deletions(-) diff --git a/FElib/src/common/scale_quicksort.F90 b/FElib/src/common/scale_quicksort.F90 index e8452909..af005600 100644 --- a/FElib/src/common/scale_quicksort.F90 +++ b/FElib/src/common/scale_quicksort.F90 @@ -20,8 +20,12 @@ module scale_quicksort ! interface QUICKSORT_exec_with_idx - module procedure QUICKSORT_exec_with_idx_int - module procedure QUICKSORT_exec_with_idx_real_RP + module procedure QUICKSORT_exec_with_idx4_int4 + module procedure QUICKSORT_exec_with_idx4_int8 + module procedure QUICKSORT_exec_with_idx4_real_RP + module procedure QUICKSORT_exec_with_idx8_int4 + module procedure QUICKSORT_exec_with_idx8_int8 + module procedure QUICKSORT_exec_with_idx8_real_RP end interface QUICKSORT_exec_with_idx public :: QUICKSORT_exec_with_idx @@ -30,34 +34,215 @@ module scale_quicksort !- private routines ------------------------------------- - subroutine QUICKSORT_exec_with_idx_int( npoints, val, indx ) + subroutine QUICKSORT_exec_with_idx4_int4( npoints, val, indx ) integer, intent(in) :: npoints - integer, intent(inout) :: val(npoints) - integer, intent(inout) :: indx(npoints) + integer(kind=4), intent(inout) :: val(npoints) + integer(kind=4), intent(inout) :: indx(npoints) !------------------------------- - call quicksort_core_int(val, indx, 1, npoints) - end subroutine QUICKSORT_exec_with_idx_int - subroutine QUICKSORT_exec_with_idx_real_RP( npoints, val, indx ) + call quicksort_core_idx4_int4(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx4_int4 + subroutine QUICKSORT_exec_with_idx4_int8( npoints, val, indx ) + integer, intent(in) :: npoints + integer(kind=8), intent(inout) :: val(npoints) + integer(kind=4), intent(inout) :: indx(npoints) + + !------------------------------- + call quicksort_core_idx4_int8(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx4_int8 + subroutine QUICKSORT_exec_with_idx4_real_RP( npoints, val, indx ) + integer, intent(in) :: npoints + real(RP), intent(inout) :: val(npoints) + integer(kind=4), intent(inout) :: indx(npoints) + + !------------------------------- + call quicksort_core_idx4_real_RP(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx4_real_RP + subroutine QUICKSORT_exec_with_idx8_int4( npoints, val, indx ) + integer, intent(in) :: npoints + integer(kind=4), intent(inout) :: val(npoints) + integer(kind=8), intent(inout) :: indx(npoints) + + !------------------------------- + call quicksort_core_idx8_int4(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx8_int4 + subroutine QUICKSORT_exec_with_idx8_int8( npoints, val, indx ) + integer, intent(in) :: npoints + integer(kind=8), intent(inout) :: val(npoints) + integer(kind=8), intent(inout) :: indx(npoints) + + !------------------------------- + call quicksort_core_idx8_int8(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx8_int8 + subroutine QUICKSORT_exec_with_idx8_real_RP( npoints, val, indx ) integer, intent(in) :: npoints real(RP), intent(inout) :: val(npoints) - integer, intent(inout) :: indx(npoints) + integer(kind=8), intent(inout) :: indx(npoints) !------------------------------- - call quicksort_core_real_RP(val, indx, 1, npoints) - end subroutine QUICKSORT_exec_with_idx_real_RP + call quicksort_core_idx8_real_RP(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx8_real_RP !-- private ------------------------------------------------ - recursive subroutine quicksort_core_int(key, ind, first, last) + recursive subroutine quicksort_core_idx4_int4(key, ind, first, last) + implicit none + + integer(kind=4), intent(inout) :: key(:) + integer(kind=4), intent(inout) :: ind(:) + integer, intent(in) :: first, last + + integer(kind=4) :: x, tmp + integer :: i, j + integer(kind=4) :: tmp_ind + !------------------------------- + + x = key( (first + last)/2 ) + i = first + j = last + + do + do while ( key(i) < x ) + i = i + 1 + end do + do while ( x < key(j) ) + j = j - 1 + end do + if ( i >= j ) exit + + ! swap + tmp = key(i); key(i) = key(j); key(j) = tmp + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind + + i = i + 1; j = j - 1 + end do + + if ( first < i-1 ) call quicksort_core_idx4_int4(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx4_int4(key, ind, j+1, last) + + return + end subroutine quicksort_core_idx4_int4 + recursive subroutine quicksort_core_idx4_int8(key, ind, first, last) + implicit none + + integer(kind=8), intent(inout) :: key(:) + integer(kind=4), intent(inout) :: ind(:) + integer, intent(in) :: first, last + + integer(kind=8) :: x, tmp + integer :: i, j + integer(kind=4) :: tmp_ind + !------------------------------- + + x = key( (first + last)/2 ) + i = first + j = last + + do + do while ( key(i) < x ) + i = i + 1 + end do + do while ( x < key(j) ) + j = j - 1 + end do + if ( i >= j ) exit + + ! swap + tmp = key(i); key(i) = key(j); key(j) = tmp + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind + + i = i + 1; j = j - 1 + end do + + if ( first < i-1 ) call quicksort_core_idx4_int8(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx4_int8(key, ind, j+1, last) + + return + end subroutine quicksort_core_idx4_int8 + recursive subroutine quicksort_core_idx4_real_RP(key, ind, first, last) + implicit none + + real(RP), intent(inout) :: key(:) + integer(kind=4), intent(inout) :: ind(:) + integer, intent(in) :: first, last + + real(RP) :: x, tmp + integer :: i, j + integer(kind=4) :: tmp_ind + !------------------------------- + + x = key( (first + last)/2 ) + i = first + j = last + + do + do while ( key(i) < x ) + i = i + 1 + end do + do while ( x < key(j) ) + j = j - 1 + end do + if ( i >= j ) exit + + ! swap + tmp = key(i); key(i) = key(j); key(j) = tmp + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind + + i = i + 1; j = j - 1 + end do + + if ( first < i-1 ) call quicksort_core_idx4_real_RP(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx4_real_RP(key, ind, j+1, last) + + return + end subroutine quicksort_core_idx4_real_RP + recursive subroutine quicksort_core_idx8_int4(key, ind, first, last) + implicit none + + integer(kind=4), intent(inout) :: key(:) + integer(kind=8), intent(inout) :: ind(:) + integer, intent(in) :: first, last + + integer(kind=4) :: x, tmp + integer :: i, j + integer(kind=8) :: tmp_ind + !------------------------------- + + x = key( (first + last)/2 ) + i = first + j = last + + do + do while ( key(i) < x ) + i = i + 1 + end do + do while ( x < key(j) ) + j = j - 1 + end do + if ( i >= j ) exit + + ! swap + tmp = key(i); key(i) = key(j); key(j) = tmp + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind + + i = i + 1; j = j - 1 + end do + + if ( first < i-1 ) call quicksort_core_idx8_int4(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx8_int4(key, ind, j+1, last) + + return + end subroutine quicksort_core_idx8_int4 + recursive subroutine quicksort_core_idx8_int8(key, ind, first, last) implicit none - integer, intent(inout) :: key(:) - integer, intent(inout) :: ind(:) + integer(kind=8), intent(inout) :: key(:) + integer(kind=8), intent(inout) :: ind(:) integer, intent(in) :: first, last - integer :: x, tmp - integer :: i, j, tmp_i + integer(kind=8) :: x, tmp + integer :: i, j + integer(kind=8) :: tmp_ind !------------------------------- x = key( (first + last)/2 ) @@ -75,25 +260,26 @@ recursive subroutine quicksort_core_int(key, ind, first, last) ! swap tmp = key(i); key(i) = key(j); key(j) = tmp - tmp_i = ind(i); ind(i) = ind(j); ind(j) = tmp_i + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind i = i + 1; j = j - 1 end do - if ( first < i-1 ) call quicksort_core_int(key, ind, first, i-1) - if ( j+1 < last ) call quicksort_core_int(key, ind, j+1, last) + if ( first < i-1 ) call quicksort_core_idx8_int8(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx8_int8(key, ind, j+1, last) return - end subroutine quicksort_core_int - recursive subroutine quicksort_core_real_RP(key, ind, first, last) + end subroutine quicksort_core_idx8_int8 + recursive subroutine quicksort_core_idx8_real_RP(key, ind, first, last) implicit none real(RP), intent(inout) :: key(:) - integer, intent(inout) :: ind(:) + integer(kind=8), intent(inout) :: ind(:) integer, intent(in) :: first, last real(RP) :: x, tmp - integer :: i, j, tmp_i + integer :: i, j + integer(kind=8) :: tmp_ind !------------------------------- x = key( (first + last)/2 ) @@ -111,14 +297,14 @@ recursive subroutine quicksort_core_real_RP(key, ind, first, last) ! swap tmp = key(i); key(i) = key(j); key(j) = tmp - tmp_i = ind(i); ind(i) = ind(j); ind(j) = tmp_i + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind i = i + 1; j = j - 1 end do - if ( first < i-1 ) call quicksort_core_real_RP(key, ind, first, i-1) - if ( j+1 < last ) call quicksort_core_real_RP(key, ind, j+1, last) + if ( first < i-1 ) call quicksort_core_idx8_real_RP(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx8_real_RP(key, ind, j+1, last) return - end subroutine quicksort_core_real_RP + end subroutine quicksort_core_idx8_real_RP end module scale_quicksort diff --git a/FElib/src/common/scale_quicksort.F90.erb b/FElib/src/common/scale_quicksort.F90.erb index 0afe9a79..17e51f68 100644 --- a/FElib/src/common/scale_quicksort.F90.erb +++ b/FElib/src/common/scale_quicksort.F90.erb @@ -20,8 +20,10 @@ module scale_quicksort ! interface QUICKSORT_exec_with_idx -% for t in ["int", "real_RP"] - module procedure QUICKSORT_exec_with_idx_<%=t%> +% for indx_intkind in [ "4", "8" ] +% for t in ["int4", "int8", "real_RP"] + module procedure QUICKSORT_exec_with_idx<%=indx_intkind%>_<%=t%> +% end % end end interface QUICKSORT_exec_with_idx @@ -31,29 +33,33 @@ contains !- private routines ------------------------------------- -% for t in [["integer", "int"], ["real(RP)", "real_RP"]] - subroutine QUICKSORT_exec_with_idx_<%=t[1]%>( npoints, val, indx ) +% for indx_intkind in [ "4", "8" ] +% for t in [["integer(kind=4)", "int4"], ["integer(kind=8)", "int8"], ["real(RP)", "real_RP"]] + subroutine QUICKSORT_exec_with_idx<%=indx_intkind%>_<%=t[1]%>( npoints, val, indx ) integer, intent(in) :: npoints <%=t[0]%>, intent(inout) :: val(npoints) - integer, intent(inout) :: indx(npoints) + integer(kind=<%=indx_intkind%>), intent(inout) :: indx(npoints) !------------------------------- - call quicksort_core_<%=t[1]%>(val, indx, 1, npoints) - end subroutine QUICKSORT_exec_with_idx_<%=t[1]%> + call quicksort_core_idx<%=indx_intkind%>_<%=t[1]%>(val, indx, 1, npoints) + end subroutine QUICKSORT_exec_with_idx<%=indx_intkind%>_<%=t[1]%> +% end % end !-- private ------------------------------------------------ -% for t in [["integer", "int"], ["real(RP)", "real_RP"]] - recursive subroutine quicksort_core_<%=t[1]%>(key, ind, first, last) +% for indx_intkind in [ "4", "8" ] +% for t in [["integer(kind=4)", "int4"], ["integer(kind=8)", "int8"], ["real(RP)", "real_RP"]] + recursive subroutine quicksort_core_idx<%=indx_intkind%>_<%=t[1]%>(key, ind, first, last) implicit none <%=t[0]%>, intent(inout) :: key(:) - integer, intent(inout) :: ind(:) + integer(kind=<%=indx_intkind%>), intent(inout) :: ind(:) integer, intent(in) :: first, last <%=t[0]%> :: x, tmp - integer :: i, j, tmp_i + integer :: i, j + integer(kind=<%=indx_intkind%>) :: tmp_ind !------------------------------- x = key( (first + last)/2 ) @@ -71,15 +77,16 @@ contains ! swap tmp = key(i); key(i) = key(j); key(j) = tmp - tmp_i = ind(i); ind(i) = ind(j); ind(j) = tmp_i + tmp_ind = ind(i); ind(i) = ind(j); ind(j) = tmp_ind i = i + 1; j = j - 1 end do - if ( first < i-1 ) call quicksort_core_<%=t[1]%>(key, ind, first, i-1) - if ( j+1 < last ) call quicksort_core_<%=t[1]%>(key, ind, j+1, last) + if ( first < i-1 ) call quicksort_core_idx<%=indx_intkind%>_<%=t[1]%>(key, ind, first, i-1) + if ( j+1 < last ) call quicksort_core_idx<%=indx_intkind%>_<%=t[1]%>(key, ind, j+1, last) return - end subroutine quicksort_core_<%=t[1]%> + end subroutine quicksort_core_idx<%=indx_intkind%>_<%=t[1]%> +% end % end end module scale_quicksort diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 4cc9e535..29195399 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -348,14 +348,14 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & !---- - call MeshUtil3D_genCubeDomain( lcmesh%pos_ev, lcmesh%EToV, & ! (out) - & lcmesh%NeX, lcmesh%xmin, lcmesh%xmax, & ! (in) - & lcmesh%NeY, lcmesh%ymin, lcmesh%ymax, & ! (in) - & lcmesh%NeZ, lcmesh%zmin, lcmesh%zmax, FZ=FZ_lc ) ! (in) + call MeshUtil3D_genCubeDomain( lcmesh%pos_ev, lcmesh%EToV, & ! (out) + lcmesh%NeX, lcmesh%xmin, lcmesh%xmax, & ! (in) + lcmesh%NeY, lcmesh%ymin, lcmesh%ymax, & ! (in) + lcmesh%NeZ, lcmesh%zmin, lcmesh%zmax, FZ=FZ_lc ) ! (in) !--- call MeshBase3D_setGeometricInfo( lcmesh, MeshCubeDom3D_coord_conv, MeshCubeDom3D_calc_normal ) - + !--- call MeshUtil3D_genConnectivity( lcmesh%EToE, lcmesh%EToF, & ! (out) lcmesh%EToV, lcmesh%Ne, elem%Nfaces ) ! (in) diff --git a/FElib/src/mesh/scale_meshutil_3d.F90 b/FElib/src/mesh/scale_meshutil_3d.F90 index 7af3a425..1c121475 100644 --- a/FElib/src/mesh/scale_meshutil_3d.F90 +++ b/FElib/src/mesh/scale_meshutil_3d.F90 @@ -120,7 +120,7 @@ subroutine MeshUtil3D_genConnectivity( EToE, EToF, & integer, intent(in) :: EToV(Ne,8) integer :: nodes(Ne*Nfaces,4) - integer :: face_ids(Ne*Nfaces) + integer(kind=8) :: face_ids(Ne*Nfaces) integer :: k integer :: f integer :: n @@ -128,23 +128,23 @@ subroutine MeshUtil3D_genConnectivity( EToE, EToF, & integer :: Nnodes integer :: tmp integer :: Nnodes_row - integer :: matchL(2,4), matchR(2,4) + integer :: matchL(2,3), matchR(2,3) real(RP) :: EToE_1d(Ne*Nfaces) real(RP) :: EToF_1d(Ne*Nfaces) - integer :: spNodeToNode(4,Ne*Nfaces) - integer :: spNodeToNodeRowTmp(4,Ne*Nfaces) + integer :: spNodeToNode(3,Ne*Nfaces) + integer :: spNodeToNodeRowTmp(3,Ne*Nfaces) integer :: sort_indx(Ne*Nfaces) - integer :: sort_val(Ne*Nfaces) + integer(kind=8) :: sorted_faceid(Ne*Nfaces) real(RP) :: vtmp(4) - + !----------------------------------------------------------------------------- Nnodes = maxval( EToV ) Nnodes_row = size(nodes,1) - + !--------- do n=1, Ne nodes(n ,:) = EToV(n,(/ 1, 2, 6, 5 /)) @@ -171,36 +171,36 @@ subroutine MeshUtil3D_genConnectivity( EToE, EToF, & end do face_ids(:) = nodes(:,1)*Nnodes**3 + nodes(:,2)*Nnodes**2 & - + nodes(:,3)*Nnodes + nodes(:,4) + 1 + + nodes(:,3)*Nnodes + nodes(:,4) + 1 do f=1, Nfaces do k=1, Ne - n = k + (f-1)*Ne - spNodeToNode(:,n) = (/ face_ids(n), n, EToE(k,f), EToF(k,f) /) - sort_val(n) = face_ids(n) - sort_indx(n) = n + n = k + (f-1)*Ne + spNodeToNode(:,n) = (/ n, EToE(k,f), EToF(k,f) /) + sorted_faceid(n) = face_ids(n) + sort_indx(n) = n ! write(*,*) "face_id, n, EToE, EToF:", spNodeToNode(:,n) end do end do - !- sort row - call QUICKSORT_exec_with_idx( Ne*Nfaces, sort_val, sort_indx ) + call QUICKSORT_exec_with_idx( Ne*Nfaces, sorted_faceid, sort_indx ) spNodeToNodeRowTmp(:,:) = spNodeToNode(:,:) + do n=1, Nnodes_row spNodeToNode(:,n) = spNodeToNodeRowTmp(:,sort_indx(n)) - ! write(*,'(a,4i10)') "(sorted) face_id, n, EToE, EToF:", spNodeToNode(:,n) + ! write(*,'(a,4i10)') "(sorted) face_id, n, EToE, EToF:", spNodeToNode(:,n) end do EToE_1d(:) = -1 EToF_1d(:) = -1 do n=1, Nnodes_row-1 - if ( spNodeToNode(1,n) - spNodeToNode(1,n+1) == 0 ) then + if ( sorted_faceid(n) - sorted_faceid(n+1) == 0 ) then matchL(:,:) = transpose( spNodeToNode(:,(/ n, n+1 /)) ) matchR(:,:) = transpose( spNodeToNode(:,(/ n+1, n /)) ) - EToE_1d(matchL(:,2)) = matchR(:,3) - EToF_1d(matchL(:,2)) = matchR(:,4) + EToE_1d(matchL(:,1)) = matchR(:,2) + EToF_1d(matchL(:,1)) = matchR(:,3) end if end do From 98991f353d5725b3e1cd52bf3696cfde52e6261b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:30:05 +0900 Subject: [PATCH 35/98] Support a HEVI scheme in the 3D global atmospheric model. --- FElib/src/depend | 2 + ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 1129 +++++++++++++++++ .../src/atmos/mod_atmos_dyn.F90 | 35 +- 3 files changed, 1157 insertions(+), 9 deletions(-) create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 diff --git a/FElib/src/depend b/FElib/src/depend index e5eda0b0..9698755f 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -1,4 +1,5 @@ $(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.o: fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_gmres.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.o: fluid_dyn_solver/scale_atm_dyn_dgm_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_base.o @@ -68,6 +69,7 @@ $(OBJ_DIR)/scale_variableinfo.o: data/scale_variableinfo.F90 $(DEPENDLIB) MODS = \ $(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_heve.mod \ + $(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_hevi.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.mod \ diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 new file mode 100644 index 00000000..f539c314 --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -0,0 +1,1129 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / Dynamics HEVI +!! +!! @par Description +!! HEVI DGM scheme for Global Atmospheric Dynamical process. +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_globalnonhydro3d_hevi + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_modalfilter, only: ModalFilter + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_globalnonhydro3d_hevi_Init + public :: atm_dyn_dgm_globalnonhydro3d_hevi_Final + public :: atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend + public :: atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + integer, private, parameter :: DDENS_VID = 1 + integer, private, parameter :: MOMX_VID = 2 + integer, private, parameter :: MOMY_VID = 3 + integer, private, parameter :: MOMZ_VID = 4 + integer, private, parameter :: DRHOT_VID = 5 + integer, private, parameter :: PROG_VARS_NUM = 5 + + real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) + integer, private, allocatable :: iM2Dto3D(:) + + + private :: cal_del_flux_dyn + +contains + subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Init( mesh ) + + implicit none + class(MeshBase3D), intent(in) :: mesh + + integer :: p1, p2, p_ + type(ElementBase3D), pointer :: elem + real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) + + integer :: f_h, f_v + integer :: fp, fp_h1, fp_h2, fp_v + type(ElementBase2D), pointer :: elem2D + class(MeshBase2D), pointer :: mesh2D + !-------------------------------------------- + + elem => mesh%refElem3D + allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) + + InvV_VPOrdM1(:,:) = elem%invV + do p2=1, elem%Nnode_h1D + do p1=1, elem%Nnode_h1D + p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 + InvV_VPOrdM1(p_,:) = 0.0_RP + end do + end do + IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) + + !-- + + allocate( iM2Dto3D(elem%NfpTot) ) + call mesh%GetMesh2D( mesh2D ) + elem2D => mesh2D%refElem2D + + do f_h=1, 4 + do fp_v=1, elem%Nnode_v + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h + iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) + end do + end do + end do + do f_v=1, 2 + do fp_h2=1, elem%Nnode_h1D + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & + + (f_v-1) * elem%Nfp_v & + + 4 * elem%Nnode_h1D * elem%Nnode_v + iM2Dto3D(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D + end do + end do + end do + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Init + + + subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Final() + implicit none + !-------------------------------------------- + + deallocate( IntrpMat_VPOrdM1 ) + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Final + + !------------------------------- + +!OCL SERIAL + subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) + SL_flag, wdamp_tau, wdamp_height, & ! (in) + Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + + use scale_atm_dyn_dgm_spongelayer, only: & + atm_dyn_dgm_spongelayer_add_tend + use scale_const, only: & + OHM => CONST_OHM + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + type(SparseMat), intent(in) :: Dx, Dy, Dz, Sx, Sy, Sz, Lift + real(RP), intent(out) :: DENS_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMX_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMY_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMZ_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: RHOT_dt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DDENS_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeA) + real(RP), intent(in) :: CORIOLIS(elem2D%Np,lmesh2D%NeA) + logical, intent(in) :: SL_flag + real(RP), intent(in) :: wdamp_tau + real(RP), intent(in) :: wdamp_height + + real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP) :: PRES_(elem%Np) + real(RP) :: RHOT_(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) + + integer :: ke, ke2d + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + real(RP) :: GIJ(elem%Np,2,2) + real(RP) :: X(elem%Np), Y(elem%Np), twoOVdel2(elem%Np) + real(RP) :: CORI(elem%Np,2) + real(RP) :: s + logical :: is_panel1to4 + + !------------------------------------------------------------------------ + + call PROF_rapstart('cal_dyn_tend_bndflux', 3) + call cal_del_flux_dyn( del_flux, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) + lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) + lmesh%vmapM, lmesh%vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) + call PROF_rapend('cal_dyn_tend_bndflux', 3) + + !----- + call PROF_rapstart('cal_dyn_tend_interior', 3) + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + s = 1.0_RP + is_panel1to4 = .true. + if ( lmesh%panelID == 5 ) then + is_panel1to4 = .false. + else if ( lmesh%panelID == 6 ) then + is_panel1to4 = .false. + s = - 1.0_RP + end if + + !$omp parallel do private( & + !$omp RHOT_, PRES_, rdens_, u_, v_, w_, ke2d, & + !$omp Fx, Fy, Fz, LiftDelFlx, & + !$omp GIJ, X, Y, twoOVdel2, CORI ) + do ke = lmesh%NeS, lmesh%NeE + !-- + X(:) = lmesh%pos_en(:,ke,1) + Y(:) = lmesh%pos_en(:,ke,2) + twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) + + RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) + PRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm + + rdens_(:) = 1.0_RP / ( DDENS_(:,ke) + DENS_hyd(:,ke) ) + u_ (:) = MOMX_(:,ke) * rdens_(:) + v_ (:) = MOMY_(:,ke) * rdens_(:) + w_ (:) = MOMZ_(:,ke) * rdens_(:) + + ke2d = lmesh%EMap3Dto2D(ke) + GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) + GIJ(:,2,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,1) + GIJ(:,1,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) + GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + + CORI(:,1) = s * OHM * twoOVdel2(:) * ( - X(:) * Y(:) * MOMX_(:,ke) + (1.0_RP + Y(:)**2) * MOMY_(:,ke) ) + CORI(:,2) = s * OHM * twoOVdel2(:) * ( - (1.0_RP + X(:)**2) * MOMX_(:,ke) + X(:) * Y(:) * MOMY_(:,ke) ) + if ( is_panel1to4 ) then + CORI(:,1) = Y(:) * CORI(:,1) + CORI(:,2) = Y(:) * CORI(:,2) + end if + + !-- DENS + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DDENS_VID), LiftDelFlx) + + DENS_dt(:,ke) = - ( & + lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + + !-- MOMX + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * PRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * PRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) + + MOMX_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twoOVdel2(:) * Y(:) * & + ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & + + CORI(:,1) + + !-- MOMY + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * PRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * PRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) + + MOMY_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twoOVdel2(:) * X(:) * & + ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + + CORI(:,2) + + !-- MOMZ + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMZ_(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) + + MOMZ_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + + !-- RHOT + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * RHOT_(:), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * RHOT_(:), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DRHOT_VID), LiftDelFlx) + + RHOT_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + end do + call PROF_rapend('cal_dyn_tend_interior', 3) + + !- Sponge layer + if (SL_flag) then + call PROF_rapstart('cal_dyn_tend_sponge', 3) + call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & + MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call PROF_rapend('cal_dyn_tend_sponge', 3) + end if + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend + + !------ + +!OCL SERIAL + subroutine cal_del_flux_dyn( del_flux, & + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & + Gsqrt, G11, G12, G22, nx, ny, nz, & + vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) + real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + + integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) + integer :: ke2D + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: dpres(elem%NfpTot), presM(elem%NfpTot), presP(elem%NfpTot) + real(RP) :: densM(elem%NfpTot), densP(elem%NfpTot) + real(RP) :: rhotM(elem%NfpTot), rhotP(elem%NfpTot) + real(RP) :: DDENS_P(elem%NfpTot), DDENS_M(elem%NfpTot) + real(RP) :: MOMX_P(elem%NfpTot), MOMX_M(elem%NfpTot) + real(RP) :: MOMY_P(elem%NfpTot), MOMY_M(elem%NfpTot) + real(RP) :: MOMZ_P(elem%NfpTot), MOMZ_M(elem%NfpTot) + real(RP) :: DRHOT_P(elem%NfpTot), DRHOT_M(elem%NfpTot) + real(RP) :: PRES_hyd_P(elem%NfpTot), PRES_hyd_M(elem%NfpTot) + real(RP) :: Gsqrt_M(elem%NfpTot) + real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) , Gnn_M(elem%NfpTot) + real(RP) :: swV(elem%NfpTot) + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + !------------------------------------------------------------------------ + + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( & + !$omp ke, iM, iP, ke2D, & + !$omp alpha, VelM, VelP, & + !$omp dpres, presM, presP, densM, densP, rhotM, rhotP, & + !$omp MOMX_M, MOMX_P, MOMY_M, MOMY_P, MOMZ_M, MOMZ_P, & + !$omp DDENS_M, DDENS_P, DRHOT_M, DRHOT_P, & + !$omp PRES_hyd_M, PRES_hyd_P, & + !$omp Gsqrt_M, G1n_M, G2n_M, Gnn_M, & + !$omp swV ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + + DDENS_M(:) = DDENS_(iM) + DDENS_P(:) = DDENS_(iP) + MOMX_M(:) = MOMX_(iM) + MOMX_P(:) = MOMX_(iP) + MOMY_M(:) = MOMY_(iM) + MOMY_P(:) = MOMY_(iP) + MOMZ_M(:) = MOMZ_(iM) + MOMZ_P(:) = MOMZ_(iP) + DRHOT_M(:) = DRHOT_(iM) + DRHOT_P(:) = DRHOT_(iP) + PRES_hyd_M(:) = PRES_hyd(iM) + PRES_hyd_P(:) = PRES_hyd(iP) + + Gsqrt_M(:) = Gsqrt(iM) + + ke2D = lmesh%EMap3Dto2D(ke) + G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) + G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) + + densM(:) = DDENS_M(:) + DENS_hyd(iM) + densP(:) = DDENS_P(:) + DENS_hyd(iP) + + swV(:) = 1.0_RP - nz(:,ke)**2 + VelM(:) = ( MOMX_M(:) * nx(:,ke) + MOMY_M(:) * ny(:,ke) + MOMZ_M(:) * nz(:,ke) ) / densM(:) + VelP(:) = ( MOMX_P(:) * nx(:,ke) + MOMY_P(:) * ny(:,ke) + MOMZ_P(:) * nz(:,ke) ) / densP(:) + + rhotM(:) = P0ovR * (PRES_hyd_M(:) * rP0)**rgamm + DRHOT_M(:) + rhotP(:) = P0ovR * (PRES_hyd_P(:) * rP0)**rgamm + DRHOT_P(:) + + presM(:) = PRES00 * (RovP0 * rhotM(:))**gamm + presP(:) = PRES00 * (RovP0 * rhotP(:))**gamm + + dpres(:) = presP(:) - presM(:) & + - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * abs( nz(:,ke) ) + + alpha(:) = swV(:) * max( sqrt( Gnn_M(:) * gamm * presM(:) / densM(:) ) + abs(VelM(:)), & + sqrt( Gnn_M(:) * gamm * presP(:) / densP(:) ) + abs(VelP(:)) ) + + del_flux(:,ke,DDENS_VID) = 0.5_RP * Gsqrt_M(:) * ( & + swV(:) * ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & + - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) + + del_flux(:,ke,MOMX_VID) = 0.5_RP * Gsqrt_M(:) * ( & + ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & + + G1n_M(:) * dpres(:) & + - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) + + del_flux(:,ke,MOMY_VID) = 0.5_RP * Gsqrt_M(:) * ( & + ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & + + G2n_M(:) * dpres(:) & + - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) + + del_flux(:,ke,MOMZ_VID) = 0.5_RP * Gsqrt_M(:) * ( & + ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:) ) & + - alpha(:) * ( MOMZ_P(:) - MOMZ_M(:) ) ) + + del_flux(:,ke,DRHOT_VID) = 0.5_RP * Gsqrt_M(:) * ( & + swV(:) * ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & + - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) + end do + + return + end subroutine cal_del_flux_dyn + + +!OCL SERIAL + subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & + DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + Dz, Lift, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, lmesh2D, elem2D ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: DENS_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMX_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMY_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMZ_dt(elem%Np,lmesh%NeA) + real(RP), intent(out) :: RHOT_dt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DDENS_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeA) + class(SparseMat), intent(in) :: Dz, Lift + logical, intent(in) :: modalFilterFlag + class(ModalFilter), intent(in) :: VModalFilter + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + + real(RP) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: PROG_VARS00(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: b(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) + integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) + real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) + real(RP) :: nz(elem%NfpTot,lmesh%NeZ) + integer :: vmapM(elem%NfpTot,lmesh%NeZ) + integer :: vmapP(elem%NfpTot,lmesh%NeZ) + integer :: ke_x, ke_y, ke_z, ke, p, v + integer :: itr_lin, itr_nlin + integer :: f, vs, ve, kl, ku, nz_1D + integer :: ij, info + logical :: is_converged + + + real(RP), allocatable :: PmatBnd(:,:,:) + !------------------------------------------------------------------------ + + + call PROF_rapstart( 'hevi_cal_vi_prep', 3) + + nz_1D = elem%Nnode_v * PROG_VARS_NUM * lmesh%NeZ + kl = 2 * elem%Nnode_v * PROG_VARS_NUM - 1 + ku = kl + allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + + !$omp parallel private(f, vs, ve) + !$omp do + do ke_z=1, lmesh%NeZ + do f=1, elem%Nfaces_h + vs = 1 + (f-1)*elem%Nfp_h + ve = vs + elem%Nfp_h - 1 + vmapM(vs:ve,ke_z) = elem%Fmask_h(:,f) + (ke_z-1)*elem%Np + end do + do f=1, elem%Nfaces_v + vs = elem%Nfp_h*elem%Nfaces_h + 1 + (f-1)*elem%Nfp_v + ve = vs + elem%Nfp_v - 1 + vmapM(vs:ve,ke_z) = elem%Fmask_v(:,f) + (ke_z-1)*elem%Np + end do + vmapP(:,ke_z) = vmapM(:,ke_z) + end do + !$omp do + do ke_z=1, lmesh%NeZ + vs = elem%Nfp_h*elem%Nfaces_h + 1 + ve = vs + elem%Nfp_v - 1 + if (ke_z > 1) & + vmapP(vs:ve,ke_z) = elem%Fmask_v(:,2) + (ke_z-2)*elem%Np + + vs = elem%Nfp_h*elem%Nfaces_h + elem%Nfp_v + 1 + ve = vs + elem%Nfp_v - 1 + if (ke_z < lmesh%NeZ) & + vmapP(vs:ve,ke_z) = elem%Fmask_v(:,1) + ke_z*elem%Np + end do + !$omp end parallel + call PROF_rapend( 'hevi_cal_vi_prep', 3) + + do ke_y=1, lmesh%NeY + do ke_x=1, lmesh%NeX + + call PROF_rapstart( 'hevi_cal_vi_get_var', 3) + + !$omp parallel do private(ke) + do ke_z=1, lmesh%NeZ + ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + + PROG_VARS(:,DDENS_VID,ke_z) = DDENS_(:,ke) + PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) + PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) + PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) + PROG_VARS(:,DRHOT_VID,ke_z) = DRHOT_(:,ke) + DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) + PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) + + PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) + nz(:,ke_z) = lmesh%normal_fn(:,ke,3) + end do + call PROF_rapend( 'hevi_cal_vi_get_var', 3) + + if ( abs(impl_fac) > 0.0_RP ) then + call PROF_rapstart( 'hevi_cal_vi_itr', 3) + + ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 + ! dG/dq^n+1 del[q] = - G(q^n*) + do itr_nlin = 1, 1 + + call vi_eval_Ax( Ax(:,:,:), & ! (out) + PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y, .false. ) ! (in) + + do ke_z=1, lmesh%NeZ + b(:,:,ke_z) = - Ax(:,:,ke_z) + PROG_VARS00(:,:,ke_z) + end do + + call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) + + call vi_construct_matbnd( PmatBnd, & ! (out) + kl, ku, nz_1D, & ! (in) + PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + + call PROF_rapend( 'hevi_cal_vi_matbnd', 3) + + call PROF_rapstart( 'hevi_cal_vi_lin', 3) + !$omp parallel private(ij, v, ke_z, info) + !$omp do + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + do v=1, PROG_VARS_NUM + b1D(:,v,ke_z,ij) = b(elem%Colmask(:,ij),v,ke_z) + end do + end do + + call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij), nz_1D, info) + + do ke_z=1, lmesh%NeZ + do v=1, PROG_VARS_NUM + PROG_VARS(elem%Colmask(:,ij),v,ke_z) = PROG_VARS(elem%Colmask(:,ij),v,ke_z) + b1D(:,v,ke_z,ij) + end do + end do + end do + !$omp do + do ke_z=1, lmesh%NeZ + PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) + end do + !$omp end parallel + call PROF_rapend( 'hevi_cal_vi_lin', 3) + end do ! itr nlin + + call PROF_rapend( 'hevi_cal_vi_itr', 3) + end if + + call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) + if ( abs(impl_fac) > 0.0_RP) then + !$omp parallel do + do ke_z=1, lmesh%NeZ + tend(:,:,ke_z) = (- PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z))/impl_fac + end do + else + call vi_eval_Ax( tend(:,:,:), & ! (out) + PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y, .true. ) ! (in) + end if + + !$omp parallel do private(ke) + do ke_z=1, lmesh%NeZ + ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + DENS_dt(:,ke) = - tend(:,DDENS_VID,ke_z) + MOMX_dt(:,ke) = - tend(:,MOMX_VID ,ke_z) + MOMY_dt(:,ke) = - tend(:,MOMY_VID ,ke_z) + MOMZ_dt(:,ke) = - tend(:,MOMZ_VID ,ke_z) + RHOT_dt(:,ke) = - tend(:,DRHOT_VID,ke_z) + end do + call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) + end do + end do + + return + end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi + + !------------------------------------------------ + +!OCL SERIAL + subroutine vi_eval_Ax( Ax, & ! (out) + PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) + Dz, Lift, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y, cal_tend_flag ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + class(SparseMat), intent(in) :: Dz, Lift + logical, intent(in) :: modalFilterFlag + real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: ke_x, ke_y + logical, intent(in) :: cal_tend_flag + + real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) + real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) + real(RP) :: DPRES(elem%Np) + real(RP) :: tmpV1D(elem%Nnode_v) + integer :: ke_z + integer :: ke + integer :: v + integer :: ij + real(RP) :: gamm, rgamm + !-------------------------------------------------------- + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + call vi_cal_del_flux_dyn( del_flux, & ! (out) + PROG_VARS(:,DDENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) + PROG_VARS(:,MOMY_VID ,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) + PROG_VARS(:,DRHOT_VID,:), & ! (in) + PROG_VARS0(:,DDENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) + PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) + PROG_VARS0(:,DRHOT_VID,:), & ! (in) + DENS_hyd, PRES_hyd, nz, vmapM, vmapP, & ! (in) + lmesh, elem ) ! (in) + + !$omp parallel do private( & + !$omp ke, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & + !$omp v, ij, tmpV1D & + !$omp ) + do ke_z=1, lmesh%NeZ + ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm + + DPRES(:) = PRES_hyd(:,ke_z) * ((1.0_RP + PROG_VARS(:,DRHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP) + POT(:) = (RHOT_hyd(:) + PROG_VARS(:,DRHOT_VID,ke_z))/(DENS_hyd(:,ke_z) + PROG_VARS(:,DDENS_VID,ke_z)) + + !- DENS + call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DDENS_VID), LiftDelFlx) + Ax(:,DDENS_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) + + !- MOMX + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) + Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) + + !-MOMY + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) + Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) + + !-MOMZ + call sparsemat_matmul(Dz, DPRES(:), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) + Ax(:,MOMZ_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) & + + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DDENS_VID,ke_z)) + + !-RHOT + call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DRHOT_VID), LiftDelFlx) + Ax(:,DRHOT_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) + + !-- Modal filtering in the vertical direction + if ( modalFilterFlag ) then + do v=1, PROG_VARS_NUM + do ij=1, elem%Nnode_h1D**2 + Ax(elem%Colmask(:,ij),v,ke_z) = Ax(elem%Colmask(:,ij),v,ke_z) & + - matmul(VModalFilter, PROG_VARS(elem%Colmask(:,ij),v,ke_z) ) / dt + end do + end do + end if + + !-- + if ( .not. cal_tend_flag ) then + Ax(:,:,ke_z) = PROG_VARS(:,:,ke_z) + impl_fac * Ax(:,:,ke_z) + end if + + end do + + return + end subroutine vi_eval_Ax + +!OCL SERIAL + subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) + DENS_hyd, PRES_hyd, nz, vmapM, vmapP, lmesh, elem ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DDENS0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMX0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMY0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMZ0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) + + integer :: i, p, ke_z, iP, iM + real(RP) :: alpha0, swV + real(RP) :: MOMZ_P + real(RP) :: rhot_hyd_M, rhot_hyd_P + real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP + real(RP) :: pres0M, pres0P, dens0M, dens0P + real(RP) :: gamm, rgamm + !------------------------------------------------------------------------ + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + !$omp parallel do private( p, i, iM, iP, & + !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & + !$omp dpresM, dpresP, MOMZ_P, & + !$omp dens0M, dens0P, pres0M, pres0P, & + !$omp swV, alpha0 ) + do ke_z=1, lmesh%NeZ + do p=1, elem%NfpTot + i = p + (ke_z-1)*elem%NfpTot + iM = vmapM(i); iP = vmapP(i) + + !- + rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm + rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm + + densM = DENS_hyd(iM) + DDENS_(iM) + densP = DENS_hyd(iP) + DDENS_(iP) + + pottM = (rhot_hyd_M + DRHOT_(iM)) / densM + pottP = (rhot_hyd_P + DRHOT_(iP)) / densP + + dpresM = PRES_hyd(iM) * ((1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - 1.0_RP) + dpresP = PRES_hyd(iP) * ((1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - 1.0_RP) + + !- + dens0M = DENS_hyd(iM) + DDENS0_(iM) + dens0P = DENS_hyd(iP) + DDENS0_(iP) + + pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm + pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm + + swV = nz(i)**2 + alpha0 = swV * max( abs(MOMZ0_(iM)/dens0M) + sqrt(gamm * pres0M/dens0M), & + abs(MOMZ0_(iP)/dens0P) + sqrt(gamm * pres0P/dens0P) ) + + if (iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ)) then + MOMZ_P = - MOMZ_(iM) + alpha0 = 0.0_RP + else + MOMZ_P = MOMZ_(iP) + end if + + del_flux(i,DDENS_VID) = 0.5_RP * ( & + + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & + - alpha0 * ( DDENS_(iP) - DDENS_(iM) ) ) + + del_flux(i,MOMX_VID) = 0.5_RP * ( & + - alpha0 * ( MOMX_(iP) - MOMX_(iM) ) ) + + del_flux(i,MOMY_VID) = 0.5_RP * ( & + - alpha0 * ( MOMY_(iP) - MOMY_(iM) ) ) + + del_flux(i,MOMZ_VID) = 0.5_RP * ( & + + ( dpresP - dpresM ) * nz(i) & + - alpha0 * ( MOMZ_P - MOMZ_(iM) ) ) + + del_flux(i,DRHOT_VID) = 0.5_RP * ( & + + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & + - alpha0 * ( DRHOT_(iP) - DRHOT_(iM) ) ) + end do + end do + + return + end subroutine vi_cal_del_flux_dyn + +!OCL SERIAL + subroutine vi_construct_matbnd( PmatBnd, & ! (out) + kl, ku, nz_1D, & ! (in) + PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) + Dz, Lift, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + integer, intent(in) :: kl, ku, nz_1D + real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + class(SparseMat), intent(in) :: Dz, Lift + logical, intent(in) :: modalFilterFlag + real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: ke_x, ke_y + + real(RP) :: RHOT_hyd(elem%Nnode_v) + real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: Cs0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + integer :: ke_z, ke_z2 + integer :: v, ke, p, f1, fp, FmV + real(RP) :: gamm, rgamm + real(RP) :: fac_dz_p(elem%Nnode_v) + real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) + real(RP) :: PmatL(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) + real(RP) :: PmatU(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) + integer :: Colmask(elem%Nnode_v) + real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) + real(RP) :: Dd(elem%Nnode_v) + real(RP) :: tmp1 + real(RP) :: alphaM, alphaP + real(RP) :: fac + + integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 + logical :: bc_flag + logical :: eval_flag(PROG_VARS_NUM,PROG_VARS_NUM) + !-------------------------------------------------------- + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + eval_flag(:,:) = .false. + do v=1, PROG_VARS_NUM + eval_flag(v,v) = .true. + end do + eval_flag(DDENS_VID,MOMZ_VID) = .true. + eval_flag(MOMZ_VID,DDENS_VID) = .true. + eval_flag(MOMZ_VID,DRHOT_VID) = .true. + eval_flag(DRHOT_VID,MOMZ_VID) = .true. + eval_flag(DRHOT_VID,DDENS_VID) = .true. + + Id(:,:) = 0.0_RP + do p=1, elem%Nnode_v + Id(p,p) = 1.0_RP + end do + + !$omp parallel private(RHOT_hyd, Colmask) + !$omp do + do v=1, PROG_VARS_NUM + PmatD(:,:,:,v) = 0.0_RP + PmatL(:,:,:,v) = 0.0_RP + PmatU(:,:,:,v) = 0.0_RP + end do + !$omp do + do ij=1, elem%Nnode_h1D**2 + PmatBnd(:,:,:,:,ij) = 0.0_RP + end do + !$omp do collapse(2) + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + Colmask(:) = elem%Colmask(:,ij) + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm + + DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & + * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**(gamm-1) + + DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DDENS_VID,ke_z) + POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) + W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) + Cs0(:,ke_z,ij) = sqrt( gamm * PRES_hyd(Colmask(:),ke_z) & + * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**gamm / DENS0(:,ke_z,ij) ) + end do + end do + !$omp end parallel + + !$omp parallel do private(ke_z, ke, ColMask, p, fp, v, f1, ke_z2, fac_dz_p, & + !$omp fac, tmp1, alphaM, alphaP, FmV, & + !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & + !$omp Dd ) & + !$omp firstprivate(PmatD, PmatL, PmatU) + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + Colmask(:) = elem%Colmask(:,ij) + + !----- + do p=1, elem%Nnode_v + fac_dz_p(:) = impl_fac * lmesh%Escale(Colmask(:),ke,3,3) * elem%Dx3(Colmask(:),Colmask(p)) + if (modalFilterFlag) then + Dd(:) = Id(:,p) - VModalFilter(:,p) * impl_fac / dt + else + Dd(:) = Id(:,p) + end if + + ! DDENS + PmatD(:,p,DDENS_VID,DDENS_VID) = Dd(:) + PmatD(:,p,DDENS_VID,MOMZ_VID) = fac_dz_p(:) + + ! MOMX + PmatD(:,p,MOMX_VID,MOMX_VID) = Dd(:) + + ! MOMY + PmatD(:,p,MOMY_VID,MOMY_VID) = Dd(:) + + ! MOMZ + PmatD(:,p,MOMZ_VID,MOMZ_VID) = Dd(:) + PmatD(:,p,MOMZ_VID,DDENS_VID) = impl_fac * Grav * IntrpMat_VPOrdM1(Colmask(:),Colmask(p)) + PmatD(:,p,MOMZ_VID,DRHOT_VID) = fac_dz_p(:) * DPDRHOT0(p,ke_z,ij) + + !DRHOT + PmatD(:,p,DRHOT_VID,DDENS_VID) = - fac_dz_p(:) * POT0(p,ke_z,ij) * W0(p,ke_z,ij) + PmatD(:,p,DRHOT_VID,MOMZ_VID ) = fac_dz_p(:) * POT0(p,ke_z,ij) + PmatD(:,p,DRHOT_VID,DRHOT_VID) = Dd(:) + fac_dz_p(:) * W0(p,ke_z,ij) + end do + + do f1=1, 2 + if (f1==1) then + ke_z2 = max(ke_z-1,1) + pv1 = 1; pv2 = elem%Nnode_v + else + ke_z2 = min(ke_z+1,lmesh%NeZ) + pv1 = elem%Nnode_v; pv2 = 1 + end if + fac = 0.5_RP * impl_fac + if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then + bc_flag = .true. + pv2 = pv1 + else + bc_flag = .false. + end if + + FmV = elem%Fmask_v(ij,f1) + fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij + + !-- + alphaM = abs( W0(pv1,ke_z ,ij) ) + Cs0(pv1,ke_z ,ij) + alphaP = abs( W0(pv2,ke_z2,ij) ) + Cs0(pv2,ke_z2,ij) + + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * max(alphaM, alphaP) + if (bc_flag) then + !PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 + else + do v=1, PROG_VARS_NUM + PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 + if (f1 == 1) then + PmatL(pv1,pv2,v,v) = - tmp1 + else + PmatU(pv1,pv2,v,v) = - tmp1 + end if + end do + end if + + !-- + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * nz(fp,ke_z) + + if (bc_flag) then + PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - 2.0_RP * tmp1 + PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) + PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) + PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - 2.0_RP * tmp1 * W0(pv1,ke_z,ij) + else + PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - tmp1 + PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) = PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) - tmp1 * DPDRHOT0(pv1,ke_z,ij) + PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - tmp1 * POT0(pv1,ke_z,ij) + PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) + PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - tmp1 * W0(pv1,ke_z,ij) + + if (f1 == 1) then + PmatL(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 + PmatL(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) + PmatL(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) + PmatL(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) + PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) & + + tmp1 * W0(pv2,ke_z2,ij) + else + PmatU(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 + PmatU(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) + PmatU(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) + PmatU(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) + PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) & + + tmp1 * W0(pv2,ke_z2,ij) + end if + end if + end do + + do v2=1, PROG_VARS_NUM + do v1=1, PROG_VARS_NUM + if ( eval_flag(v1,v2) ) then + do pv2=1, elem%Nnode_v + g_kj = pv2 + (v2-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM + g_kjm1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z-2)*elem%Nnode_v*PROG_VARS_NUM + g_kjp1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z )*elem%Nnode_v*PROG_VARS_NUM + + do pv1=1, elem%Nnode_v + pb1 = pv1 + (v1-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM + if (ke_z > 1) then + PmatBnd(kl+ku+1+pb1-g_kjm1, pv2,v2,ke_z-1, ij) = PmatL(pv1,pv2,v1,v2) + end if + PmatBnd(kl+ku+1+pb1-g_kj, pv2,v2,ke_z, ij) = PmatD(pv1,pv2,v1,v2) + if (ke_z < lmesh%NeZ) then + PmatBnd(kl+ku+1+pb1-g_kjp1, pv2,v2,ke_z+1, ij) = PmatU(pv1,pv2,v1,v2) + end if + end do + end do + end if + end do + end do + end do + end do + + return + end subroutine vi_construct_matbnd + +end module scale_atm_dyn_dgm_globalnonhydro3d_hevi diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 index fdcada1c..d0b13603 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 @@ -45,12 +45,7 @@ module mod_atmos_dyn atm_dyn_dgm_nonhydro3d_heve_Init, & atm_dyn_dgm_nonhydro3d_heve_Final, & atm_dyn_dgm_nonhydro3d_heve_cal_tend - - use scale_atm_dyn_dgm_globalnonhydro3d_heve, only: & - atm_dyn_dgm_globalnonhydro3d_heve_Init, & - atm_dyn_dgm_globalnonhydro3d_heve_Final, & - atm_dyn_dgm_globalnonhydro3d_heve_cal_tend - + use scale_atm_dyn_dgm_nonhydro3d_hevi, only: & atm_dyn_dgm_nonhydro3d_hevi_Init, & atm_dyn_dgm_nonhydro3d_hevi_Final, & @@ -68,6 +63,18 @@ module mod_atmos_dyn atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend, & atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi + use scale_atm_dyn_dgm_globalnonhydro3d_heve, only: & + atm_dyn_dgm_globalnonhydro3d_heve_Init, & + atm_dyn_dgm_globalnonhydro3d_heve_Final, & + atm_dyn_dgm_globalnonhydro3d_heve_cal_tend + + use scale_atm_dyn_dgm_globalnonhydro3d_hevi, only: & + atm_dyn_dgm_globalnonhydro3d_hevi_Init, & + atm_dyn_dgm_globalnonhydro3d_hevi_Final, & + atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend, & + atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi + + use scale_atm_dyn_dgm_nonhydro3d_numdiff, only: & atm_dyn_dgm_nonhydro3d_numdiff_Init, & atm_dyn_dgm_nonhydro3d_numdiff_Final @@ -217,9 +224,10 @@ end subroutine atm_dyn_nonhydro3d_cal_vi integer, public, parameter :: EQS_TYPEID_NONHYD3D_HEVE = 1 integer, public, parameter :: EQS_TYPEID_GLOBALNONHYD3D_HEVE = 2 - integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE = 3 - integer, public, parameter :: EQS_TYPEID_NONHYD3D_HEVI = 4 - integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVI = 5 + integer, public, parameter :: EQS_TYPEID_GLOBALNONHYD3D_HEVI = 3 + integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE = 4 + integer, public, parameter :: EQS_TYPEID_NONHYD3D_HEVI = 5 + integer, public, parameter :: EQS_TYPEID_NONHYD3D_SPLITFORM_HEVI = 6 !----------------------------------------------------------------------------- @@ -342,6 +350,11 @@ subroutine AtmosDyn_setup( this, model_mesh, tm_parent_comp ) call atm_dyn_dgm_globalnonhydro3d_heve_Init( mesh3D ) this%cal_tend_ex => atm_dyn_dgm_globalnonhydro3d_heve_cal_tend this%cal_vi => null() + case("GLOBALNONHYDRO3D_HEVI") + this%EQS_TYPEID = EQS_TYPEID_GLOBALNONHYD3D_HEVI + call atm_dyn_dgm_globalnonhydro3d_hevi_Init( mesh3D ) + this%cal_tend_ex => atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend + this%cal_vi => atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi case("NONHYDRO3D_SPLITFORM_HEVE") this%EQS_TYPEID = EQS_TYPEID_NONHYD3D_SPLITFORM_HEVE call atm_dyn_dgm_nonhydro3d_heve_splitform_Init( mesh3D ) @@ -628,6 +641,10 @@ subroutine AtmosDyn_finalize( this ) select case(this%EQS_TYPEID) case(EQS_TYPEID_NONHYD3D_HEVE) call atm_dyn_dgm_nonhydro3d_heve_Final() + case(EQS_TYPEID_GLOBALNONHYD3D_HEVE) + call atm_dyn_dgm_globalnonhydro3d_heve_Final() + case(EQS_TYPEID_GLOBALNONHYD3D_HEVI) + call atm_dyn_dgm_globalnonhydro3d_hevi_Final() case(EQS_TYPEID_NONHYD3D_HEVI) call atm_dyn_dgm_nonhydro3d_hevi_Final() case(EQS_TYPEID_NONHYD3D_SPLITFORM_HEVI) From 53110195b6c32af31e3b85a4137d2042c23d0cc1 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:32:17 +0900 Subject: [PATCH 36/98] Fix some bugs. --- FElib/src/Makefile | 1 + ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 111 +++++++++--------- .../src/atmos/mod_atmos_mesh_gm.F90 | 2 +- .../src/atmos/mod_atmos_mesh_rm.F90 | 2 +- .../src/atmos/mod_atmos_vars.F90 | 36 +++--- 5 files changed, 75 insertions(+), 77 deletions(-) diff --git a/FElib/src/Makefile b/FElib/src/Makefile index d65e0235..37600793 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -95,6 +95,7 @@ OBJS_NAME_FLUID_DYN_SOLVER = \ scale_atm_dyn_dgm_nonhydro3d_numdiff.o \ scale_atm_dyn_dgm_nonhydro2d.o \ scale_atm_dyn_dgm_globalnonhydro3d_heve.o \ + scale_atm_dyn_dgm_globalnonhydro3d_hevi.o \ scale_atm_dyn_dgm_nonhydro3d_heve.o \ scale_atm_dyn_dgm_nonhydro3d_hevi.o \ scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o \ diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index f8efff4f..28f4a677 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -2,7 +2,7 @@ !> module Atmosphere / Dynamics HEVE !! !! @par Description -!! HEVE DGM scheme for Atmospheric dynamical process. +!! HEVE DGM scheme for Global Atmospheric Dynamical process. !! !! @author Team SCALE !< @@ -108,7 +108,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_Init( mesh ) do f_h=1, 4 do fp_v=1, elem%Nnode_v do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_v)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h + fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) end do end do @@ -116,10 +116,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_Init( mesh ) do f_v=1, 2 do fp_h2=1, elem%Nnode_h1D do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_h2)*elem%Nnode_h1D & - + (f_v-1) * elem%Nnode_h1D**2 & + fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & + + (f_v-1) * elem%Nfp_v & + 4 * elem%Nnode_h1D * elem%Nnode_v - iM2Dto3D(fp) = fp_h1 + (fp_h2)*elem%Nnode_h1D + iM2Dto3D(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D end do end do end do @@ -187,7 +187,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & real(RP) :: rP0 real(RP) :: RovP0, P0ovR real(RP) :: GIJ(elem%Np,2,2) - real(RP) :: X(elem%Np), Y(elem%Np), twordel2(elem%Np) + real(RP) :: X(elem%Np), Y(elem%Np), twoOVdel2(elem%Np) real(RP) :: CORI(elem%Np,2) real(RP) :: s logical :: is_panel1to4 @@ -199,8 +199,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) - lmesh%vmapM, lmesh%vmapP, lmesh, elem, & ! (in) - lmesh2D%vmapM, lmesh2D%vmapP, lmesh2D, elem2D ) ! (in) + lmesh%vmapM, lmesh%vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) !----- @@ -213,29 +212,28 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & s = 1.0_RP is_panel1to4 = .true. - if (lmesh%panelID == 5) then + if ( lmesh%panelID == 5 ) then is_panel1to4 = .false. - else if (lmesh%panelID == 6) then + else if ( lmesh%panelID == 6 ) then is_panel1to4 = .false. s = - 1.0_RP - else end if !$omp parallel private( & !$omp RHOT_, PRES_, rdens_, u_, v_, w_, ke2d, drho, & !$omp Fx, Fy, Fz, LiftDelFlx, & - !$omp GIJ, X, Y, twordel2, CORI ) + !$omp GIJ, X, Y, twoOVdel2, CORI ) !$omp do do ke = lmesh%NeS, lmesh%NeE !-- X(:) = lmesh%pos_en(:,ke,1) Y(:) = lmesh%pos_en(:,ke,2) - twordel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) + twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) - RHOT_(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT_(:,ke) - PRES_(:) = PRES00 * (RovP0 * RHOT_(:))**gamm + RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) + PRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm - rdens_(:) = 1.0_RP / (DDENS_(:,ke) + DENS_hyd(:,ke)) + rdens_(:) = 1.0_RP / ( DDENS_(:,ke) + DENS_hyd(:,ke) ) u_ (:) = MOMX_(:,ke) * rdens_(:) v_ (:) = MOMY_(:,ke) * rdens_(:) w_ (:) = MOMZ_(:,ke) * rdens_(:) @@ -243,13 +241,14 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & ke2d = lmesh%EMap3Dto2D(ke) GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) GIJ(:,2,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,1) - GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) + GIJ(:,1,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) - CORI(:,1) = s * OHM * twordel2(:) * ( - X(:) * Y(:) * MOMX_(:,ke) + (1.0_RP + Y(:)**2) * MOMY_(:,ke) ) - CORI(:,2) = s * OHM * twordel2(:) * ( - (1.0_RP + X(:)**2) * MOMX_(:,ke) + X(:) * Y(:) * MOMY_(:,ke) ) + CORI(:,1) = s * OHM * twoOVdel2(:) * ( - X(:) * Y(:) * MOMX_(:,ke) + (1.0_RP + Y(:)**2) * MOMY_(:,ke) ) + CORI(:,2) = s * OHM * twoOVdel2(:) * ( - (1.0_RP + X(:)**2) * MOMX_(:,ke) + X(:) * Y(:) * MOMY_(:,ke) ) if ( is_panel1to4 ) then - CORI(:,1) = Y(:); CORI(:,2) = Y(:) + CORI(:,1) = Y(:) * CORI(:,1) + CORI(:,2) = Y(:) * CORI(:,2) end if drho(:) = matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) @@ -269,36 +268,36 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !-- MOMX call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * PRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * PRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMX_ID), LiftDelFlx) MOMX_dt(:,ke) = & - - ( lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & - + twordel2 * Y(:) * & - ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2)*v_(:) ) * MOMX_(:,ke) & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twoOVdel2(:) * Y(:) * & + ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & + CORI(:,1) !-- MOMY call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * PRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * PRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMY_ID), LiftDelFlx) MOMY_dt(:,ke) = & - - ( lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & - + twordel2 * X(:) * & - ( (1.0_RP + X(:)**2)*u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twoOVdel2(:) * X(:) * & + ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + CORI(:,2) !-- MOMZ - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( w_(:) * MOMZ_(:,ke) + PRES_(:) - PRES_hyd(:,ke) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMZ_ID), LiftDelFlx) @@ -319,7 +318,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + lmesh%Escale(:,ke,2,2) * Fy(:) & + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + end do !$omp end do !$omp end parallel @@ -342,7 +342,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend subroutine cal_del_flux_dyn( del_flux, & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & Gsqrt, G11, G12, G22, nx, ny, nz, & - vmapM, vmapP, lmesh, elem, vmapM_2d, vmapP_2d, lmesh2D, elem2D ) + vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) implicit none @@ -359,19 +359,17 @@ subroutine cal_del_flux_dyn( del_flux, & real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) - real(RP), intent(in) :: G11(elem2D%Np*lmesh2D%Ne) - real(RP), intent(in) :: G12(elem2D%Np*lmesh2D%Ne) - real(RP), intent(in) :: G22(elem2D%Np*lmesh2D%Ne) + real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapM_2d(elem2D%NfpTot,lmesh2D%Ne) - integer, intent(in) :: vmapP_2d(elem2D%NfpTot,lmesh2D%Ne) integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) - integer :: ke2D, iM_2d(elem%NfpTot) + integer :: ke2D real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) real(RP) :: dpres(elem%NfpTot), presM(elem%NfpTot), presP(elem%NfpTot) real(RP) :: densM(elem%NfpTot), densP(elem%NfpTot) @@ -383,7 +381,6 @@ subroutine cal_del_flux_dyn( del_flux, & real(RP) :: DRHOT_P(elem%NfpTot), DRHOT_M(elem%NfpTot) real(RP) :: PRES_hyd_P(elem%NfpTot), PRES_hyd_M(elem%NfpTot) real(RP) :: Gsqrt_M(elem%NfpTot) - real(RP) :: G11_2D(elem2D%NfpTot), G12_2D(elem2D%NfpTot), G22_2D(elem2D%NfpTot) real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) , Gnn_M(elem%NfpTot) real(RP) :: gamm, rgamm real(RP) :: rP0 @@ -397,18 +394,16 @@ subroutine cal_del_flux_dyn( del_flux, & P0ovR = PRES00 / Rdry !$omp parallel do private( & - !$omp ke, iM, iP, ke2d, iM_2d, & + !$omp ke, iM, iP, ke2d, & !$omp alpha, VelM, VelP, & !$omp dpres, presM, presP, densM, densP, rhotM, rhotP, & !$omp MOMX_M, MOMX_P, MOMY_M, MOMY_P, MOMZ_M, MOMZ_P, & !$omp DDENS_M, DDENS_P, DRHOT_M, DRHOT_P, & !$omp PRES_hyd_M, PRES_hyd_P, & - !$omp Gsqrt_M, G1n_M, G2n_M, Gnn_M, G11_2D, G12_2D, G22_2D ) + !$omp Gsqrt_M, G1n_M, G2n_M, Gnn_M ) do ke=lmesh%NeS, lmesh%NeE - ke2D = lmesh%EMap3Dto2D(ke) iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) - iM_2d(:) = vmapM_2d(:,ke2D) DDENS_M(:) = DDENS_(iM) DDENS_P(:) = DDENS_(iP) @@ -424,12 +419,11 @@ subroutine cal_del_flux_dyn( del_flux, & PRES_hyd_P(:) = PRES_hyd(iP) Gsqrt_M(:) = Gsqrt(iM) - G11_2D(:) = G11(iM_2d(:)) - G12_2D(:) = G12(iM_2d(:)) - G22_2D(:) = G22(iM_2d(:)) - G1n_M(:) = G11_2D(iM2Dto3D(:)) * nx(:,ke) + G12(iM2Dto3D(:)) * ny(:,ke) - G2n_M(:) = G12_2D(iM2Dto3D(:)) * nx(:,ke) + G22(iM2Dto3D(:)) * ny(:,ke) - Gnn_M(:) = G11_2D(iM2Dto3D(:)) * abs(nx(:,ke)) + G22(iM2Dto3D(:)) * abs(ny(:,ke)) + + ke2D = lmesh%EMap3Dto2D(ke) + G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) + G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) densM(:) = DDENS_M(:) + DENS_hyd(iM) densP(:) = DDENS_P(:) + DENS_hyd(iP) @@ -448,19 +442,19 @@ subroutine cal_del_flux_dyn( del_flux, & alpha(:) = max( sqrt( Gnn_M(:) * gamm * presM(:) / densM(:) ) + abs(VelM(:)), & sqrt( Gnn_M(:) * gamm * presP(:) / densP(:) ) + abs(VelP(:)) ) - + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * Gsqrt_M(:) * ( & ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) del_flux(:,ke,VARS_MOMX_ID) = 0.5_RP * Gsqrt_M(:) * ( & ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & - + G1n_M(:) * dpres(:) & + + G1n_M(:) * dpres(:) & - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) del_flux(:,ke,VARS_MOMY_ID) = 0.5_RP * Gsqrt_M(:) * ( & ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & - + G2n_M(:) * dpres(:) & + + G2n_M(:) * dpres(:) & - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) del_flux(:,ke,VARS_MOMZ_ID) = 0.5_RP * Gsqrt_M(:) * ( & @@ -471,6 +465,7 @@ subroutine cal_del_flux_dyn( del_flux, & del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * Gsqrt_M(:) * ( & ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) + end do return diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 index 430b87aa..94cd503f 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 @@ -174,7 +174,7 @@ subroutine AtmosMeshGM_create_communicator( this, sfield_num, hvfield_num, var_m !----------------------------------------------------- commid = this%Get_communicatorID( ATM_MESH_MAX_COMMNUICATOR_NUM ) - call this%comm_list(commid)%Init( hvfield_num, sfield_num, this%mesh ) + call this%comm_list(commid)%Init( sfield_num, hvfield_num, this%mesh ) call var_manager%MeshFieldComm_Prepair( this%comm_list(commid), field_list ) return diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 index bc4ecd6b..eaae1fd9 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 @@ -187,7 +187,7 @@ subroutine AtmosMeshRM_create_communicator( this, sfield_num, hvfield_num, var_m !----------------------------------------------------- commid = this%Get_communicatorID( ATM_MESH_MAX_COMMNUICATOR_NUM ) - call this%comm_list(commid)%Init( hvfield_num, sfield_num, this%mesh ) + call this%comm_list(commid)%Init(sfield_num, hvfield_num, this%mesh ) call var_manager%MeshFieldComm_Prepair( this%comm_list(commid), field_list ) return diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 index 167488f8..ef6a6188 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 @@ -83,29 +83,31 @@ module mod_atmos_vars ! Prognostic variables in dynamical process - integer, public, parameter :: ATMOS_PROGVARS_DDENS_ID = 1 - integer, public, parameter :: ATMOS_PROGVARS_MOMX_ID = 2 - integer, public, parameter :: ATMOS_PROGVARS_MOMY_ID = 3 - integer, public, parameter :: ATMOS_PROGVARS_MOMZ_ID = 4 - integer, public, parameter :: ATMOS_PROGVARS_DRHOT_ID = 5 - integer, public, parameter :: ATMOS_PROGVARS_NUM = 5 + integer, public, parameter :: ATMOS_PROGVARS_DDENS_ID = 1 + integer, public, parameter :: ATMOS_PROGVARS_DRHOT_ID = 2 + integer, public, parameter :: ATMOS_PROGVARS_MOMZ_ID = 3 + integer, public, parameter :: ATMOS_PROGVARS_MOMX_ID = 4 + integer, public, parameter :: ATMOS_PROGVARS_MOMY_ID = 5 + integer, public, parameter :: ATMOS_PROGVARS_SCALAR_NUM = 3 + integer, public, parameter :: ATMOS_PROGVARS_HVEC_NUM = 1 + integer, public, parameter :: ATMOS_PROGVARS_NUM = 5 type(VariableInfo), public :: ATMOS_PROGVARS_VINFO(ATMOS_PROGVARS_NUM) DATA ATMOS_PROGVARS_VINFO / & VariableInfo( ATMOS_PROGVARS_DDENS_ID, 'DDENS', 'deviation of density', & 'kg/m3', 3, 'XYZ', 'air_density' ), & + VariableInfo( ATMOS_PROGVARS_DRHOT_ID, 'DRHOT', 'deviation of rho * theta', & + 'kg/m3*K', 3, 'XYZ', '' ), & + VariableInfo( ATMOS_PROGVARS_MOMZ_ID , 'MOMZ', 'momentum z', & + 'kg/m2/s', 3, 'XYZ', 'northward_mass_flux_of_air' ), & VariableInfo( ATMOS_PROGVARS_MOMX_ID , 'MOMX', 'momentum x', & 'kg/m2/s', 3, 'XYZ', 'upward_mass_flux_of_air' ), & VariableInfo( ATMOS_PROGVARS_MOMY_ID , 'MOMY', 'momentum y', & - 'kg/m2/s', 3, 'XYZ', 'eastward_mass_flux_of_air' ), & - VariableInfo( ATMOS_PROGVARS_MOMZ_ID , 'MOMZ', 'momentum z', & - 'kg/m2/s', 3, 'XYZ', 'northward_mass_flux_of_air' ), & - VariableInfo( ATMOS_PROGVARS_DRHOT_ID, 'DRHOT', 'deviation of rho * theta', & - 'kg/m3*K', 3, 'XYZ', '' ) / + 'kg/m2/s', 3, 'XYZ', 'eastward_mass_flux_of_air' ) / - real(RP), parameter :: PROGVARS_check_min(ATMOS_PROGVARS_NUM) = (/ -1.0_RP, -200.0_RP, -200.0_RP, -200.0_RP, -100.0_RP /) - real(RP), parameter :: PROGVARS_check_max(ATMOS_PROGVARS_NUM) = (/ 1.0_RP, 200.0_RP, 200.0_RP, 200.0_RP, 100.0_RP /) + real(RP), parameter :: PROGVARS_check_min(ATMOS_PROGVARS_NUM) = (/ -1.0_RP, -100.0_RP, -200.0_RP, -200.0_RP, -200.0_RP /) + real(RP), parameter :: PROGVARS_check_max(ATMOS_PROGVARS_NUM) = (/ 1.0_RP, 100.0_RP, 200.0_RP, 200.0_RP, 200.0_RP /) ! Reference state @@ -271,10 +273,10 @@ subroutine AtmosVars_Init( this, atm_mesh ) end do call atm_mesh%Create_communicator( & - ATMOS_PROGVARS_NUM, 0, & ! (in) - this%PROGVARS_manager, & ! (inout) - this%PROG_VARS(:), & ! (in) - this%PROG_VARS_commID ) ! (out) + ATMOS_PROGVARS_SCALAR_NUM, ATMOS_PROGVARS_HVEC_NUM, & ! (in) + this%PROGVARS_manager, & ! (inout) + this%PROG_VARS(:), & ! (in) + this%PROG_VARS_commID ) ! (out) LOG_NEWLINE LOG_INFO("ATMOS_vars_setup",*) 'List of prognostic variables (ATMOS) ' From f8d26625ebba815f2e9c51cf97d2209e812a9646 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:33:37 +0900 Subject: [PATCH 37/98] Provide the subroutines for preparing initial data of idealized test cases. --- .../scale_atm_dyn_dgm_hydrostatic.F90 | 32 ++++++++ .../src/preprocess/mod_mkinit_util.F90 | 75 +++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 index d6c4c029..b7da4379 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 @@ -44,6 +44,7 @@ module scale_atm_dyn_dgm_hydrostatic ! !++ Public procedures ! + public :: hydrostatic_calc_basicstate_constT public :: hydrostatic_calc_basicstate_constPT public :: hydrostatic_calc_basicstate_constPTLAPS public :: hydrostatic_calc_basicstate_constBVFreq @@ -60,6 +61,37 @@ module scale_atm_dyn_dgm_hydrostatic ! contains + subroutine hydrostatic_calc_basicstate_constT( & + DENS_hyd, PRES_hyd, & + Temp0, PRES_sfc, x, y, z, lcmesh3D, elem ) + + implicit none + + class(LocalMesh3D), intent(in) :: lcmesh3D + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh3D%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh3D%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh3D%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh3D%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh3D%Ne) + real(RP), intent(in) :: Temp0 + real(RP), intent(in) :: PRES_sfc + + integer :: ke + real(RP) :: H0 + !----------------------------------------------- + + H0 = Rdry * Temp0 / Grav + + !$omp parallel do + do ke=lcmesh3D%NeS, lcmesh3D%NeE + PRES_hyd(:,ke) = PRES_sfc * exp( - z(:,ke) / H0 ) + DENS_hyd(:,ke) = PRES_hyd(:,ke) / ( Rdry * Temp0 ) + end do + + return + end subroutine hydrostatic_calc_basicstate_constT + subroutine hydrostatic_calc_basicstate_constPT( & DENS_hyd, PRES_hyd, & PotTemp0, PRES_sfc, x, y, z, lcmesh3D, elem ) diff --git a/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 b/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 index 4493df58..c83e85d1 100644 --- a/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 +++ b/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 @@ -39,6 +39,7 @@ module mod_mkinit_util public :: mkinitutil_gen_GPMat public :: mkinitutil_gen_Vm1Mat public :: mkinitutil_calc_cosinebell + public :: mkinitutil_calc_cosinebell_global contains @@ -170,6 +171,80 @@ subroutine mkinitutil_calc_cosinebell( & return end subroutine mkinitutil_calc_cosinebell + subroutine mkinitutil_calc_cosinebell_global( & + q, & + qmax, rh, lonc, latc, rplanet, & + x, y, z, lcmesh3D, elem, & + IntrpPolyOrder_h, IntrpPolyOrder_v ) + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatCoord + implicit none + + class(LocalMesh3D), intent(in) :: lcmesh3D + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: q(elem%Np,lcmesh3D%NeA) + real(RP), intent(in) :: qmax + real(RP), intent(in) :: rh + real(RP), intent(in) :: lonc, latc + real(RP), intent(in) :: rplanet + real(RP), intent(in) :: x(elem%Np,lcmesh3D%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh3D%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh3D%Ne) + integer, intent(in) :: IntrpPolyOrder_h + integer, intent(in) :: IntrpPolyOrder_v + + integer :: ke + + type(HexahedralElement) :: elem_intrp + real(RP), allocatable :: x_intrp(:,:), y_intrp(:,:), z_intrp(:,:) + real(RP), allocatable :: lon_intrp(:,:), lat_intrp(:,:) + real(RP), allocatable :: r_intrp(:) + real(RP) :: vx(elem%Nv), vy(elem%Nv), vz(elem%Nv) + + real(RP), allocatable :: IntrpMat(:,:) + real(RP), allocatable :: q_intrp(:) + !----------------------------------------------- + + call elem_intrp%Init( IntrpPolyOrder_h, IntrpPolyOrder_v, .false. ) + + allocate( IntrpMat(elem%Np,elem_intrp%Np) ) + call mkinitutil_gen_GPMat( IntrpMat, elem_intrp, elem ) + + allocate( x_intrp(elem_intrp%Np,lcmesh3D%Ne), y_intrp(elem_intrp%Np,lcmesh3D%Ne), z_intrp(elem_intrp%Np,lcmesh3D%Ne) ) + allocate( lon_intrp(elem_intrp%Np,lcmesh3D%Ne), lat_intrp(elem_intrp%Np,lcmesh3D%Ne) ) + allocate( r_intrp(elem_intrp%Np) ) + allocate( q_intrp(elem_intrp%Np) ) + + + !$omp parallel do private(vx, vy, vz) + do ke=lcmesh3D%NeS, lcmesh3D%NeE + vx(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),1) + vy(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),2) + vz(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),3) + x_intrp(:,ke) = vx(1) + 0.5_RP * ( elem_intrp%x1(:) + 1.0_RP ) * ( vx(2) - vx(1) ) + y_intrp(:,ke) = vy(1) + 0.5_RP * ( elem_intrp%x2(:) + 1.0_RP ) * ( vy(4) - vy(1) ) + z_intrp(:,ke) = vz(1) + 0.5_RP * ( elem_intrp%x3(:) + 1.0_RP ) * ( vz(5) - vz(1) ) + end do + + call CubedSphereCnv_CS2LonLatCoord( lcmesh3D%panelID, x_intrp, y_intrp, elem_intrp%Np * lcmesh3D%Ne, & + rplanet, lon_intrp(:,:), lat_intrp(:,:) ) + + !$omp parallel do private( r_intrp, q_intrp ) + do ke=lcmesh3D%NeS, lcmesh3D%NeE + r_intrp(:) = rplanet / rh * acos( sin(latc) * sin(lat_intrp(:,ke)) + cos(latc) * cos(lat_intrp(:,ke)) * cos(lon_intrp(:,ke) - lonc) ) + where( r_intrp(:) <= 1.0_RP ) + q_intrp(:) = qmax * cos( 0.5_RP * PI * r_intrp(:) ) + elsewhere + q_intrp(:) = 0.0_RP + end where + q(:,ke) = matmul(IntrpMat, q_intrp) + end do + + call elem_intrp%Final() + + return + end subroutine mkinitutil_calc_cosinebell_global !------------------------------------------ From c3f0d9575c96d775dedf890a73c5090f220d189a Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:37:23 +0900 Subject: [PATCH 38/98] Update a test case of soud wave in 3D regional and global cubed sphere domains. --- .../test/case/sound_wave/mod_user.F90 | 2 +- .../test/case/sound_wave_global/cs2lonlat.cnf | 35 +++++++ .../test/case/sound_wave_global/init.conf | 31 +++--- .../test/case/sound_wave_global/mod_user.F90 | 69 +++++++------- .../test/case/sound_wave_global/run.conf | 68 ++++++++----- .../test/case/sound_wave_global/run_heve.conf | 95 +++++++++++++++++++ 6 files changed, 222 insertions(+), 78 deletions(-) create mode 100644 model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf create mode 100644 model/atm_nonhydro3d/test/case/sound_wave_global/run_heve.conf diff --git a/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 b/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 index 3ce0e78b..cdda8150 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 @@ -218,7 +218,7 @@ subroutine exp_SetInitCond_sound_wave( this, & do ke=lcmesh%NeS, lcmesh%NeE DRHOT(:,ke) = PRES00/Rdry * ( & ( ( PRES_hyd(:,ke) + PRES_purtub(:,ke) ) / PRES00 )**rgamm & - - ( PRES_hyd(:,ke) / PRES00 )*rgamm ) + - ( PRES_hyd(:,ke) / PRES00 )**rgamm ) end do return diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf new file mode 100644 index 00000000..d9c15e49 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf @@ -0,0 +1,35 @@ +&PARAM_IO + IO_LOG_BASENAME = "cs2lonlat_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="./history", + vars = "W", "DDENS", "DRHOT", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_INTERP_MESH + !-- input ---------------- + in_Nprc = 6, + in_NeGX = 5, + in_NeGY = 5, + in_NeGZ = 3, + in_PolyOrder_h = 7, + in_PolyOrder_v = 7, + in_NLocalMeshPerPrc = 1, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + !-- output ---------------- + out_NprcX = 2, + out_NeX = 32, + out_NprcY = 2, + out_NeY = 16, + out_NeZ = 15, + out_PolyOrder_h =2, + out_PolyOrder_v =2, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf b/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf index 225ac462..b35b6ef5 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/init.conf @@ -13,18 +13,13 @@ TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, TIME_STARTMS = 0.D0, / -&PARAM_CONST - CONST_GRAV = 0D0, -/ &PARAM_EXP TEMP0 = 300.0D0, - DPRES = 0.1D0, - x_c = 0.0D3, - y_c = 0.0D3, - z_c = 5.0D3, - r_x = 1.0D20, - r_y = 1.0D20, - r_z = 1.0D3, + DPRES = 100.0D0, +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +! CONST_GRAV = 0.0D0, / #** ATMOS ****************************************************** &PARAM_ATMOS @@ -33,15 +28,15 @@ ATMOS_DYN_DO = .true. / &PARAM_ATMOS_MESH - NLocalMeshNum = 6, - Nprc = 1, - NeGX = 1, - NeGY = 1, - NeZ = 30, - dom_zmin = 0.0D0, + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + NeZ = 3, + dom_zmin = 0.0D0, dom_zmax = 10.0D3, - PolyOrder_h = 1, - PolyOrder_v = 1, + PolyOrder_h = 7, + PolyOrder_v = 7, ! LumpedMassMatFlag = .true., / #** ATMOS / DYN ****************************************************** diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 index 94563683..8e75f9c0 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 @@ -129,17 +129,18 @@ subroutine exp_SetInitCond_sound_wave( this, & lcmesh, elem ) use scale_const, only: & - PI => CONST_PI, & - GRAV => CONST_GRAV, & - Rdry => CONST_Rdry, & - CPdry => CONST_CPdry, & - CVdry => CONST_CVdry, & - PRES00 => CONST_PRE00 + PI => CONST_PI, & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS use scale_atm_dyn_dgm_hydrostatic, only: & - hydrostatic_calc_basicstate_constPT + hydrostatic_calc_basicstate_constT use mod_mkinit_util, only: & - mkinitutil_calc_cosinebell + mkinitutil_calc_cosinebell_global implicit none @@ -161,18 +162,19 @@ subroutine exp_SetInitCond_sound_wave( this, & real(RP), intent(in) :: dom_zmin, dom_zmax real(RP) :: TEMP0 = 300.0_RP - real(RP) :: DPRES = 1.0_RP - real(RP) :: x_c, y_c, z_c - real(RP) :: r_x, r_y, r_z - + real(RP) :: DPRES = 100.0_RP + real(RP) :: lonc, latc + real(RP) :: rh + integer :: nv + real(RP) :: Zt namelist /PARAM_EXP/ & TEMP0, DPRES, & - x_c, y_c, z_c, & - r_x, r_y, r_z - - integer, parameter :: IntrpPolyOrder_h = 6 - integer, parameter :: IntrpPolyOrder_v = 6 + lonc, latc, rh, & + nv + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 real(RP), allocatable :: PRES_purtub(:,:) + real(RP) :: pres(elem%Np) real(RP) :: rgamm @@ -180,13 +182,10 @@ subroutine exp_SetInitCond_sound_wave( this, & integer :: ierr !----------------------------------------------------------------------------- - x_c = 0.5_RP * (dom_xmax + dom_xmin) - y_c = 0.5_RP * (dom_ymax + dom_ymin) - z_c = 0.5_RP * (dom_zmax + dom_zmin) - - r_x = 0.1_RP * (dom_xmax - dom_xmin) - r_y = 0.1_RP * (dom_ymax - dom_ymin) - r_z = 0.1_RP * (dom_zmax - dom_zmin) + rh = RPlanet / 3.0_RP + lonc = 0.0_RP + latc = 0.0_RP + nv = 1 rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) @@ -201,24 +200,26 @@ subroutine exp_SetInitCond_sound_wave( this, & !--- allocate( PRES_purtub(elem%Np,lcmesh%NeA) ) - ! call mkinitutil_calc_cosinebell( & - ! PRES_purtub, & - ! DPRES, r_x, r_y, r_z, x_c, y_c, z_c, & - ! x, y, z, lcmesh, elem, & - ! IntrpPolyOrder_h, IntrpPolyOrder_v ) + call mkinitutil_calc_cosinebell_global( & + PRES_purtub, & + DPRES, rh, lonc, latc, RPlanet, & + x, y, z, lcmesh, elem, & + IntrpPolyOrder_h, IntrpPolyOrder_v ) - call hydrostatic_calc_basicstate_constPT( DENS_hyd, PRES_hyd, & + call hydrostatic_calc_basicstate_constT( DENS_hyd, PRES_hyd, & TEMP0, PRES00, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), lcmesh%pos_en(:,:,3), & lcmesh, elem ) !--- rgamm = CvDry / CpDry + Zt = dom_zmax - dom_zmin - !$omp parallel do + !$omp parallel do private(pres) do ke=lcmesh%NeS, lcmesh%NeE - DRHOT(:,ke) = 0.0_RP!PRES00/Rdry * ( & -! ( ( PRES_hyd(:,ke) + PRES_purtub(:,ke) ) / PRES00 )**rgamm & -! - ( PRES_hyd(:,ke) / PRES00 )*rgamm ) + pres(:) = PRES_hyd(:,ke) + PRES_purtub(:,ke) * sin( dble(nv) * PI * z(:,ke) / Zt ) + DRHOT(:,ke) = PRES00/Rdry * ( & + ( pres(:) / PRES00 )**rgamm & + - ( PRES_hyd(:,ke) / PRES00 )**rgamm ) end do return diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf b/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf index 010014f3..98e3c8aa 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf @@ -7,64 +7,69 @@ &PARAM_TIME TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, TIME_STARTMS = 0.D0, - TIME_DURATION = 0.25D0, - TIME_DURATION_UNIT = 'SEC', - TIME_DT = 0.25D0, + TIME_DURATION = 24.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 360.0D0, TIME_DT_UNIT = 'SEC', / &PARAM_CONST - CONST_GRAV = 0D0, + CONST_OHM = 0.0D0, +! CONST_GRAV = 0.0D0, / #** ATMOS ****************************************************** &PARAM_ATMOS ATMOS_MESH_TYPE = 'GLOBAL', ACTIVATE_FLAG = .true., - TIME_DT = 0.25D0, + TIME_DT = 360.0D0, TIME_DT_UNIT = 'SEC', ATMOS_DYN_DO = .true. / &PARAM_ATMOS_MESH - NLocalMeshNum = 6, - Nprc = 1, - NeGX = 1, - NeGY = 1, - NeZ = 30, + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + NeZ = 3, dom_zmin = 0.0D0, dom_zmax = 10.0D3, - PolyOrder_h = 1, - PolyOrder_v = 1, -! LumpedMassMatFlag = .true., + PolyOrder_h = 7, + PolyOrder_v = 7, + LumpedMassMatFlag = .true., +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., / #** ATMOS / DYN ****************************************************** &PARAM_ATMOS_DYN - EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + EQS_TYPE = "GLOBALNONHYDRO3D_HEVI", !- - TINTEG_TYPE = 'ERK_SSP_3s3o', - TIME_DT = 0.25D0, + TINTEG_TYPE = 'IMEX_ARK324', ! [IMEX_ARK_232, IMEX_ARK324, RK_TVD_3] + TIME_DT = 120.0D0, TIME_DT_UNIT = 'SEC', !- MODALFILTER_FLAG = .false., NUMDIFF_FLAG = .false., / +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.66666666666666D0, + MF_ALPHA_h = 0.2D0, + MF_ORDER_h = 8, + MF_ETAC_v = 0.66666666666666D0, + MF_ALPHA_v = 0.2D0, + MF_ORDER_v = 8, +/ &PARAM_ATMOS_DYN_BND btm_vel_bc = 'SLIP', top_vel_bc = 'SLIP', - north_vel_bc = 'PERIODIC', - south_vel_bc = 'PERIODIC', - east_vel_bc = 'PERIODIC', - west_vel_bc = 'PERIODIC', btm_thermal_bc = 'ADIABATIC', top_thermal_bc = 'ADIABATIC', - north_thermal_bc = 'PERIODIC', - south_thermal_bc = 'PERIODIC', - west_thermal_bc = 'PERIODIC', - east_thermal_bc = 'PERIODIC', / #*** OUTPUT ******************************************* &PARAM_FILE_HISTORY FILE_HISTORY_DEFAULT_BASENAME = "history", - FILE_HISTORY_DEFAULT_TINTERVAL = 0.25D0, + FILE_HISTORY_DEFAULT_TINTERVAL = 7200.0D0, FILE_HISTORY_DEFAULT_TUNIT = "SEC", FILE_HISTORY_DEFAULT_TAVERAGE = .false., FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", @@ -82,4 +87,17 @@ &HISTORY_ITEM name='PRES_hyd' / !&HISTORY_ITEM name='DTHETA' / +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/run_heve.conf b/model/atm_nonhydro3d/test/case/sound_wave_global/run_heve.conf new file mode 100644 index 00000000..212e70ad --- /dev/null +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/run_heve.conf @@ -0,0 +1,95 @@ +#--- Configuration file for a test case of sound wave ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 4.0D0, !24.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 6D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +! CONST_GRAV = 0.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 6D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + NeZ = 3, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, +! LumpedMassMatFlag = .true., +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + TIME_DT = 0.3D0 + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .false., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 1800.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='DDENS' / +&HISTORY_ITEM name='MOMX' / +&HISTORY_ITEM name='MOMY' / +&HISTORY_ITEM name='MOMZ' / +&HISTORY_ITEM name='DRHOT' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='W' / +!&HISTORY_ITEM name='DPRES' / +&HISTORY_ITEM name='DENS_hyd' / +&HISTORY_ITEM name='PRES_hyd' / +!&HISTORY_ITEM name='DTHETA' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + From 96b238f0120c30d1c8482b57242856fc0c0c8060 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 29 May 2021 02:40:15 +0900 Subject: [PATCH 39/98] Fix some bugs in cs2lonlat program. --- .../mod_cs2lonlat_interp_field.F90 | 27 ++++++++++--------- .../mod_cs2lonlat_interp_mesh.F90 | 5 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 index 9dfcb39a..0e8913e9 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 @@ -325,8 +325,7 @@ subroutine interpolate_local_2D( out_val, & use scale_polynominal, only: & Polynominal_GenLegendrePoly_sub use mod_cs2lonlat_interp_mesh, only: & - nodeMap_list, & - in_Nprc, in_elem2D, in_NLocalMeshPerPrc + in_elem2D implicit none class(LocalMesh2D), intent(in) :: out_lcmesh @@ -338,6 +337,7 @@ subroutine interpolate_local_2D( out_val, & type(NodeMappingInfo), intent(in), target :: mappingInfo class(MeshRectDom2D), intent(in) :: out_mesh2D + integer :: nprc_local integer :: ke2D, ke_h integer :: p, p_h, pX, pY integer :: p1, p2, l @@ -359,9 +359,10 @@ subroutine interpolate_local_2D( out_val, & !--------------------------------------------- - allocate( in_val_list(in_Nprc) ) + nprc_local = size(mappingInfo%in_mesh3D_list) + allocate( in_val_list(nprc_local) ) - do in_prc=1, in_Nprc + do in_prc=1, nprc_local in_rank = in_prc - 1 in_csmesh => mappingInfo%in_mesh2D_list(in_prc) @@ -444,7 +445,7 @@ subroutine interpolate_local_2D( out_val, & end do end do - do in_prc=1, in_Nprc + do in_prc=1, nprc_local deallocate( in_val_list(in_prc)%spectral_coef2D ) end do @@ -466,9 +467,7 @@ subroutine interpolate_local_3D( out_val, & use scale_polynominal, only: & Polynominal_GenLegendrePoly_sub use mod_cs2lonlat_interp_mesh, only: & - nodeMap_list, & - in_Nprc, in_elem3D, in_NLocalMeshPerPrc - + in_elem3D implicit none class(LocalMesh3D), intent(in) :: out_lcmesh class(ElementBase3D), intent(in) :: out_elem3D @@ -479,6 +478,7 @@ subroutine interpolate_local_3D( out_val, & type(NodeMappingInfo), intent(in), target :: mappingInfo class(MeshCubeDom3D), intent(in) :: out_mesh3D + integer :: nprc_local integer :: ke3D, ke_h integer :: p, p_h, pX, pY, pZ integer :: p1, p2, p3, l @@ -498,12 +498,13 @@ subroutine interpolate_local_3D( out_val, & real(RP) :: vx(in_elem3D%Nv), vy(in_elem3D%Nv), vz(in_elem3D%Nv) integer :: node_ids(in_elem3D%Nv) type(MeshField3D) :: tmp_field3D - !--------------------------------------------- - allocate( in_val_list(in_Nprc) ) + nprc_local = size(mappingInfo%in_mesh3D_list) - do in_prc=1, in_Nprc + allocate( in_val_list(nprc_local) ) + + do in_prc=1, nprc_local in_rank = in_prc - 1 in_csmesh => mappingInfo%in_mesh3D_list(in_prc) @@ -530,7 +531,7 @@ subroutine interpolate_local_3D( out_val, & call tmp_field3D%Final() end do - + !$omp parallel do collapse(3) private( ke_h, ke3D, & !$omp pX, pY, pZ, p_h, p, in_domID, in_prc, & !$omp in_ex, in_ey, in_ez, in_ke3D, & @@ -598,7 +599,7 @@ subroutine interpolate_local_3D( out_val, & end do end do - do in_prc=1, in_Nprc + do in_prc=1, nprc_local deallocate( in_val_list(in_prc)%spectral_coef3D ) end do diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 index 8318ac58..be5d4c58 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 @@ -214,10 +214,9 @@ subroutine interp_mesh_Init() call construct_map() else is_mesh3D = .true. - call in_elem3D%Init( in_PolyOrder_h, in_PolyOrder_v, .false. ) call out_elem3D%Init( out_PolyOrder_h, out_PolyOrder_v, .false. ) - + if ( is_spec_out_FZ ) then call out_mesh3D%Init( out_NprcX * out_NeX, out_NprcY * out_NeY, out_NeZ, & 0.0_RP, 360.0_RP, -90.0_RP, 90.0_RP, out_dom_zmin, out_dom_zmax, & @@ -236,7 +235,7 @@ subroutine interp_mesh_Init() call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude' ) call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatz', 'degree', 'longitude,latitude,altitude' ) call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzt', 'degree', 'longitude,latitude,altitude' ) - + call out_mesh3D%Generate() call construct_map( in_FZ(1:in_NeGZ+1), is_spec_in_FZ ) end if From 22dea3392b2182a3aa417c0d9be500f906b28d9c Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 31 May 2021 09:52:34 +0900 Subject: [PATCH 40/98] Fix a bug of the time interval at which restart data is output. --- FElib/src/common/scale_time_manager.F90 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/FElib/src/common/scale_time_manager.F90 b/FElib/src/common/scale_time_manager.F90 index b314ba8a..d0f45580 100644 --- a/FElib/src/common/scale_time_manager.F90 +++ b/FElib/src/common/scale_time_manager.F90 @@ -102,6 +102,8 @@ module scale_time_manager integer, public :: TIME_ENDDAY real(DP), public :: TIME_ENDSEC + real(DP), public :: TIME_DURATIONSEC + logical, public :: TIME_DOresume logical, public :: TIME_DOend @@ -190,7 +192,6 @@ subroutine TIME_manager_Init( & real(DP) :: cftime(1) character(len=H_MID) :: cfunits - real(DP) :: TIME_DURATIONSEC character(len=27) :: startchardate character(len=27) :: endchardate @@ -526,6 +527,9 @@ subroutine TIME_manager_component_Init( this, comp_name, & character(*), intent(in) :: dt_unit real(DP), intent(in) :: dt_restart character(*), intent(in) :: dt_restart_unit + + real(RP) :: start_sec, end_sec + real(RP) :: absday, absdaysec, abssec !------------------------------------------------------------------------ this%process_num = 0 @@ -555,7 +559,7 @@ subroutine TIME_manager_component_Init( this, comp_name, & if (dt_restart == UNDEF8) then LOG_INFO_CONT(*) 'Not found TIME_DT_'//trim(comp_name)//'_RESTART. TIME_DURATION is used.' - this%dtsec_restart = TIME_ENDSEC - TIME_STARTSEC + this%dtsec_restart = TIME_DURATIONSEC else call CALENDAR_unit2sec( this%dtsec_restart, dt_restart, dt_restart_unit ) end if @@ -734,4 +738,6 @@ subroutine TIME_manager_process_checkstate( this ) return end subroutine TIME_manager_process_checkstate +!-- + end module scale_time_manager \ No newline at end of file From de080978cfeeedc1af7e618f08aafd8d178648a0 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 31 May 2021 09:53:28 +0900 Subject: [PATCH 41/98] Support history_in. --- .../src/file/scale_file_history_meshfield.F90 | 130 +++++++++++++++++- .../scale_model_var_manager.F90 | 14 +- 2 files changed, 140 insertions(+), 4 deletions(-) diff --git a/FElib/src/file/scale_file_history_meshfield.F90 b/FElib/src/file/scale_file_history_meshfield.F90 index ea954052..a75a8c4b 100644 --- a/FElib/src/file/scale_file_history_meshfield.F90 +++ b/FElib/src/file/scale_file_history_meshfield.F90 @@ -1,4 +1,13 @@ !------------------------------------------------------------------------------- +!> module file_history_meshfield +!! +!! @par Description +!! managing file history +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- #include "scaleFElib.h" module scale_file_history_meshfield !----------------------------------------------------------------------------- @@ -32,7 +41,9 @@ module scale_file_history_meshfield use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D - use scale_meshfield_base, only: MeshField1D, MeshField2D, MeshField3D + use scale_meshfield_base, only: & + MeshFieldBase, & + MeshField1D, MeshField2D, MeshField3D !----------------------------------------------------------------------------- implicit none @@ -43,6 +54,7 @@ module scale_file_history_meshfield ! public :: FILE_HISTORY_meshfield_setup public :: FILE_HISTORY_meshfield_put + public :: FILE_HISTORY_meshfield_in public :: FILE_HISTORY_meshfield_write public :: FILE_HISTORY_meshfield_finalize @@ -52,6 +64,12 @@ module scale_file_history_meshfield module procedure FILE_HISTORY_meshfield_put3D end interface + interface FILE_HISTORY_meshfield_in + module procedure FILE_HISTORY_meshfield_in1D + module procedure FILE_HISTORY_meshfield_in2D + module procedure FILE_HISTORY_meshfield_in3D + end interface + !----------------------------------------------------------------------------- ! !++ Public parameters & variables @@ -60,8 +78,11 @@ module scale_file_history_meshfield ! !++ Private procedures ! + !----------------------------------------------------------------------------- + ! + !++ Private variables + ! !------------------- - integer, parameter :: nzs = 1 character(len=8), parameter :: zs(nzs) = (/ "model " /) @@ -78,6 +99,8 @@ module scale_file_history_meshfield integer :: dims2D_size(2) integer :: dims3D_size(3,nzs) + logical, private :: FILE_HISTORY_FILEMESHFILED_DISABLE = .true. + contains !---------------- @@ -170,6 +193,8 @@ subroutine FILE_HISTORY_meshfield_setup( & call PRC_abort end if + FILE_HISTORY_FILEMESHFILED_DISABLE = .false. + return end subroutine FILE_HISTORY_meshfield_setup @@ -189,6 +214,8 @@ subroutine FILE_HISTORY_meshfield_finalize() return end subroutine FILE_HISTORY_meshfield_finalize + !-- 1D + subroutine FILE_HISTORY_meshfield_put1D(hstid, field1d) use scale_file_common_meshfield, only: & File_common_meshfield_put_field1D_cartesbuf @@ -207,6 +234,26 @@ subroutine FILE_HISTORY_meshfield_put1D(hstid, field1d) return end subroutine FILE_HISTORY_meshfield_put1D + subroutine FILE_HISTORY_meshfield_in1D( field1d, desc, standard_name ) + implicit none + class(MeshField1D), intent(in) :: field1d + character(len=*), intent(in) :: desc !< description of the item + character(len=*), intent(in), optional :: standard_name + + integer :: hstid + logical :: do_put + !------------------------------------------------- + + call history_in_regvar( hstid, do_put, & ! (out) + field1d, desc, 1, standard_name, 'XYZ' ) ! (in) + + if ( do_put ) call FILE_HISTORY_meshfield_put( hstid, field1d ) + + return + end subroutine FILE_HISTORY_meshfield_in1D + + !-- 2D + subroutine FILE_HISTORY_meshfield_put2D(hstid, field2d) use scale_file_common_meshfield, only: & File_common_meshfield_put_field2D_cartesbuf, & @@ -232,6 +279,26 @@ subroutine FILE_HISTORY_meshfield_put2D(hstid, field2d) return end subroutine FILE_HISTORY_meshfield_put2D + subroutine FILE_HISTORY_meshfield_in2D( field2d, desc, standard_name ) + implicit none + class(MeshField2D), intent(in) :: field2d + character(len=*), intent(in) :: desc !< description of the item + character(len=*), intent(in), optional :: standard_name + + integer :: hstid + logical :: do_put + !------------------------------------------------- + + call history_in_regvar( hstid, do_put, & ! (out) + field2d, desc, 2, standard_name, 'XY' ) ! (in) + + if ( do_put ) call FILE_HISTORY_meshfield_put( hstid, field2d ) + + return + end subroutine FILE_HISTORY_meshfield_in2D + + !-- 3D + subroutine FILE_HISTORY_meshfield_put3D(hstid, field3d) use scale_file_common_meshfield, only: & File_common_meshfield_put_field3D_cartesbuf, & @@ -256,9 +323,68 @@ subroutine FILE_HISTORY_meshfield_put3D(hstid, field3d) return end subroutine FILE_HISTORY_meshfield_put3D + + subroutine FILE_HISTORY_meshfield_in3D( field3d, desc, standard_name ) + implicit none + class(MeshField3D), intent(in) :: field3d + character(len=*), intent(in) :: desc !< description of the item + character(len=*), intent(in), optional :: standard_name + + integer :: hstid + logical :: do_put + !------------------------------------------------- + + call history_in_regvar( hstid, do_put, & ! (out) + field3d, desc, 3, standard_name, 'XYZ' ) ! (in) + + if ( do_put ) call FILE_HISTORY_meshfield_put( hstid, field3d ) + + return + end subroutine FILE_HISTORY_meshfield_in3D !---------------- + subroutine history_in_regvar( hstid, do_put, & + field, desc, ndim, standard_name, dim_type ) + + use scale_file_history, only: & + FILE_HISTORY_reg, & + FILE_HISTORY_query + + implicit none + + integer, intent(out) :: hstid + logical, intent(out) :: do_put + class(MeshFieldBase), intent(in) :: field + character(len=*), intent(in) :: desc !< description of the item + integer, intent(in) :: ndim + character(len=*), intent(in), optional :: standard_name + character(len=*), intent(in), optional :: dim_type + + logical, parameter :: fill_halo = .false. + !------------------------------------------------------ + + hstid = -1 + do_put = .false. + + if ( FILE_HISTORY_FILEMESHFILED_DISABLE ) return + + ! Check whether the item has been already registered + call FILE_HISTORY_reg( field%varname, desc, field%unit, & ! [IN] + hstid, & ! [OUT] + standard_name=standard_name, & ! [IN] + ndims=ndim, & ! [IN] + dim_type=dim_type, & ! [IN] + fill_halo=fill_halo ) ! [IN] + + if ( hstid < 0 ) return + + ! Check whether it is time to input the item + call FILE_HISTORY_query( hstid, do_put ) ! [IN], [OUT] + + return + end subroutine history_in_regvar + subroutine set_dim_axis1D() use scale_file_common_meshfield, only: & FILE_common_meshfield_diminfo, & diff --git a/FElib/src/model_framework/scale_model_var_manager.F90 b/FElib/src/model_framework/scale_model_var_manager.F90 index 641a1b34..4297c5e1 100644 --- a/FElib/src/model_framework/scale_model_var_manager.F90 +++ b/FElib/src/model_framework/scale_model_var_manager.F90 @@ -1,3 +1,13 @@ +!------------------------------------------------------------------------------- +!> module model_var_manager +!! +!! @par Description +!! managing data of variables used in models +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- #include "scaleFElib.h" module scale_model_var_manager !----------------------------------------------------------------------------- @@ -122,7 +132,7 @@ subroutine ModelVarManager_Regist1D( this, & call field%Init( varinfo%NAME, varinfo%UNIT, mesh ) if (reg_file_history_flag) then - call FILE_HISTORY_reg( varinfo%NAME, varinfo%DESC, varinfo%UNIT, field%hist_id, dim_type=varinfo%dim_type) + call FILE_HISTORY_reg( varinfo%NAME, varinfo%DESC, varinfo%UNIT, field%hist_id, dim_type=varinfo%dim_type ) end if if ( present(monitor_flag) ) then if (monitor_flag) then @@ -140,7 +150,7 @@ end subroutine ModelVarManager_Regist1D subroutine ModelVarManager_Regist2D( this, & varinfo, mesh, field, reg_file_history_flag, & - monitor_flag ) + monitor_flag ) use scale_mesh_base2d, only: Meshbase2d implicit none From 9e1b68545a045fac3d11e40e03ea045ce3769f11 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 31 May 2021 09:58:38 +0900 Subject: [PATCH 42/98] Available to output the velocity components in the lon-lat coordinate. --- model/atm_nonhydro2d/src/mod_atmos_vars.F90 | 6 +- .../src/atmos/mod_atmos_component.F90 | 2 +- .../src/atmos/mod_atmos_mesh.F90 | 13 ++ .../src/atmos/mod_atmos_mesh_gm.F90 | 35 +++++ .../src/atmos/mod_atmos_mesh_rm.F90 | 28 ++++ .../src/atmos/mod_atmos_vars.F90 | 142 +++++++++++++----- 6 files changed, 181 insertions(+), 45 deletions(-) diff --git a/model/atm_nonhydro2d/src/mod_atmos_vars.F90 b/model/atm_nonhydro2d/src/mod_atmos_vars.F90 index d98eb990..fcac2a6a 100644 --- a/model/atm_nonhydro2d/src/mod_atmos_vars.F90 +++ b/model/atm_nonhydro2d/src/mod_atmos_vars.F90 @@ -210,7 +210,7 @@ subroutine ATMOS_VARS_history() do n=1, mesh%LOCAL_MESH_NUM lcmesh => mesh%lcmesh_list(n) - call vars_calc_diagnoseVar( & + call vars_calc_diagnoseVar_lc( & U%local(n)%val, W%local(n)%val, DPRES%local(n)%val, TEMP%local(n)%val, DTHETA%local(n)%val, & DDENS%local(n)%val, MOMX%local(n)%val, MOMZ%local(n)%val, DRHOT%local(n)%val, & PRES_hydro%local(n)%val, DENS_hydro%local(n)%val, & @@ -227,7 +227,7 @@ subroutine ATMOS_VARS_history() return end subroutine ATMOS_VARS_history - subroutine vars_calc_diagnoseVar( & + subroutine vars_calc_diagnoseVar_lc( & U_, W_, DPRES_, TEMP_, DTHETA_, & DDENS_, MOMX_, MOMZ_, DRHOT_, PRES_hyd, DENS_hyd, & lcmesh, elem ) @@ -277,6 +277,6 @@ subroutine vars_calc_diagnoseVar( & end do return - end subroutine vars_calc_diagnoseVar + end subroutine vars_calc_diagnoseVar_lc end module mod_atmos_vars \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 index ef01f8eb..0569f782 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 @@ -291,7 +291,7 @@ subroutine Atmos_update( this ) !########## Calculate diagnostic variables ########## - call this%vars%Clac_diagnostics() + call this%vars%Calc_diagnostics() call this%vars%AUXVARS_manager%MeshFieldComm_Exchange() !########## Adjustment ########## diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 index 758dfde6..f149304d 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 @@ -36,6 +36,7 @@ module mod_atmos_mesh procedure(AtmosMesh_create_communicator), public, deferred :: Create_communicator procedure(AtmosMesh_setup_restartfile1), public, deferred :: Setup_restartfile1 procedure(AtmosMesh_setup_restartfile2), public, deferred :: Setup_restartfile2 + procedure(AtmosMesh_calc_UVMet), public, deferred :: Calc_UVmet generic :: Setup_restartfile => Setup_restartfile1, Setup_restartfile2 procedure :: Construct_ModalFilter3D => AtmosMesh_construct_ModalFilter3D procedure :: Construct_ModalFilterHV => AtmosMesh_construct_ModalFilterHV @@ -81,6 +82,18 @@ subroutine AtmosMesh_setup_restartfile2( this, restart_file, & integer, intent(in) :: var_num end subroutine AtmosMesh_setup_restartfile2 end interface + interface + subroutine AtmosMesh_calc_UVMet( this, U, V, & + Umet, Vmet ) + import AtmosMesh + import MeshField3D + class(AtmosMesh), target, intent(in) :: this + type(MeshField3D), intent(in) :: U + type(MeshField3D), intent(in) :: V + type(MeshField3D), intent(inout) :: Umet + type(MeshField3D), intent(inout) :: Vmet + end subroutine AtmosMesh_calc_UVMet + end interface integer, parameter, public :: ATM_MESH_MAX_COMMNUICATOR_NUM = 10 diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 index 94cd503f..88538e45 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 @@ -42,6 +42,7 @@ module mod_atmos_mesh_gm procedure :: Create_communicator => AtmosMeshGM_Create_communicator procedure :: Setup_restartfile1 => AtmosMeshGM_setup_restartfile1 procedure :: Setup_restartfile2 => AtmosMeshGM_setup_restartfile2 + procedure :: Calc_UVmet => AtmosMeshGM_calc_UVMet end type AtmosMeshGM !----------------------------------------------------------------------------- @@ -213,4 +214,38 @@ subroutine AtmosMeshGM_setup_restartfile2( this, restart_file, & end subroutine AtmosMeshGM_setup_restartfile2 + + subroutine AtmosMeshGM_calc_UVMet( this, U, V, & + Umet, Vmet ) + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatVec + implicit none + class(AtmosMeshGM), target, intent(in) :: this + type(MeshField3D), intent(in) :: U + type(MeshField3D), intent(in) :: V + type(MeshField3D), intent(inout) :: Umet + type(MeshField3D), intent(inout) :: Vmet + + integer :: n + integer :: ke + type(LocalMesh3D), pointer :: lcmesh + class(ElementBase3D), pointer :: elem + !------------------------------------------ + + do n=1, this%mesh%LOCAL_MESH_NUM + lcmesh => this%mesh%lcmesh_list(n) + elem => lcmesh%refElem3D + call CubedSphereCnv_CS2LonLatVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), & + elem%Np * lcmesh%Ne, this%mesh%RPlanet, & + U%local(n)%val(:,lcmesh%NeS:lcmesh%NeE), & + V%local(n)%val(:,lcmesh%NeS:lcmesh%NeE), & + Umet%local(n)%val(:,lcmesh%NeS:lcmesh%NeE), & + Vmet%local(n)%val(:,lcmesh%NeS:lcmesh%NeE) ) + end do + + return + end subroutine AtmosMeshGM_calc_UVMet + end module mod_atmos_mesh_gm \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 index eaae1fd9..837ba2f1 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 @@ -41,6 +41,7 @@ module mod_atmos_mesh_rm procedure :: Create_communicator => AtmosMeshRM_Create_communicator procedure :: Setup_restartfile1 => AtmosMeshRM_setup_restartfile1 procedure :: Setup_restartfile2 => AtmosMeshRM_setup_restartfile2 + procedure :: Calc_UVmet => AtmosMeshRM_calc_UVmet end type AtmosMeshRM !----------------------------------------------------------------------------- @@ -224,6 +225,33 @@ subroutine AtmosMeshRM_setup_restartfile2( this, restart_file, & out_basename, out_postfix_timelabel, out_dtype, out_title, var_num, & mesh3D=this%mesh ) + return end subroutine AtmosMeshRM_setup_restartfile2 + subroutine AtmosMeshRM_calc_UVMet( this, U, V, & + Umet, Vmet ) + implicit none + class(AtmosMeshRM), target, intent(in) :: this + type(MeshField3D), intent(in) :: U + type(MeshField3D), intent(in) :: V + type(MeshField3D), intent(inout) :: Umet + type(MeshField3D), intent(inout) :: Vmet + + integer :: n + integer :: ke + type(LocalMesh3D), pointer :: lcmesh + !------------------------------------------ + + do n=1, this%mesh%LOCAL_MESH_NUM + lcmesh => this%mesh%lcmesh_list(n) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + Umet%local(n)%val(:,ke) = U%local(n)%val(:,ke) + Vmet%local(n)%val(:,ke) = V%local(n)%val(:,ke) + end do + end do + + return +end subroutine AtmosMeshRM_calc_UVMet + end module mod_atmos_mesh_rm \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 index ef6a6188..4e93a1e2 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_vars.F90 @@ -41,6 +41,8 @@ module mod_atmos_vars !++ Public type & procedures ! type, public :: AtmosVars + class(AtmosMesh), pointer :: mesh + type(MeshField3D), allocatable :: PROG_VARS(:) type(ModelVarManager) :: PROGVARS_manager integer :: PROG_VARS_commID @@ -63,7 +65,8 @@ module mod_atmos_vars contains procedure :: Init => AtmosVars_Init procedure :: Final => AtmosVars_Final - procedure :: Clac_diagnostics => AtmosVars_CalculateDiagnostics + procedure :: Calc_diagnostics => AtmosVars_CalculateDiagnostics + procedure :: Calc_diagVar => AtmosVars_CalcDiagvar procedure :: History => AtmosVars_History procedure :: Check => AtmosVars_Check procedure :: Monitor => AtmosVars_Monitor @@ -159,24 +162,28 @@ module mod_atmos_vars integer, public, parameter :: ATMOS_DIAGVARS_V_ID = 2 integer, public, parameter :: ATMOS_DIAGVARS_W_ID = 3 integer, public, parameter :: ATMOS_DIAGVARS_T_ID = 4 - integer, public, parameter :: ATMOS_DIAGVARS_QDRY = 5 - integer, public, parameter :: ATMOS_DIAGVARS_ENGT = 6 - integer, public, parameter :: ATMOS_DIAGVARS_ENGP = 7 - integer, public, parameter :: ATMOS_DIAGVARS_ENGK = 8 - integer, public, parameter :: ATMOS_DIAGVARS_ENGI = 9 - integer, public, parameter :: ATMOS_DIAGVARS_NUM = 9 + integer, public, parameter :: ATMOS_DIAGVARS_Umet_ID = 5 + integer, public, parameter :: ATMOS_DIAGVARS_Vmet_ID = 6 + integer, public, parameter :: ATMOS_DIAGVARS_QDRY = 7 + integer, public, parameter :: ATMOS_DIAGVARS_ENGT = 8 + integer, public, parameter :: ATMOS_DIAGVARS_ENGP = 9 + integer, public, parameter :: ATMOS_DIAGVARS_ENGK = 10 + integer, public, parameter :: ATMOS_DIAGVARS_ENGI = 11 + integer, public, parameter :: ATMOS_DIAGVARS_NUM = 11 type(VariableInfo), public :: ATMOS_DIAGVARS_VINFO(ATMOS_DIAGVARS_NUM) DATA ATMOS_DIAGVARS_VINFO / & - VariableInfo( ATMOS_DIAGVARS_U_ID , 'U' , 'velocity u' , 'm/s' , 3, 'XYZ', 'x_wind' ), & - VariableInfo( ATMOS_DIAGVARS_V_ID , 'V' , 'velocity v' , 'm/s' , 3, 'XYZ', 'y_wind' ), & - VariableInfo( ATMOS_DIAGVARS_W_ID , 'W' , 'velocity w' , 'm/s' , 3, 'XYZ', 'upward_air_velocity' ), & - VariableInfo( ATMOS_DIAGVARS_T_ID , 'T' , 'temperature' , 'K' , 3, 'XYZ', 'air_temperature' ), & - Variableinfo( ATMOS_DIAGVARS_QDRY , 'QDRY', 'dry air' , 'kg/kg', 3, 'XYZ', '' ), & - Variableinfo( ATMOS_DIAGVARS_ENGT , 'ENGT', 'total energy' , 'J/m3' , 3, 'XYZ', '' ), & - Variableinfo( ATMOS_DIAGVARS_ENGP , 'ENGP', 'potential energy' , 'J/m3' , 3, 'XYZ', '' ), & - Variableinfo( ATMOS_DIAGVARS_ENGK , 'ENGK', 'kinetic energy' , 'J/m3' , 3, 'XYZ', '' ), & - Variableinfo( ATMOS_DIAGVARS_ENGI , 'ENGI', 'internal energy' , 'J/m3' , 3, 'XYZ', '' ) / + VariableInfo( ATMOS_DIAGVARS_U_ID , 'U' , 'velocity u' , 'm/s' , 3, 'XYZ', 'x_wind' ), & + VariableInfo( ATMOS_DIAGVARS_V_ID , 'V' , 'velocity v' , 'm/s' , 3, 'XYZ', 'y_wind' ), & + VariableInfo( ATMOS_DIAGVARS_W_ID , 'W' , 'velocity w' , 'm/s' , 3, 'XYZ', 'upward_air_velocity' ), & + VariableInfo( ATMOS_DIAGVARS_T_ID , 'T' , 'temperature' , 'K' , 3, 'XYZ', 'air_temperature' ), & + VariableInfo( ATMOS_DIAGVARS_Umet_ID, 'Umet', 'eastward velocity' , 'm/s' , 3, 'XYZ', 'x_wind' ), & + VariableInfo( ATMOS_DIAGVARS_Vmet_ID, 'Vmet', 'northward velocity' , 'm/s' , 3, 'XYZ', 'y_wind' ), & + Variableinfo( ATMOS_DIAGVARS_QDRY , 'QDRY', 'dry air' , 'kg/kg', 3, 'XYZ', '' ), & + Variableinfo( ATMOS_DIAGVARS_ENGT , 'ENGT', 'total energy' , 'J/m3' , 3, 'XYZ', '' ), & + Variableinfo( ATMOS_DIAGVARS_ENGP , 'ENGP', 'potential energy' , 'J/m3' , 3, 'XYZ', '' ), & + Variableinfo( ATMOS_DIAGVARS_ENGK , 'ENGK', 'kinetic energy' , 'J/m3' , 3, 'XYZ', '' ), & + Variableinfo( ATMOS_DIAGVARS_ENGI , 'ENGI', 'internal energy' , 'J/m3' , 3, 'XYZ', '' ) / !----------------------------------------------------------------------------- ! @@ -202,7 +209,7 @@ subroutine AtmosVars_Init( this, atm_mesh ) implicit none class(AtmosVars), target, intent(inout) :: this - class(AtmosMesh), intent(inout) :: atm_mesh + class(AtmosMesh), target, intent(inout) :: atm_mesh integer :: iv integer :: n @@ -252,6 +259,7 @@ subroutine AtmosVars_Init( this, atm_mesh ) LOG_NML(PARAM_ATMOS_VARS) !- Set the pointer of mesh + this%mesh => atm_mesh mesh3D => atm_mesh%ptr_mesh !- Initialize prognostic variables @@ -430,7 +438,7 @@ subroutine AtmosVars_history( this ) if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%PROG_VARS(v) ) end do - call this%Clac_diagnostics() + call this%Calc_diagnostics() do v = 1, ATMOS_AUXVARS_NUM hst_id = this%AUX_VARS(v)%hist_id if ( hst_id > 0 ) call FILE_HISTORY_meshfield_put( hst_id, this%AUX_VARS(v) ) @@ -445,7 +453,7 @@ subroutine AtmosVars_history( this ) do v = 1, ATMOS_DIAGVARS_NUM hst_id = this%DIAGVARS_HISTID(v) if ( hst_id > 0 ) then - call vars_calc_diagvar( this, ATMOS_DIAGVARS_VINFO(v)%NAME, tmp_field ) + call AtmosVars_CalcDiagvar( this, ATMOS_DIAGVARS_VINFO(v)%NAME, tmp_field ) call FILE_HISTORY_meshfield_put( hst_id, tmp_field ) end if end do @@ -490,7 +498,7 @@ subroutine AtmosVar_Read_restart_file( this, atmos_mesh ) call this%Check( force = .true. ) !-- Calculate diagnostic variables - call this%Clac_diagnostics() + call this%Calc_diagnostics() !-- Communicate halo data of hydrostatic & diagnostic variables call this%AUXVARS_manager%MeshFieldComm_Exchange() @@ -593,7 +601,7 @@ subroutine AtmosVars_Check( this, force ) do iv=1, 3 iv_diag = ATMOS_DIAGVARS_U_ID + iv - 1 call vel_fields(iv)%Init( ATMOS_DIAGVARS_VINFO(iv_diag)%NAME, "", mesh3D ) - call vars_calc_diagvar( this, vel_fields(iv)%varname, vel_fields(iv) ) + call AtmosVars_CalcDiagvar( this, vel_fields(iv)%varname, vel_fields(iv) ) end do call MeshField_statistics_detail( vel_fields(:) ) do iv=1, 3 @@ -636,19 +644,19 @@ subroutine AtmosVars_Monitor( this ) call work%Init("tmp", "", mesh3D) if ( DV_MONIT_id(IM_ENGT) > 0 ) then - call vars_calc_diagvar( this, 'ENGT', work ) + call AtmosVars_CalcDiagvar( this, 'ENGT', work ) call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGT), work ) end if if ( DV_MONIT_id(IM_ENGP) > 0 ) then - call vars_calc_diagvar( this, 'ENGP', work ) + call AtmosVars_CalcDiagvar( this, 'ENGP', work ) call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGP), work ) end if if ( DV_MONIT_id(IM_ENGK) > 0 ) then - call vars_calc_diagvar( this, 'ENGK', work ) + call AtmosVars_CalcDiagvar( this, 'ENGK', work ) call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGK), work ) end if if ( DV_MONIT_id(IM_ENGI) > 0 ) then - call vars_calc_diagvar( this, 'ENGI', work ) + call AtmosVars_CalcDiagvar( this, 'ENGI', work ) call FILE_monitor_meshfield_put( DV_MONIT_id(IM_ENGI), work ) end if @@ -873,7 +881,7 @@ subroutine AtmosVars_CalculateDiagnostics( this ) field => this%AUX_VARS(varid) do n=1, field%mesh%LOCAL_MESH_NUM lcmesh3D => field%mesh%lcmesh_list(n) - call vars_calc_diagnoseVar( & + call vars_calc_diagnoseVar_lc( & field%varname, field%local(n)%val, & this%PROG_VARS(ATMOS_PROGVARS_DDENS_ID)%local(n)%val, & this%PROG_VARS(ATMOS_PROGVARS_MOMX_ID)%local(n)%val, & @@ -889,9 +897,7 @@ subroutine AtmosVars_CalculateDiagnostics( this ) return end subroutine AtmosVars_CalculateDiagnostics -!-- private ----------------------------------------------------------------------- - - subroutine vars_calc_diagvar( this, field_name, field_work ) + subroutine AtmosVars_CalcDiagvar( this, field_name, field_work ) use scale_const, only: & Rdry => CONST_Rdry, & CPdry => CONST_CPdry, & @@ -905,27 +911,57 @@ subroutine vars_calc_diagvar( this, field_name, field_work ) type(LocalMesh3D), pointer :: lcmesh3D integer :: n + integer :: ke + + type(MeshField3D) :: field_work_UVmet(2) + logical :: is_UVmet + integer :: UVmet_i !-------------------------------------------------- + is_UVmet = .false. + if ( field_name == 'Umet' ) then + is_UVmet = .true.; UVmet_i = 1 + else if ( field_name == 'Vmet' ) then + is_UVmet = .true.; UVmet_i = 2 + end if + field_work%varname = field_name do n=1, field_work%mesh%LOCAL_MESH_NUM lcmesh3D => field_work%mesh%lcmesh_list(n) - call vars_calc_diagnoseVar( field_name, field_work%local(n)%val, & - this%PROG_VARS(ATMOS_PROGVARS_DDENS_ID)%local(n)%val, & - this%PROG_VARS(ATMOS_PROGVARS_MOMX_ID)%local(n)%val, & - this%PROG_VARS(ATMOS_PROGVARS_MOMY_ID)%local(n)%val, & - this%PROG_VARS(ATMOS_PROGVARS_MOMZ_ID)%local(n)%val, & - this%PROG_VARS(ATMOS_PROGVARS_DRHOT_ID)%local(n)%val, & - this%AUX_VARS(ATMOS_AUXVARS_DENSHYDRO_ID)%local(n)%val, & - this%AUX_VARS(ATMOS_AUXVARS_PRESHYDRO_ID)%local(n)%val, & - lcmesh3D, lcmesh3D%refElem3D ) + if ( .not. is_UVmet ) then + call vars_calc_diagnoseVar_lc( field_name, field_work%local(n)%val, & + this%PROG_VARS(ATMOS_PROGVARS_DDENS_ID)%local(n)%val, & + this%PROG_VARS(ATMOS_PROGVARS_MOMX_ID)%local(n)%val, & + this%PROG_VARS(ATMOS_PROGVARS_MOMY_ID)%local(n)%val, & + this%PROG_VARS(ATMOS_PROGVARS_MOMZ_ID)%local(n)%val, & + this%PROG_VARS(ATMOS_PROGVARS_DRHOT_ID)%local(n)%val, & + this%AUX_VARS(ATMOS_AUXVARS_DENSHYDRO_ID)%local(n)%val, & + this%AUX_VARS(ATMOS_AUXVARS_PRESHYDRO_ID)%local(n)%val, & + lcmesh3D, lcmesh3D%refElem3D ) + else + call field_work_UVmet(1)%Init( 'Umet', '', field_work%mesh ) + call field_work_UVmet(2)%Init( 'Vmet', '', field_work%mesh ) + call this%mesh%Calc_UVmet( & + this%PROG_VARS(ATMOS_PROGVARS_MOMX_ID), this%PROG_VARS(ATMOS_PROGVARS_MOMY_ID), & ! (in) + field_work_UVmet(1), field_work_UVmet(2) ) ! (inout) + !$omp parallel do + do ke=lcmesh3D%NeS, lcmesh3D%NeE + field_work%local(n)%val(:,ke) = field_work_UVmet(UVmet_i)%local(n)%val(:,ke) & + / ( this%AUX_VARS (ATMOS_AUXVARS_DENSHYDRO_ID)%local(n)%val(:,ke) & + + this%PROG_VARS(ATMOS_PROGVARS_DDENS_ID )%local(n)%val(:,ke) ) + end do + call field_work_UVmet(1)%Final() + call field_work_UVmet(2)%Final() + end if end do return - end subroutine vars_calc_diagvar + end subroutine AtmosVars_CalcDiagvar - subroutine vars_calc_diagnoseVar( field_name, var_out, & +!-- private ----------------------------------------------------------------------- + + subroutine vars_calc_diagnoseVar_lc( field_name, var_out, & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & lcmesh, elem ) @@ -979,6 +1015,12 @@ subroutine vars_calc_diagnoseVar( field_name, var_out, & RHOT(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) + DRHOT_(:,ke) var_out(:,ke) = PRES00 * (Rdry*RHOT(:)/PRES00)**(CPdry/Cvdry) end do + case('PRES_diff') + !$omp parallel do private (RHOT) + do ke=1, lcmesh%Ne + RHOT(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) + DRHOT_(:,ke) + var_out(:,ke) = PRES00 * (Rdry*RHOT(:)/PRES00)**(CPdry/Cvdry) - PRES_hyd(:,ke) + end do case('T') !$omp parallel do private (RHOT, PRES) do ke=1, lcmesh%Ne @@ -986,12 +1028,27 @@ subroutine vars_calc_diagnoseVar( field_name, var_out, & PRES(:) = PRES00 * (Rdry*RHOT(:)/PRES00)**(CPdry/Cvdry) var_out(:,ke) = PRES(:) / (Rdry * (DDENS_(:,ke) + DENS_hyd(:,ke)) ) end do + case('T_diff') + !$omp parallel do private (RHOT, PRES) + do ke=1, lcmesh%Ne + RHOT(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) + DRHOT_(:,ke) + PRES(:) = PRES00 * (Rdry*RHOT(:)/PRES00)**(CPdry/Cvdry) + var_out(:,ke) = PRES(:) / (Rdry * (DDENS_(:,ke) + DENS_hyd(:,ke)) ) & + - PRES_hyd(:,ke) / ( Rdry * DENS_hyd(:,ke) ) + end do case('PT') !$omp parallel do private (RHOT) do ke=1, lcmesh%Ne RHOT(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) + DRHOT_(:,ke) var_out(:,ke) = RHOT(:) / (DDENS_(:,ke) + DENS_hyd(:,ke)) end do + case('PT_diff') + !$omp parallel do private (RHOT) + do ke=1, lcmesh%Ne + RHOT(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) + DRHOT_(:,ke) + var_out(:,ke) = RHOT(:) / (DDENS_(:,ke) + DENS_hyd(:,ke)) & + - PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**(CVdry/CPdry) / DENS_hyd(:,ke) + end do case('ENGK') !$omp parallel do private (DENS) do ke=1, lcmesh%Ne @@ -1022,8 +1079,11 @@ subroutine vars_calc_diagnoseVar( field_name, var_out, & + PRES(:) * CvDry / Rdry & ! ENGI + DENS(:) * Grav * lcmesh%pos_en(:,ke,3) ! ENGP end do + case default + LOG_ERROR("AtmosVars_calc_diagnoseVar_lc",*) 'The name of diagnostic variable is not suported. Check!', field_name + call PRC_abort end select return - end subroutine vars_calc_diagnoseVar + end subroutine vars_calc_diagnoseVar_lc end module mod_atmos_vars \ No newline at end of file From c1f6221139d9be5ccb5631f4b3b03bd0eccb0656 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 31 May 2021 10:01:21 +0900 Subject: [PATCH 43/98] Modify the interfaces of mod_user in scale-dg. --- .../src/admin/mod_dg_driver.F90 | 6 +-- .../src/preprocess/mod_mkinit_util.F90 | 39 ++++++++++++-- model/atm_nonhydro3d/src/user/mod_user.F90 | 10 ++-- .../test/case/baroclinic_wave/mod_user.F90 | 8 ++- .../test/case/density_current/mod_user.F90 | 6 ++- .../case/inertia_gravity_wave/mod_user.F90 | 16 +++--- .../test/case/pbl_turbulence/mod_user.F90 | 6 ++- .../test/case/sound_wave/mod_user.F90 | 6 ++- .../test/case/sound_wave_global/mod_user.F90 | 51 +++++++++++-------- 9 files changed, 100 insertions(+), 48 deletions(-) diff --git a/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 b/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 index 27184fcf..a409997f 100644 --- a/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 +++ b/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 @@ -136,7 +136,7 @@ subroutine dg_driver( & call TIME_manager_advance call FILE_HISTORY_set_nowdate( TIME_NOWDATE, TIME_NOWSUBSEC, TIME_NOWSTEP ) - + !* change to next state ************************* !- ATMOS @@ -145,7 +145,7 @@ subroutine dg_driver( & end if !- USER - call USER_update + call USER_update( atmos ) !* restart and monitor output ******************* if ( atmos%IsActivated() ) call atmos%vars%Monitor() @@ -160,7 +160,7 @@ subroutine dg_driver( & end if !- USER - call USER_calc_tendency + call USER_calc_tendency( atmos ) !* output history files ************************* diff --git a/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 b/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 index c83e85d1..c7e8cfca 100644 --- a/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 +++ b/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 @@ -159,7 +159,7 @@ subroutine mkinitutil_calc_cosinebell( & + ( (z_intrp(:) - zc) / rz )**2 ) where( r_intrp(:) <= 1.0_RP ) - q_intrp(:) = qmax * cos( 0.5_RP * PI * r_intrp(:) ) + q_intrp(:) = qmax * 0.5_RP * (1.0_RP + cos( PI * r_intrp(:) ) ) elsewhere q_intrp(:) = 0.0_RP end where @@ -171,11 +171,19 @@ subroutine mkinitutil_calc_cosinebell( & return end subroutine mkinitutil_calc_cosinebell + !> + !! Calculate the distribution function of a cosine bell. + !! + !! If the vertical dependence is considered, specify z_func_type and z_func_params. + !! For z_func_type = 'sin', the values of z_func_params is + !! 1: the vertical model, 2: the half of wavelength + !! subroutine mkinitutil_calc_cosinebell_global( & q, & qmax, rh, lonc, latc, rplanet, & x, y, z, lcmesh3D, elem, & - IntrpPolyOrder_h, IntrpPolyOrder_v ) + IntrpPolyOrder_h, IntrpPolyOrder_v, & + z_func_type, z_func_params ) use scale_cubedsphere_cnv, only: & CubedSphereCnv_CS2LonLatCoord @@ -193,12 +201,15 @@ subroutine mkinitutil_calc_cosinebell_global( & real(RP), intent(in) :: z(elem%Np,lcmesh3D%Ne) integer, intent(in) :: IntrpPolyOrder_h integer, intent(in) :: IntrpPolyOrder_v + character(len=*), optional, intent(in) :: z_func_type + real(RP), optional, intent(in) :: z_func_params(:) integer :: ke type(HexahedralElement) :: elem_intrp real(RP), allocatable :: x_intrp(:,:), y_intrp(:,:), z_intrp(:,:) real(RP), allocatable :: lon_intrp(:,:), lat_intrp(:,:) + real(RP), allocatable :: z_func(:,:) real(RP), allocatable :: r_intrp(:) real(RP) :: vx(elem%Nv), vy(elem%Nv), vz(elem%Nv) @@ -213,6 +224,7 @@ subroutine mkinitutil_calc_cosinebell_global( & allocate( x_intrp(elem_intrp%Np,lcmesh3D%Ne), y_intrp(elem_intrp%Np,lcmesh3D%Ne), z_intrp(elem_intrp%Np,lcmesh3D%Ne) ) allocate( lon_intrp(elem_intrp%Np,lcmesh3D%Ne), lat_intrp(elem_intrp%Np,lcmesh3D%Ne) ) + allocate( z_func(elem_intrp%Np,lcmesh3D%Ne) ) allocate( r_intrp(elem_intrp%Np) ) allocate( q_intrp(elem_intrp%Np) ) @@ -224,21 +236,38 @@ subroutine mkinitutil_calc_cosinebell_global( & vz(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),3) x_intrp(:,ke) = vx(1) + 0.5_RP * ( elem_intrp%x1(:) + 1.0_RP ) * ( vx(2) - vx(1) ) y_intrp(:,ke) = vy(1) + 0.5_RP * ( elem_intrp%x2(:) + 1.0_RP ) * ( vy(4) - vy(1) ) - z_intrp(:,ke) = vz(1) + 0.5_RP * ( elem_intrp%x3(:) + 1.0_RP ) * ( vz(5) - vz(1) ) + z_intrp(:,ke) = vz(1) + 0.5_RP * ( elem_intrp%x3(:) + 1.0_RP ) * ( vz(5) - vz(1) ) + + z_func(:,ke) = 1.0_RP end do call CubedSphereCnv_CS2LonLatCoord( lcmesh3D%panelID, x_intrp, y_intrp, elem_intrp%Np * lcmesh3D%Ne, & rplanet, lon_intrp(:,:), lat_intrp(:,:) ) + ! Calculate the vertical function + if ( present(z_func_type) ) then + select case(z_func_type) + case ('sin') + !$omp parallel do + do ke=lcmesh3D%NeS, lcmesh3D%NeE + z_func(:,ke) = sin( z_func_params(1) * PI * z_intrp(:,ke) / z_func_params(2) ) + end do + end select + end if + !$omp parallel do private( r_intrp, q_intrp ) do ke=lcmesh3D%NeS, lcmesh3D%NeE + + ! Calculate the horizontal function r_intrp(:) = rplanet / rh * acos( sin(latc) * sin(lat_intrp(:,ke)) + cos(latc) * cos(lat_intrp(:,ke)) * cos(lon_intrp(:,ke) - lonc) ) where( r_intrp(:) <= 1.0_RP ) - q_intrp(:) = qmax * cos( 0.5_RP * PI * r_intrp(:) ) + q_intrp(:) = qmax * 0.5_RP * (1.0_RP + cos( PI * r_intrp(:) ) ) elsewhere q_intrp(:) = 0.0_RP end where - q(:,ke) = matmul(IntrpMat, q_intrp) + + ! Perform Galerkin projection + q(:,ke) = matmul(IntrpMat, q_intrp * z_func(:,ke)) end do call elem_intrp%Final() diff --git a/model/atm_nonhydro3d/src/user/mod_user.F90 b/model/atm_nonhydro3d/src/user/mod_user.F90 index b3a019da..24c54c7f 100644 --- a/model/atm_nonhydro3d/src/user/mod_user.F90 +++ b/model/atm_nonhydro3d/src/user/mod_user.F90 @@ -2,7 +2,7 @@ !> module USER !! !! @par Description -!! User defined module +!! User defined module (dummy) !! !! @author Team SCALE !! @@ -93,15 +93,19 @@ subroutine USER_setup( atm ) return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) implicit none + + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave/mod_user.F90 b/model/atm_nonhydro3d/test/case/baroclinic_wave/mod_user.F90 index b82841a9..6c7a7928 100644 --- a/model/atm_nonhydro3d/test/case/baroclinic_wave/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave/mod_user.F90 @@ -125,15 +125,19 @@ subroutine USER_setup( atm ) return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) implicit none + + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return diff --git a/model/atm_nonhydro3d/test/case/density_current/mod_user.F90 b/model/atm_nonhydro3d/test/case/density_current/mod_user.F90 index c1cdc174..317c49cb 100644 --- a/model/atm_nonhydro3d/test/case/density_current/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/density_current/mod_user.F90 @@ -110,15 +110,17 @@ subroutine USER_setup( atm ) return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave/mod_user.F90 b/model/atm_nonhydro3d/test/case/inertia_gravity_wave/mod_user.F90 index c229f46a..0ef226b8 100644 --- a/model/atm_nonhydro3d/test/case/inertia_gravity_wave/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave/mod_user.F90 @@ -110,15 +110,17 @@ subroutine USER_setup( atm ) return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return @@ -215,10 +217,8 @@ subroutine exp_SetInitCond_inertia_gravity_wave( this, & allocate( x_intrp(elem_intrp%Np), y_intrp(elem_intrp%Np), z_intrp(elem_intrp%Np) ) - call hydrostatic_calc_basicstate_constBVFreq( DENS_hyd, PRES_hyd, & - BruntVaisalaFreq, THETA0, PRES00, & - lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), lcmesh%pos_en(:,:,3), & - lcmesh, elem ) + call hydrostatic_calc_basicstate_constBVFreq( DENS_hyd, PRES_hyd, & ! (out) + BruntVaisalaFreq, THETA0, PRES00, x, y, z, lcmesh, elem ) ! (in) !--- RovCp = Rdry / CpDry @@ -247,8 +247,8 @@ subroutine exp_SetInitCond_inertia_gravity_wave( this, & return end subroutine exp_SetInitCond_inertia_gravity_wave - subroutine exp_geostrophic_balance_correction( this, & - DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & lcmesh, elem ) implicit none diff --git a/model/atm_nonhydro3d/test/case/pbl_turbulence/mod_user.F90 b/model/atm_nonhydro3d/test/case/pbl_turbulence/mod_user.F90 index 3b802328..8fac5eb3 100644 --- a/model/atm_nonhydro3d/test/case/pbl_turbulence/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/pbl_turbulence/mod_user.F90 @@ -123,15 +123,17 @@ subroutine USER_setup( atm ) return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return diff --git a/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 b/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 index cdda8150..03f4761c 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/sound_wave/mod_user.F90 @@ -108,15 +108,17 @@ subroutine USER_setup( atm ) return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 index 8e75f9c0..ef1c3bc3 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/mod_user.F90 @@ -27,6 +27,7 @@ module mod_user use scale_element_base, only: ElementBase3D use scale_element_hexahedral, only: HexahedralElement use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfield_base, only: MeshField3D !----------------------------------------------------------------------------- implicit none @@ -62,6 +63,8 @@ module mod_user logical, private :: USER_do = .false. !< do user step? + type(MeshField3D), private :: PRES_diff + !----------------------------------------------------------------------------- contains subroutine USER_mkinit ( atm ) @@ -105,18 +108,30 @@ subroutine USER_setup( atm ) LOG_NML(PARAM_USER) !- + if ( USER_do ) call PRES_diff%Init( 'PRES_diff', 'Pa', atm%mesh%ptr_mesh ) + return end subroutine USER_setup - subroutine USER_calc_tendency + subroutine USER_calc_tendency( atm ) + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in implicit none + + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ + if ( USER_do ) then + call atm%vars%Calc_diagVar( 'PRES_diff', PRES_diff ) + call FILE_HISTORY_meshfield_in( PRES_diff, "perturbation of PRES" ) + end if + return end subroutine USER_calc_tendency - subroutine USER_update + subroutine USER_update( atm ) implicit none + class(AtmosComponent), intent(inout) :: atm !------------------------------------------ return @@ -163,9 +178,10 @@ subroutine exp_SetInitCond_sound_wave( this, & real(RP) :: TEMP0 = 300.0_RP real(RP) :: DPRES = 100.0_RP - real(RP) :: lonc, latc + real(RP) :: lonc = 0.0_RP + real(RP) :: latc = 0.0_RP + integer :: nv = 1 real(RP) :: rh - integer :: nv real(RP) :: Zt namelist /PARAM_EXP/ & TEMP0, DPRES, & @@ -174,7 +190,6 @@ subroutine exp_SetInitCond_sound_wave( this, & integer, parameter :: IntrpPolyOrder_h = 8 integer, parameter :: IntrpPolyOrder_v = 8 real(RP), allocatable :: PRES_purtub(:,:) - real(RP) :: pres(elem%Np) real(RP) :: rgamm @@ -183,9 +198,6 @@ subroutine exp_SetInitCond_sound_wave( this, & !----------------------------------------------------------------------------- rh = RPlanet / 3.0_RP - lonc = 0.0_RP - latc = 0.0_RP - nv = 1 rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) @@ -200,26 +212,23 @@ subroutine exp_SetInitCond_sound_wave( this, & !--- allocate( PRES_purtub(elem%Np,lcmesh%NeA) ) - call mkinitutil_calc_cosinebell_global( & - PRES_purtub, & - DPRES, rh, lonc, latc, RPlanet, & - x, y, z, lcmesh, elem, & - IntrpPolyOrder_h, IntrpPolyOrder_v ) + call mkinitutil_calc_cosinebell_global( PRES_purtub, & ! (out) + DPRES, rh, lonc, latc, RPlanet, & ! (in) + x, y, z, lcmesh, elem, & ! (in) + IntrpPolyOrder_h, IntrpPolyOrder_v, & ! (in) + 'sin', (/ real(nv,kind=RP), dom_zmax - dom_zmin /) ) ! (in) - call hydrostatic_calc_basicstate_constT( DENS_hyd, PRES_hyd, & - TEMP0, PRES00, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), lcmesh%pos_en(:,:,3), & - lcmesh, elem ) + call hydrostatic_calc_basicstate_constT( DENS_hyd, PRES_hyd, & ! (out) + TEMP0, PRES00, x, y, z, lcmesh, elem ) ! (in) !--- rgamm = CvDry / CpDry - Zt = dom_zmax - dom_zmin - !$omp parallel do private(pres) + !$omp parallel do do ke=lcmesh%NeS, lcmesh%NeE - pres(:) = PRES_hyd(:,ke) + PRES_purtub(:,ke) * sin( dble(nv) * PI * z(:,ke) / Zt ) DRHOT(:,ke) = PRES00/Rdry * ( & - ( pres(:) / PRES00 )**rgamm & - - ( PRES_hyd(:,ke) / PRES00 )**rgamm ) + ( ( PRES_hyd(:,ke) + PRES_purtub(:,ke) ) / PRES00 )**rgamm & + - ( PRES_hyd(:,ke) / PRES00 )**rgamm ) end do return From 266fb7a3de171ed161b2f4158a9d3dc82a5c9a6b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 31 May 2021 13:14:57 +0900 Subject: [PATCH 44/98] Fix some bugs. --- ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 9 ++--- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 33 ++++++++++--------- .../scale_atm_dyn_dgm_hydrostatic.F90 | 4 +-- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index 28f4a677..cb3513e8 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -423,7 +423,8 @@ subroutine cal_del_flux_dyn( del_flux, & ke2D = lmesh%EMap3Dto2D(ke) G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) - Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + abs( nz(:,ke) ) densM(:) = DDENS_M(:) + DENS_hyd(iM) densP(:) = DDENS_P(:) + DENS_hyd(iP) @@ -449,16 +450,16 @@ subroutine cal_del_flux_dyn( del_flux, & del_flux(:,ke,VARS_MOMX_ID) = 0.5_RP * Gsqrt_M(:) * ( & ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & - + G1n_M(:) * dpres(:) & + + G1n_M(:) * dpres(:) & - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) del_flux(:,ke,VARS_MOMY_ID) = 0.5_RP * Gsqrt_M(:) * ( & ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & - + G2n_M(:) * dpres(:) & + + G2n_M(:) * dpres(:) & - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) del_flux(:,ke,VARS_MOMZ_ID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:)) & + ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:) ) & + dpres(:) * nz(:,ke) & - alpha(:) * ( MOMZ_P(:) - MOMZ_M(:) ) ) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index f539c314..1f514519 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -178,7 +178,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP) :: PRES_(elem%Np) + real(RP) :: DPRES_(elem%Np) real(RP) :: RHOT_(elem%Np) real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) @@ -220,10 +220,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & s = - 1.0_RP end if - !$omp parallel do private( & - !$omp RHOT_, PRES_, rdens_, u_, v_, w_, ke2d, & - !$omp Fx, Fy, Fz, LiftDelFlx, & - !$omp GIJ, X, Y, twoOVdel2, CORI ) + !$omp parallel do private( & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, ke2d, & + !$omp Fx, Fy, Fz, LiftDelFlx, & + !$omp GIJ, X, Y, twoOVdel2, CORI ) do ke = lmesh%NeS, lmesh%NeE !-- X(:) = lmesh%pos_en(:,ke,1) @@ -231,7 +231,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) - PRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm + DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & + - PRES_hyd(:,ke) rdens_(:) = 1.0_RP / ( DDENS_(:,ke) + DENS_hyd(:,ke) ) u_ (:) = MOMX_(:,ke) * rdens_(:) @@ -262,9 +263,9 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- MOMX - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * PRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * PRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) MOMX_dt(:,ke) = & @@ -277,8 +278,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + CORI(:,1) !-- MOMY - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * PRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * PRES_(:) ), Fy) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * DPRES_(:) ), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) @@ -430,11 +431,11 @@ subroutine cal_del_flux_dyn( del_flux, & presP(:) = PRES00 * (RovP0 * rhotP(:))**gamm dpres(:) = presP(:) - presM(:) & - - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * abs( nz(:,ke) ) - + - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) + alpha(:) = swV(:) * max( sqrt( Gnn_M(:) * gamm * presM(:) / densM(:) ) + abs(VelM(:)), & sqrt( Gnn_M(:) * gamm * presP(:) / densP(:) ) + abs(VelP(:)) ) - + del_flux(:,ke,DDENS_VID) = 0.5_RP * Gsqrt_M(:) * ( & swV(:) * ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) @@ -859,7 +860,7 @@ subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) if (iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ)) then MOMZ_P = - MOMZ_(iM) - alpha0 = 0.0_RP + !alpha0 = 0.0_RP else MOMZ_P = MOMZ_(iP) end if @@ -1053,7 +1054,7 @@ subroutine vi_construct_matbnd( PmatBnd, & ! (out) tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * max(alphaM, alphaP) if (bc_flag) then - !PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 + PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 else do v=1, PROG_VARS_NUM PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 index b7da4379..7f9751f0 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 @@ -164,9 +164,9 @@ subroutine hydrostatic_calc_basicstate_constBVFreq( & !$omp parallel do private(PT, exner) do ke=lcmesh3D%NeS, lcmesh3D%NeE ! d exner / dz = - g / ( Cp * PT0 ) * exp (- N2/g * z) - ! exner = exner(zs) - g^2 / (Cp * N2) [ 1/PT (z) - 1/PT(zs) ] + ! exner = exner(zs) - g^2 / (Cp * N^2) [ 1/PT (z) - 1/PT(zs) ] PT(:) = PotTemp0 * exp( BruntVaisalaFreq**2 / Grav * z(:,ke) ) - exner(:) = exner_sfc + Grav**2 / ( CpDry * BruntVaisalaFreq ) * ( 1.0_RP / PT(:) - 1.0_RP / PotTemp0 ) + exner(:) = exner_sfc + Grav**2 / ( CpDry * BruntVaisalaFreq**2 ) * ( 1.0_RP / PT(:) - 1.0_RP / PotTemp0 ) PRES_hyd(:,ke) = PRES00 * exner(:)**CPovR DENS_hyd(:,ke) = PRES_hyd(:,ke) / ( Rdry * exner(:) * PT(:) ) From 3efbe37feaf9d2ad9bd03b0f6e27f3b9cd9e4054 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 31 May 2021 13:16:34 +0900 Subject: [PATCH 45/98] Add a test case of gravity wave for global dynamical core. --- .../case/inertia_gravity_wave_global/Makefile | 28 ++ .../inertia_gravity_wave_global/init.conf | 47 ++++ .../inertia_gravity_wave_global/mod_user.F90 | 264 ++++++++++++++++++ .../case/inertia_gravity_wave_global/run.conf | 101 +++++++ 4 files changed, 440 insertions(+) create mode 100644 model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/Makefile create mode 100644 model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/init.conf create mode 100644 model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/run.conf diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/Makefile b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/init.conf b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/init.conf new file mode 100644 index 00000000..96c34eb6 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/init.conf @@ -0,0 +1,47 @@ +#--- Configuration file for a test case of (inertia) gravity wave ------- +# Test Case 2-#1 in Tomita et al. (2004) / Test case 6-0-0 of DCMIP 2008 (Jablonowski et al., 2008) +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'inertia_gravity_wave', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP + BruntVaisalaFreq = 1.0D-2, + DTHETA = 10.0D0, + nv = 1, +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeZ = 2, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, +! LumpedMassMatFlag = .true., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 new file mode 100644 index 00000000..11d5c8dd --- /dev/null +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 @@ -0,0 +1,264 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfield_base, only: MeshField3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_inertia_gravity_wave_global + contains + procedure :: setInitCond_lc => exp_SetInitCond_inertia_gravity_wave + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_inertia_gravity_wave_global), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + type(MeshField3D), private :: PT_diff + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + call exp_manager%Init('inertia_gravity_wave_global') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + if ( USER_do ) call PT_diff%Init( 'PT_diff', 'K', atm%mesh%ptr_mesh ) + + return + end subroutine USER_setup + + subroutine USER_calc_tendency( atm ) + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + if ( USER_do ) then + call atm%vars%Calc_diagVar( 'PT_diff', PT_diff ) + call FILE_HISTORY_meshfield_in( PT_diff, "perturbation of T" ) + end if + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_inertia_gravity_wave( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS + + use scale_atm_dyn_dgm_hydrostatic, only: & + hydrostatic_calc_basicstate_constBVFreq + use mod_mkinit_util, only: & + mkinitutil_calc_cosinebell_global + + implicit none + + class(Exp_inertia_gravity_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + real(RP) :: THETA0 = 300.0_RP + real(RP) :: BruntVaisalaFreq = 0.01_RP + real(RP) :: DTHETA = 0.01_RP + real(RP) :: lonc = 0.0_RP + real(RP) :: latc = 0.0_RP + integer :: nv = 1 + real(RP) :: rh + real(RP) :: Zt + namelist /PARAM_EXP/ & + THETA0, DTHETA, & + lonc, latc, rh, & + nv, & + BruntVaisalaFreq + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 + real(RP), allocatable :: PT_purtub(:,:) + real(RP) :: EXNER(elem%Np) + + real(RP) :: RovCp + + integer :: ke + integer :: ierr + !----------------------------------------------------------------------------- + + rh = RPlanet / 3.0_RP + lonc = PI + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("INERTIA_GRAVITY_WAVE_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("INERTIA_GRAVITY_WAVE_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + allocate( PT_purtub(elem%Np,lcmesh%NeA) ) + call mkinitutil_calc_cosinebell_global( PT_purtub, & ! (out) + DTHETA, rh, lonc, latc, RPlanet, & ! (in) + x, y, z, lcmesh, elem, & ! (in) + IntrpPolyOrder_h, IntrpPolyOrder_v, & ! (in) + 'sin', (/ real(nv,kind=RP), dom_zmax - dom_zmin /) ) ! (in) + + call hydrostatic_calc_basicstate_constBVFreq( DENS_hyd, PRES_hyd, & ! (out) + BruntVaisalaFreq, THETA0, PRES00, & ! (in) + x, y, z, lcmesh, elem ) ! (in) + + !--- + RovCp = Rdry / CPdry + Zt = dom_zmax - dom_zmin + + !$omp parallel do private(EXNER) + do ke=lcmesh%NeS, lcmesh%NeE + EXNER(:) = ( PRES_hyd(:,ke) / PRES00 )**(RovCp) + DDENS(:,ke) = PRES_hyd(:,ke) / ( Rdry * ( PRES_hyd(:,ke) / ( Rdry * DENS_hyd(:,ke) ) + PT_purtub(:,ke) * EXNER(:) ) ) & + - DENS_hyd(:,ke) + end do + + return + end subroutine exp_SetInitCond_inertia_gravity_wave + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_inertia_gravity_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + !--------------------------------------------------- + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/run.conf b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/run.conf new file mode 100644 index 00000000..0922b646 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/run.conf @@ -0,0 +1,101 @@ +#--- Configuration file for a test case of (inertia) gravity wave ------- +# Test Case 2-#1 in Tomita et al. (2004) / Test case 6-0-0 of DCMIP 2008 (Jablonowski et al., 2008) +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 96.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 900.0D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +&PARAM_USER + USER_do = .true., +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 900.0D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeZ = 2, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + LumpedMassMatFlag = .true., +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVI", + !- + TINTEG_TYPE = 'IMEX_ARK324', ! [IMEX_ARK_232, IMEX_ARK324, RK_TVD_3] + TIME_DT = 75.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 10.0D0, + MF_ORDER_h = 32, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 10.0D0, + MF_ORDER_v = 32, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 21600.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='Umet' / +&HISTORY_ITEM name='Vmet' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='PT_diff' / +!&HISTORY_ITEM name='DENS_hyd' / +!&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + From 55541ce6befc19f323f8e35d6320819399c7d640 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 1 Jun 2021 12:36:40 +0900 Subject: [PATCH 46/98] Fix a bugs when we specify the number of MPI process larger than 6 in 2D/3D cubed sphere mesh. --- .../scale_meshfieldcomm_cubedspheredom2d.F90 | 2 +- .../scale_meshfieldcomm_cubedspheredom3d.F90 | 6 +- .../src/mesh/scale_meshutil_cubedsphere2d.F90 | 128 ++++++++++++++---- .../src/mesh/scale_meshutil_cubedsphere3d.F90 | 52 +------ .../inertia_gravity_wave_global/mod_user.F90 | 2 +- .../test/case/sound_wave_global/cs2lonlat.cnf | 2 +- .../test/case/sound_wave_global/run.conf | 10 +- 7 files changed, 123 insertions(+), 79 deletions(-) diff --git a/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 index b48359a5..e278efc4 100644 --- a/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 +++ b/FElib/src/data/scale_meshfieldcomm_cubedspheredom2d.F90 @@ -303,6 +303,7 @@ subroutine MeshFieldCommCubedSphereDom2D_exchange( this ) irs = 1 do f=1, this%nfaces_comm commdata => commdata_list(f,n) + ire = irs + commdata%Nnode_LCMeshFace - 1 if ( commdata%s_panelID /= lcmesh%panelID ) then if ( this%hvfield_num > 0 ) then @@ -311,7 +312,6 @@ subroutine MeshFieldCommCubedSphereDom2D_exchange( this ) call push_localsendbuf( lcfpos2D, & fpos2D, f, is_f(f), Nnode_LCMeshFace(f), 2 ) - ire = irs + commdata%Nnode_LCMeshFace - 1 do varid=this%sfield_num+1, this%field_num_tot-1, 2 call CubedSphereCnv_LonLat2CSVec( & lcmesh%panelID, lcfpos2D(:,1), lcfpos2D(:,2), Nnode_LCMeshFace(f), & diff --git a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 index 1d798781..7ddfd8bd 100644 --- a/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 +++ b/FElib/src/data/scale_meshfieldcomm_cubedspheredom3d.F90 @@ -218,7 +218,7 @@ end subroutine MeshFieldCommCubedSphereDom3D_get subroutine MeshFieldCommCubedSphereDom3D_exchange( this ) use scale_prc, only: & - PRC_LOCAL_COMM_WORLD, PRC_abort, PRC_MPIbarrier + PRC_LOCAL_COMM_WORLD, PRC_abort, PRC_MPIbarrier, PRC_myrank use scale_meshfieldcomm_base, only: & MeshFieldCommBase_exchange_core, & @@ -332,6 +332,7 @@ subroutine MeshFieldCommCubedSphereDom3D_exchange( this ) irs = 1 do f=1, this%nfaces_comm commdata => commdata_list(f,n) + ire = irs + commdata%Nnode_LCMeshFace - 1 if ( commdata%s_panelID /= lcmesh%panelID ) then if ( this%hvfield_num > 0 ) then @@ -340,8 +341,7 @@ subroutine MeshFieldCommCubedSphereDom3D_exchange( this ) call push_localsendbuf( lcfpos3D, & fpos3D, f, is_f(f), Nnode_LCMeshFace(f), 2, & lcmesh, elem ) - - ire = irs + commdata%Nnode_LCMeshFace - 1 + do varid=this%sfield_num+1, this%field_num_tot-1, 2 call CubedSphereCnv_LonLat2CSVec( & lcmesh%panelID, lcfpos3D(:,1), lcfpos3D(:,2), Nnode_LCMeshFace(f), & diff --git a/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 b/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 index 58827b7b..1452d17a 100644 --- a/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 +++ b/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 @@ -30,6 +30,7 @@ module scale_meshutil_cubedsphere2d public :: MeshUtilCubedSphere2D_buildInteriorMap public :: MeshUtilCubedSphere2D_buildGlobalMap public :: MeshUtilCubedSphere2D_genPatchBoundaryMap + public :: MeshUtilCubedSphere2D_modifyConnectivity public :: MeshUtilCubedSphere2D_GetPanelConnectivity contains @@ -38,7 +39,6 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & tileID_map, tileFaceID_map, tilePanelID_map, & Ntile ) - ! use scale_prc, only: PRC_isMaster use scale_meshutil_2d, only: & MeshUtil2D_genConnectivity implicit none @@ -61,11 +61,6 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & integer :: panelID integer :: tileID, tileID_R integer :: counter - - integer :: panel_connectivity(4,6) - integer :: face_connectivity (4,6) - - integer :: pi_, pj_ !----------------------------------------------------------------------------- NtilePerPanel = Ntile / 6 @@ -105,9 +100,6 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & EToV, Ntile, 4 ) tileID_map(:,:) = transpose(EToE) tileFaceID_map(:,:) = transpose(EToF) - - call MeshUtilCubedSphere2D_getPanelConnectivity( & - panel_connectivity, face_connectivity ) do tileID=1, Ntile do f=1, 4 @@ -116,7 +108,40 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & end do end do - !- + call MeshUtilCubedSphere2D_modifyConnectivity( & + tilePanelID_map, tileID_map, tileFaceID_map, & ! (inout) + panelID_table, pi_table, pj_table, NeX, NeY, Ntile, 4 ) ! (in) + + return + end subroutine MeshUtilCubedSphere2D_buildGlobalMap + + !---- + subroutine MeshUtilCubedSphere2D_modifyConnectivity( tilePanelID_map, tileID_map, tileFaceID_map, & + panelID_table, pi_table, pj_table, NeX, NeY, Ntile, Nface ) + + integer, intent(in) :: Ntile + integer, intent(in) :: Nface + integer, intent(out) :: tileID_map(Nface,Ntile) + integer, intent(out) :: tileFaceID_map(Nface,Ntile) + integer, intent(out) :: tilePanelID_map(Nface,Ntile) + integer, intent(in) :: panelID_table(Ntile) + integer, intent(in) :: pi_table(Ntile) + integer, intent(in) :: pj_table(Ntile) + integer, intent(in) :: NeX, NeY + + integer :: panel_connectivity(4,6) + integer :: face_connectivity (4,6) + + integer :: tileID + integer :: panelID + integer :: f + integer :: pi_, pj_ + !----------------------------------------------------------------------------- + + call MeshUtilCubedSphere2D_getPanelConnectivity( & + panel_connectivity, face_connectivity ) + + do tileID=1, Ntile panelID = panelID_table(tileID) @@ -127,23 +152,68 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & pj_ = pj_table(tileID) select case( panelID ) - case ( 1, 2, 3, 4 ) - if ( pi_table(tileID) == 1 ) pi_ = NeX - if ( pi_table(tileID) == NeX ) pi_ = 1 - if ( pj_table(tileID) == 1 ) pj_ = NeY - if ( pj_table(tileID) == NeY ) pj_ = 1 + case ( 1 ) + if ( mod(f,2) == 0 ) then ! West / East + if ( pi_table(tileID) == 1 ) pi_ = NeX + if ( pi_table(tileID) == NeX ) pi_ = 1 + else ! North / South + if ( pj_table(tileID) == 1 ) pj_ = NeY + if ( pj_table(tileID) == NeY ) pj_ = 1 + end if + case ( 2 ) + if ( mod(f,2) == 0 ) then ! West / East + if ( pi_table(tileID) == 1 ) pi_ = NeX + if ( pi_table(tileID) == NeX ) pi_ = 1 + else ! North / South + if ( pj_table(tileID) == 1 ) then + pi_ = NeX; pj_ = NeY - pi_table(tileID) + 1 + end if + if ( pj_table(tileID) == NeY ) then + pi_ = NeX ; pj_ = pi_table(tileID) + end if + end if + case ( 3 ) + if ( mod(f,2) == 0 ) then ! West / East + if ( pi_table(tileID) == 1 ) pi_ = NeX + if ( pi_table(tileID) == NeX ) pi_ = 1 + else ! North / South + if ( pj_table(tileID) == 1 ) then + pi_ = NeX - pi_table(tileID) + 1; pj_ = 1 + end if + if ( pj_table(tileID) == NeY ) then + pi_ = NeX - pi_table(tileID) + 1; pj_ = NeY + end if + end if + case ( 4 ) + if ( mod(f,2) == 0 ) then ! West / East + if ( pi_table(tileID) == 1 ) pi_ = NeX + if ( pi_table(tileID) == NeX ) pi_ = 1 + else ! North / South + if ( pj_table(tileID) == 1 ) then + pi_ = 1; pj_ = pi_table(tileID) + end if + if ( pj_table(tileID) == NeY ) then + pi_ = 1; pj_ = NeY - pi_table(tileID) + 1; + end if + end if case ( 5 ) pj_ = NeY - if ( pi_table(tileID) == 1 ) pi_ = NeY - pj_table(tileID) + 1 ! West - if ( pi_table(tileID) == NeX ) pi_ = pj_table(tileID) ! East - if ( pj_table(tileID) == 1 ) pi_ = pi_table(tileID) ! South - if ( pj_table(tileID) == NeY ) pi_ = NeX - pi_table(tileID) + 1 ! North + if ( mod(f,2) == 0 ) then + if ( pi_table(tileID) == 1 ) pi_ = NeY - pj_table(tileID) + 1 ! West + if ( pi_table(tileID) == NeX ) pi_ = pj_table(tileID) ! East + else + if ( pj_table(tileID) == 1 ) pi_ = pi_table(tileID) ! South + if ( pj_table(tileID) == NeY ) pi_ = NeX - pi_table(tileID) + 1 ! North + end if case ( 6 ) pj_ = 1 - if ( pi_table(tileID) == 1 ) pi_ = pj_table(tileID) ! West - if ( pi_table(tileID) == NeX ) pi_ = NeY - pj_table(tileID) + 1 ! East - if ( pj_table(tileID) == 1 ) pi_ = NeX - pi_table(tileID) + 1 ! South - if ( pj_table(tileID) == NeY ) pi_ = pi_table(tileID) ! North + if ( mod(f,2) == 0 ) then + if ( pi_table(tileID) == 1 ) pi_ = pj_table(tileID) ! West + if ( pi_table(tileID) == NeX ) pi_ = NeY - pj_table(tileID) + 1 ! East + else + if ( pj_table(tileID) == 1 ) pi_ = NeX - pi_table(tileID) + 1 ! South + if ( pj_table(tileID) == NeY ) pi_ = pi_table(tileID) ! North + end if end select tilePanelID_map(f,tileID) = panel_connectivity(f,panelID) @@ -152,8 +222,18 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & end do ! loop for f end do ! loop for tile + ! if (PRC_myrank==0) then + ! write(*,*) " MeshUtilCubedSphere2D_modifyConnectivity" + ! do tileID=1, Ntile + ! write(*,'(a,i3,a,2i3)') "tileID=", tileID, ":", pi_table(tileID), pj_table(tileID) + ! write(*,'(a,6i4)') "map_tile:", tileID_map(:,tileID) + ! write(*,'(a,6i4)') "map_panel:", tilePanelID_map(:,tileID) + ! write(*,'(a,6i4)') "mac_face:", tileFaceID_map(:,tileID) + ! end do + ! end if + return - end subroutine MeshUtilCubedSphere2D_buildGlobalMap + end subroutine MeshUtilCubedSphere2D_modifyConnectivity subroutine MeshUtilCubedSphere2D_getPanelConnectivity( panel_connectivity, face_connectivity ) diff --git a/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 b/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 index ea5ced94..56e10dc0 100644 --- a/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 +++ b/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 @@ -13,9 +13,9 @@ module scale_meshutil_cubedsphere3d use scale_prc use scale_meshutil_3d, only: & - MeshUtilCubedSphere3D_genCubeDomain => MeshUtil3D_genCubeDomain, & - MeshUtilCubedSphere3D_genConnectivity => MeshUtil3D_genConnectivity, & - MeshUtilCubedSphere3D_BuildInteriorMap => MeshUtil3D_BuildInteriorMap, & + MeshUtilCubedSphere3D_genCubeDomain => MeshUtil3D_genCubeDomain, & + MeshUtilCubedSphere3D_genConnectivity => MeshUtil3D_genConnectivity, & + MeshUtilCubedSphere3D_BuildInteriorMap => MeshUtil3D_BuildInteriorMap, & MeshUtilCubedSphere3D_genPatchBoundaryMap => MeshUtil3D_genPatchBoundaryMap !----------------------------------------------------------------------------- implicit none @@ -42,7 +42,7 @@ subroutine MeshUtilCubedSphere3D_buildGlobalMap( & use scale_meshutil_3d, only: & MeshUtil3D_genConnectivity use scale_meshutil_cubedsphere2d, only: & - MeshUtilCubedSphere2D_getPanelConnectivity + MeshUtilCubedSphere2D_modifyConnectivity implicit none integer, intent(in) :: Ntile @@ -65,9 +65,6 @@ subroutine MeshUtilCubedSphere3D_buildGlobalMap( & integer :: panelID integer :: tileID, tileID_R integer :: counter - - integer :: panel_connectivity(4,6) - integer :: face_connectivity (4,6) integer :: pi_, pj_ !----------------------------------------------------------------------------- @@ -116,9 +113,6 @@ subroutine MeshUtilCubedSphere3D_buildGlobalMap( & EToV, Ntile, 6 ) tileID_map(:,:) = transpose(EToE) tileFaceID_map(:,:) = transpose(EToF) - - call MeshUtilCubedSphere2D_getPanelConnectivity( & - panel_connectivity, face_connectivity ) do tileID=1, Ntile do f=1, 6 @@ -127,42 +121,10 @@ subroutine MeshUtilCubedSphere3D_buildGlobalMap( & end do end do - !- - do tileID=1, Ntile - panelID = panelID_table(tileID) - - do f=1, 4 - if ( tileFaceID_map(f,tileID) /= f ) cycle ! Does the face correspond the boundary of panel of cubed sphere? - - pi_ = pi_table(tileID) - pj_ = pj_table(tileID) + call MeshUtilCubedSphere2D_modifyConnectivity( & + tilePanelID_map, tileID_map, tileFaceID_map, & ! (inout) + panelID_table, pi_table, pj_table, NeX, NeY, Ntile, 6 ) ! (in) - select case( panelID ) - case ( 1, 2, 3, 4 ) - if ( pi_table(tileID) == 1 ) pi_ = NeX - if ( pi_table(tileID) == NeX ) pi_ = 1 - if ( pj_table(tileID) == 1 ) pj_ = NeY - if ( pj_table(tileID) == NeY ) pj_ = 1 - case ( 5 ) - pj_ = NeY - if ( pi_table(tileID) == 1 ) pi_ = NeY - pj_table(tileID) + 1 ! West - if ( pi_table(tileID) == NeX ) pi_ = pj_table(tileID) ! East - if ( pj_table(tileID) == 1 ) pi_ = pi_table(tileID) ! South - if ( pj_table(tileID) == NeY ) pi_ = NeX - pi_table(tileID) + 1 ! North - case ( 6 ) - pj_ = 1 - if ( pi_table(tileID) == 1 ) pi_ = pj_table(tileID) ! West - if ( pi_table(tileID) == NeX ) pi_ = NeY - pj_table(tileID) + 1 ! East - if ( pj_table(tileID) == 1 ) pi_ = NeX - pi_table(tileID) + 1 ! South - if ( pj_table(tileID) == NeY ) pi_ = pi_table(tileID) ! North - end select - - tilePanelID_map(f,tileID) = panel_connectivity(f,panelID) - tileID_map(f,tileID) = pi_ + (pj_ - 1) * NeX + (tilePanelID_map(f,tileID) - 1) * NeX * NeY - tileFaceID_map(f,tileID) = face_connectivity(f,panelID) - end do ! loop for f - end do ! loop for tile - return end subroutine MeshUtilCubedSphere3D_buildGlobalMap diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 index 11d5c8dd..d5749552 100644 --- a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/mod_user.F90 @@ -123,7 +123,7 @@ subroutine USER_calc_tendency( atm ) if ( USER_do ) then call atm%vars%Calc_diagVar( 'PT_diff', PT_diff ) - call FILE_HISTORY_meshfield_in( PT_diff, "perturbation of T" ) + call FILE_HISTORY_meshfield_in( PT_diff, "perturbation of potential temperature" ) end if return diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf index d9c15e49..5cba1ec1 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/cs2lonlat.cnf @@ -5,7 +5,7 @@ &PARAM_INTERP_FIELD !- input -------------------- in_basename="./history", - vars = "W", "DDENS", "DRHOT", + vars = "W", "PRES_diff", !out_tinterval = 5, / &PARAM_INTERP_FILE diff --git a/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf b/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf index 98e3c8aa..046e1373 100644 --- a/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf +++ b/model/atm_nonhydro3d/test/case/sound_wave_global/run.conf @@ -16,6 +16,9 @@ CONST_OHM = 0.0D0, ! CONST_GRAV = 0.0D0, / +&PARAM_USER + USER_do = .true., +/ #** ATMOS ****************************************************** &PARAM_ATMOS ATMOS_MESH_TYPE = 'GLOBAL', @@ -75,17 +78,16 @@ FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", FILE_HISTORY_OUTPUT_STEP0 = .true., / -&HISTORY_ITEM name='DDENS' / +!&HISTORY_ITEM name='DDENS' / &HISTORY_ITEM name='MOMX' / &HISTORY_ITEM name='MOMY' / &HISTORY_ITEM name='MOMZ' / -&HISTORY_ITEM name='DRHOT' / +!&HISTORY_ITEM name='DRHOT' / &HISTORY_ITEM name='U' / &HISTORY_ITEM name='W' / -!&HISTORY_ITEM name='DPRES' / +&HISTORY_ITEM name='PRES_diff' / &HISTORY_ITEM name='DENS_hyd' / &HISTORY_ITEM name='PRES_hyd' / -!&HISTORY_ITEM name='DTHETA' / #*** Statistics ******************************************* From 324849c221724fd8edad3eaf3c69a5e079fd3587 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 2 Jun 2021 13:46:26 +0900 Subject: [PATCH 47/98] Modify some codes useful for generating initial data. --- FElib/src/mesh/scale_localmesh_1d.F90 | 5 +- FElib/src/mesh/scale_localmesh_2d.F90 | 5 +- FElib/src/mesh/scale_localmesh_3d.F90 | 5 +- FElib/src/mesh/scale_localmesh_base.F90 | 5 +- FElib/src/mesh/scale_mesh_base1d.F90 | 2 +- FElib/src/mesh/scale_mesh_base2d.F90 | 2 +- FElib/src/mesh/scale_mesh_base3d.F90 | 2 +- .../src/admin/mod_dg_driver.F90 | 5 +- .../src/atmos/mod_atmos_mesh_gm.F90 | 8 +- .../src/preprocess/mod_mkinit_util.F90 | 83 ++++++++++++++++++- 10 files changed, 108 insertions(+), 14 deletions(-) diff --git a/FElib/src/mesh/scale_localmesh_1d.F90 b/FElib/src/mesh/scale_localmesh_1d.F90 index 8b2d5264..5f1147d5 100644 --- a/FElib/src/mesh/scale_localmesh_1d.F90 +++ b/FElib/src/mesh/scale_localmesh_1d.F90 @@ -43,17 +43,18 @@ module scale_localmesh_1d contains subroutine LocalMesh1D_Init( this, & - refElem, myrank ) + lcdomID, refElem, myrank ) implicit none type(LocalMesh1D), intent(inout) :: this + integer, intent(in) :: lcdomID class(elementbase1D), intent(in), target :: refElem integer, intent(in), optional :: myrank !------------------------------------------------- this%refElem1D => refElem - call LocalMeshBase_Init(this, refElem, 1, myrank) + call LocalMeshBase_Init(this, lcdomID, refElem, 1, myrank) return end subroutine LocalMesh1D_Init diff --git a/FElib/src/mesh/scale_localmesh_2d.F90 b/FElib/src/mesh/scale_localmesh_2d.F90 index 9e2e3a10..0dc2437b 100644 --- a/FElib/src/mesh/scale_localmesh_2d.F90 +++ b/FElib/src/mesh/scale_localmesh_2d.F90 @@ -48,17 +48,18 @@ module scale_localmesh_2d contains subroutine LocalMesh2D_Init( this, & - refElem, myrank ) + lcdomID, refElem, myrank ) implicit none class(LocalMesh2D), intent(inout) :: this + integer, intent(in) :: lcdomID class(ElementBase2D), intent(in), target :: refElem integer, intent(in), optional :: myrank !------------------------------------------------- this%refElem2D => refElem - call LocalMeshBase_Init(this, refElem, 2, myrank) + call LocalMeshBase_Init(this, lcdomID, refElem, 2, myrank) return end subroutine LocalMesh2D_Init diff --git a/FElib/src/mesh/scale_localmesh_3d.F90 b/FElib/src/mesh/scale_localmesh_3d.F90 index a121636e..e297ca9d 100644 --- a/FElib/src/mesh/scale_localmesh_3d.F90 +++ b/FElib/src/mesh/scale_localmesh_3d.F90 @@ -59,10 +59,11 @@ module scale_localmesh_3d contains subroutine LocalMesh3D_Init( this, & - refElem, myrank ) + lcdomID, refElem, myrank ) implicit none class(LocalMesh3D), intent(inout) :: this + integer, intent(in) :: lcdomID class(ElementBase3D), intent(in), target :: refElem integer, intent(in), optional :: myrank !------------------------------------------------- @@ -70,7 +71,7 @@ subroutine LocalMesh3D_Init( this, & this%refElem3D => refElem nullify( this%lcmesh2D ) - call LocalMeshBase_Init( this, refElem, 3, myrank ) + call LocalMeshBase_Init( this, lcdomID, refElem, 3, myrank ) return end subroutine LocalMesh3D_Init diff --git a/FElib/src/mesh/scale_localmesh_base.F90 b/FElib/src/mesh/scale_localmesh_base.F90 index dbe8cd5b..27823d3a 100644 --- a/FElib/src/mesh/scale_localmesh_base.F90 +++ b/FElib/src/mesh/scale_localmesh_base.F90 @@ -57,6 +57,7 @@ module scale_localmesh_base integer :: tileID integer :: panelID integer :: PRC_myrank + integer :: lcdomID real(DP), allocatable :: G_ij(:,:,:,:) real(DP), allocatable :: GIJ(:,:,:,:) @@ -88,17 +89,19 @@ module scale_localmesh_base ! contains - subroutine LocalMeshBase_Init( this, refElem, ndim, myrank ) + subroutine LocalMeshBase_Init( this, lcdomID, refElem, ndim, myrank ) use scale_prc, only: PRC_myrank implicit none class(LocalMeshBase), intent(inout) :: this + integer, intent(in) :: lcdomID class(ElementBase), intent(in), target :: refElem integer, intent(in) :: ndim integer, intent(in), optional :: myrank !----------------------------------------------------------------------------- + this%lcdomID = lcdomID this%refElem => refElem if (present(myrank)) then diff --git a/FElib/src/mesh/scale_mesh_base1d.F90 b/FElib/src/mesh/scale_mesh_base1d.F90 index a0f0818a..13da3c89 100644 --- a/FElib/src/mesh/scale_mesh_base1d.F90 +++ b/FElib/src/mesh/scale_mesh_base1d.F90 @@ -118,7 +118,7 @@ subroutine Meshbase1d_Init( this, & allocate( this%lcmesh_list(this%LOCAL_MESH_NUM) ) do n=1, this%LOCAL_MESH_NUM - call LocalMesh1D_Init( this%lcmesh_list(n), refElem, myrank ) + call LocalMesh1D_Init( this%lcmesh_list(n), n, refElem, myrank ) end do call this%SetDimInfo( MeshBase1D_DIMTYPEID_X, "x", "m", "X-coordinate" ) diff --git a/FElib/src/mesh/scale_mesh_base2d.F90 b/FElib/src/mesh/scale_mesh_base2d.F90 index 751459b0..2213cfa5 100644 --- a/FElib/src/mesh/scale_mesh_base2d.F90 +++ b/FElib/src/mesh/scale_mesh_base2d.F90 @@ -85,7 +85,7 @@ subroutine MeshBase2D_Init(this, & allocate( this%lcmesh_list(this%LOCAL_MESH_NUM) ) do n=1, this%LOCAL_MESH_NUM - call LocalMesh2D_Init( this%lcmesh_list(n), refElem, myrank ) + call LocalMesh2D_Init( this%lcmesh_list(n), n, refElem, myrank ) end do call this%SetDimInfo( MeshBase2D_DIMTYPEID_X, "x", "m", "X-coordinate" ) diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index 94977e28..4bf36a64 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -96,7 +96,7 @@ subroutine MeshBase3D_Init(this, & allocate( this%lcmesh_list(this%LOCAL_MESH_NUM) ) do n=1, this%LOCAL_MESH_NUM - call LocalMesh3D_Init( this%lcmesh_list(n), refElem, myrank ) + call LocalMesh3D_Init( this%lcmesh_list(n), n, refElem, myrank ) end do call this%SetDimInfo( MeshBase3D_DIMTYPEID_X, "x", "m", "X-coordinate" ) diff --git a/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 b/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 index a409997f..ee96710f 100644 --- a/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 +++ b/model/atm_nonhydro3d/src/admin/mod_dg_driver.F90 @@ -141,7 +141,7 @@ subroutine dg_driver( & !- ATMOS if ( atmos%IsActivated() .and. atmos%time_manager%do_step ) then - call atmos%update() + call atmos%update() end if !- USER @@ -303,7 +303,8 @@ subroutine restart_read() if ( atmos%IsActivated() ) then call atmos%calc_tendency() end if - + + call USER_calc_tendency( atmos ) !- History & Monitor diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 index 88538e45..14abe3dc 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 @@ -228,7 +228,7 @@ subroutine AtmosMeshGM_calc_UVMet( this, U, V, & type(MeshField3D), intent(inout) :: Vmet integer :: n - integer :: ke + integer :: ke, ke2D type(LocalMesh3D), pointer :: lcmesh class(ElementBase3D), pointer :: elem !------------------------------------------ @@ -243,6 +243,12 @@ subroutine AtmosMeshGM_calc_UVMet( this, U, V, & V%local(n)%val(:,lcmesh%NeS:lcmesh%NeE), & Umet%local(n)%val(:,lcmesh%NeS:lcmesh%NeE), & Vmet%local(n)%val(:,lcmesh%NeS:lcmesh%NeE) ) + + !$omp parallel do private(ke2D) + do ke=lcmesh%NeS, lcmesh%NeE + ke2D = lcmesh%EMap3Dto2D(ke) + Umet%local(n)%val(:,ke) = Umet%local(n)%val(:,ke) * cos(lcmesh%lat2D(elem%IndexH2Dto3D(:),ke2D)) + end do end do return diff --git a/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 b/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 index c7e8cfca..496b8174 100644 --- a/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 +++ b/model/atm_nonhydro3d/src/preprocess/mod_mkinit_util.F90 @@ -22,8 +22,10 @@ module mod_mkinit_util use scale_const, only: & PI => CONST_PI - use scale_element_base, only: ElementBase3D + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_element_quadrilateral, only: QuadrilateralElement use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_localmeshfield_base, only: LocalMeshFieldBase @@ -40,6 +42,7 @@ module mod_mkinit_util public :: mkinitutil_gen_Vm1Mat public :: mkinitutil_calc_cosinebell public :: mkinitutil_calc_cosinebell_global + public :: mkinitutil_GalerkinProjection_global contains @@ -277,4 +280,82 @@ end subroutine mkinitutil_calc_cosinebell_global !------------------------------------------ + subroutine mkinitutil_GalerkinProjection_global( q, & + func, IntrpPolyOrder_h, IntrpPolyOrder_v, & + lcmesh3D, elem, rplanet ) + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatCoord + + implicit none + class(LocalMesh3D), intent(in) :: lcmesh3D + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: q(elem%Np,lcmesh3D%NeA) + integer, intent(in) :: IntrpPolyOrder_h + integer, intent(in) :: IntrpPolyOrder_v + real(RP), intent(in) :: rplanet + + interface + subroutine func( q_intrp, & + lon, lat, z, elem_intrp, rplanet_ ) + import ElementBase3D + import RP + class(ElementBase3D), intent(in) :: elem_intrp + real(RP), intent(out) :: q_intrp(elem_intrp%Np) + real(RP), intent(in) :: lon(elem_intrp%Np) + real(RP), intent(in) :: lat(elem_intrp%Np) + real(RP), intent(in) :: z(elem_intrp%Np) + real(RP), intent(in) :: rplanet_ + end subroutine func + end interface + + type(HexahedralElement) :: elem_intrp + real(RP), allocatable :: x_intrp(:,:), y_intrp(:,:), z_intrp(:,:) + real(RP), allocatable :: lon_intrp(:,:), lat_intrp(:,:) + real(RP) :: vx(elem%Nv), vy(elem%Nv), vz(elem%Nv) + + real(RP), allocatable :: IntrpMat(:,:) + real(RP), allocatable :: q_intrp(:) + + integer :: ke + !----------------------------------------------- + + call elem_intrp%Init( IntrpPolyOrder_h, IntrpPolyOrder_v, .false. ) + + allocate( IntrpMat(elem%Np,elem_intrp%Np) ) + call mkinitutil_gen_GPMat( IntrpMat, elem_intrp, elem ) + + allocate( x_intrp(elem_intrp%Np,lcmesh3D%Ne), y_intrp(elem_intrp%Np,lcmesh3D%Ne), z_intrp(elem_intrp%Np,lcmesh3D%Ne) ) + allocate( lon_intrp(elem_intrp%Np,lcmesh3D%Ne), lat_intrp(elem_intrp%Np,lcmesh3D%Ne) ) + allocate( q_intrp(elem_intrp%Np) ) + + !$omp parallel do private(vx, vy, vz) + do ke=lcmesh3D%NeS, lcmesh3D%NeE + vx(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),1) + vy(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),2) + vz(:) = lcmesh3D%pos_ev(lcmesh3D%EToV(ke,:),3) + x_intrp(:,ke) = vx(1) + 0.5_RP * ( elem_intrp%x1(:) + 1.0_RP ) * ( vx(2) - vx(1) ) + y_intrp(:,ke) = vy(1) + 0.5_RP * ( elem_intrp%x2(:) + 1.0_RP ) * ( vy(4) - vy(1) ) + z_intrp(:,ke) = vz(1) + 0.5_RP * ( elem_intrp%x3(:) + 1.0_RP ) * ( vz(5) - vz(1) ) + end do + + call CubedSphereCnv_CS2LonLatCoord( lcmesh3D%panelID, x_intrp, y_intrp, elem_intrp%Np * lcmesh3D%Ne, & + rplanet, lon_intrp(:,:), lat_intrp(:,:) ) + + !$omp parallel do private( q_intrp ) + do ke=lcmesh3D%NeS, lcmesh3D%NeE + + call func( q_intrp, & ! (out) + lon_intrp(:,ke), lat_intrp(:,ke), z_intrp(:,ke), & ! (in) + elem_intrp, rplanet ) ! (in) + + ! Perform Galerkin projection + q(:,ke) = matmul( IntrpMat, q_intrp ) + end do + + call elem_intrp%Final() + + return + end subroutine mkinitutil_GalerkinProjection_global + end module mod_mkinit_util From 61a375c5a0094f18b46f8267931c60458fd3bb5e Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 2 Jun 2021 13:55:13 +0900 Subject: [PATCH 48/98] Fix a bug in source codes of global dynamical core. --- ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 85 ++++++++++++------- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 74 +++++++++++----- 2 files changed, 108 insertions(+), 51 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index cb3513e8..c5060e4f 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -175,27 +175,30 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & real(RP), intent(in) :: wdamp_height real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP) :: PRES_(elem%Np) + real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP) :: DPRES_(elem%Np) real(RP) :: RHOT_(elem%Np) - real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) - real(RP) :: drho(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), drho(elem%Np) - integer :: ke, ke2d - - real(RP) :: gamm, rgamm - real(RP) :: rP0 - real(RP) :: RovP0, P0ovR real(RP) :: GIJ(elem%Np,2,2) + real(RP) :: X2D(elem%Np,lmesh2D%Ne), Y2D(elem%Np,lmesh2D%Ne) real(RP) :: X(elem%Np), Y(elem%Np), twoOVdel2(elem%Np) real(RP) :: CORI(elem%Np,2) - real(RP) :: s logical :: is_panel1to4 + real(RP) :: s + + integer :: ke, ke2d + integer :: p, p12, p3 + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR !------------------------------------------------------------------------ call PROF_rapstart('cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, & ! (out) + call cal_del_flux_dyn( del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) @@ -219,19 +222,25 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & s = - 1.0_RP end if - !$omp parallel private( & - !$omp RHOT_, PRES_, rdens_, u_, v_, w_, ke2d, drho, & - !$omp Fx, Fy, Fz, LiftDelFlx, & - !$omp GIJ, X, Y, twoOVdel2, CORI ) + !$omp parallel private( & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, & + !$omp Fx, Fy, Fz, LiftDelFlx, & + !$omp drho, GradPhyd_x, GradPhyd_y, & + !$omp GIJ, X, Y, twoOVdel2, & + !$omp CORI, ke, ke2D ) + + !$omp do + do ke2D = lmesh2D%NeS, lmesh2D%NeE + X2D(:,ke2d) = tan(lmesh2D%pos_en(:,ke2d,1)) + Y2D(:,ke2d) = tan(lmesh2D%pos_en(:,ke2d,2)) + end do + !$omp do do ke = lmesh%NeS, lmesh%NeE !-- - X(:) = lmesh%pos_en(:,ke,1) - Y(:) = lmesh%pos_en(:,ke,2) - twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) - RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) - PRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm + DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & + - PRES_hyd(:,ke) rdens_(:) = 1.0_RP / ( DDENS_(:,ke) + DENS_hyd(:,ke) ) u_ (:) = MOMX_(:,ke) * rdens_(:) @@ -244,15 +253,28 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & GIJ(:,1,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + X(:) = X2D(elem%IndexH2Dto3D,ke2d) + Y(:) = Y2D(elem%IndexH2Dto3D,ke2d) + twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) + CORI(:,1) = s * OHM * twoOVdel2(:) * ( - X(:) * Y(:) * MOMX_(:,ke) + (1.0_RP + Y(:)**2) * MOMY_(:,ke) ) CORI(:,2) = s * OHM * twoOVdel2(:) * ( - (1.0_RP + X(:)**2) * MOMX_(:,ke) + X(:) * Y(:) * MOMY_(:,ke) ) if ( is_panel1to4 ) then - CORI(:,1) = Y(:) * CORI(:,1) - CORI(:,2) = Y(:) * CORI(:,2) + CORI(:,1) = s * Y(:) * CORI(:,1) + CORI(:,2) = s * Y(:) * CORI(:,2) end if drho(:) = matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) + !-- Gradient hydrostatic pressure + call sparsemat_matmul(Dx, PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) + LiftDelFlx(:) + + call sparsemat_matmul(Dy, PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) + LiftDelFlx(:) + !-- DENS call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) @@ -266,9 +288,9 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- MOMX - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * PRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * PRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMX_ID), LiftDelFlx) MOMX_dt(:,ke) = & @@ -278,12 +300,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + twoOVdel2(:) * Y(:) * & ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & + - ( GIJ(:,1,1) * GradPhyd_x(:) + GIJ(:,1,2) * GradPhyd_y(:) ) & + CORI(:,1) !-- MOMY - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * PRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * PRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMY_ID), LiftDelFlx) MOMY_dt(:,ke) = & @@ -293,12 +316,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + twoOVdel2(:) * X(:) * & ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + - ( GIJ(:,2,1) * GradPhyd_x(:) + GIJ(:,2,2) * GradPhyd_y(:) ) & + CORI(:,2) !-- MOMZ call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( w_(:) * MOMZ_(:,ke) + PRES_(:) - PRES_hyd(:,ke) ), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( w_(:) * MOMZ_(:,ke) + DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMZ_ID), LiftDelFlx) MOMZ_dt(:,ke) = & @@ -339,7 +363,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend !------ !OCL SERIAL - subroutine cal_del_flux_dyn( del_flux, & + subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & Gsqrt, G11, G12, G22, nx, ny, nz, & vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) @@ -351,6 +375,7 @@ subroutine cal_del_flux_dyn( del_flux, & class(LocalMesh2D), intent(in) :: lmesh2D class(elementbase2D), intent(in) :: elem2D real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) @@ -467,6 +492,8 @@ subroutine cal_del_flux_dyn( del_flux, & ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) + del_flux_hyd(:,ke,1) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * nx(:,ke) + del_flux_hyd(:,ke,2) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * ny(:,ke) end do return diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index 1f514519..f2ad9a1f 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -177,26 +177,30 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & real(RP), intent(in) :: wdamp_height real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) real(RP) :: DPRES_(elem%Np) real(RP) :: RHOT_(elem%Np) real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) - integer :: ke, ke2d - - real(RP) :: gamm, rgamm - real(RP) :: rP0 - real(RP) :: RovP0, P0ovR real(RP) :: GIJ(elem%Np,2,2) + real(RP) :: X2D(elem%Np,lmesh2D%Ne), Y2D(elem%Np,lmesh2D%Ne) real(RP) :: X(elem%Np), Y(elem%Np), twoOVdel2(elem%Np) real(RP) :: CORI(elem%Np,2) - real(RP) :: s logical :: is_panel1to4 + real(RP) :: s + + integer :: ke, ke2d + integer :: p, p12, p3 + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR !------------------------------------------------------------------------ call PROF_rapstart('cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, & ! (out) + call cal_del_flux_dyn( del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) @@ -220,20 +224,26 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & s = - 1.0_RP end if - !$omp parallel do private( & - !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, ke2d, & + !$omp parallel private( & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, & !$omp Fx, Fy, Fz, LiftDelFlx, & - !$omp GIJ, X, Y, twoOVdel2, CORI ) + !$omp GradPhyd_x, GradPhyd_y, & + !$omp GIJ, X, Y, twoOVdel2, & + !$omp CORI, ke, ke2D ) + + !$omp do + do ke2D = lmesh2D%NeS, lmesh2D%NeE + X2D(:,ke2d) = tan(lmesh2D%pos_en(:,ke2d,1)) + Y2D(:,ke2d) = tan(lmesh2D%pos_en(:,ke2d,2)) + end do + + !$omp do do ke = lmesh%NeS, lmesh%NeE !-- - X(:) = lmesh%pos_en(:,ke,1) - Y(:) = lmesh%pos_en(:,ke,2) - twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) - RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & - PRES_hyd(:,ke) - + rdens_(:) = 1.0_RP / ( DDENS_(:,ke) + DENS_hyd(:,ke) ) u_ (:) = MOMX_(:,ke) * rdens_(:) v_ (:) = MOMY_(:,ke) * rdens_(:) @@ -245,13 +255,26 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & GIJ(:,1,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + X(:) = X2D(elem%IndexH2Dto3D,ke2d) + Y(:) = Y2D(elem%IndexH2Dto3D,ke2d) + twoOVdel2(:) = 2.0_RP / ( 1.0_RP + X(:)**2 + Y(:)**2 ) + CORI(:,1) = s * OHM * twoOVdel2(:) * ( - X(:) * Y(:) * MOMX_(:,ke) + (1.0_RP + Y(:)**2) * MOMY_(:,ke) ) CORI(:,2) = s * OHM * twoOVdel2(:) * ( - (1.0_RP + X(:)**2) * MOMX_(:,ke) + X(:) * Y(:) * MOMY_(:,ke) ) if ( is_panel1to4 ) then - CORI(:,1) = Y(:) * CORI(:,1) - CORI(:,2) = Y(:) * CORI(:,2) + CORI(:,1) = s * Y(:) * CORI(:,1) + CORI(:,2) = s * Y(:) * CORI(:,2) end if - + + !-- Gradient hydrostatic pressure + call sparsemat_matmul(Dx, PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) + LiftDelFlx(:) + + call sparsemat_matmul(Dy, PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) + LiftDelFlx(:) + !-- DENS call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) @@ -275,12 +298,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + twoOVdel2(:) * Y(:) * & ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & + - ( GIJ(:,1,1) * GradPhyd_x(:) + GIJ(:,1,2) * GradPhyd_y(:) ) & + CORI(:,1) - + !-- MOMY call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) MOMY_dt(:,ke) = & @@ -290,8 +314,9 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + twoOVdel2(:) * X(:) * & ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + - ( GIJ(:,2,1) * GradPhyd_x(:) + GIJ(:,2,2) * GradPhyd_y(:) ) & + CORI(:,2) - + !-- MOMZ call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) @@ -314,6 +339,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + lmesh%Escale(:,ke,2,2) * Fy(:) & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) end do + !$omp end parallel call PROF_rapend('cal_dyn_tend_interior', 3) !- Sponge layer @@ -330,7 +356,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend !------ !OCL SERIAL - subroutine cal_del_flux_dyn( del_flux, & + subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & Gsqrt, G11, G12, G22, nx, ny, nz, & vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) @@ -342,6 +368,7 @@ subroutine cal_del_flux_dyn( del_flux, & class(LocalMesh2D), intent(in) :: lmesh2D class(elementbase2D), intent(in) :: elem2D real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) @@ -457,6 +484,9 @@ subroutine cal_del_flux_dyn( del_flux, & del_flux(:,ke,DRHOT_VID) = 0.5_RP * Gsqrt_M(:) * ( & swV(:) * ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * nx(:,ke) + del_flux_hyd(:,ke,2) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * ny(:,ke) end do return From 9af7fbe2bfe9bf2062962f9a5aa0d1346547c414 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 2 Jun 2021 13:55:28 +0900 Subject: [PATCH 49/98] Update a document. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36337db0..d87c123a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Futhermore, some dynamical cores of atmospheric and oceanic model with DGM will ### Nonhydrostatic atmospheric model - Simple 2D model with only dynamical process -- 3D model with dynamical process and some physical processes +- Regional/Global model with dynamical process and some physical processes ## Simple samples for intrduction to DGM. ### 1D problems From 6a26e584c95a79bfdd7922f9e401b7c40df127b6 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 2 Jun 2021 13:56:55 +0900 Subject: [PATCH 50/98] Add two test cases to vertify a global dynamical core. --- .../test/case/baroclinic_wave_global/Makefile | 28 + .../case/baroclinic_wave_global/cs2lonlat.cnf | 36 ++ .../case/baroclinic_wave_global/init.conf | 45 ++ .../case/baroclinic_wave_global/mod_user.F90 | 529 ++++++++++++++++++ .../test/case/baroclinic_wave_global/run.conf | 103 ++++ .../test/case/equatorial_wave_global/Makefile | 28 + .../case/equatorial_wave_global/cs2lonlat.cnf | 35 ++ .../case/equatorial_wave_global/init.conf | 41 ++ .../case/equatorial_wave_global/mod_user.F90 | 321 +++++++++++ .../test/case/equatorial_wave_global/run.conf | 101 ++++ 10 files changed, 1267 insertions(+) create mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/Makefile create mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf create mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/init.conf create mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf create mode 100644 model/atm_nonhydro3d/test/case/equatorial_wave_global/Makefile create mode 100644 model/atm_nonhydro3d/test/case/equatorial_wave_global/cs2lonlat.cnf create mode 100644 model/atm_nonhydro3d/test/case/equatorial_wave_global/init.conf create mode 100644 model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/Makefile b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf new file mode 100644 index 00000000..7b18895a --- /dev/null +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf @@ -0,0 +1,36 @@ +&PARAM_IO + IO_LOG_BASENAME = "cs2lonlat_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "W", "Umet", "Vmet", "T", "PRES_hyd", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_INTERP_MESH + !-- input ---------------- + in_Nprc = 6, + in_NeGX = 9, + in_NeGY = 9, + in_NeGZ = 4, + in_PolyOrder_h = 7, + in_PolyOrder_v = 7, + in_NLocalMeshPerPrc = 1, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + in_Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, + !-- output ---------------- + out_NprcX = 2, + out_NeX = 32, + out_NprcY = 2, + out_NeY = 16, + out_NeZ = 15, + out_PolyOrder_h =3, + out_PolyOrder_v =2, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/init.conf b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/init.conf new file mode 100644 index 00000000..087491b2 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/init.conf @@ -0,0 +1,45 @@ +#--- Configuration file for a test case of baroclinic wave proposed by Jablonowski and Williamson (2006) ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'baroclinic_wave_global', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP + Up=1.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeZ = 4, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, +! LumpedMassMatFlag = .true., + +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "NONHYDRO3D_HEVE", + !- + TINTEG_TYPE = 'ERK_SSP_3s3o', + !- +/ diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/mod_user.F90 new file mode 100644 index 00000000..6b2e2301 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/mod_user.F90 @@ -0,0 +1,529 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! Set the initial data for baroclinic wave in global model based on Jablonowski and Williamson (2006). +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + + use scale_const, only: & + EPS => CONST_EPS, & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS, & + OHM => CONST_OHM + + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_3d, only: LocalMesh3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + + real(RP), private :: f0, beta0 + real(RP), private :: y0 + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_baroclinic_wave_global + contains + procedure :: setInitCond_lc => exp_SetInitCond_baroclinicwave + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_baroclinic_wave_global), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + !------------------------------------------ + + call exp_manager%Init('baroclinic_wave') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + + return + end subroutine USER_setup + + subroutine USER_calc_tendency( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_update + + !------ + + subroutine exp_SetInitCond_baroclinicwave( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatCoord, & + CubedSphereCnv_LonLat2CSVec + + use mod_mkinit_util, only: & + mkinitutil_gen_GPMat, & + mkinitutil_gen_Vm1Mat + + implicit none + + class(Exp_baroclinic_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + ! Parameters for inital stratification + real(RP) :: REF_TEMP = 288.E0_RP ! The reference temperature [K] + real(RP) :: REF_PRES = 1.E5_RP ! The reference pressure [Pa] + real(RP) :: LAPSE_RATE = 5.E-3_RP ! The lapse rate [K/m] + + real(RP) :: ETA_tropo = 0.2_RP ! The value oftropopause level + real(RP) :: ETA0 = 0.252_RP ! The value of η at a reference level (position of the jet) + real(RP) :: DT_strat = 4.8E5_RP ! The empirical temperature difference + + ! Parameters for background zonal jet + real(RP) :: U0 = 35.E0_RP ! The parameter associated with zonal jet maximum amplitude [m/s] + + ! Parameters for inital perturbation of zonal wind with a Gaussian profile + ! + real(RP) :: Up = 1.E0_RP ! The maximum amplitude of zonal wind perturbation [m/s] + real(RP) :: Lp ! The width of Gaussian profile + real(RP) :: latc ! The center point (lat) of inital perturbation + real(RP) :: lonc ! The center point (lon) of inital perturbation + + namelist /PARAM_EXP/ & + REF_TEMP, REF_PRES, LAPSE_RATE, & + ETA_tropo, ETA0, U0, & + Up, Lp, latc, lonc + + real(RP) :: geopot_hvari1, geopot_hvari2 + real(RP), allocatable :: pres_intrp(:,:,:,:,:,:) + real(RP), allocatable :: temp_intrp(:,:,:,:,:,:) + + integer :: ke, ke2D + integer :: i, j, k + integer :: p1, p2, p3, p_, p2D_ + + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 + type(HexahedralElement) :: elem_intrp + real(RP), allocatable :: x_intrp(:), y_intrp(:), z_intrp(:) + real(RP), allocatable :: x_intrp2D(:), y_intrp2D(:) + real(RP), allocatable :: gauss_intrp2D(:) + real(RP) :: vx(elem%Nv), vy(elem%Nv), vz(elem%Nv) + real(RP), allocatable :: IntrpMat(:,:) + real(RP), allocatable :: IntrpVM1Mat(:,:) + integer :: p_intrp + + real(RP), allocatable :: dens_intrp(:) + real(RP), allocatable :: etav_intrp(:) + real(RP), allocatable :: pres_hyd_intrp(:) + real(RP), allocatable :: temp_hyd_intrp(:) + real(RP), allocatable :: dens_hyd_intrp(:) + real(RP), allocatable :: cos_3ov2_etav_intrp(:) + + real(RP), allocatable :: lon(:,:,:) + real(RP), allocatable :: lat(:,:,:) + real(RP) :: MOMX_met_ov_coslat(elem%Np,lcmesh%Ne) + real(RP) :: MOMY_met (elem%Np,lcmesh%Ne) + + real(RP) :: Gamm, RGamma + real(RP) :: Fy(elem%Np) + + integer :: ierr + !----------------------------------------------------------------------------- + + Lp = RPlanet / 10.0_RP + lonc = PI / 9.0_RP + latc = PI * 2.0_RP / 9.0_RP + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("BAROCLINIC_WAVE_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("BAROCLINIC_WAVE_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + + call elem_intrp%Init( IntrpPolyOrder_h, IntrpPolyOrder_v, elem%IsLumpedMatrix() ) + + allocate( IntrpMat(elem%Np,elem_intrp%Np) ) + call mkinitutil_gen_GPMat( IntrpMat, elem_intrp, elem ) + + allocate( IntrpVm1Mat(elem%Np,elem_intrp%Np) ) + call mkinitutil_gen_Vm1Mat( IntrpVM1Mat, elem_intrp, elem ) + + !--- + + allocate( pres_intrp(elem_intrp%Nnode_h1D,elem_intrp%Nnode_h1D,elem_intrp%Nnode_v,lcmesh%NeX,lcmesh%NeY,lcmesh%NeZ) ) + allocate( temp_intrp(elem_intrp%Nnode_h1D,elem_intrp%Nnode_h1D,elem_intrp%Nnode_v,lcmesh%NeX,lcmesh%NeY,lcmesh%NeZ) ) + + allocate( x_intrp(elem_intrp%Np), y_intrp(elem_intrp%Np), z_intrp(elem_intrp%Np) ) + allocate( x_intrp2D(elem_intrp%Nnode_h1D**2), y_intrp2D(elem_intrp%Nnode_h1D**2) ) + allocate( pres_hyd_intrp(elem_intrp%Np), temp_hyd_intrp(elem_intrp%Np) ) + allocate( dens_intrp(elem_intrp%Np), dens_hyd_intrp(elem_intrp%Np) ) + allocate( etav_intrp(elem_intrp%Np), cos_3ov2_etav_intrp(elem_intrp%Np) ) + allocate( gauss_intrp2D(elem_intrp%Nnode_h1D**2) ) + + allocate( lon(elem_intrp%Nnode_h1D**2,lcmesh%NeX,lcmesh%NeY) ) + allocate( lat(elem_intrp%Nnode_h1D**2,lcmesh%NeX,lcmesh%NeY) ) + + ! Calculate eta(=p/p_s) level corresponding to z level of each (y,z) grid point + ! using Newton's iteration method + + do j=1, lcmesh%NeY + do i=1, lcmesh%NeX + ke2D = i + (j-1)*lcmesh%NeX + vx(:) = lcmesh%pos_ev(lcmesh%EToV(ke2D,:),1) + vy(:) = lcmesh%pos_ev(lcmesh%EToV(ke2D,:),2) + x_intrp2D(:) = vx(1) + 0.5_RP * (elem_intrp%x1(elem_intrp%Hslice(:,1)) + 1.0_RP) * ( vx(2) - vx(1) ) + y_intrp2D(:) = vy(1) + 0.5_RP * (elem_intrp%x2(elem_intrp%Hslice(:,1)) + 1.0_RP) * ( vy(3) - vy(1) ) + + call CubedSphereCnv_CS2LonLatCoord( lcmesh%panelID, x_intrp2D(:), y_intrp2D(:), elem_intrp%Nnode_h1D**2, RPlanet, & + lon(:,i,j), lat(:,i,j) ) + where( abs( lat(:,i,j) - 0.5_RP * PI ) < EPS .or. abs( lat(:,i,j) + 0.5_RP * PI ) < EPS ) + lat(:,i,j) =lat(:,i,j) - sign(1.0E-16_RP, lat(:,i,j)) + end where + end do + end do + + !$omp parallel do collapse(2) private( & + !$omp ke2D, p2D_, geopot_hvari1, geopot_hvari2, & + !$omp k, ke, vz, z_intrp, p1, p2, p3, p_ ) + do j=1, lcmesh%NeY + do i=1, lcmesh%NeX + do p2=1, elem_intrp%Nnode_h1D + do p1=1, elem_intrp%Nnode_h1D + + ke2D = i + (j-1)*lcmesh%NeX + p2D_ = p1 + (p2-1)*elem_intrp%Nnode_h1D + + call get_thermal_wind_balance_1point_geopot_hvari( & + geopot_hvari1, geopot_hvari2, & ! (out) + lat(p2D_,i,j), U0 ) ! (in) + + do k=1, lcmesh%NeZ + ke = ke2D + (k-1)*lcmesh%NeX*lcmesh%NeY + + vz(:) = lcmesh%pos_ev(lcmesh%EToV(ke,:),3) + z_intrp(:) = vz(1) + 0.5_RP*(elem_intrp%x3(:) + 1.0_RP)*(vz(5) - vz(1)) + + do p3=1, elem_intrp%Nnode_v + p_ = p2D_ + (p3-1)*elem_intrp%Nnode_h1D**2 + call get_thermal_wind_balance_1point_itr( & + pres_intrp(p1,p2,p3,i,j,k), temp_intrp(p1,p2,p3,i,j,k), & ! (out) + geopot_hvari1, geopot_hvari2, REF_TEMP, REF_PRES, LAPSE_RATE, & ! (in) + ETA0, ETA_tropo, DT_strat, & ! (in) + p_, ke, lat(p2D_,i,j), z_intrp(p_), .false. ) ! (in) + + end do ! for p3 + end do ! for k + end do ! for p1 + end do ! for p2 + end do ! for i + end do ! for j + + Gamm = CpDry/CvDry + RGamma = CvDry/CpDry + + !$omp parallel do collapse(3) private( ke, ke2D, p3, p2, p1, p_, & + !$omp etav_intrp, cos_3ov2_etav_intrp, & + !$omp pres_hyd_intrp, temp_hyd_intrp, dens_hyd_intrp, & + !$omp gauss_intrp2D ) + do k = 1, lcmesh%NeZ + do j = 1, lcmesh%NeY + do i = 1, lcmesh%NeX + ke = i + (j-1)*lcmesh%NeX + (k-1)*lcmesh%NeX*lcmesh%NeY + ke2D = i + (j-1)*lcmesh%NeX + + do p3 = 1, elem_intrp%Nnode_v + do p2 = 1, elem_intrp%Nnode_h1D + do p1 = 1, elem_intrp%Nnode_h1D + p_ = p1 + (p2-1)*elem_intrp%Nnode_h1D + (p3-1)*elem_intrp%Nnode_h1D**2 + pres_hyd_intrp(p_) = pres_intrp(p1,p2,p3,i,j,k) + temp_hyd_intrp(p_) = temp_intrp(p1,p2,p3,i,j,k) + end do + end do + end do + + PRES_hyd(:,ke) = matmul(IntrpMat, pres_hyd_intrp(:)) + + dens_hyd_intrp(:) = pres_hyd_intrp(:) / ( Rdry * temp_hyd_intrp(:) ) + DENS_hyd(:,ke) = matmul(IntrpVM1Mat, dens_hyd_intrp) + + etav_intrp(:) = 0.5_RP * PI * ( pres_hyd_intrp(:) / REF_PRES - ETA0 ) + cos_3ov2_etav_intrp(:) = cos( etav_intrp(:) ) * sqrt( cos(etav_intrp(:)) ) + + gauss_intrp2D(:) = exp ( - ( RPlanet / Lp & + * acos( sin(latc) * sin(lat(:,i,j)) + cos(latc) * cos(lat(:,i,j)) * cos(lon(:,i,j) - lonc) ) )**2 ) + + MOMX_met_ov_coslat(:,ke) = & + + matmul( IntrpMat, & + dens_hyd_intrp(:) * ( & + U0 * sin(2.0_RP * lat(elem_intrp%IndexH2Dto3D,i,j))**2 * cos_3ov2_etav_intrp(:) & + + Up * gauss_intrp2D(elem_intrp%IndexH2Dto3D(:)) ) ) + + MOMX_met_ov_coslat(:,ke) = MOMX_met_ov_coslat(:,ke) / cos( lcmesh%lat2D(elem%IndexH2Dto3D,ke2D) ) + MOMY_met(:,ke) = 0.0_RP + end do + end do + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + MOMX_met_ov_coslat(:,:), MOMY_met(:,:), & + MOMX(:,lcmesh%NeS:lcmesh%NeE), MOMY(:,lcmesh%NeS:lcmesh%NeE) ) + + !------ + call elem_intrp%Final() + + return + end subroutine exp_SetInitCond_baroclinicwave + + subroutine get_thermal_wind_balance_1point_geopot_hvari( & + geopot_hvari1, geopot_hvari2, & + lat, U0 ) + implicit none + + real(RP), intent(out) :: geopot_hvari1 + real(RP), intent(out) :: geopot_hvari2 + real(RP), intent(in) :: lat + real(RP), intent(in) :: U0 + + real(RP) :: cos_lat, sin_lat + !------------------------------------------- + + cos_lat = cos(lat) + sin_lat = sin(lat) + + ! Calc horizontal variation of geopotential height + geopot_hvari1 = ( - 2.0_RP * sin_lat**6 * ( cos_lat**2 + 1.0_RP/3.0_RP ) & + + 10.0_RP / 63.0_RP ) * U0**2 + geopot_hvari2 = ( 8.0_RP / 5.0_RP * cos_lat**3 * (sin_lat**2 + 2.0_RP/3.0_RP) & + - PI / 4.0_RP ) * RPlanet * OHM * U0 + + return + end subroutine get_thermal_wind_balance_1point_geopot_hvari + + subroutine get_thermal_wind_balance_1point_itr( & + pres_yz, temp_yz, & + geopot_hvari1, geopot_hvari2, REF_TEMP, REF_PRES, LAPSE_RATE, & + ETA0, ETA_t, DT_strat, & + p_, ke, lat, z, debug ) + + implicit none + + real(RP), intent(out) :: pres_yz + real(RP), intent(out) :: temp_yz + real(RP), intent(in) :: geopot_hvari1, geopot_hvari2 + real(RP), intent(in) :: REF_TEMP, REF_PRES, LAPSE_RATE + real(RP), intent(in) :: ETA0, ETA_t, DT_strat + integer, intent(in) :: p_, ke + real(RP), intent(in) :: lat, z + logical, intent(in) :: debug + + integer :: itr + real(RP) :: eta, del_eta + real(RP) :: ln_eta + real(RP) :: temp_vfunc + real(RP) :: geop_vfunc + real(RP) :: temp_ + real(RP) :: geopot + real(RP) :: eta_v + real(RP) :: cos_etav + real(RP) :: sqrt_cos_etav + + integer, parameter :: ITRMAX = 1000 + real(RP), parameter :: CONV_EPS = 1E-14_RP + !------------------------------------------------ + + del_eta = 1.0_RP + + !-- The loop for iteration + itr = 0 + eta = 1.0E-7_RP ! Set first guess of eta + + do while( abs(del_eta) > CONV_EPS ) + ln_eta = log(eta) + eta_v = ( eta - ETA0 ) * 0.5_RP * PI + cos_etav = cos(eta_v) + sqrt_cos_etav = sqrt( cos_etav ) + + temp_vfunc = eta**( Rdry * LAPSE_RATE / Grav ) + geop_vfunc = GRAV / LAPSE_RATE * (1.0_RP - temp_vfunc) + if ( eta < ETA_t ) then + temp_vfunc = temp_vfunc & + + DT_strat / REF_TEMP * (ETA_t - eta)**5 + geop_vfunc = geop_vfunc & + - Rdry * DT_strat / REF_TEMP * ( & + (log(eta/ETA_t) + 137.0_RP/60.0_RP) * ETA_t**5 - 5.0_RP * ETA_t**4 * eta & + + 5.0_RP * ETA_t**3 * eta**2 - 10.0_RP/3.0_RP * ETA_t**2 * eta**3 & + + 1.25_RP * ETA_t * eta**4 - 0.2_RP * eta**5 ) + end if + + temp_ = REF_TEMP * temp_vfunc & + + ( geopot_hvari1 * 2.0_RP * cos_etav * sqrt_cos_etav + geopot_hvari2 ) & + * 0.75_RP * PI * eta / Rdry * sin(eta_v) * sqrt_cos_etav + geopot = REF_TEMP * geop_vfunc & + + ( geopot_hvari1 * cos_etav * sqrt_cos_etav + geopot_hvari2 ) & + * cos_etav * sqrt_cos_etav + del_eta = - ( - Grav * z + geopot ) & ! <- F + * ( - eta / ( Rdry * temp_ ) ) ! <- (dF/deta)^-1 + + eta = eta + del_eta + itr = itr + 1 + + if ( debug ) then + write(*,*) "itr=", itr, "del_eta=", del_eta, "eta=", eta, "temp=", temp_ + write(*,*) " -- geopot=", geopot, "old_eta=", eta - del_eta + end if + if ( itr > ITRMAX ) then + LOG_ERROR("BAROCLINIC_WAVE_setup",*) "Fail the convergence of iteration. Check!" + LOG_ERROR_CONT(*) "* (lat,Z)=", lat, z + LOG_ERROR_CONT(*) "itr=", itr, "del_eta=", del_eta, "eta=", eta, "temp=", temp_ + call PRC_abort + end if + end do !- End of loop for iteration ---------------------------- + + pres_yz = eta*REF_PRES + temp_yz = temp_ + + return + end subroutine get_thermal_wind_balance_1point_itr + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_baroclinic_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + integer :: ke + real(RP) :: LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lcmesh%Ne,5) + !--------------------------------------------------- + + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf new file mode 100644 index 00000000..69cb0b2e --- /dev/null +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf @@ -0,0 +1,103 @@ +#--- Configuration file for a test case of baroclinic wave proposed by Jablonowski and Williamson (2006) ------- +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 10.0D0, + TIME_DURATION_UNIT = 'DAY', + TIME_DT = 600D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_USER + USER_do = .true., +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeZ = 4, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, + LumpedMassMatFlag = .true., +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVI", + !- + TINTEG_TYPE = 'IMEX_ARK324', ! [IMEX_ARK_232, IMEX_ARK324, RK_TVD_3] + TIME_DT = 75.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .false., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 10.0D0, + MF_ORDER_h = 32, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 10.0D0, + MF_ORDER_v = 32, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ +&PARAM_ATMOS_DYN_SPONGELAYER + SL_WDAMP_TAU = 86400.0D0, + SL_WDAMP_HEIGHT = 20.0D3, +/ +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 43200.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "SEC", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='Umet' / +&HISTORY_ITEM name='Vmet' / +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='T' / +!&HISTORY_ITEM name='DENS_hyd' / +&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/Makefile b/model/atm_nonhydro3d/test/case/equatorial_wave_global/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/equatorial_wave_global/cs2lonlat.cnf new file mode 100644 index 00000000..06912862 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/cs2lonlat.cnf @@ -0,0 +1,35 @@ +&PARAM_IO + IO_LOG_BASENAME = "cs2lonlat_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="./history", + vars = "W", "Umet", "Vmet", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_INTERP_MESH + !-- input ---------------- + in_Nprc = 6, + in_NeGX = 9, + in_NeGY = 9, + in_NeGZ = 2, + in_PolyOrder_h = 7, + in_PolyOrder_v = 7, + in_NLocalMeshPerPrc = 1, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + !-- output ---------------- + out_NprcX = 2, + out_NeX = 64, + out_NprcY = 2, + out_NeY = 32, + out_NeZ = 15, + out_PolyOrder_h =3, + out_PolyOrder_v =2, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/init.conf b/model/atm_nonhydro3d/test/case/equatorial_wave_global/init.conf new file mode 100644 index 00000000..1b99bce2 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/init.conf @@ -0,0 +1,41 @@ +#--- Configuration file for a test case of equatorial wave ------- +# Test Case 4 in Tomita et al. (2004) +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'equatorial_wave_global', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeZ = 2, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, +! LumpedMassMatFlag = .true., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 new file mode 100644 index 00000000..171ff02f --- /dev/null +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 @@ -0,0 +1,321 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module for a test case of equatorial wave (Test Case 4 in Tomita et al. (2004)) +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_mesh_base3d, only: MeshBase3D + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfield_base, only: MeshField3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_equatorial_wave_global + contains + procedure :: setInitCond_lc => exp_SetInitCond_equatorial_wave + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_equatorial_wave_global), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + type(MeshField3D), private :: q_heat + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + call exp_manager%Init('equatorial_wave_global') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + call q_heat%Init( 'Qheat', 'J/kg.s-1', atm%mesh%ptr_mesh ) + + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + + return + end subroutine USER_setup + + subroutine USER_calc_tendency( atm ) + use scale_const, only: & + Rdry => CONST_Rdry + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + use mod_atmos_vars, only: & + AtmosVars_GetLocalMeshPrgVars, & + AtmosVars_GetLocalMeshPhyAuxVars, & + MOMX_p => ATMOS_PHYTEND_MOMX_ID, & + MOMY_p => ATMOS_PHYTEND_MOMY_ID, & + MOMZ_p => ATMOS_PHYTEND_MOMZ_ID, & + RHOH_p => ATMOS_PHYTEND_RHOH_ID + use scale_localmeshfield_base, only: LocalMeshFieldBase + + implicit none + + class(AtmosComponent), intent(inout) :: atm + + class(LocalMesh3D), pointer :: lcmesh + class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT + class(LocalMeshFieldBase), pointer :: DENS_hyd, PRES_hyd + class(LocalMeshFieldBase), pointer :: PRES, PT + + real(RP), parameter :: rtau = 1.0_RP / ( 10.0_RP * 864000.0_RP ) ! (10 day)^-1 + + integer :: n + integer :: ke + + real(RP), allocatable :: DENS(:) + !------------------------------------------ + + call FILE_HISTORY_meshfield_in( q_heat, "heating source" ) + + do n=1, atm%mesh%ptr_mesh%LOCAL_MESH_NUM + call AtmosVars_GetLocalMeshPrgVars( n, atm%mesh%ptr_mesh, & + atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager, & + DDENS, MOMX, MOMY, MOMZ, DRHOT, & + DENS_hyd, PRES_hyd, lcmesh ) + + call AtmosVars_GetLocalMeshPhyAuxVars( n, atm%mesh%ptr_mesh, & + atm%vars%AUXVARS_manager, PRES, PT ) + + allocate( DENS(lcmesh%refElem3D%Np) ) + !$omp parallel do private(DENS) + do ke=lcmesh%NeS, lcmesh%NeE + DENS(:) = DENS_hyd%val(:,ke) + DDENS%val(:,ke) + + atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) & + - rtau * MOMX%val(:,ke) + atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) & + - rtau * MOMY%val(:,ke) + atm%vars%PHY_TEND(MOMZ_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMZ_p)%local(n)%val(:,ke) & + - rtau * MOMZ%val(:,ke) + + atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) & + + DENS(:) * ( q_heat%local(n)%val(:,ke) & + - rtau * ( PRES%val(:,ke) / DENS(:) - PRES_hyd%val(:,ke) / DENS_hyd%val(:,ke) ) / Rdry ) + end do + + deallocate( DENS ) + end do + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_equatorial_wave( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS + + use scale_atm_dyn_dgm_hydrostatic, only: & + hydrostatic_calc_basicstate_constBVFreq + use mod_mkinit_util, only: & + mkinitutil_GalerkinProjection_global + + implicit none + + class(Exp_equatorial_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + real(RP) :: THETA0 = 300.0_RP + real(RP) :: BruntVaisalaFreq = 0.01_RP + real(RP) :: Q0 = 5.0_RP / 86400.0_RP !< the maximum heating ratio (5 K / day) + real(RP) :: DLon !< The halfwidths of the heating region in the zonal direction + real(RP) :: DLat !< The halfwidths of the heating region in the meridional direction + integer :: nv = 1 + real(RP) :: Zt + namelist /PARAM_EXP/ & + Q0, DLon, DLat, & + nv, & + BruntVaisalaFreq + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 + + integer :: ke + integer :: ierr + !----------------------------------------------------------------------------- + + DLon = 30.0_RP / 180.0_RP * PI + DLat = 10.0_RP / 180.0_RP * PI + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("EQUATORIAL_WAVE_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("EQUATORIAL_WAVE_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + Zt = dom_zmax - dom_zmin + + call hydrostatic_calc_basicstate_constBVFreq( DENS_hyd, PRES_hyd, & ! (out) + BruntVaisalaFreq, THETA0, PRES00, & ! (in) + x, y, z, lcmesh, elem ) ! (in) + + if ( USER_do ) then + call mkinitutil_GalerkinProjection_global( q_heat%local(lcmesh%lcdomID)%val(:,:), & ! (out) + func_qheat, IntrpPolyOrder_h, IntrpPolyOrder_v, lcmesh, elem, RPlanet ) ! (in) + end if + + return + contains +!OCL SERIAL + subroutine func_qheat( q_intrp, & + lon, lat, zlev, elem_intrp, rplanet_ ) + implicit none + class(ElementBase3D), intent(in) :: elem_intrp + real(RP), intent(out) :: q_intrp(elem_intrp%Np) + real(RP), intent(in) :: lon(elem_intrp%Np) + real(RP), intent(in) :: lat(elem_intrp%Np) + real(RP), intent(in) :: zlev(elem_intrp%Np) + real(RP), intent(in) :: rplanet_ + !------------------------------------------ + + where ( abs(lon(:)) < DLon .and. abs(lat(:)) < DLat ) + q_intrp(:) = CpDry * Q0 * cos(0.5_RP * PI * lon(:) / DLon)**2 & + * cos(0.5_RP * PI * lat(:) / DLat)**2 & + * sin( real(nv,kind=RP) * PI * zlev(:) / Zt ) + elsewhere + q_intrp(:) = 0.0_RP + end where + + return + end subroutine func_qheat + end subroutine exp_SetInitCond_equatorial_wave + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_equatorial_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + !--------------------------------------------------- + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf b/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf new file mode 100644 index 00000000..2d4cec2a --- /dev/null +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf @@ -0,0 +1,101 @@ +#--- Configuration file for a test case of equatorial wave ------- +# Test Case 4 in Tomita et al. (2004) +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 24.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +&PARAM_USER + USER_do = .true., +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeZ = 2, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + LumpedMassMatFlag = .true., +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVI", + !- + TINTEG_TYPE = 'IMEX_ARK324', ! [IMEX_ARK_232, IMEX_ARK324, RK_TVD_3] + TIME_DT = 75.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 10.0D0, + MF_ORDER_h = 32, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 10.0D0, + MF_ORDER_v = 32, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 4.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "HOUR", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='Umet' / +&HISTORY_ITEM name='Vmet' / +&HISTORY_ITEM name='W' / +!&HISTORY_ITEM name='Qheat' / +!&HISTORY_ITEM name='DENS_hyd' / +!&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + From de4d1210eb43d008302dfab6fa221c1412614ff0 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 2 Jun 2021 14:06:49 +0900 Subject: [PATCH 51/98] Add target keyword into a argument in a subroutin to setup globalSW. --- model/global_shallow_water/src/mod_globalsw_component.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/global_shallow_water/src/mod_globalsw_component.F90 b/model/global_shallow_water/src/mod_globalsw_component.F90 index 02931d1b..777bcf8e 100644 --- a/model/global_shallow_water/src/mod_globalsw_component.F90 +++ b/model/global_shallow_water/src/mod_globalsw_component.F90 @@ -73,7 +73,7 @@ subroutine SW_setup( this ) implicit none - class(GlobalSWComponent), intent(inout) :: this + class(GlobalSWComponent), intent(inout), target :: this logical :: ACTIVATE_FLAG = .true. From 18ca61eb1c49d5356031479f8a594babccbacea7 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 3 Jun 2021 11:44:00 +0900 Subject: [PATCH 52/98] Add OCL SERIAL. --- FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 | 3 +++ FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 | 1 + 2 files changed, 4 insertions(+) diff --git a/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 b/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 index 1452d17a..42e87e59 100644 --- a/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 +++ b/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 @@ -34,6 +34,7 @@ module scale_meshutil_cubedsphere2d public :: MeshUtilCubedSphere2D_GetPanelConnectivity contains +!OCL SERIAL subroutine MeshUtilCubedSphere2D_buildGlobalMap( & panelID_table, pi_table, pj_table, & tileID_map, tileFaceID_map, tilePanelID_map, & @@ -116,6 +117,7 @@ subroutine MeshUtilCubedSphere2D_buildGlobalMap( & end subroutine MeshUtilCubedSphere2D_buildGlobalMap !---- +!OCL SERIAL subroutine MeshUtilCubedSphere2D_modifyConnectivity( tilePanelID_map, tileID_map, tileFaceID_map, & panelID_table, pi_table, pj_table, NeX, NeY, Ntile, Nface ) @@ -235,6 +237,7 @@ subroutine MeshUtilCubedSphere2D_modifyConnectivity( tilePanelID_map, tileID_map return end subroutine MeshUtilCubedSphere2D_modifyConnectivity +!OCL SERIAL subroutine MeshUtilCubedSphere2D_getPanelConnectivity( panel_connectivity, face_connectivity ) implicit none diff --git a/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 b/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 index 56e10dc0..f1395e5f 100644 --- a/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 +++ b/FElib/src/mesh/scale_meshutil_cubedsphere3d.F90 @@ -32,6 +32,7 @@ module scale_meshutil_cubedsphere3d public :: MeshUtilCubedSphere3D_genPatchBoundaryMap contains +!OCL SERIAL subroutine MeshUtilCubedSphere3D_buildGlobalMap( & panelID_table, pi_table, pj_table, pk_table, & tileID_map, tileFaceID_map, tilePanelID_map, & From 0bcf136d3e70901bcf927536d8a8fcb2131f24d2 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 3 Jun 2021 11:46:00 +0900 Subject: [PATCH 53/98] Modify the calculation at the edge of panel4 and the poles in cubed sphere mesh. --- FElib/src/common/scale_cubedsphere_cnv.F90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/FElib/src/common/scale_cubedsphere_cnv.F90 b/FElib/src/common/scale_cubedsphere_cnv.F90 index 7dc3c957..ea44bd63 100644 --- a/FElib/src/common/scale_cubedsphere_cnv.F90 +++ b/FElib/src/common/scale_cubedsphere_cnv.F90 @@ -186,6 +186,8 @@ subroutine CubedSphereCnv_CS2LonLatVec( & VecAlpha, VecBeta, & ! (in) VecLon, VecLat ) ! (out) + use scale_const, only: & + EPS => CONST_EPS implicit none integer, intent(in) :: panelID @@ -233,9 +235,9 @@ subroutine CubedSphereCnv_CS2LonLatVec( & del2 = 1.0_RP + X**2 + Y**2 VecLon(p) = (- Y * ( 1.0 + X**2 ) * VecAlpha(p) + X * ( 1.0_RP + Y**2 ) * VecBeta(p) ) & - * s / ( X**2 + Y**2 ) + * s / ( X**2 + Y**2 + EPS ) VecLat(p) = (- X * ( 1.0 + X**2 ) * VecAlpha(p) - Y * ( 1.0_RP + Y**2 ) * VecBeta(p) ) & - * s / ( del2 * sqrt( X**2 + Y**2 ) ) + * s / ( del2 * sqrt( X**2 + Y**2 ) + EPS ) end do end select @@ -356,7 +358,7 @@ subroutine CubedSphereCnv_LonLat2CSPos( & !$omp parallel if ( panelID == 1 ) then !$omp workshare - where (lon(:) > 2.0_RP * PI - 0.25_RP * PI ) + where (lon(:) >= 2.0_RP * PI - 0.25_RP * PI ) lon_(:) = lon(:) - 2.0_RP * PI elsewhere lon_(:) = lon(:) From 290e3f78b1aac3f257d52600db27be77fc71c662 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 14 Jun 2021 14:30:12 +0900 Subject: [PATCH 54/98] Add comments. --- FElib/src/common/scale_cubedsphere_cnv.F90 | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/FElib/src/common/scale_cubedsphere_cnv.F90 b/FElib/src/common/scale_cubedsphere_cnv.F90 index ea44bd63..6cf7eb2a 100644 --- a/FElib/src/common/scale_cubedsphere_cnv.F90 +++ b/FElib/src/common/scale_cubedsphere_cnv.F90 @@ -1,3 +1,11 @@ +!------------------------------------------------------------------------------- +!> module common / Coordinate conversion with a cubed-sphere +!! +!! @par Description +!! Coordinate conversion with a cubed-sphere +!! +!! @author Team SCALE +!! #include "scaleFElib.h" module scale_cubedsphere_cnv !----------------------------------------------------------------------------- @@ -63,7 +71,7 @@ subroutine CubedSphereCnv_CS2LonLatCoord( & !----------------------------------------------------------------------------- select case( panelID ) - case(1, 2, 3, 4) + case( 1, 2, 3, 4 ) !$omp parallel !$omp do do p=1, Np @@ -182,9 +190,9 @@ subroutine CubedSphereCnv_LonLat2CSVec( & end subroutine CubedSphereCnv_LonLat2CSVec subroutine CubedSphereCnv_CS2LonLatVec( & - panelID, alpha, beta, Np, radius, & ! (in) - VecAlpha, VecBeta, & ! (in) - VecLon, VecLat ) ! (out) + panelID, alpha, beta, Np, radius, & ! (in) + VecAlpha, VecBeta, & ! (in) + VecLon, VecLat ) ! (out) use scale_const, only: & EPS => CONST_EPS @@ -245,8 +253,8 @@ subroutine CubedSphereCnv_CS2LonLatVec( & end subroutine CubedSphereCnv_CS2LonLatVec subroutine CubedSphereCnv_CS2CartCoord( & - panelID, alpha, beta, Np, radius, & - X, Y, Z ) + panelID, alpha, beta, Np, radius, & ! (in) + X, Y, Z ) ! (out) implicit none integer, intent(in) :: panelID @@ -407,7 +415,7 @@ end subroutine CubedSphereCnv_LonLat2CSPos subroutine CubedSphereCnv_GetMetric( & alpha, beta, Np, radius, & ! (in) - G_ij, GIJ, Gsqrt ) ! (out) + G_ij, GIJ, Gsqrt ) ! (out) implicit none From baecf87cdcd2bc1f8a8fe36e11e3c6c25fbd9909 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 14 Jun 2021 14:32:00 +0900 Subject: [PATCH 55/98] Relax the condition of inside judgement. --- .../mod_cs2lonlat_interp_mesh.F90 | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 index be5d4c58..530fc3a6 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 @@ -501,7 +501,13 @@ subroutine NodeMappingInfo_Init_2D( this, & in_elem_y(:) = tile_y(1,lc_domID,prcID) + dely * dble( (/ j-1, j-1, j, j /) ) is_inside_elem = inpoly( out_x(1), out_y(1), & 4, in_elem_x(:), in_elem_y(:) ) - + if (i==in_NeX) then + in_elem_x(2:3) = in_elem_x(2:3) + 1.0E-12_RP * delx + end if + if (j==in_NeY) then + in_elem_y(3:4) = in_elem_y(3:4) + 1.0E-12_RP * dely + end if + if (is_inside_elem) then this%elem_i(p_h,ke_h) = i this%elem_j(p_h,ke_h) = j @@ -618,7 +624,7 @@ subroutine NodeMappingInfo_Init_3D( this, & do p_h_x=1, elem3D%Nnode_h1D p_h = p_h_x + (p_h_y-1)*elem3D%Nnode_h1D this%local_domID(p_h,ke_h) = -1 - this%lcprc(p_h,ke_h) = -1 + this%lcprc(p_h,ke_h) = -1 out_cspanel = this%inCSPanelID(p_h,ke_h) out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) * PI / 180.0_RP @@ -653,10 +659,8 @@ subroutine NodeMappingInfo_Init_3D( this, & exit loop_prc end if - end do end do loop_prc - end do end do @@ -683,7 +687,7 @@ subroutine NodeMappingInfo_Init_3D( this, & call CubedSphereCnv_LonLat2CSPos( & out_cspanel, out_lon, out_lat, 1, & out_x, out_y ) - + this%elem_i(p_h,ke_h) = -1 this%elem_j(p_h,ke_h) = -1 if ( lc_domID > 0 .and. prcID > 0 ) then @@ -694,6 +698,14 @@ subroutine NodeMappingInfo_Init_3D( this, & do i=1, in_NeX in_elem_x(:) = tile_x(1,lc_domID,prcID) + delx * dble( (/ i-1, i, i, i-1 /) ) in_elem_y(:) = tile_y(1,lc_domID,prcID) + dely * dble( (/ j-1, j-1, j, j /) ) + + if (i==in_NeX) then + in_elem_x(2:3) = in_elem_x(2:3) + 1.0E-12_RP * delx + end if + if (j==in_NeY) then + in_elem_y(3:4) = in_elem_y(3:4) + 1.0E-12_RP * dely + end if + is_inside_elem = inpoly( out_x(1), out_y(1), & 4, in_elem_x(:), in_elem_y(:) ) @@ -707,6 +719,7 @@ subroutine NodeMappingInfo_Init_3D( this, & end do end do loop_ne end if + end do end do end do @@ -862,14 +875,15 @@ subroutine get_panelID( panelID, lon, lat, Np ) real(RP), parameter :: EPS = 1.0E-64_RP !------------------------------------------ + !$omp parallel do do p=1, Np - if ( abs(lon(p)) < EPS ) then + if ( abs(cos(lon(p))) < EPS ) then lon_(p) = lon(p) + EPS else lon_(p) = lon(p) end if - if ( abs(lat(p)) < EPS ) then - lat_(p) = lat(p) + EPS + if ( abs( lat(p) - 0.5_RP * PI ) < EPS ) then + lat_(p) = lat(p) - sign(EPS, lat(p)) else lat_(p) = lat(p) end if From f2df4c7d8317323735c7fb3aa587dfdc483b3ef0 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 14 Jun 2021 14:33:56 +0900 Subject: [PATCH 56/98] Support the Rayleigh damping of horizontal wind in sponge layer. --- ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 9 +++-- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 39 ++++++++++++++++--- .../scale_atm_dyn_dgm_nonhydro3d_heve.F90 | 9 +++-- .../scale_atm_dyn_dgm_nonhydro3d_hevi.F90 | 9 +++-- ..._atm_dyn_dgm_nonhydro3d_splitform_heve.F90 | 9 +++-- ..._atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 | 9 +++-- .../scale_atm_dyn_dgm_spongelayer.F90 | 19 ++++++++- .../src/atmos/mod_atmos_dyn.F90 | 18 ++++++--- 8 files changed, 93 insertions(+), 28 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index c5060e4f..25940521 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -143,7 +143,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_heve_Final subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) use scale_atm_dyn_dgm_spongelayer, only: & @@ -173,6 +173,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) @@ -352,8 +353,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !- Sponge layer if (SL_flag) then call PROF_rapstart('cal_dyn_tend_sponge', 3) - call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call atm_dyn_dgm_spongelayer_add_tend( & + MOMX_dt, MOMY_dt, MOMZ_dt, & ! (out) + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, & ! (in) + hveldamp_flag, lmesh, elem ) ! (in) call PROF_rapend('cal_dyn_tend_sponge', 3) end if diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index f2ad9a1f..3f1aa3b9 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -36,7 +36,7 @@ module scale_atm_dyn_dgm_globalnonhydro3d_hevi use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D - + use, intrinsic :: ieee_arithmetic !----------------------------------------------------------------------------- implicit none private @@ -145,7 +145,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Final subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) use scale_atm_dyn_dgm_spongelayer, only: & @@ -175,6 +175,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) @@ -345,8 +346,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & !- Sponge layer if (SL_flag) then call PROF_rapstart('cal_dyn_tend_sponge', 3) - call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call atm_dyn_dgm_spongelayer_add_tend( & + MOMX_dt, MOMY_dt, MOMZ_dt, & ! (out) + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, & ! (in) + hveldamp_flag, lmesh, elem ) ! (in) call PROF_rapend('cal_dyn_tend_sponge', 3) end if @@ -652,6 +655,20 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & end do end do + ! if ( lmesh%PRC_myrank==11 .and. ke_x==3 .and. ke_y==3 .and. ij == 1) then + ! LOG_INFO("check_check_vi",*) "V1", PROG_VARS(elem%Colmask(:,ij),1,:) + ! LOG_INFO("check_check_vi",*) "V2", PROG_VARS(elem%Colmask(:,ij),2,:) + ! LOG_INFO("check_check_vi",*) "V3", PROG_VARS(elem%Colmask(:,ij),3,:) + ! LOG_INFO("check_check_vi",*) "V4", PROG_VARS(elem%Colmask(:,ij),4,:) + ! LOG_INFO("check_check_vi",*) "V5", PROG_VARS(elem%Colmask(:,ij),5,:) + ! LOG_INFO("check_check_vi",*) "b1D1", b1D(:,1,:,ij) + ! LOG_INFO("check_check_vi",*) "b1D2", b1D(:,2,:,ij) + ! LOG_INFO("check_check_vi",*) "b1D3", b1D(:,3,:,ij) + ! LOG_INFO("check_check_vi",*) "b1D4", b1D(:,4,:,ij) + ! LOG_INFO("check_check_vi",*) "b1D5", b1D(:,5,:,ij) + ! LOG_INFO("check_check_vi",*) "PmatBand", PmatBnd(:,:,ij) + ! end if + call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij), nz_1D, info) do ke_z=1, lmesh%NeZ @@ -687,6 +704,18 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & nz, vmapM, vmapP, ke_x, ke_y, .true. ) ! (in) end if +! if (lmesh%PRC_myrank==11) then + ! do ke_z=1, lmesh%NeZ + ! ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ! do p=1, elem%Np + ! if ( IEEE_IS_NAN(tend(p,DDENS_VID,ke_z)) .and. ke_x==3 .and. ke_y==3 .and. p==1 .and. ke_z == 1) then + ! LOG_INFO("check_nan_vi",*) impl_fac, lmesh%PRC_myrank, "Nan:", lmesh%pos_en(p,ke,:), ":", MOMX_(p,ke), MOMY_(p,ke), MOMZ_(p,ke), DRHOT_(p,ke) + ! LOG_INFO("check_nan_vi",*) p, ke_x, ke_y, " Nan_tend:", tend(p,:,ke_z) + ! end if + ! end do + ! end do +! end if + !$omp parallel do private(ke) do ke_z=1, lmesh%NeZ ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY @@ -900,7 +929,7 @@ subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) - alpha0 * ( DDENS_(iP) - DDENS_(iM) ) ) del_flux(i,MOMX_VID) = 0.5_RP * ( & - - alpha0 * ( MOMX_(iP) - MOMX_(iM) ) ) + - alpha0 * ( MOMX_(iP) - MOMX_(iM) ) ) del_flux(i,MOMY_VID) = 0.5_RP * ( & - alpha0 * ( MOMY_(iP) - MOMY_(iM) ) ) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 index 2206c4b8..91a94a53 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 @@ -111,7 +111,7 @@ end subroutine atm_dyn_dgm_nonhydro3d_heve_Final subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) use scale_atm_dyn_dgm_spongelayer, only: & @@ -140,6 +140,7 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) @@ -261,8 +262,10 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & !- Sponge layer if (SL_flag) then call PROF_rapstart('cal_dyn_tend_sponge', 3) - call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call atm_dyn_dgm_spongelayer_add_tend( & + MOMX_dt, MOMY_dt, MOMZ_dt, & ! (out) + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, & ! (in) + hveldamp_flag, lmesh, elem ) ! (in) call PROF_rapend('cal_dyn_tend_sponge', 3) end if diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 index 95a6f15c..6a954baa 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 @@ -115,7 +115,7 @@ end subroutine atm_dyn_dgm_nonhydro3d_hevi_Final subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) use scale_atm_dyn_dgm_spongelayer, only: & @@ -144,6 +144,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) @@ -253,8 +254,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & !- Sponge layer if (SL_flag) then call PROF_rapstart( 'cal_dyn_tend_sponge', 3) - call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call atm_dyn_dgm_spongelayer_add_tend( & + MOMX_dt, MOMY_dt, MOMZ_dt, & ! (out) + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, & ! (in) + hveldamp_flag, lmesh, elem ) ! (in) call PROF_rapend( 'cal_dyn_tend_sponge', 3) end if diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 index fd5cb52c..2c36d31c 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 @@ -140,7 +140,7 @@ end subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_Final subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) use scale_atm_dyn_dgm_spongelayer, only: & @@ -169,6 +169,7 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: Fx_sp(elem%Np), Fy_sp(elem%Np), Fz_sp(elem%Np) @@ -290,8 +291,10 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & !- Sponge layer if (SL_flag) then call PROF_rapstart( 'cal_dyn_tend_sponge', 3) - call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call atm_dyn_dgm_spongelayer_add_tend( & + MOMX_dt, MOMY_dt, MOMZ_dt, & ! (out) + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, & ! (in) + hveldamp_flag, lmesh, elem ) ! (in) call PROF_rapend( 'cal_dyn_tend_sponge', 3) end if diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 index 76d6ac1e..b717d179 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 @@ -141,7 +141,7 @@ end subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_Final subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) use scale_atm_dyn_dgm_spongelayer, only: & @@ -170,6 +170,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: Fx_sp(elem%Np), Fy_sp(elem%Np), Fz_sp(elem%Np) @@ -282,8 +283,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend( & !- Sponge layer if (SL_flag) then call PROF_rapstart( 'cal_dyn_tend_sponge', 3) - call atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + call atm_dyn_dgm_spongelayer_add_tend( & + MOMX_dt, MOMY_dt, MOMZ_dt, & ! (out) + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, & ! (in) + hveldamp_flag, lmesh, elem ) ! (in) call PROF_rapend( 'cal_dyn_tend_sponge', 3) end if diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_spongelayer.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_spongelayer.F90 index 16447b23..ce66756f 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_spongelayer.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_spongelayer.F90 @@ -43,24 +43,37 @@ module scale_atm_dyn_dgm_spongelayer contains - subroutine atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & - MOMZ_, wdamp_tau, wdamp_height, lmesh, elem ) + subroutine atm_dyn_dgm_spongelayer_add_tend( MOMX_dt, MOMY_dt, MOMZ_dt, & + MOMX_, MOMY_, MOMZ_, wdamp_tau, wdamp_height, hveldamp_flag, & + lmesh, elem ) implicit none class(LocalMesh3D), intent(in) :: lmesh class(elementbase3D), intent(in) :: elem + real(RP), intent(inout) :: MOMX_dt(elem%Np,lmesh%NeA) + real(RP), intent(inout) :: MOMY_dt(elem%Np,lmesh%NeA) real(RP), intent(inout) :: MOMZ_dt(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np,lmesh%NeA) real(RP), intent(in) :: MOMZ_(elem%Np,lmesh%NeA) real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height + logical, intent(in) :: hveldamp_flag integer :: ke integer :: ke_x, ke_y, ke_z integer :: keZtop real(RP) :: wdamp_coef(elem%Np) real(RP) :: zTop(elem%Nnode_h1D**2) + real(RP) :: s !----------------------------------------------------------------- + if ( hveldamp_flag ) then + s = 1.0_RP + else + s = 0.0_RP + end if + !$omp parallel do collapse(3) private(ke,keZtop,zTop,wdamp_coef) do ke_z = 1, lmesh%NeZ do ke_y = 1, lmesh%NeY @@ -74,6 +87,8 @@ subroutine atm_dyn_dgm_spongelayer_add_tend( MOMZ_dt, & elem%Nnode_h1D, elem%Nnode_v, & wdamp_coef(:) ) + MOMX_dt(:,ke) = MOMX_dt(:,ke) - s * wdamp_coef(:) * MOMX_(:,ke) + MOMY_dt(:,ke) = MOMY_dt(:,ke) - s * wdamp_coef(:) * MOMY_(:,ke) MOMZ_dt(:,ke) = MOMZ_dt(:,ke) - wdamp_coef(:) * MOMZ_(:,ke) end do end do diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 index d0b13603..3423fa24 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 @@ -108,7 +108,7 @@ module mod_atmos_dyn subroutine atm_dyn_nonhydro3d_cal_tend_ex( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, CORIOLIS, & ! (in) - SL_flag, wdamp_tau, wdamp_height, & ! (in) + SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) import RP @@ -140,7 +140,7 @@ subroutine atm_dyn_nonhydro3d_cal_tend_ex( & logical, intent(in) :: SL_flag real(RP), intent(in) :: wdamp_tau real(RP), intent(in) :: wdamp_height - + logical, intent(in) :: hveldamp_flag end subroutine atm_dyn_nonhydro3d_cal_tend_ex end interface @@ -210,6 +210,7 @@ end subroutine atm_dyn_nonhydro3d_cal_vi logical :: SPONGELAYER_FLAG real(RP) :: wdamp_tau real(RP) :: wdamp_height + logical :: hvel_damp_flag contains procedure, public :: setup => AtmosDyn_setup @@ -542,6 +543,7 @@ subroutine AtmosDyn_update( this, model_mesh, prgvars_list, auxvars_list, forcin DENS_hyd%val, PRES_hyd%val, & Coriolis%val, & this%SPONGELAYER_FLAG, this%wdamp_tau, this%wdamp_height, & + this%hvel_damp_flag, & model_mesh%DOptrMat(1), model_mesh%DOptrMat(2), model_mesh%DOptrMat(3), & model_mesh%SOptrMat(1), model_mesh%SOptrMat(2), model_mesh%SOptrMat(3), & model_mesh%LiftOptrMat, & @@ -984,14 +986,16 @@ subroutine setup_spongelayer( this, atm_mesh, dtsec ) class(AtmosMesh), target, intent(in) :: atm_mesh real(RP), intent(in) :: dtsec - real(RP) :: SL_WDAMP_TAU = -1.0_RP ! the maximum tau for Rayleigh damping of w [s] - real(RP) :: SL_WDAMP_HEIGHT = -1.0_RP ! the height to start apply Rayleigh damping [m] - integer :: SL_WDAMP_LAYER = -1 ! the vertical number of finite element to start apply Rayleigh damping [num] + real(RP) :: SL_WDAMP_TAU = -1.0_RP ! the maximum tau for Rayleigh damping of w [s] + real(RP) :: SL_WDAMP_HEIGHT = -1.0_RP ! the height to start apply Rayleigh damping [m] + integer :: SL_WDAMP_LAYER = -1 ! the vertical number of finite element to start apply Rayleigh damping [num] + logical :: SL_HORIVELDAMP_FLAG = .false. ! Is the horizontal velocity damped? namelist /PARAM_ATMOS_DYN_SPONGELAYER/ & SL_WDAMP_TAU, & SL_WDAMP_HEIGHT, & - SL_WDAMP_LAYER + SL_WDAMP_LAYER, & + SL_HORIVELDAMP_FLAG class(MeshBase3D), pointer :: mesh3D class(LocalMesh3D), pointer :: lcmesh3D @@ -1038,6 +1042,8 @@ subroutine setup_spongelayer( this, atm_mesh, dtsec ) call PRC_abort end if + this%hvel_damp_flag = SL_HORIVELDAMP_FLAG + return end subroutine setup_spongelayer From 4adfa1f3b572e9c0ab72e82a3345d07032a85cf0 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 14 Jun 2021 14:40:33 +0900 Subject: [PATCH 57/98] Modify the setting of dissipation in two test cases. --- .../test/case/baroclinic_wave_global/run.conf | 10 +++++----- .../test/case/equatorial_wave_global/mod_user.F90 | 5 +++-- .../test/case/equatorial_wave_global/run.conf | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf index 69cb0b2e..b479d089 100644 --- a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/run.conf @@ -48,16 +48,16 @@ TIME_DT = 75.0D0, TIME_DT_UNIT = 'SEC', !- - MODALFILTER_FLAG = .false., + MODALFILTER_FLAG = .true., NUMDIFF_FLAG = .false., / &PARAM_ATMOS_DYN_MODALFILTER MF_ETAC_h = 0.0D0, - MF_ALPHA_h = 10.0D0, - MF_ORDER_h = 32, + MF_ALPHA_h = 1.0D0, + MF_ORDER_h = 16, MF_ETAC_v = 0.0D0, - MF_ALPHA_v = 10.0D0, - MF_ORDER_v = 32, + MF_ALPHA_v = 1.0D0, + MF_ORDER_v = 16, / &PARAM_ATMOS_DYN_BND btm_vel_bc = 'SLIP', diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 index 171ff02f..68e6747c 100644 --- a/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 @@ -119,7 +119,8 @@ end subroutine USER_setup subroutine USER_calc_tendency( atm ) use scale_const, only: & - Rdry => CONST_Rdry + Rdry => CONST_Rdry, & + CpDry => CONST_CPdry use scale_file_history_meshfield, only: & FILE_HISTORY_meshfield_in use mod_atmos_vars, only: & @@ -173,7 +174,7 @@ subroutine USER_calc_tendency( atm ) atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) & + DENS(:) * ( q_heat%local(n)%val(:,ke) & - - rtau * ( PRES%val(:,ke) / DENS(:) - PRES_hyd%val(:,ke) / DENS_hyd%val(:,ke) ) / Rdry ) + - rtau * CpDry * ( PRES%val(:,ke) / DENS(:) - PRES_hyd%val(:,ke) / DENS_hyd%val(:,ke) ) / Rdry ) end do deallocate( DENS ) diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf b/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf index 2d4cec2a..8186a173 100644 --- a/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf @@ -8,8 +8,8 @@ &PARAM_TIME TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, TIME_STARTMS = 0.D0, - TIME_DURATION = 24.0D0, - TIME_DURATION_UNIT = 'HOUR', + TIME_DURATION = 30.0D0, + TIME_DURATION_UNIT = 'DAY', TIME_DT = 600.0D0, TIME_DT_UNIT = 'SEC', / @@ -72,7 +72,7 @@ #*** OUTPUT ******************************************* &PARAM_FILE_HISTORY FILE_HISTORY_DEFAULT_BASENAME = "history", - FILE_HISTORY_DEFAULT_TINTERVAL = 4.0D0, + FILE_HISTORY_DEFAULT_TINTERVAL = 6.0D0, FILE_HISTORY_DEFAULT_TUNIT = "HOUR", FILE_HISTORY_DEFAULT_TAVERAGE = .false., FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", From 3ece150223d07358876034905854ee762158d743 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Fri, 18 Jun 2021 19:38:31 +0900 Subject: [PATCH 58/98] Fix the setup of test case of equatorial wave. --- model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf b/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf index 8186a173..bcc11a0f 100644 --- a/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/run.conf @@ -13,9 +13,6 @@ TIME_DT = 600.0D0, TIME_DT_UNIT = 'SEC', / -&PARAM_CONST - CONST_OHM = 0.0D0, -/ &PARAM_USER USER_do = .true., / From edc32395e2d99c344cc929b6a6ef720e8fd7b357 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Fri, 18 Jun 2021 19:35:23 +0900 Subject: [PATCH 59/98] Add modules to support topography in 3D global model. --- FElib/src/Makefile | 4 +- FElib/src/depend | 8 +- ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 297 ++++++++----- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 412 +++++++++++------- FElib/src/mesh/scale_localmesh_3d.F90 | 10 +- FElib/src/mesh/scale_localmesh_base.F90 | 10 +- FElib/src/mesh/scale_mesh_base3d.F90 | 60 ++- FElib/src/mesh/scale_mesh_cubedom3d.F90 | 4 +- .../src/mesh/scale_mesh_cubedspheredom2d.F90 | 5 +- .../src/mesh/scale_mesh_cubedspheredom3d.F90 | 27 +- FElib/src/mesh/scale_mesh_topography.F90 | 162 +++++++ FElib/src/mesh/scale_meshutil_vcoord.F90 | 155 +++++++ .../src/atmos/mod_atmos_mesh.F90 | 44 +- .../src/atmos/mod_atmos_mesh_gm.F90 | 30 +- .../src/atmos/mod_atmos_mesh_rm.F90 | 32 +- 15 files changed, 948 insertions(+), 312 deletions(-) create mode 100644 FElib/src/mesh/scale_mesh_topography.F90 create mode 100644 FElib/src/mesh/scale_meshutil_vcoord.F90 diff --git a/FElib/src/Makefile b/FElib/src/Makefile index 37600793..d4804a64 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -52,6 +52,7 @@ OBJS_NAME_MESH = \ scale_meshutil_1d.o \ scale_meshutil_2d.o \ scale_meshutil_3d.o \ + scale_meshutil_vcoord.o \ scale_meshutil_cubedsphere2d.o \ scale_meshutil_cubedsphere3d.o \ scale_mesh_bndinfo.o \ @@ -67,7 +68,8 @@ OBJS_NAME_MESH = \ scale_mesh_rectdom2d.o \ scale_mesh_cubedom3d.o \ scale_mesh_cubedspheredom2d.o \ - scale_mesh_cubedspheredom3d.o + scale_mesh_cubedspheredom3d.o \ + scale_mesh_topography.o OBJS_NAME_DATA = \ scale_variableinfo.o \ diff --git a/FElib/src/depend b/FElib/src/depend index 9698755f..84f0bf4b 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -35,13 +35,14 @@ $(OBJ_DIR)/scale_localmeshfield_base.o: data/scale_localmeshfield_base.F90 $(DEP $(OBJ_DIR)/scale_mesh_base.o: mesh/scale_mesh_base.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o: mesh/scale_mesh_base1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_meshutil_1d.o $(OBJ_DIR)/scale_mesh_base2d.o: mesh/scale_mesh_base2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o -$(OBJ_DIR)/scale_mesh_base3d.o: mesh/scale_mesh_base3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o +$(OBJ_DIR)/scale_mesh_base3d.o: mesh/scale_mesh_base3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_vcoord.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_mesh_bndinfo.o: mesh/scale_mesh_bndinfo.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_mesh_cubedom3d.o: mesh/scale_mesh_cubedom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshutil_3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o: mesh/scale_mesh_cubedspheredom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o -$(OBJ_DIR)/scale_mesh_cubedspheredom3d.o: mesh/scale_mesh_cubedspheredom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere3d.o +$(OBJ_DIR)/scale_mesh_cubedspheredom3d.o: mesh/scale_mesh_cubedspheredom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere3d.o $(OBJ_DIR)/scale_mesh_linedom1d.o: mesh/scale_mesh_linedom1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o: mesh/scale_mesh_rectdom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_2d.o +$(OBJ_DIR)/scale_mesh_topography.o: mesh/scale_mesh_topography.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o $(OBJ_DIR)/scale_meshutil_vcoord.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_meshfield_base.o: data/scale_meshfield_base.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_statistics.o: data/scale_meshfield_statistics.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_1d.o: data/scale_meshfieldcomm_1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o @@ -55,6 +56,7 @@ $(OBJ_DIR)/scale_meshutil_2d.o: mesh/scale_meshutil_2d.F90 $(DEPENDLIB) $(OBJ_DI $(OBJ_DIR)/scale_meshutil_3d.o: mesh/scale_meshutil_3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_quicksort.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o: mesh/scale_meshutil_cubedsphere2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere3d.o: mesh/scale_meshutil_cubedsphere3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_3d.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o +$(OBJ_DIR)/scale_meshutil_vcoord.o: mesh/scale_meshutil_vcoord.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_model_component.o: model_framework/scale_model_component.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_time_manager.o $(OBJ_DIR)/scale_model_component_proc.o: model_framework/scale_model_component_proc.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_model_mesh_manager.o $(OBJ_DIR)/scale_model_var_manager.o $(OBJ_DIR)/scale_time_manager.o $(OBJ_DIR)/scale_model_mesh_manager.o: model_framework/scale_model_mesh_manager.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_sparsemat.o @@ -112,6 +114,7 @@ MODS = \ $(OBJ_DIR)/scale_mesh_cubedspheredom3d.mod \ $(OBJ_DIR)/scale_mesh_linedom1d.mod \ $(OBJ_DIR)/scale_mesh_rectdom2d.mod \ + $(OBJ_DIR)/scale_mesh_topography.mod \ $(OBJ_DIR)/scale_meshfield_base.mod \ $(OBJ_DIR)/scale_meshfield_statistics.mod \ $(OBJ_DIR)/scale_meshfieldcomm_1d.mod \ @@ -125,6 +128,7 @@ MODS = \ $(OBJ_DIR)/scale_meshutil_3d.mod \ $(OBJ_DIR)/scale_meshutil_cubedsphere2d.mod \ $(OBJ_DIR)/scale_meshutil_cubedsphere3d.mod \ + $(OBJ_DIR)/scale_meshutil_vcoord.mod \ $(OBJ_DIR)/scale_model_component.mod \ $(OBJ_DIR)/scale_model_component_proc.mod \ $(OBJ_DIR)/scale_model_mesh_manager.mod \ diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index 25940521..5c9e4f74 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -181,9 +181,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) real(RP) :: DPRES_(elem%Np) real(RP) :: RHOT_(elem%Np) - real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), drho(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), wt_(elem%np), drho(elem%Np) - real(RP) :: GIJ(elem%Np,2,2) + real(RP) :: G11(elem%Np), G12(elem%Np), G22(elem%Np) + real(RP) :: GsqrtV(elem%Np), RGsqrtV(elem%Np) real(RP) :: X2D(elem%Np,lmesh2D%Ne), Y2D(elem%Np,lmesh2D%Ne) real(RP) :: X(elem%Np), Y(elem%Np), twoOVdel2(elem%Np) real(RP) :: CORI(elem%Np,2) @@ -202,6 +203,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & call cal_del_flux_dyn( del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) + lmesh%GsqrtH, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) lmesh%vmapM, lmesh%vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) @@ -224,10 +226,11 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & end if !$omp parallel private( & - !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, wt_, & !$omp Fx, Fy, Fz, LiftDelFlx, & !$omp drho, GradPhyd_x, GradPhyd_y, & - !$omp GIJ, X, Y, twoOVdel2, & + !$omp G11, G12, G22, GsqrtV, RGsqrtV, & + !$omp X, Y, twoOVdel2, & !$omp CORI, ke, ke2D ) !$omp do @@ -238,6 +241,14 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !$omp do do ke = lmesh%NeS, lmesh%NeE + !-- + ke2d = lmesh%EMap3Dto2D(ke) + G11(:) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) + G12(:) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) + G22(:) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + GsqrtV(:) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2d) + RGsqrtV(:) = 1.0_RP / GsqrtV(:) + !-- RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & @@ -247,12 +258,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & u_ (:) = MOMX_(:,ke) * rdens_(:) v_ (:) = MOMY_(:,ke) * rdens_(:) w_ (:) = MOMZ_(:,ke) * rdens_(:) - - ke2d = lmesh%EMap3Dto2D(ke) - GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) - GIJ(:,2,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,1) - GIJ(:,1,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) - GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + wt_(:) = w_(:) * RGsqrtV(:) + lmesh%GI3(:,ke,1) * u_(:) + lmesh%GI3(:,ke,2) * v_(:) X(:) = X2D(elem%IndexH2Dto3D,ke2d) Y(:) = Y2D(elem%IndexH2Dto3D,ke2d) @@ -268,18 +274,25 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & drho(:) = matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) !-- Gradient hydrostatic pressure - call sparsemat_matmul(Dx, PRES_hyd(:,ke), Fx) + + call sparsemat_matmul(Dx, GsqrtV(:) * PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,1) * PRES_hyd(:,ke), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) - GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) + LiftDelFlx(:) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) - call sparsemat_matmul(Dy, PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dy, GsqrtV(:) * PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,2) * PRES_hyd(:,ke), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) - GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) + LiftDelFlx(:) - + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + !-- DENS call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * MOMZ_(:,ke), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) * wt_(:), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DDENS_ID), LiftDelFlx) DENS_dt(:,ke) = - ( & @@ -289,41 +302,43 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- MOMX - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * DPRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMX_(:,ke) + G11(:) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMX_(:,ke) + G12(:) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMX_ID), LiftDelFlx) MOMX_dt(:,ke) = & - - ( lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & - + twoOVdel2(:) * Y(:) * & - ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & - - ( GIJ(:,1,1) * GradPhyd_x(:) + GIJ(:,1,2) * GradPhyd_y(:) ) & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twoOVdel2(:) * Y(:) * & + ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & + - ( G11(:) * GradPhyd_x(:) + G12(:) * GradPhyd_y(:) ) * RGsqrtV(:) & + CORI(:,1) !-- MOMY - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * DPRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMY_(:,ke) + G12(:) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMY_(:,ke) + G22(:) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & + ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMY_ID), LiftDelFlx) MOMY_dt(:,ke) = & - - ( lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & - + twoOVdel2(:) * X(:) * & - ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & - - ( GIJ(:,2,1) * GradPhyd_x(:) + GIJ(:,2,2) * GradPhyd_y(:) ) & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + + twoOVdel2(:) * X(:) * & + ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & + - ( G12(:) * GradPhyd_x(:) + G22(:) * GradPhyd_y(:) ) * RGsqrtV(:) & + CORI(:,2) !-- MOMZ - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( w_(:) * MOMZ_(:,ke) + DPRES_(:) ), Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMZ_(:,ke) + RGsqrtV(:) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMZ_ID), LiftDelFlx) MOMZ_dt(:,ke) = & @@ -334,9 +349,9 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & - Grav * drho(:) !-- RHOT - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * RHOT_(:), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * RHOT_(:), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * RHOT_(:), Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * RHOT_(:), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * RHOT_(:), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * wt_(:) * RHOT_(:), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DRHOT_ID), LiftDelFlx) RHOT_dt(:,ke) = & @@ -368,7 +383,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend !OCL SERIAL subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - Gsqrt, G11, G12, G22, nx, ny, nz, & + Gsqrt, G11, G12, G22, GsqrtH, G13, G23, nx, ny, nz, & vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) implicit none @@ -386,10 +401,13 @@ subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) @@ -399,17 +417,24 @@ subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) integer :: ke2D real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) - real(RP) :: dpres(elem%NfpTot), presM(elem%NfpTot), presP(elem%NfpTot) - real(RP) :: densM(elem%NfpTot), densP(elem%NfpTot) - real(RP) :: rhotM(elem%NfpTot), rhotP(elem%NfpTot) - real(RP) :: DDENS_P(elem%NfpTot), DDENS_M(elem%NfpTot) - real(RP) :: MOMX_P(elem%NfpTot), MOMX_M(elem%NfpTot) - real(RP) :: MOMY_P(elem%NfpTot), MOMY_M(elem%NfpTot) - real(RP) :: MOMZ_P(elem%NfpTot), MOMZ_M(elem%NfpTot) - real(RP) :: DRHOT_P(elem%NfpTot), DRHOT_M(elem%NfpTot) - real(RP) :: PRES_hyd_P(elem%NfpTot), PRES_hyd_M(elem%NfpTot) - real(RP) :: Gsqrt_M(elem%NfpTot) - real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) , Gnn_M(elem%NfpTot) + real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) + real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) + real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) + real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) + real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) + real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) + real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) + real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) + real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) + real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) + real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) + real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) + real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) + real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) + real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) + real(RP) :: Gxz_M(elem%NfpTot), Gxz_P(elem%NfpTot) + real(RP) :: Gyz_M(elem%NfpTot), Gyz_P(elem%NfpTot) + real(RP) :: gamm, rgamm real(RP) :: rP0 real(RP) :: RovP0, P0ovR @@ -422,81 +447,111 @@ subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & P0ovR = PRES00 / Rdry !$omp parallel do private( & - !$omp ke, iM, iP, ke2d, & - !$omp alpha, VelM, VelP, & - !$omp dpres, presM, presP, densM, densP, rhotM, rhotP, & - !$omp MOMX_M, MOMX_P, MOMY_M, MOMY_P, MOMZ_M, MOMZ_P, & - !$omp DDENS_M, DDENS_P, DRHOT_M, DRHOT_P, & - !$omp PRES_hyd_M, PRES_hyd_P, & - !$omp Gsqrt_M, G1n_M, G2n_M, Gnn_M ) + !$omp ke, iM, iP, ke2d, & + !$omp alpha, VelM, VelP, & + !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & + !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & + !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & + !$omp Phyd_M, Phyd_P, & + !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & + !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M ) do ke=lmesh%NeS, lmesh%NeE - iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) - - DDENS_M(:) = DDENS_(iM) - DDENS_P(:) = DDENS_(iP) - MOMX_M(:) = MOMX_(iM) - MOMX_P(:) = MOMX_(iP) - MOMY_M(:) = MOMY_(iM) - MOMY_P(:) = MOMY_(iP) - MOMZ_M(:) = MOMZ_(iM) - MOMZ_P(:) = MOMZ_(iP) - DRHOT_M(:) = DRHOT_(iM) - DRHOT_P(:) = DRHOT_(iP) - PRES_hyd_M(:) = PRES_hyd(iM) - PRES_hyd_P(:) = PRES_hyd(iP) + ke2D = lmesh%EMap3Dto2D(ke) Gsqrt_M(:) = Gsqrt(iM) - - ke2D = lmesh%EMap3Dto2D(ke) + Gsqrt_P(:) = Gsqrt(iP) + GsqrtV_M(:) = Gsqrt_M(:) / GsqrtH(iM2Dto3D(:),ke2D) + GsqrtV_P(:) = Gsqrt_P(:) / GsqrtH(iM2Dto3D(:),ke2D) + + G13_M(:) = G13(iM) + G13_P(:) = G13(iP) + G23_M(:) = G23(iM) + G23_P(:) = G23(iP) + + GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) + GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) + GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) + GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) + GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) + GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) + GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) + GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) + GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) + GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) + Phyd_M(:) = PRES_hyd(iM) + Phyd_P(:) = PRES_hyd(iP) + + Gxz_M(:) = G11(iM2Dto3D(:),ke2D) * G13_M(:) + G12(iM2Dto3D(:),ke2D) * G23_M(:) + Gxz_P(:) = G11(iM2Dto3D(:),ke2D) * G13_P(:) + G12(iM2Dto3D(:),ke2D) * G23_P(:) + + Gyz_M(:) = G12(iM2Dto3D(:),ke2D) * G13_M(:) + G22(iM2Dto3D(:),ke2D) * G23_M(:) + Gyz_P(:) = G12(iM2Dto3D(:),ke2D) * G13_P(:) + G22(iM2Dto3D(:),ke2D) * G23_P(:) + G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) - Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & - + abs( nz(:,ke) ) - - densM(:) = DDENS_M(:) + DENS_hyd(iM) - densP(:) = DDENS_P(:) + DENS_hyd(iP) - - VelM(:) = ( MOMX_M(:) * nx(:,ke) + MOMY_M(:) * ny(:,ke) + MOMZ_M(:) * nz(:,ke) ) / densM(:) - VelP(:) = ( MOMX_P(:) * nx(:,ke) + MOMY_P(:) * ny(:,ke) + MOMZ_P(:) * nz(:,ke) ) / densP(:) - - rhotM(:) = P0ovR * (PRES_hyd_M(:) * rP0)**rgamm + DRHOT_M(:) - rhotP(:) = P0ovR * (PRES_hyd_P(:) * rP0)**rgamm + DRHOT_P(:) - presM(:) = PRES00 * (RovP0 * rhotM(:))**gamm - presP(:) = PRES00 * (RovP0 * rhotP(:))**gamm - - dpres(:) = presP(:) - presM(:) & - - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * abs( nz(:,ke) ) - - alpha(:) = max( sqrt( Gnn_M(:) * gamm * presM(:) / densM(:) ) + abs(VelM(:)), & - sqrt( Gnn_M(:) * gamm * presP(:) / densP(:) ) + abs(VelP(:)) ) - - del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * Gsqrt_M(:) * ( & - ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & - - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) - - del_flux(:,ke,VARS_MOMX_ID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & - + G1n_M(:) * dpres(:) & - - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_M(:) + G13_M(:) * Gxz_M(:) + G23_M(:) * Gyz_M(:) ) * abs( nz(:,ke) ) + Gnn_P(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_P(:) + G13_P(:) * Gxz_P(:) + G23_P(:) * Gyz_P(:) ) * abs( nz(:,ke) ) + + GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) + GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) + + GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) + GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) + + VelM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( ( GsqrtMOMZ_M(:) / GsqrtV_M(:) & + + G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) ) & + ) / GsqrtDensM(:) + VelP(:) = ( GsqrtMOMX_P(:) * nx(:,ke) + GsqrtMOMY_P(:) * ny(:,ke) & + + ( ( GsqrtMOMZ_P(:) / GsqrtV_P(:) & + + G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & + ) / GsqrtDensP(:) + + dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & + - Phyd_M(:) + dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & + - Phyd_P(:) + + alpha(:) = max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & + sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) - del_flux(:,ke,VARS_MOMY_ID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & - + G2n_M(:) * dpres(:) & - - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & + ( GsqrtDensP(:) * VelP(:) - GsqrtDensM(:) * VelM(:) ) & + - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) + + del_flux(:,ke,VARS_MOMX_ID ) = 0.5_RP * ( & + ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & + + ( ( G1n_M(:) + Gxz_P(:) * nz(:,ke)) * dpresP(:) & + - ( G1n_M(:) + Gxz_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) + + del_flux(:,ke,VARS_MOMY_ID ) = 0.5_RP * ( & + ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & + + ( ( G2n_M(:) + Gyz_P(:) * nz(:,ke) ) * dpresP(:) & + - ( G2n_M(:) + Gyz_M(:) * nz(:,ke) ) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) + + del_flux(:,ke,VARS_MOMZ_ID ) = 0.5_RP * ( & + ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & + + ( dpresP(:) / GsqrtV_P(:) & + - dpresM(:) / GsqrtV_M(:) ) * nz(:,ke) & + - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) + + del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & + ( GsqrtRhotP(:) * VelP(:) - GsqrtRhotM(:) * VelM(:) ) & + - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( & + GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) - del_flux(:,ke,VARS_MOMZ_ID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:) ) & - + dpres(:) * nz(:,ke) & - - alpha(:) * ( MOMZ_P(:) - MOMZ_M(:) ) ) - - del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * Gsqrt_M(:) * ( & - ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & - - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) - - del_flux_hyd(:,ke,1) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * nx(:,ke) - del_flux_hyd(:,ke,2) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * ny(:,ke) + del_flux_hyd(:,ke,2) = 0.5_RP * ( & + GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) end do return diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index 3f1aa3b9..efd4ef1e 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -183,9 +183,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) real(RP) :: DPRES_(elem%Np) real(RP) :: RHOT_(elem%Np) - real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), wt_(elem%Np) - real(RP) :: GIJ(elem%Np,2,2) + real(RP) :: G11(elem%Np), G12(elem%Np), G22(elem%Np) + real(RP) :: GsqrtV(elem%Np), RGsqrtV(elem%Np) real(RP) :: X2D(elem%Np,lmesh2D%Ne), Y2D(elem%Np,lmesh2D%Ne) real(RP) :: X(elem%Np), Y(elem%Np), twoOVdel2(elem%Np) real(RP) :: CORI(elem%Np,2) @@ -204,6 +205,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & call cal_del_flux_dyn( del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) + lmesh%GsqrtH, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) lmesh%vmapM, lmesh%vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) @@ -226,10 +228,11 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & end if !$omp parallel private( & - !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, wt_, & !$omp Fx, Fy, Fz, LiftDelFlx, & !$omp GradPhyd_x, GradPhyd_y, & - !$omp GIJ, X, Y, twoOVdel2, & + !$omp G11, G12, G22, GsqrtV, RGsqrtV, & + !$omp X, Y, twoOVdel2, & !$omp CORI, ke, ke2D ) !$omp do @@ -240,6 +243,14 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & !$omp do do ke = lmesh%NeS, lmesh%NeE + !-- + ke2d = lmesh%EMap3Dto2D(ke) + G11(:) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) + G12(:) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) + G22(:) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + GsqrtV(:) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2d) + RGsqrtV(:) = 1.0_RP / GsqrtV(:) + !-- RHOT_(:) = P0ovR * ( PRES_hyd(:,ke) * rP0 )**rgamm + DRHOT_(:,ke) DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & @@ -249,12 +260,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & u_ (:) = MOMX_(:,ke) * rdens_(:) v_ (:) = MOMY_(:,ke) * rdens_(:) w_ (:) = MOMZ_(:,ke) * rdens_(:) - - ke2d = lmesh%EMap3Dto2D(ke) - GIJ(:,1,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,1) - GIJ(:,2,1) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,1) - GIJ(:,1,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,1,2) - GIJ(:,2,2) = lmesh%GIJ(elem%IndexH2Dto3D,ke2d,2,2) + wt_(:) = w_(:) * RGsqrtV(:) + lmesh%GI3(:,ke,1) * u_(:) + lmesh%GI3(:,ke,2) * v_(:) X(:) = X2D(elem%IndexH2Dto3D,ke2d) Y(:) = Y2D(elem%IndexH2Dto3D,ke2d) @@ -268,28 +274,39 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & end if !-- Gradient hydrostatic pressure - call sparsemat_matmul(Dx, PRES_hyd(:,ke), Fx) + + call sparsemat_matmul(Dx, GsqrtV(:) * PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,1) * PRES_hyd(:,ke), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) - GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) + LiftDelFlx(:) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) - call sparsemat_matmul(Dy, PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dy, GsqrtV(:) * PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,2) * PRES_hyd(:,ke), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) - GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) + LiftDelFlx(:) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) !-- DENS call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) & + * ( wt_(:) - w_(:) * RGsqrtV(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DDENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx(:) & + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- MOMX - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + GIJ(:,1,1) * DPRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMX_(:,ke) + GIJ(:,1,2) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMX_(:,ke) + G11(:) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMX_(:,ke) + G12(:) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) MOMX_dt(:,ke) = & @@ -299,13 +316,14 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + twoOVdel2(:) * Y(:) * & ( - X(:) * Y(:) * u_(:) + (1.0_RP + Y(:)**2) * v_(:) ) * MOMX_(:,ke) & - - ( GIJ(:,1,1) * GradPhyd_x(:) + GIJ(:,1,2) * GradPhyd_y(:) ) & + - ( G11(:) * GradPhyd_x(:) + G12(:) * GradPhyd_y(:) ) * RGsqrtV(:) & + CORI(:,1) !-- MOMY - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMY_(:,ke) + GIJ(:,2,1) * DPRES_(:) ), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + GIJ(:,2,2) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMY_(:,ke) + G12(:) * DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMY_(:,ke) + G22(:) * DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & + ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) MOMY_dt(:,ke) = & @@ -315,13 +333,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + twoOVdel2(:) * X(:) * & ( (1.0_RP + X(:)**2) * u_(:) - X(:) * Y(:) * v_(:) ) * MOMY_(:,ke) & - - ( GIJ(:,2,1) * GradPhyd_x(:) + GIJ(:,2,2) * GradPhyd_y(:) ) & + - ( G12(:) * GradPhyd_x(:) + G22(:) * GradPhyd_y(:) ) * RGsqrtV(:) & + CORI(:,2) !-- MOMZ - call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) - call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * w_(:) * MOMZ_(:,ke), Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * wt_(:) * MOMZ_(:,ke), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) MOMZ_dt(:,ke) = & @@ -333,11 +351,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & !-- RHOT call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * RHOT_(:), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * RHOT_(:), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) - w_(:) * RGsqrtV(:) ) * RHOT_(:), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DRHOT_VID), LiftDelFlx) RHOT_dt(:,ke) = & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) end do !$omp end parallel @@ -361,7 +381,7 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend !OCL SERIAL subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - Gsqrt, G11, G12, G22, nx, ny, nz, & + Gsqrt, G11, G12, G22, GsqrtH, G13, G23, nx, ny, nz, & vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) implicit none @@ -379,10 +399,13 @@ subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) @@ -391,19 +414,28 @@ subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) integer :: ke2D - real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) - real(RP) :: dpres(elem%NfpTot), presM(elem%NfpTot), presP(elem%NfpTot) - real(RP) :: densM(elem%NfpTot), densP(elem%NfpTot) - real(RP) :: rhotM(elem%NfpTot), rhotP(elem%NfpTot) - real(RP) :: DDENS_P(elem%NfpTot), DDENS_M(elem%NfpTot) - real(RP) :: MOMX_P(elem%NfpTot), MOMX_M(elem%NfpTot) - real(RP) :: MOMY_P(elem%NfpTot), MOMY_M(elem%NfpTot) - real(RP) :: MOMZ_P(elem%NfpTot), MOMZ_M(elem%NfpTot) - real(RP) :: DRHOT_P(elem%NfpTot), DRHOT_M(elem%NfpTot) - real(RP) :: PRES_hyd_P(elem%NfpTot), PRES_hyd_M(elem%NfpTot) - real(RP) :: Gsqrt_M(elem%NfpTot) - real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) , Gnn_M(elem%NfpTot) + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot) + real(RP) :: VelhP(elem%NfpTot), VelhM(elem%NfpTot) + real(RP) :: alpha(elem%NfpTot) + real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) + real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) + real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) + real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) + real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) + real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) + real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) + real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) + real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) + real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) + real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) + real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) + real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) + real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) + real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) + real(RP) :: Gxz_M(elem%NfpTot), Gxz_P(elem%NfpTot) + real(RP) :: Gyz_M(elem%NfpTot), Gyz_P(elem%NfpTot) real(RP) :: swV(elem%NfpTot) + real(RP) :: gamm, rgamm real(RP) :: rP0 real(RP) :: RovP0, P0ovR @@ -416,80 +448,111 @@ subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & P0ovR = PRES00 / Rdry !$omp parallel do private( & - !$omp ke, iM, iP, ke2D, & - !$omp alpha, VelM, VelP, & - !$omp dpres, presM, presP, densM, densP, rhotM, rhotP, & - !$omp MOMX_M, MOMX_P, MOMY_M, MOMY_P, MOMZ_M, MOMZ_P, & - !$omp DDENS_M, DDENS_P, DRHOT_M, DRHOT_P, & - !$omp PRES_hyd_M, PRES_hyd_P, & - !$omp Gsqrt_M, G1n_M, G2n_M, Gnn_M, & + !$omp ke, iM, iP, ke2d, & + !$omp alpha, VelM, VelP, VelhM, VelhP, & + !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & + !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & + !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & + !$omp Phyd_M, Phyd_P, & + !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & + !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M, & !$omp swV ) do ke=lmesh%NeS, lmesh%NeE iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) - - DDENS_M(:) = DDENS_(iM) - DDENS_P(:) = DDENS_(iP) - MOMX_M(:) = MOMX_(iM) - MOMX_P(:) = MOMX_(iP) - MOMY_M(:) = MOMY_(iM) - MOMY_P(:) = MOMY_(iP) - MOMZ_M(:) = MOMZ_(iM) - MOMZ_P(:) = MOMZ_(iP) - DRHOT_M(:) = DRHOT_(iM) - DRHOT_P(:) = DRHOT_(iP) - PRES_hyd_M(:) = PRES_hyd(iM) - PRES_hyd_P(:) = PRES_hyd(iP) + ke2D = lmesh%EMap3Dto2D(ke) Gsqrt_M(:) = Gsqrt(iM) + Gsqrt_P(:) = Gsqrt(iP) + GsqrtV_M(:) = Gsqrt_M(:) / GsqrtH(iM2Dto3D(:),ke2D) + GsqrtV_P(:) = Gsqrt_P(:) / GsqrtH(iM2Dto3D(:),ke2D) + + G13_M(:) = G13(iM) + G13_P(:) = G13(iP) + G23_M(:) = G23(iM) + G23_P(:) = G23(iP) + + GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) + GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) + GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) + GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) + GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) + GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) + GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) + GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) + GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) + GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) + Phyd_M(:) = PRES_hyd(iM) + Phyd_P(:) = PRES_hyd(iP) + swV(:) = 1.0_RP - nz(:,ke)**2 - ke2D = lmesh%EMap3Dto2D(ke) + Gxz_M(:) = G11(iM2Dto3D(:),ke2D) * G13_M(:) + G12(iM2Dto3D(:),ke2D) * G23_M(:) + Gxz_P(:) = G11(iM2Dto3D(:),ke2D) * G13_P(:) + G12(iM2Dto3D(:),ke2D) * G23_P(:) + + Gyz_M(:) = G12(iM2Dto3D(:),ke2D) * G13_M(:) + G22(iM2Dto3D(:),ke2D) * G23_M(:) + Gyz_P(:) = G12(iM2Dto3D(:),ke2D) * G13_P(:) + G22(iM2Dto3D(:),ke2D) * G23_P(:) + G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) - Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) - - densM(:) = DDENS_M(:) + DENS_hyd(iM) - densP(:) = DDENS_P(:) + DENS_hyd(iP) - swV(:) = 1.0_RP - nz(:,ke)**2 - VelM(:) = ( MOMX_M(:) * nx(:,ke) + MOMY_M(:) * ny(:,ke) + MOMZ_M(:) * nz(:,ke) ) / densM(:) - VelP(:) = ( MOMX_P(:) * nx(:,ke) + MOMY_P(:) * ny(:,ke) + MOMZ_P(:) * nz(:,ke) ) / densP(:) + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) + Gnn_P(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) - rhotM(:) = P0ovR * (PRES_hyd_M(:) * rP0)**rgamm + DRHOT_M(:) - rhotP(:) = P0ovR * (PRES_hyd_P(:) * rP0)**rgamm + DRHOT_P(:) + GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) + GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) - presM(:) = PRES00 * (RovP0 * rhotM(:))**gamm - presP(:) = PRES00 * (RovP0 * rhotP(:))**gamm + GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) + GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) - dpres(:) = presP(:) - presM(:) & - - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) + VelhM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) & + ) / GsqrtDensM(:) - alpha(:) = swV(:) * max( sqrt( Gnn_M(:) * gamm * presM(:) / densM(:) ) + abs(VelM(:)), & - sqrt( Gnn_M(:) * gamm * presP(:) / densP(:) ) + abs(VelP(:)) ) + VelhP(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) & + ) / GsqrtDensM(:) - del_flux(:,ke,DDENS_VID) = 0.5_RP * Gsqrt_M(:) * ( & - swV(:) * ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & - - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) + VelM(:) = VelhM(:) + GsqrtMOMZ_M(:) / ( GsqrtV_M(:) * GsqrtDensM(:) ) * nz(:,ke) + VelP(:) = VelhP(:) + GsqrtMOMZ_P(:) / ( GsqrtV_P(:) * GsqrtDensP(:) ) * nz(:,ke) - del_flux(:,ke,MOMX_VID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & - + G1n_M(:) * dpres(:) & - - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) - - del_flux(:,ke,MOMY_VID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & - + G2n_M(:) * dpres(:) & - - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) - - del_flux(:,ke,MOMZ_VID) = 0.5_RP * Gsqrt_M(:) * ( & - ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:) ) & - - alpha(:) * ( MOMZ_P(:) - MOMZ_M(:) ) ) + dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & + - Phyd_M(:) + dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & + - Phyd_P(:) + + alpha(:) = swV(:) * max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & + sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) - del_flux(:,ke,DRHOT_VID) = 0.5_RP * Gsqrt_M(:) * ( & - swV(:) * ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & - - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) + del_flux(:,ke,DDENS_VID) = 0.5_RP * ( & + ( GsqrtDensP(:) * VelhP(:) - GsqrtDensM(:) * VelhM(:) ) & + - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) + + del_flux(:,ke,MOMX_VID ) = 0.5_RP * ( & + ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & + + ( ( G1n_M(:) + Gxz_P(:) * nz(:,ke)) * dpresP(:) & + - ( G1n_M(:) + Gxz_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) + + del_flux(:,ke,MOMY_VID ) = 0.5_RP * ( & + ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & + + ( ( G2n_M(:) + Gyz_P(:) * nz(:,ke) ) * dpresP(:) & + - ( G2n_M(:) + Gyz_M(:) * nz(:,ke) ) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) + + del_flux(:,ke,MOMZ_VID ) = 0.5_RP * ( & + ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & + - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) + + del_flux(:,ke,DRHOT_VID) = 0.5_RP * ( & + ( GsqrtRhotP(:) * VelhP(:) - GsqrtRhotM(:) * VelhM(:) ) & + - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( & + GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) - del_flux_hyd(:,ke,1) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * nx(:,ke) - del_flux_hyd(:,ke,2) = 0.5_RP * ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * ny(:,ke) + del_flux_hyd(:,ke,2) = 0.5_RP * ( & + GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) end do return @@ -536,13 +599,18 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: alph(elem%NfpTot,lmesh%NeZ) real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) + real(RP) :: GnnM_z(elem%Np,lmesh%NeZ) + real(RP) :: G13_z(elem%Np,lmesh%NeZ) + real(RP) :: G23_z(elem%Np,lmesh%NeZ) + real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ) real(RP) :: nz(elem%NfpTot,lmesh%NeZ) integer :: vmapM(elem%NfpTot,lmesh%NeZ) integer :: vmapP(elem%NfpTot,lmesh%NeZ) - integer :: ke_x, ke_y, ke_z, ke, p, v + integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v integer :: itr_lin, itr_nlin integer :: f, vs, ve, kl, ku, nz_1D integer :: ij, info @@ -595,9 +663,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & call PROF_rapstart( 'hevi_cal_vi_get_var', 3) - !$omp parallel do private(ke) + !$omp parallel do private( ke, ke2D ) do ke_z=1, lmesh%NeZ ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2D = lmesh%EMap3Dto2D(ke) PROG_VARS(:,DDENS_VID,ke_z) = DDENS_(:,ke) PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) @@ -609,7 +678,18 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) + nz(:,ke_z) = lmesh%normal_fn(:,ke,3) + G13_z(:,ke_z) = lmesh%GI3(:,ke,1) + G23_z(:,ke_z) = lmesh%GI3(:,ke,2) + GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) + + GnnM_z(:,ke_z) = ( & + 1.0_RP / lmesh%Gsqrt(:,ke) & + + G13_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,1) * G13_z(:,ke_z) & + + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G23_z(:,ke_z) ) & + + G23_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G13_z(:,ke_z) & + + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,2,2) * G23_z(:,ke_z) ) ) end do call PROF_rapend( 'hevi_cal_vi_get_var', 3) @@ -620,9 +700,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & ! dG/dq^n+1 del[q] = - G(q^n*) do itr_nlin = 1, 1 - call vi_eval_Ax( Ax(:,:,:), & ! (out) + call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) Dz, Lift, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -637,6 +718,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & call vi_construct_matbnd( PmatBnd, & ! (out) kl, ku, nz_1D, & ! (in) PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) + alph, & ! (in) Dz, Lift, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) @@ -695,9 +777,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & tend(:,:,ke_z) = (- PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z))/impl_fac end do else - call vi_eval_Ax( tend(:,:,:), & ! (out) + call vi_eval_Ax( tend(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) Dz, Lift, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -735,9 +818,10 @@ end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi !------------------------------------------------ !OCL SERIAL - subroutine vi_eval_Ax( Ax, & ! (out) + subroutine vi_eval_Ax( Ax, alph, & ! (out) PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) Dz, Lift, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -748,11 +832,16 @@ subroutine vi_eval_Ax( Ax, & ! (out) class(LocalMesh3D), intent(in) :: lmesh class(elementbase3D), intent(in) :: elem real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(out) :: alph(elem%NfpTot,lmesh%NeZ) real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) class(SparseMat), intent(in) :: Dz, Lift + real(RP), intent(in) :: GnnM_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G13_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G23_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: GsqrtV_z(elem%Np,lmesh%NeZ) logical, intent(in) :: modalFilterFlag real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) real(RP), intent(in) :: impl_fac @@ -763,13 +852,13 @@ subroutine vi_eval_Ax( Ax, & ! (out) integer, intent(in) :: ke_x, ke_y logical, intent(in) :: cal_tend_flag + real(RP) :: RGsqrtV(elem%Np) real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) real(RP) :: DPRES(elem%Np) - real(RP) :: tmpV1D(elem%Nnode_v) integer :: ke_z - integer :: ke + integer :: ke, ke2d integer :: v integer :: ij real(RP) :: gamm, rgamm @@ -778,51 +867,55 @@ subroutine vi_eval_Ax( Ax, & ! (out) gamm = CpDry/CvDry rgamm = CvDry/CpDry - call vi_cal_del_flux_dyn( del_flux, & ! (out) + call vi_cal_del_flux_dyn( del_flux, alph, & ! (out) PROG_VARS(:,DDENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) PROG_VARS(:,MOMY_VID ,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) PROG_VARS(:,DRHOT_VID,:), & ! (in) PROG_VARS0(:,DDENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) PROG_VARS0(:,DRHOT_VID,:), & ! (in) - DENS_hyd, PRES_hyd, nz, vmapM, vmapP, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, nz, vmapM, vmapP, & ! (in) lmesh, elem ) ! (in) !$omp parallel do private( & - !$omp ke, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & - !$omp v, ij, tmpV1D & + !$omp ke, ke2d, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & + !$omp v, ij, RGsqrtV & !$omp ) do ke_z=1, lmesh%NeZ ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2d = lmesh%EMap3Dto2D(ke) RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm - DPRES(:) = PRES_hyd(:,ke_z) * ((1.0_RP + PROG_VARS(:,DRHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP) - POT(:) = (RHOT_hyd(:) + PROG_VARS(:,DRHOT_VID,ke_z))/(DENS_hyd(:,ke_z) + PROG_VARS(:,DDENS_VID,ke_z)) + DPRES(:) = PRES_hyd(:,ke_z) * ( (1.0_RP + PROG_VARS(:,DRHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP ) + POT(:) = ( RHOT_hyd(:) + PROG_VARS(:,DRHOT_VID,ke_z) ) / ( DENS_hyd(:,ke_z) + PROG_VARS(:,DDENS_VID,ke_z) ) + + RGsqrtV(:) = 1.0_RP / GsqrtV_z(:,ke_z) !- DENS call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DDENS_VID), LiftDelFlx) - Ax(:,DDENS_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) + Ax(:,DDENS_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) !- MOMX call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) - Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) + Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) !-MOMY call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) - Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) + Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) !-MOMZ call sparsemat_matmul(Dz, DPRES(:), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) - Ax(:,MOMZ_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) & + Ax(:,MOMZ_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) & + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DDENS_VID,ke_z)) !-RHOT call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DRHOT_VID), LiftDelFlx) - Ax(:,DRHOT_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) + Ax(:,DRHOT_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) !-- Modal filtering in the vertical direction if ( modalFilterFlag ) then @@ -845,16 +938,18 @@ subroutine vi_eval_Ax( Ax, & ! (out) end subroutine vi_eval_Ax !OCL SERIAL - subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) - DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) - DENS_hyd, PRES_hyd, nz, vmapM, vmapP, lmesh, elem ) ! (in) + subroutine vi_cal_del_flux_dyn( del_flux, alph, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + Gnn_, G13_, G23_, GsqrtV_, nz, vmapM, vmapP, lmesh, elem ) ! (in) implicit none class(LocalMesh3D), intent(in) :: lmesh class(elementbase3D), intent(in) :: elem real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) + real(RP), intent(out) :: alph(elem%NfpTot*lmesh%NeZ) real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) @@ -867,13 +962,18 @@ subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: Gnn_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: G13_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: G23_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: GsqrtV_(elem%Np*lmesh%NeZ) real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) - integer :: i, p, ke_z, iP, iM - real(RP) :: alpha0, swV - real(RP) :: MOMZ_P + integer :: i, p, ke_z, iP, iM, iM2D + real(RP) :: alpha0 + real(RP) :: MOMZ_P + real(RP) :: wt0M, wt0P real(RP) :: rhot_hyd_M, rhot_hyd_P real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP real(RP) :: pres0M, pres0P, dens0M, dens0P @@ -885,13 +985,13 @@ subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) !$omp parallel do private( p, i, iM, iP, & !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & - !$omp dpresM, dpresP, MOMZ_P, & - !$omp dens0M, dens0P, pres0M, pres0P, & - !$omp swV, alpha0 ) + !$omp dpresM, dpresP, MOMZ_P, wt0M, wt0P, & + !$omp dens0M, dens0P, pres0M, pres0P ) do ke_z=1, lmesh%NeZ do p=1, elem%NfpTot i = p + (ke_z-1)*elem%NfpTot iM = vmapM(i); iP = vmapP(i) + iM2D = iM2Dto3D(p) !- rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm @@ -913,34 +1013,37 @@ subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm - swV = nz(i)**2 - alpha0 = swV * max( abs(MOMZ0_(iM)/dens0M) + sqrt(gamm * pres0M/dens0M), & - abs(MOMZ0_(iP)/dens0P) + sqrt(gamm * pres0P/dens0P) ) + wt0M = ( MOMZ0_(iM) / GsqrtV_(iM) + G13_(iM) * MOMX0_(iM) + G23_(iM) * MOMY0_(iM) ) / dens0M + wt0P = ( MOMZ0_(iP) / GsqrtV_(iP) + G13_(iP) * MOMX0_(iP) + G23_(iP) * MOMY0_(iP) ) / dens0M + + alph(i) = nz(i)**2 * max( abs( wt0M ) + sqrt( Gnn_(iM) * gamm * pres0M / dens0M ), & + abs( wt0P ) + sqrt( Gnn_(iP) * gamm * pres0M / dens0M ) ) + !---- if (iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ)) then MOMZ_P = - MOMZ_(iM) - !alpha0 = 0.0_RP + !alph(i) = 0.0_RP else MOMZ_P = MOMZ_(iP) end if - del_flux(i,DDENS_VID) = 0.5_RP * ( & - + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & - - alpha0 * ( DDENS_(iP) - DDENS_(iM) ) ) + del_flux(i,DDENS_VID) = 0.5_RP * ( & + + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & + - alph(i) * ( DDENS_(iP) - DDENS_(iM) ) ) - del_flux(i,MOMX_VID) = 0.5_RP * ( & - - alpha0 * ( MOMX_(iP) - MOMX_(iM) ) ) + del_flux(i,MOMX_VID) = 0.5_RP * ( & + - alph(i) * ( MOMX_(iP) - MOMX_(iM) ) ) - del_flux(i,MOMY_VID) = 0.5_RP * ( & - - alpha0 * ( MOMY_(iP) - MOMY_(iM) ) ) + del_flux(i,MOMY_VID) = 0.5_RP * ( & + - alph(i) * ( MOMY_(iP) - MOMY_(iM) ) ) - del_flux(i,MOMZ_VID) = 0.5_RP * ( & - + ( dpresP - dpresM ) * nz(i) & - - alpha0 * ( MOMZ_P - MOMZ_(iM) ) ) + del_flux(i,MOMZ_VID) = 0.5_RP * ( & + + ( dpresP - dpresM ) * nz(i) & + - alph(i) * ( MOMZ_P - MOMZ_(iM) ) ) del_flux(i,DRHOT_VID) = 0.5_RP * ( & + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & - - alpha0 * ( DRHOT_(iP) - DRHOT_(iM) ) ) + - alph(i) * ( DRHOT_(iP) - DRHOT_(iM) ) ) end do end do @@ -951,6 +1054,7 @@ end subroutine vi_cal_del_flux_dyn subroutine vi_construct_matbnd( PmatBnd, & ! (out) kl, ku, nz_1D, & ! (in) PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) + alph, & ! (in) Dz, Lift, & ! (in) modalFilterFlag, VModalFilter, & ! (in) impl_fac, dt, & ! (in) @@ -966,6 +1070,7 @@ subroutine vi_construct_matbnd( PmatBnd, & ! (out) real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: alph(elem%NfpTot,lmesh%NeZ) class(SparseMat), intent(in) :: Dz, Lift logical, intent(in) :: modalFilterFlag real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) @@ -978,12 +1083,11 @@ subroutine vi_construct_matbnd( PmatBnd, & ! (out) real(RP) :: RHOT_hyd(elem%Nnode_v) real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: Cs0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) integer :: ke_z, ke_z2 - integer :: v, ke, p, f1, fp, FmV + integer :: v, ke, p, f1, f2, fp, fp2, FmV real(RP) :: gamm, rgamm real(RP) :: fac_dz_p(elem%Nnode_v) real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) @@ -993,7 +1097,6 @@ subroutine vi_construct_matbnd( PmatBnd, & ! (out) real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) real(RP) :: Dd(elem%Nnode_v) real(RP) :: tmp1 - real(RP) :: alphaM, alphaP real(RP) :: fac integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 @@ -1042,16 +1145,14 @@ subroutine vi_construct_matbnd( PmatBnd, & ! (out) DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DDENS_VID,ke_z) POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) - Cs0(:,ke_z,ij) = sqrt( gamm * PRES_hyd(Colmask(:),ke_z) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**gamm / DENS0(:,ke_z,ij) ) end do end do !$omp end parallel - !$omp parallel do private(ke_z, ke, ColMask, p, fp, v, f1, ke_z2, fac_dz_p, & - !$omp fac, tmp1, alphaM, alphaP, FmV, & - !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & - !$omp Dd ) & + !$omp parallel do private(ke_z, ke, ColMask, p, fp, fp2, v, f1, f2, ke_z2, fac_dz_p, & + !$omp fac, tmp1, FmV, & + !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & + !$omp Dd ) & !$omp firstprivate(PmatD, PmatL, PmatU) do ij=1, elem%Nnode_h1D**2 do ke_z=1, lmesh%NeZ @@ -1092,26 +1193,27 @@ subroutine vi_construct_matbnd( PmatBnd, & ! (out) if (f1==1) then ke_z2 = max(ke_z-1,1) pv1 = 1; pv2 = elem%Nnode_v + f2 = 2 else ke_z2 = min(ke_z+1,lmesh%NeZ) pv1 = elem%Nnode_v; pv2 = 1 + f2 = 1 end if fac = 0.5_RP * impl_fac if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then bc_flag = .true. - pv2 = pv1 + pv2 = pv1; f2 = f1 else bc_flag = .false. end if FmV = elem%Fmask_v(ij,f1) - fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij - - !-- - alphaM = abs( W0(pv1,ke_z ,ij) ) + Cs0(pv1,ke_z ,ij) - alphaP = abs( W0(pv2,ke_z2,ij) ) + Cs0(pv2,ke_z2,ij) + fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij + fp2 = elem%Nfp_h * elem%Nfaces_h + (f2-1)*elem%Nfp_v + ij - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * max(alphaM, alphaP) + !-- + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) & + * max( alph(fp,ke_z), alph(fp2,ke_z2) ) if (bc_flag) then PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 else diff --git a/FElib/src/mesh/scale_localmesh_3d.F90 b/FElib/src/mesh/scale_localmesh_3d.F90 index e297ca9d..c00a13e3 100644 --- a/FElib/src/mesh/scale_localmesh_3d.F90 +++ b/FElib/src/mesh/scale_localmesh_3d.F90 @@ -25,10 +25,16 @@ module scale_localmesh_3d real(DP) :: xmin, xmax real(DP) :: ymin, ymax real(DP) :: zmin, zmax - integer :: NeX, NeY, Ne2D, NeZ + integer :: NeX + integer :: NeY + integer :: NeZ + integer :: Ne2D + integer :: Ne2DA real(DP), allocatable :: Sz(:,:) real(DP), allocatable :: zS(:,:) + real(RP), allocatable :: GI3(:,:,:) !< The contravariant component of metric tensor with vertical general coordinate + real(RP), allocatable :: zlev(:,:) class(LocalMesh2D), pointer :: lcmesh2D real(DP), allocatable :: lon2D(:,:) @@ -85,6 +91,8 @@ subroutine LocalMesh3D_Final( this, is_generated ) call LocalMeshBase_Final( this, is_generated ) if (is_generated) then deallocate( this%zS, this%Sz ) + deallocate( this%GI3, this%Gsqrt ) + deallocate( this%zlev ) deallocate( this%lon2D, this%lat2D ) deallocate( this%EMap3Dto2D ) end if diff --git a/FElib/src/mesh/scale_localmesh_base.F90 b/FElib/src/mesh/scale_localmesh_base.F90 index 27823d3a..eae0a390 100644 --- a/FElib/src/mesh/scale_localmesh_base.F90 +++ b/FElib/src/mesh/scale_localmesh_base.F90 @@ -59,9 +59,10 @@ module scale_localmesh_base integer :: PRC_myrank integer :: lcdomID - real(DP), allocatable :: G_ij(:,:,:,:) - real(DP), allocatable :: GIJ(:,:,:,:) - real(DP), allocatable :: Gsqrt(:,:) + real(RP), allocatable :: G_ij(:,:,:,:) !< The covariant component of metric tensor with horizontal general curvilinear coordinate + real(RP), allocatable :: GIJ(:,:,:,:) !< The contravariant component of metric tensor with horizontal general curvilinear coordinate + real(RP), allocatable :: GsqrtH(:,:) !< The Jacobian of horizontal transformation in the computational coordinate + real(RP), allocatable :: Gsqrt(:,:) !< The Jacobian of 3D transformation in the computational coordinate (=GsqrtH * GsqrtV) end type LocalMeshBase public :: LocalMeshBase_Init @@ -136,7 +137,8 @@ subroutine LocalMeshBase_Final( this, is_generated ) deallocate( this%VMapB, this%MapB ) end if if ( allocated(this%G_ij) ) then - deallocate( this%G_ij, this%GIJ, this%Gsqrt ) + deallocate( this%G_ij, this%GIJ ) + deallocate( this%Gsqrt, this%GsqrtH ) end if end if diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index 4bf36a64..d717062a 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -9,7 +9,8 @@ module scale_mesh_base3d use scale_localmesh_3d, only: & LocalMesh3D, LocalMesh3D_Init, LocalMesh3D_Final - + use scale_localmesh_2d, only: & + LocalMesh2D use scale_mesh_base, only: & MeshBase, MeshBase_Init, MeshBase_Final use scale_mesh_base2d, only: & @@ -31,6 +32,7 @@ module scale_mesh_base3d procedure(MeshBase3D_generate), deferred :: Generate procedure(MeshBase3D_getMesh2D), deferred :: GetMesh2D procedure :: GetLocalMesh => MeshBase3D_get_localmesh + procedure :: SetVCoordinate_lcdom => MeshBase3D_set_vcoordinate_lcdom end type MeshBase3D interface @@ -117,7 +119,7 @@ subroutine MeshBase3D_Final( this ) integer :: n !----------------------------------------------------------------------------- - + do n=1, this%LOCAL_MESH_NUM call LocalMesh3D_Final( this%lcmesh_list(n), this%isGenerated ) end do @@ -141,6 +143,36 @@ subroutine MeshBase3D_get_localmesh( this, id, ptr_lcmesh ) return end subroutine MeshBase3D_get_localmesh + subroutine MeshBase3D_set_vcoordinate_lcdom( this, & + vcoord_name, domid, topo, zTop, Dx2D, Dy2D, Lift2D ) + + use scale_sparsemat, only: SparseMat + use scale_meshutil_vcoord, only: MeshUtil_VCoord_GetMetric + implicit none + + class(MeshBase3D), target, intent(in) :: this + character(len=*), intent(in) :: vcoord_name + integer, intent(in) :: domid + real(RP), intent(in) :: topo(this%lcmesh_list(domid)%refElem3D%Nfp_v,this%lcmesh_list(domid)%lcmesh2D%NeA) + real(RP), intent(in) :: zTop + type(SparseMat), intent(in) :: Dx2D, Dy2D, Lift2D + + class(LocalMesh3D), pointer :: lcmesh + class(LocalMesh2D), pointer :: lcmesh2D + integer :: n + !------------------------------------------------------------- + + lcmesh => this%lcmesh_list(domid) + lcmesh2D => lcmesh%lcmesh2D + call MeshUtil_VCoord_GetMetric( & + lcmesh%GI3(:,:,1), lcmesh%GI3(:,:,2), lcmesh%zlev(:,:), & ! (out) + lcmesh%Gsqrt(:,:), & ! (inout) + topo(:,:), zTop, vcoord_name, lcmesh, lcmesh%refElem3D, lcmesh2D, lcmesh2D%refElem2D, & ! (in + Dx2D, Dy2D, Lift2D ) ! (in) + + return + end subroutine MeshBase3D_set_vcoordinate_lcdom + subroutine MeshBase3D_setGeometricInfo( lcmesh, coord_conv, calc_normal ) implicit none @@ -170,7 +202,7 @@ end subroutine calc_normal end interface class(ElementBase3D), pointer :: refElem - integer :: ke + integer :: ke, ke2D integer :: f integer :: i, j integer :: d @@ -184,7 +216,6 @@ end subroutine calc_normal real(RP) :: xX(lcmesh%refElem%Np), xY(lcmesh%refElem%Np), xZ(lcmesh%refElem%Np) real(RP) :: yX(lcmesh%refElem%Np), yY(lcmesh%refElem%Np), yZ(lcmesh%refElem%Np) real(RP) :: zX(lcmesh%refElem%Np), zY(lcmesh%refElem%Np), zZ(lcmesh%refElem%Np) - !----------------------------------------------------------------------------- refElem => lcmesh%refElem3D @@ -199,9 +230,12 @@ end subroutine calc_normal allocate( lcmesh%Escale(refElem%Np,lcmesh%Ne,3,3) ) allocate( lcmesh%zS(refElem%Np,lcmesh%Ne) ) allocate( lcmesh%Sz(refElem%Np,lcmesh%Ne) ) - allocate( lcmesh%Gsqrt(refElem%Np,lcmesh%Ne) ) + allocate( lcmesh%Gsqrt(refElem%Np,lcmesh%NeA) ) + allocate( lcmesh%GsqrtH(refElem%Nfp_v,lcmesh%Ne2D) ) allocate( lcmesh%G_ij(refElem%Nfp_v,lcmesh%Ne2D,2,2) ) allocate( lcmesh%GIJ (refElem%Nfp_v,lcmesh%Ne2D,2,2) ) + allocate( lcmesh%GI3 (refElem%Np,lcmesh%NeA,2) ) + allocate( lcmesh%zlev(refElem%Np,lcmesh%Ne) ) allocate( lcmesh%lon2D(refElem%Nfp_v,lcmesh%Ne2D) ) allocate( lcmesh%lat2D(refElem%Nfp_v,lcmesh%Ne2D) ) @@ -218,9 +252,11 @@ end subroutine calc_normal end do end do - !$omp parallel do private( ke, node_ids, vx, vy, vz, & + !$omp parallel private( ke, node_ids, vx, vy, vz, & !$omp xX, xY, xZ, yX, yY, yZ, zX, zY, zZ, & !$omp i, j, Escale_f, d ) + + !$omp do do ke=1, lcmesh%Ne node_ids(:) = lcmesh%EToV(ke,:) vx(:) = lcmesh%pos_ev(node_ids(:),1) @@ -270,8 +306,18 @@ end subroutine calc_normal lcmesh%sJ(:,ke) = lcmesh%sJ(:,ke)*lcmesh%J(fmask(:),ke) lcmesh%Fscale(:,ke) = lcmesh%sJ(:,ke)/lcmesh%J(fmask(:),ke) - lcmesh%Gsqrt(:,ke) = 1.0_RP + lcmesh%zlev(:,ke) = lcmesh%pos_en(:,ke,3) end do + !$omp end do + + !$omp workshare + lcmesh%Gsqrt (:,:) = 1.0_RP + lcmesh%GI3 (:,:,1) = 0.0_RP + lcmesh%GI3 (:,:,2) = 0.0_RP + lcmesh%GsqrtH(:,:) = 1.0_RP + !$omp end workshare + + !$omp end parallel return end subroutine MeshBase3D_setGeometricInfo diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 29195399..63b8b235 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -310,7 +310,6 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & !-- lcmesh%Ne = NeX * NeY * NeZ - lcmesh%Ne2D = NeX * NeY lcmesh%Nv = (NeX + 1)*(NeY + 1)*(NeZ + 1) lcmesh%NeS = 1 lcmesh%NeE = lcmesh%Ne @@ -320,6 +319,9 @@ subroutine MeshCubeDom3D_setupLocalDom( lcmesh, & lcmesh%NeY = NeY lcmesh%NeZ = NeZ + lcmesh%Ne2D = NeX * NeY + lcmesh%Ne2DA = NeX * NeY + 2*(NeX + NeY) + !-- delx = (dom_xmax - dom_xmin)/dble(NprcX) dely = (dom_ymax - dom_ymin)/dble(NprcY) diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 index 1e73578a..edabf5f0 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 @@ -45,6 +45,7 @@ module scale_mesh_cubedspheredom2d end type MeshCubedSphereDom2D public :: MeshCubedSphereDom2D_check_division_params + public :: MeshCubedSphereDom2D_setupLocalDom !----------------------------------------------------------------------------- ! @@ -233,8 +234,6 @@ subroutine MeshCubedSphereDom2D_check_division_params( & return end subroutine MeshCubedSphereDom2D_check_division_params - !- private ------------------------------ - subroutine MeshCubedSphereDom2D_setupLocalDom( lcmesh, & tileID, panelID, & i, j, NprcX, NprcY, & @@ -343,6 +342,8 @@ subroutine MeshCubedSphereDom2D_setupLocalDom( lcmesh, & return end subroutine MeshCubedSphereDom2D_setupLocalDom + !- private ------------------------------ + subroutine MesshCubedSphereDom2D_assignDomID( this, & NprcX_lc, NprcY_lc, & tileID_table, panelID_table, & diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 index 8137acc6..0e960772 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 @@ -20,8 +20,8 @@ module scale_mesh_cubedspheredom3d use scale_mesh_base2d, only: & MeshBase2D, MeshBase2D_Init, MeshBase2D_Final, & MeshBase2D_setGeometricInfo - use scale_mesh_rectdom2d, only: & - MeshRectDom2D, MeshRectDom2D_setupLocalDom + use scale_mesh_cubedspheredom2d, only: & + MeshCubedSphereDom2D, MeshCubedSphereDom2D_setupLocalDom use scale_localmesh_2d, only: LocalMesh2D use scale_element_quadrilateral, only: QuadrilateralElement @@ -50,7 +50,7 @@ module scale_mesh_cubedspheredom3d real(RP) :: RPlanet - type(MeshRectDom2D) :: mesh2D + type(MeshCubedSphereDom2D) :: mesh2D type(QuadrilateralElement) :: refElem2D contains procedure :: Init => MeshCubedSphereDom3D_Init @@ -205,7 +205,6 @@ subroutine MeshCubedSphereDom3D_generate( this ) integer :: NprcX_lc, NprcY_lc, NprcZ_lc integer :: tileID - real(RP), allocatable :: Gsqrt_tmp(:,:) integer :: ke, ke2D !----------------------------------------------------------------------------- @@ -237,11 +236,11 @@ subroutine MeshCubedSphereDom3D_generate( this ) this%NeGX/NprcX_lc, this%NeGY/NprcY_lc, this%NeGZ/NprcZ_lc, & this%FZ(:) ) - call MeshRectDom2D_setupLocalDom( this%mesh2D%lcmesh_list(n), & - tileID, panelID_table(tileID), & - pi_table(tileID), pj_table(tileID), NprcX_lc, NprcY_lc, & - this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & - this%NeGX/NprcX_lc, this%NeGY/NprcY_lc ) + call MeshCubedSphereDom2D_setupLocalDom( this%mesh2D%lcmesh_list(n), & + tileID, panelID_table(tileID), & + pi_table(tileID), pj_table(tileID), NprcX_lc, NprcY_lc, & + this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & + this%RPlanet, this%NeGX/NprcX_lc, this%NeGY/NprcY_lc ) call mesh%SetLocalMesh2D( this%mesh2D%lcmesh_list(n) ) @@ -252,17 +251,15 @@ subroutine MeshCubedSphereDom3D_generate( this ) lcmesh2D%Ne * elem2D%Np, this%RPlanet, & mesh%lon2D(:,:), mesh%lat2D(:,:) ) - allocate( Gsqrt_tmp(lcmesh2D%refElem2D%Np,lcmesh2D%Ne) ) call CubedSphereCnv_GetMetric( & lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), elem2D%Np * lcmesh2D%Ne, this%RPlanet, & ! (in) - mesh%G_ij, mesh%GIJ, Gsqrt_tmp(:,:) ) ! (out) + mesh%G_ij, mesh%GIJ, mesh%GsqrtH ) ! (out) !$omp parallel do private(ke2D) do ke=mesh%NeS, mesh%NeE ke2D = mesh%EMap3Dto2D(ke) - mesh%Gsqrt(:,ke) = Gsqrt_tmp(elem3D%IndexH2Dto3D(:),ke2D) + mesh%Gsqrt(:,ke) = mesh%GsqrtH(elem3D%IndexH2Dto3D(:),ke2D) end do - deallocate( Gsqrt_tmp ) !--- ! write(*,*) "** my_rank=", mesh%PRC_myrank @@ -330,7 +327,6 @@ subroutine MeshCubedSphereDom3D_setupLocalDom( lcmesh, & !-- lcmesh%Ne = NeX * NeY * NeZ - lcmesh%Ne2D = NeX * NeY lcmesh%Nv = (NeX + 1)*(NeY + 1)*(NeZ + 1) lcmesh%NeS = 1 lcmesh%NeE = lcmesh%Ne @@ -340,6 +336,9 @@ subroutine MeshCubedSphereDom3D_setupLocalDom( lcmesh, & lcmesh%NeY = NeY lcmesh%NeZ = NeZ + lcmesh%Ne2D = NeX * NeY + lcmesh%Ne2DA = NeX * NeY + 2*(NeX + NeY) + !-- delx = ( dom_xmax - dom_xmin ) / dble(NprcX) dely = ( dom_ymax - dom_ymin ) / dble(NprcY) diff --git a/FElib/src/mesh/scale_mesh_topography.F90 b/FElib/src/mesh/scale_mesh_topography.F90 new file mode 100644 index 00000000..0420967a --- /dev/null +++ b/FElib/src/mesh/scale_mesh_topography.F90 @@ -0,0 +1,162 @@ +#include "scaleFElib.h" +module scale_mesh_topography + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + + use scale_localmesh_3d, only: LocalMesh3D + use scale_localmesh_2d, only: LocalMesh2D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_element_base, only: ElementBase3D + use scale_meshfield_base, only: & + MeshField2D, MeshField3D + use scale_meshfieldcomm_base, only: & + MeshFieldCommBase, MeshFieldContainer + + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public type & procedure + ! + type, abstract, public :: MeshTopography + type(MeshField2D) :: topo + contains + procedure :: Init => MeshTopography_Init + procedure :: Final => MeshTopography_Final + procedure :: SetVCoordinate => MeshTopography_set_vcoordinate + end type MeshTopography + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + subroutine MeshTopography_Init( this, mesh ) + implicit none + + class(MeshTopography), intent(inout) :: this + class(MeshBase2D), intent(in), target :: mesh + !----------------------------------------------------------------------------- + + call this%topo%Init( "TOPO", "m", mesh ) + + return + end subroutine MeshTopography_Init + + subroutine MeshTopography_Final( this ) + implicit none + + class(MeshTopography), intent(inout) :: this + !----------------------------------------------------------------------------- + + call this%topo%Final() + + return + end subroutine MeshTopography_Final + + subroutine MeshTopography_set_vcoordinate( this, mesh3D, & + vcoord_name, zTop, comm3D, comm2D ) + + use scale_sparsemat, only: SparseMat + use scale_meshutil_vcoord, only: MeshUtil_VCoord_GetMetric + implicit none + + class(MeshTopography), target, intent(in) :: this + class(MeshBase3D), intent(inout), target :: mesh3D + character(len=*), intent(in) :: vcoord_name + real(RP), intent(in) :: zTop + class(MeshFieldCommBase) :: comm3D + class(MeshFieldCommBase) :: comm2D + + type(SparseMat) :: Dx2D, Dy2D, Lift2D + class(LocalMesh3D), pointer :: lcmesh + class(LocalMesh2D), pointer :: lcmesh2D + + integer :: n + integer :: ke + + type(MeshFieldContainer) :: comm2d_varlist(1) + type(MeshFieldContainer) :: comm3d_varlist(3) + + type(MeshField3D), target :: Gsqrt, G13, G23 + !------------------------------------------------------------- + + lcmesh => mesh3D%lcmesh_list(1) + lcmesh2D => lcmesh%lcmesh2D + call Dx2D %Init( lcmesh2D%refElem2D%Dx1 ) + call Dy2D %Init( lcmesh2D%refElem2D%Dx2 ) + call Lift2D%Init( lcmesh2D%refElem2D%Lift ) + + !-- + call Gsqrt%Init( "Gsqrt", "", mesh3D ) + call G13%Init( "G13", "", mesh3D ) + call G23%Init( "G23", "", mesh3D ) + + do n=1, mesh3D%LOCAL_MESH_NUM + lcmesh => mesh3D%lcmesh_list(n) + lcmesh2D => lcmesh%lcmesh2D + + Gsqrt%local(n)%val(:,:) = lcmesh%Gsqrt(:,:) + call MeshUtil_VCoord_GetMetric( & + G13%local(n)%val, G23%local(n)%val, lcmesh%zlev(:,:), & ! (out) + Gsqrt%local(n)%val, & ! (inout) + this%topo%local(n)%val(:,:), zTop, vcoord_name, & ! (in) + lcmesh, lcmesh%refElem3D, lcmesh2D, lcmesh2D%refElem2D, & ! (in) + Dx2D, Dy2D, Lift2D ) ! (in) + end do + + !-- Communicate halo data + + ! 2D + + comm2d_varlist(1)%field2d => this%topo + call comm2D%Put(comm2d_varlist, 1) + call comm2D%Exchange() + call comm2D%Get(comm2d_varlist, 1) + + ! 3D + comm3d_varlist(1)%field3d => Gsqrt + comm3d_varlist(2)%field3d => G13 + comm3d_varlist(3)%field3d => G23 + + call comm3D%Put(comm3d_varlist, 1) + call comm3D%Exchange() + call comm3D%Get(comm3d_varlist, 1) + + do n=1, mesh3D%LOCAL_MESH_NUM + lcmesh => mesh3D%lcmesh_list(n) + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeA + lcmesh%Gsqrt(:,ke) = Gsqrt%local(n)%val(:,ke) + lcmesh%GI3(:,ke,1) = G13%local(n)%val(:,ke) + lcmesh%GI3(:,ke,2) = G23%local(n)%val(:,ke) + end do + end do + + !--- + call Dx2D%Final() + call Dy2D%Final() + call Lift2D%Final() + + return + end subroutine MeshTopography_set_vcoordinate + +end module scale_mesh_topography \ No newline at end of file diff --git a/FElib/src/mesh/scale_meshutil_vcoord.F90 b/FElib/src/mesh/scale_meshutil_vcoord.F90 new file mode 100644 index 00000000..4c76a758 --- /dev/null +++ b/FElib/src/mesh/scale_meshutil_vcoord.F90 @@ -0,0 +1,155 @@ +#include "scaleFElib.h" +module scale_meshutil_vcoord + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_const, only: & + PI => CONST_PI, & + EPS => CONST_EPS + use scale_precision + use scale_prc + use scale_io + use scale_prc + + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_sparsemat, only:& + SparseMat, sparsemat_matmul + !----------------------------------------------------------------------------- + implicit none + private + + !----------------------------------------------------------------------------- + ! + !++ Public type & procedure + ! + public :: MeshUtil_VCoord_GetMetric + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + character(*), public, parameter :: MESH_VCOORD_TERRAIN_FOLLOWING_NAME = "TERRAIN_FOLLOWING" + + !----------------------------------------------------------------------------- + ! + !++ Private type & procedure + ! + !----------------------------------------------------------------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + !----------------------------------------------------------------------------- + +contains + subroutine MeshUtil_VCoord_GetMetric( G13, G23, zlev, & + Gsqrt, & + topo, zTop, vcoord_type, lcmesh, elem, lcmesh2D, elem2D, & + Dx2D, Dy2D, Lift2D ) + implicit none + + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lcmesh2D + class(ElementBase2D), intent(in) :: elem2D + real(RP), intent(out) :: G13(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: G23(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: zlev(elem%Np,lcmesh%Ne) + real(RP), intent(inout) :: Gsqrt(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: topo(elem2D%Np,lcmesh2D%Ne) + character(len=*), intent(in) :: vcoord_type + real(RP), intent(in) :: zTop + type(SparseMat), intent(in) :: Dx2D + type(SparseMat), intent(in) :: Dy2D + type(SparseMat), intent(in) :: Lift2D + + integer :: ke, ke2D + real(RP) :: del_flux(elem2D%Np,lcmesh2D%Ne,2) + real(RP) :: Fx2D(elem2D%NP), Fy2D(elem2D%NP), LiftDelFlux2D(elem2D%NP) + real(RP) :: GsqrtV(elem%Np,lcmesh2D%Ne) + real(RP) :: GradZs(elem2D%Np,lcmesh2D%Ne,2) + real(RP) :: coef3D(elem%NP) + !------------------------------------------------ + + if ( vcoord_type == MESH_VCOORD_TERRAIN_FOLLOWING_NAME ) then + + ! * z = topo + (1 - topo / zTop ) * zeta + ! * zeta = zTop * (z - topo)/(zTop - topo) + ! * Gi3 = (dzeta(x1,x2,z)/dxi)_z = d (zeta,z) / d (xi,z) = - d(z,zeta)/ d(xi,zeta) * d(xi,zeta)/d(xi,z) + ! = - (dz/dxi)_zeta * dzeta/dz + ! = (GsqrtV)^-1 * [ - 1 + zeta / zTop ] * d topo /dxi (i=1, 2) + + !$omp parallel private(ke2D, ke, & + !$omp Fx2D, Fy2D, LiftDelFlux2D, coef3D ) + + !$omp do + do ke2D=1, lcmesh2D%Ne + GsqrtV(:,ke2D) = 1.0_RP - topo(:,ke2D) / zTop ! dz/dzeta + + call sparsemat_matmul( Dx2D, topo(:,ke2D), Fx2D ) + call sparsemat_matmul( Lift2D, lcmesh2D%Fscale(:,ke2D) * del_flux(:,ke2D,1), LiftDelFlux2D) + GradZs(:,ke2D,1) = lcmesh2D%Escale(:,ke2D,1,1) * Fx2D(:) + LiftDelFlux2D(:) + + call sparsemat_matmul( Dy2D, topo(:,ke2D), Fy2D ) + call sparsemat_matmul( Lift2D, lcmesh2D%Fscale(:,ke2D) * del_flux(:,ke2D,2), LiftDelFlux2D) + GradZs(:,ke2D,2) = lcmesh2D%Escale(:,ke2D,2,2) * Fy2D(:) + LiftDelFlux2D(:) + end do + + !$omp end do + !$omp do + do ke=1, lcmesh%Ne + ke2D = lcmesh%EMap3Dto2D(ke) + coef3D(:) = 1.0_RP - lcmesh%pos_en(:,ke,3) / zTop + zlev(:,ke) = lcmesh%pos_en(:,ke,3) & + + coef3D(:) * topo(elem%IndexH2Dto3D,ke2D) + + coef3D(:) = - coef3D(:) / GsqrtV(elem%IndexH2Dto3D,ke2D) + G13(:,ke) = coef3D(:) * GradZs(elem%IndexH2Dto3D,ke2D,1) + G23(:,ke) = coef3D(:) * GradZs(elem%IndexH2Dto3D,ke2D,2) + + Gsqrt(:,ke) = Gsqrt(:,ke) * GsqrtV(elem%IndexH2Dto3D,ke2D) + end do + !$omp end do + !$omp end parallel + else + LOG_ERROR("Mesh_VCoord_GetMetric",*) "vcoord_type is inappropriate. Check!", vcoord_type + call PRC_abort + end if + + return + end subroutine MeshUtil_VCoord_GetMetric + + subroutine cal_del_flux( del_flux, & + topo, nx, ny, vmapM, vmapP,lmesh, elem ) + implicit none + type(LocalMesh2D), intent(in) :: lmesh + type(ElementBase2D), intent(in) :: elem + real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%Ne,2) + real(RP), intent(in) :: topo(elem%Np*lmesh%NeA) + real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) + + integer :: i + integer :: iP, iM + real(RP) :: dtopo + !------------------------------------- + + !$omp parallel do private( i, iM, iP, dtopo ) + do i=1, elem%NfpTot * lmesh%Ne + iM = vmapM(i); iP = vmapP(i) + + dtopo = 0.5_RP * ( topo(iP) - topo(iM) ) + del_flux(i,1) = dtopo * nx(i) + del_flux(i,2) = dtopo * ny(i) + end do + + return + end subroutine cal_del_flux +end module scale_meshutil_vcoord \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 index f149304d..9c250072 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 @@ -10,11 +10,15 @@ module mod_atmos_mesh use scale_prc use scale_meshfield_base, only: MeshField3D + use scale_mesh_base2d, only: MeshBase2D use scale_mesh_base3d, only: MeshBase3D use scale_element_base, only: ElementBase3D use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D use scale_localmesh_3d, only: LocalMesh3D use scale_sparsemat, only: sparsemat + use scale_meshfield_base, only: MeshField2D + use scale_mesh_topography, only: MeshTopography use scale_file_restart_meshfield, only: FILE_restart_meshfield_component use scale_model_var_manager, only: ModelVarManager @@ -29,7 +33,7 @@ module mod_atmos_mesh ! type, abstract, extends(ModelMesh3D), public :: AtmosMesh type(HexahedralElement) :: element - + type(MeshTopography) :: topography contains procedure :: AtmosMesh_Init procedure :: AtmosMesh_Final @@ -40,6 +44,7 @@ module mod_atmos_mesh generic :: Setup_restartfile => Setup_restartfile1, Setup_restartfile2 procedure :: Construct_ModalFilter3D => AtmosMesh_construct_ModalFilter3D procedure :: Construct_ModalFilterHV => AtmosMesh_construct_ModalFilterHV + procedure :: Setup_vcoordinate => AtmosMesh_setup_vcoordinate end type AtmosMesh interface subroutine AtmosMesh_create_communicator( this, sfield_num, hvfield_num, var_manager, field_list, commid ) @@ -125,6 +130,7 @@ subroutine AtmosMesh_Init( this, mesh ) class(MeshBase3D), intent(in) :: mesh character(len=H_SHORT) :: SpMV_storage_format = 'ELL' ! CSR or ELL + class(MeshBase2D), pointer :: mesh2D !------------------------------------------- call this%ModelMesh3D_Init( mesh ) @@ -141,6 +147,10 @@ subroutine AtmosMesh_Init( this, mesh ) !- call FILE_monitor_meshfield_set_dim( mesh, 'ATM3D' ) + + !- + call mesh%GetMesh2D( mesh2D ) + call this%topography%Init( mesh2D ) return end subroutine AtmosMesh_Init @@ -151,11 +161,43 @@ subroutine AtmosMesh_Final(this) class(AtmosMesh), intent(inout) :: this !------------------------------------------- + call this%topography%Final() call this%ModelMesh3D_Final() return end subroutine AtmosMesh_Final + subroutine AtmosMesh_setup_vcoordinate( this, & + vcoord_name, zTop, & + file_topo, in_basename, in_varname, & + comm3D, comm2D ) + + use scale_file_base_meshfield, only: FILE_base_meshfield + use scale_mesh_base2d, only: & + MFTYPE2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_meshfieldcomm_base, only: MeshFieldCommBase + implicit none + + class(AtmosMesh), intent(inout), target :: this + character(len=*), intent(in) :: vcoord_name + real(RP), intent(in) :: zTop + type(FILE_base_meshfield), intent(inout) :: file_topo + character(len=*), intent(in) :: in_basename + character(len=*), intent(in) :: in_varname + class(MeshFieldCommBase) :: comm3D + class(MeshFieldCommBase) :: comm2D + !------------------------------------------- + + call file_topo%Open( in_basename ) + call file_topo%Read_Var( MFTYPE2D_XY, in_varname, this%topo ) + call file_topo%Close() + + call this%topography%SetVCoordinate( this%ptr_mesh, & + vcoord_name, zTop, comm3D, comm2D ) + + return + end subroutine AtmosMesh_setup_vcoordinate + subroutine AtmosMesh_construct_ModalFilter3D( this, & filter, & etac_h, alpha_h, ord_h, & diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 index 14abe3dc..65baa40f 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 @@ -66,6 +66,8 @@ module mod_atmos_mesh_gm subroutine AtmosMeshGM_Init( this ) use scale_const, only: & RPlanet => CONST_RADIUS + use scale_file_base_meshfield, only: FILE_base_meshfield + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D implicit none class(AtmosMeshGM), target, intent(inout) :: this @@ -86,17 +88,26 @@ subroutine AtmosMeshGM_Init( this ) integer :: PolyOrder_h = 2 integer :: PolyOrder_v = 2 logical :: LumpedMassMatFlag = .false. + character(len=H_LONG) :: TOPO_IN_BASENAME = '' !< basename of the input file + character(len=H_MID) :: TOPO_IN_VARNAME = 'topo' !< variable name of topo in the input file + character(len=H_MID) :: VERTICAL_COORD_NAME = "TERRAIN_FOLLOWING" namelist / PARAM_ATMOS_MESH / & dom_zmin, dom_zmax, & FZ, isPeriodicZ, & NeGX, NeGY, NeZ, NLocalMeshPerPrc, Nprc, & - PolyOrder_h, PolyOrder_v, LumpedMassMatFlag + PolyOrder_h, PolyOrder_v, LumpedMassMatFlag, & + TOPO_IN_BASENAME, TOPO_IN_VARNAME, & + VERTICAL_COORD_NAME integer :: k logical :: is_spec_FZ integer :: ierr + + type(FILE_base_meshfield) :: file_topo + type(MeshFieldCommCubedSphereDom3D) :: comm3D + type(MeshFieldCommCubedSphereDom2D) :: comm2D !------------------------------------------- LOG_NEWLINE @@ -144,6 +155,23 @@ subroutine AtmosMeshGM_Init( this ) !- call this%AtmosMesh_Init( this%mesh ) + !- Set topography & vertical coordinate + + if ( TOPO_IN_VARNAME /= '' ) then + call file_topo%Init(1, meshcubedsphere2D=this%mesh%mesh2D ) + call comm2D%Init( 1, 0, this%mesh%mesh2D ) + call comm3D%Init( 1, 1, this%mesh ) + + call this%Setup_vcoordinate( & + VERTICAL_COORD_NAME, dom_zmax, & + file_topo, TOPO_IN_BASENAME, TOPO_IN_VARNAME, & + comm3D, comm2D ) + + call comm2D%Final() + call comm3D%Final() + call file_topo%Final() + end if + return end subroutine AtmosMeshGM_Init diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 index 837ba2f1..cbb09e36 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 @@ -64,7 +64,9 @@ module mod_atmos_mesh_rm !- AtmosMesh RM ----------------------------------------- - subroutine AtmosMeshRM_Init( this ) + subroutine AtmosMeshRM_Init( this ) + use scale_file_base_meshfield, only: FILE_base_meshfield + use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D implicit none class(AtmosMeshRM), target, intent(inout) :: this @@ -86,6 +88,9 @@ subroutine AtmosMeshRM_Init( this ) integer :: PolyOrder_h = 2 integer :: PolyOrder_v = 2 logical :: LumpedMassMatFlag = .false. + character(len=H_LONG) :: TOPO_IN_BASENAME = '' !< basename of the input file + character(len=H_MID) :: TOPO_IN_VARNAME = 'topo' !< variable name of topo in the input file + character(len=H_MID) :: VERTICAL_COORD_NAME = "TERRAIN_FOLLOWING" integer, parameter :: ATMOS_MESH_NLocalMeshPerPrc = 1 @@ -100,12 +105,18 @@ subroutine AtmosMeshRM_Init( this ) isPeriodicX, isPeriodicY, isPeriodicZ, & NeX, NeY, NeZ, & PolyOrder_h, PolyOrder_v, LumpedMassMatFlag, & - NprcX, NprcY + NprcX, NprcY, & + TOPO_IN_BASENAME, TOPO_IN_VARNAME, & + VERTICAL_COORD_NAME integer :: k logical :: is_spec_FZ integer :: ierr + + type(FILE_base_meshfield) :: file_topo + type(MeshFieldCommRectDom2D) :: comm2D + type(MeshFieldCommCubeDom3D) :: comm3D !------------------------------------------- LOG_NEWLINE @@ -157,6 +168,23 @@ subroutine AtmosMeshRM_Init( this ) !- call this%AtmosMesh_Init( this%mesh ) + !- Set topography & vertical coordinate + + if ( TOPO_IN_VARNAME /= '' ) then + call file_topo%Init(1, mesh2D=this%mesh%mesh2D ) + call comm2D%Init( 1, 0, this%mesh%mesh2D ) + call comm3D%Init( 1, 1, this%mesh%mesh3D ) + + call this%Setup_vcoordinate( & + VERTICAL_COORD_NAME, dom_zmax, & + file_topo, TOPO_IN_BASENAME, TOPO_IN_VARNAME, & + comm3D, comm2D ) + + call comm2D%Final() + call comm3D%Final() + call file_topo%Final() + end if + return end subroutine AtmosMeshRM_Init From a9c1d96d496864b75b0bd7d083a9785b92ce9485 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 19 Jun 2021 22:13:10 +0900 Subject: [PATCH 60/98] Add a dry test case of Held Suarez. --- .../test/case/Held_Suarez/Makefile | 28 ++ .../test/case/Held_Suarez/init.conf | 41 +++ .../test/case/Held_Suarez/mod_user.F90 | 300 ++++++++++++++++++ .../test/case/Held_Suarez/run.conf | 105 ++++++ 4 files changed, 474 insertions(+) create mode 100644 model/atm_nonhydro3d/test/case/Held_Suarez/Makefile create mode 100644 model/atm_nonhydro3d/test/case/Held_Suarez/init.conf create mode 100644 model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/Held_Suarez/run.conf diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/Makefile b/model/atm_nonhydro3d/test/case/Held_Suarez/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/init.conf b/model/atm_nonhydro3d/test/case/Held_Suarez/init.conf new file mode 100644 index 00000000..7f481bf2 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/init.conf @@ -0,0 +1,41 @@ +#--- Configuration file for a test case of Held-Suarez (1994) ------- +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'Held-Suarez_1994', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_EXP +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 24, + NeGX = 6, + NeGY = 6, + NeZ = 4, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, + LumpedMassMatFlag = .true., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 new file mode 100644 index 00000000..de629c0b --- /dev/null +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 @@ -0,0 +1,300 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module for a test case of Held-Suarez (1994) +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_mesh_base3d, only: MeshBase3D + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfield_base, only: MeshField3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_Held_Suarez + contains + procedure :: setInitCond_lc => exp_SetInitCond_Held_Suarez + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_Held_Suarez), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + call exp_manager%Init('Held_Suarez_global') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + + return + end subroutine USER_setup + + subroutine USER_calc_tendency( atm ) + use scale_const, only: & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + PRES00 => CONST_PRE00 + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + use mod_atmos_vars, only: & + AtmosVars_GetLocalMeshPrgVars, & + AtmosVars_GetLocalMeshPhyAuxVars, & + MOMX_p => ATMOS_PHYTEND_MOMX_ID, & + MOMY_p => ATMOS_PHYTEND_MOMY_ID, & + MOMZ_p => ATMOS_PHYTEND_MOMZ_ID, & + RHOH_p => ATMOS_PHYTEND_RHOH_ID + use scale_localmeshfield_base, only: LocalMeshFieldBase + + implicit none + + class(AtmosComponent), intent(inout) :: atm + + class(LocalMesh3D), pointer :: lcmesh + class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT + class(LocalMeshFieldBase), pointer :: DENS_hyd, PRES_hyd + class(LocalMeshFieldBase), pointer :: PRES, PT + type(ElementBase3D), pointer :: elem3D + + integer :: n + integer :: ke, ke2D + + real(RP), allocatable :: DENS(:), Teq(:), sig(:), PRES_sfc(:) + real(RP), allocatable :: rtauT(:), rtauV(:) + real(RP), allocatable :: lat(:) + real(RP), parameter :: kf = 1.0_RP / ( 86400.0_RP * 1.0_RP ) + real(RP), parameter :: ka = 1.0_RP / ( 86400.0_RP * 40.0_RP ) + real(RP), parameter :: ks = 1.0_RP / ( 86400.0_RP * 4.0_RP ) + real(RP), parameter :: DelT_y = 60.0_RP + real(RP), parameter :: DelPT_z = 10.0_RP + real(RP), parameter :: sigb = 0.7_RP + + real(RP) :: dt + !------------------------------------------ + + do n=1, atm%mesh%ptr_mesh%LOCAL_MESH_NUM + call AtmosVars_GetLocalMeshPrgVars( n, atm%mesh%ptr_mesh, & + atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager, & + DDENS, MOMX, MOMY, MOMZ, DRHOT, & + DENS_hyd, PRES_hyd, lcmesh ) + + call AtmosVars_GetLocalMeshPhyAuxVars( n, atm%mesh%ptr_mesh, & + atm%vars%AUXVARS_manager, PRES, PT ) + + elem3D => lcmesh%refElem3D + + allocate( DENS(elem3D%Np), Teq(elem3D%Np), sig(elem3D%Np) ) + allocate( PRES_sfc(elem3D%Nnode_h1D**2) ) + allocate( rtauT(elem3D%Np), rtauV(elem3D%Np) ) + allocate( lat(elem3D%Np) ) + + !$omp parallel do private(DENS, Teq, PRES_sfc, sig, lat, rtauT, rtauV, ke2D) + do ke=lcmesh%NeS, lcmesh%NeE + ke2D = lcmesh%EMap3Dto2D(ke) + + PRES_sfc(:) = PRES%val(elem3D%Hslice(:,1),ke2D) + sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) + lat(:) = lcmesh%lat2D(elem3D%IndexH2Dto3D,ke2D) + + rtauT(:) = ka + (ks - ka) * max( 0.0_RP, (sig(:) - sigb)/(1.0_RP - sigb) ) * cos(lat(:))**4 + rtauV(:) = kf * max( 0.0_RP, (sig(:) - sigb)/(1.0_RP - sigb) ) + + Teq(:) = max(200.0_RP, & + ( 315.0_RP - DelT_y * sin(lat(:))**2 - DelPT_z * log(PRES%val(:,ke)/PRES00) * cos(lat(:))**2 ) & + * (PRES%val(:,ke)/PRES00)**(Rdry/CPDry) ) + DENS(:) = DENS_hyd%val(:,ke) + DDENS%val(:,ke) + + atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) & + - rtauV(:) * MOMX%val(:,ke) + atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) & + - rtauV(:) * MOMY%val(:,ke) + + atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) & + - DENS(:) * CpDry * rtauT(:) * ( PRES%val(:,ke) / (Rdry * DENS(:)) - Teq(:) ) + end do + + deallocate( DENS, Teq, sig, PRES_sfc ) + deallocate( rtauT, rtauV ) + deallocate( lat ) + end do + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_Held_Suarez( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS + + use scale_atm_dyn_dgm_hydrostatic, only: & + hydrostatic_calc_basicstate_constT + + implicit none + + class(Exp_Held_Suarez), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + real(RP) :: TEMP0 = 280.0_RP + namelist /PARAM_EXP/ & + TEMP0 + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 + + integer :: ke + integer :: ierr + !----------------------------------------------------------------------------- + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("Held_Suarez_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("Held_Suarez_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + + !--- + call hydrostatic_calc_basicstate_constT( DENS_hyd, PRES_hyd, & ! (out) + TEMP0, PRES00, & ! (in) + x, y, z, lcmesh, elem ) ! (in) + + return + end subroutine exp_SetInitCond_Held_Suarez + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_Held_Suarez), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + !--------------------------------------------------- + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf b/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf new file mode 100644 index 00000000..6c48542a --- /dev/null +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf @@ -0,0 +1,105 @@ +#--- Configuration file for a test case of Held-Suarez (1994) ------- +# +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 300.0D0, + TIME_DURATION_UNIT = 'DAY', + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_USER + USER_do = .true., +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 600.0D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 24, + NeGX = 6, + NeGY = 6, + NeZ = 4, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, + LumpedMassMatFlag = .true., +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVI", + !- + TINTEG_TYPE = 'IMEX_ARK324', ! [IMEX_ARK_232, IMEX_ARK324, RK_TVD_3] + TIME_DT = 60.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., + SPONGELAYER_FLAG = .true., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 5.0D0, + MF_ORDER_h = 16, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 5.0D0, + MF_ORDER_v = 16, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ +&PARAM_ATMOS_DYN_SPONGELAYER + SL_WDAMP_TAU = 43200.0D0, + SL_WDAMP_HEIGHT = 12.0D3, + SL_HORIVELDAMP_FLAG = .true. +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 5.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "DAY", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='Umet' / +&HISTORY_ITEM name='Vmet' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='T' / +!&HISTORY_ITEM name='DENS_hyd' / +!&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + From 7c305133a6d05b29d043d7065e56536995ec6169 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 23 Jun 2021 22:28:41 +0900 Subject: [PATCH 61/98] Refactor source codes of dynamical core and treat topography in a limited area model. --- FElib/src/Makefile | 28 +- .../data/scale_meshfieldcomm_cubedom3d.F90 | 2 +- FElib/src/depend | 22 +- ...cale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 267 +----- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 838 +----------------- .../scale_atm_dyn_dgm_nonhydro3d_common.F90 | 137 +++ .../scale_atm_dyn_dgm_nonhydro3d_heve.F90 | 309 +++---- ...le_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 | 421 +++++++++ .../scale_atm_dyn_dgm_nonhydro3d_hevi.F90 | 830 ++++------------- ...ale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 | 597 +++++++++++++ ...le_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 | 417 +++++++++ ..._atm_dyn_dgm_nonhydro3d_splitform_heve.F90 | 289 +++--- ..._atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 | 824 ++++------------- FElib/src/mesh/scale_localmesh_3d.F90 | 3 +- FElib/src/mesh/scale_localmesh_base.F90 | 3 +- FElib/src/mesh/scale_mesh_base3d.F90 | 31 - FElib/src/mesh/scale_mesh_cubedom3d.F90 | 15 +- .../src/mesh/scale_mesh_cubedspheredom2d.F90 | 6 +- .../src/mesh/scale_mesh_cubedspheredom3d.F90 | 110 ++- FElib/src/mesh/scale_mesh_rectdom2d.F90 | 32 +- FElib/src/mesh/scale_mesh_topography.F90 | 51 +- FElib/src/mesh/scale_meshutil_2d.F90 | 32 +- FElib/src/mesh/scale_meshutil_vcoord.F90 | 55 +- .../{scale-dg_init.F90 => scale-dg_pp.F90} | 0 24 files changed, 2384 insertions(+), 2935 deletions(-) create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 create mode 100644 FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 rename model/atm_nonhydro3d/src/{scale-dg_init.F90 => scale-dg_pp.F90} (100%) diff --git a/FElib/src/Makefile b/FElib/src/Makefile index d4804a64..68f31564 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -91,18 +91,22 @@ OBJS_NAME_FILE = \ scale_file_monitor_meshfield.o OBJS_NAME_FLUID_DYN_SOLVER = \ - scale_atm_dyn_dgm_modalfilter.o \ - scale_atm_dyn_dgm_spongelayer.o \ - scale_atm_dyn_dgm_hydrostatic.o \ - scale_atm_dyn_dgm_nonhydro3d_numdiff.o \ - scale_atm_dyn_dgm_nonhydro2d.o \ - scale_atm_dyn_dgm_globalnonhydro3d_heve.o \ - scale_atm_dyn_dgm_globalnonhydro3d_hevi.o \ - scale_atm_dyn_dgm_nonhydro3d_heve.o \ - scale_atm_dyn_dgm_nonhydro3d_hevi.o \ - scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o \ - scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.o \ - scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.o \ + scale_atm_dyn_dgm_modalfilter.o \ + scale_atm_dyn_dgm_spongelayer.o \ + scale_atm_dyn_dgm_hydrostatic.o \ + scale_atm_dyn_dgm_nonhydro3d_numdiff.o \ + scale_atm_dyn_dgm_nonhydro2d.o \ + scale_atm_dyn_dgm_nonhydro3d_common.o \ + scale_atm_dyn_dgm_nonhydro3d_heve_numflux.o \ + scale_atm_dyn_dgm_nonhydro3d_heve.o \ + scale_atm_dyn_dgm_nonhydro3d_hevi_common.o \ + scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.o \ + scale_atm_dyn_dgm_nonhydro3d_hevi.o \ + scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o \ + scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.o \ + scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.o \ + scale_atm_dyn_dgm_globalnonhydro3d_heve.o \ + scale_atm_dyn_dgm_globalnonhydro3d_hevi.o \ scale_atm_dyn_dgm_globalsw.o OBJS_NAME_TURBULENCE = \ diff --git a/FElib/src/data/scale_meshfieldcomm_cubedom3d.F90 b/FElib/src/data/scale_meshfieldcomm_cubedom3d.F90 index 7d25db6f..4e940380 100644 --- a/FElib/src/data/scale_meshfieldcomm_cubedom3d.F90 +++ b/FElib/src/data/scale_meshfieldcomm_cubedom3d.F90 @@ -76,7 +76,7 @@ subroutine MeshFieldCommCubeDom3D_Init( this, & bufsize_per_field = 2*(lcmesh%NeX + lcmesh%NeY)*lcmesh%NeZ*elem%Nfp_h & + 2*lcmesh%NeX*lcmesh%NeY*elem%Nfp_v - call MeshFieldCommBase_Init( this, sfield_num, hvfield_num, bufsize_per_field, 6, mesh3d) + call MeshFieldCommBase_Init( this, sfield_num, hvfield_num, bufsize_per_field, 6, mesh3d ) return end subroutine MeshFieldCommCubeDom3D_Init diff --git a/FElib/src/depend b/FElib/src/depend index 84f0bf4b..e9ea08f5 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -1,15 +1,19 @@ -$(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o -$(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_globalnonhydro3d_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_globalsw.o: fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.o: fluid_dyn_solver/scale_atm_dyn_dgm_hydrostatic.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_gmres.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.o: fluid_dyn_solver/scale_atm_dyn_dgm_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro2d.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o -$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o -$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_common.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_gmres.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_numdiff.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_numdiff.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o -$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o -$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.o: fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_common.o $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_modalfilter.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_atm_dyn_dgm_spongelayer.o: fluid_dyn_solver/scale_atm_dyn_dgm_spongelayer.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_atm_phy_tb_dgm_smg.o: turbulence/scale_atm_phy_tb_dgm_smg.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmeshfield_base.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_coriolis_param.o: common/scale_coriolis_param.F90 $(DEPENDLIB) @@ -35,7 +39,7 @@ $(OBJ_DIR)/scale_localmeshfield_base.o: data/scale_localmeshfield_base.F90 $(DEP $(OBJ_DIR)/scale_mesh_base.o: mesh/scale_mesh_base.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o: mesh/scale_mesh_base1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_localmesh_1d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_meshutil_1d.o $(OBJ_DIR)/scale_mesh_base2d.o: mesh/scale_mesh_base2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o -$(OBJ_DIR)/scale_mesh_base3d.o: mesh/scale_mesh_base3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_vcoord.o $(OBJ_DIR)/scale_sparsemat.o +$(OBJ_DIR)/scale_mesh_base3d.o: mesh/scale_mesh_base3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_bndinfo.o: mesh/scale_mesh_bndinfo.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_mesh_cubedom3d.o: mesh/scale_mesh_cubedom3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_mesh_rectdom2d.o $(OBJ_DIR)/scale_meshutil_3d.o $(OBJ_DIR)/scale_mesh_cubedspheredom2d.o: mesh/scale_mesh_cubedspheredom2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_base.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o @@ -76,9 +80,13 @@ MODS = \ $(OBJ_DIR)/scale_atm_dyn_dgm_hydrostatic.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_modalfilter.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro2d.mod \ + $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_common.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve.mod \ + $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi.mod \ + $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_common.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_gmres.mod \ + $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_numdiff.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.mod \ $(OBJ_DIR)/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.mod \ diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index 5c9e4f74..c55e6976 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -35,7 +35,13 @@ module scale_atm_dyn_dgm_globalnonhydro3d_heve use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D - + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + atm_dyn_dgm_nonhydro3d_common_Init, & + atm_dyn_dgm_nonhydro3d_common_Final, & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM, & + IntrpMat_VPOrdM1, iM2Dto3D + !----------------------------------------------------------------------------- implicit none private @@ -58,72 +64,14 @@ module scale_atm_dyn_dgm_globalnonhydro3d_heve ! !------------------- - integer, private, parameter :: VARS_DDENS_ID = 1 - integer, private, parameter :: VARS_MOMX_ID = 2 - integer, private, parameter :: VARS_MOMY_ID = 3 - integer, private, parameter :: VARS_MOMZ_ID = 4 - integer, private, parameter :: VARS_DRHOT_ID = 5 - integer, private, parameter :: PROG_VARS_NUM = 5 - - real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) - integer, private, allocatable :: iM2Dto3D(:) - - - private :: cal_del_flux_dyn - contains subroutine atm_dyn_dgm_globalnonhydro3d_heve_Init( mesh ) implicit none class(MeshBase3D), intent(in) :: mesh - - integer :: p1, p2, p_ - type(ElementBase3D), pointer :: elem - real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) - - integer :: f_h, f_v - integer :: fp, fp_h1, fp_h2, fp_v - type(ElementBase2D), pointer :: elem2D - class(MeshBase2D), pointer :: mesh2D !-------------------------------------------- - elem => mesh%refElem3D - allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) - - InvV_VPOrdM1(:,:) = elem%invV - do p2=1, elem%Nnode_h1D - do p1=1, elem%Nnode_h1D - p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 - InvV_VPOrdM1(p_,:) = 0.0_RP - end do - end do - IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) - - !-- - - allocate( iM2Dto3D(elem%NfpTot) ) - call mesh%GetMesh2D( mesh2D ) - elem2D => mesh2D%refElem2D - - do f_h=1, 4 - do fp_v=1, elem%Nnode_v - do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h - iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) - end do - end do - end do - do f_v=1, 2 - do fp_h2=1, elem%Nnode_h1D - do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & - + (f_v-1) * elem%Nfp_v & - + 4 * elem%Nnode_h1D * elem%Nnode_v - iM2Dto3D(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D - end do - end do - end do - + call atm_dyn_dgm_nonhydro3d_common_Init( mesh ) return end subroutine atm_dyn_dgm_globalnonhydro3d_heve_Init @@ -132,8 +80,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_Final() implicit none !-------------------------------------------- - deallocate( IntrpMat_VPOrdM1 ) - + call atm_dyn_dgm_nonhydro3d_common_Final() return end subroutine atm_dyn_dgm_globalnonhydro3d_heve_Final @@ -146,6 +93,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + use scale_atm_dyn_dgm_nonhydro3d_heve_numflux, only: & + atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc use scale_atm_dyn_dgm_spongelayer, only: & atm_dyn_dgm_spongelayer_add_tend use scale_const, only: & @@ -200,12 +149,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !------------------------------------------------------------------------ call PROF_rapstart('cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, del_flux_hyd, & ! (out) + call atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc( & + del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) lmesh%GsqrtH, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) - lmesh%vmapM, lmesh%vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) + lmesh%vmapM, lmesh%vmapP, iM2Dto3D, lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) !----- @@ -293,7 +243,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) * wt_(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DDENS_ID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx(:) & @@ -306,7 +256,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMX_(:,ke) + G12(:) * DPRES_(:) ), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMX_ID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) MOMX_dt(:,ke) = & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & @@ -323,7 +273,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMY_(:,ke) + G22(:) * DPRES_(:) ), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMY_ID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) MOMY_dt(:,ke) = & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & @@ -339,7 +289,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * MOMZ_(:,ke), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * MOMZ_(:,ke), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMZ_(:,ke) + RGsqrtV(:) * DPRES_(:) ), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMZ_ID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) MOMZ_dt(:,ke) = & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & @@ -352,7 +302,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * RHOT_(:), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * RHOT_(:), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * wt_(:) * RHOT_(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DRHOT_ID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,RHOT_VID), LiftDelFlx) RHOT_dt(:,ke) = & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & @@ -378,183 +328,4 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & return end subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend - !------ - -!OCL SERIAL - subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - Gsqrt, G11, G12, G22, GsqrtH, G13, G23, nx, ny, nz, & - vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - class(LocalMesh2D), intent(in) :: lmesh2D - class(elementbase2D), intent(in) :: elem2D - real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) - real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) - real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) - real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) - real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) - - integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) - integer :: ke2D - real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) - real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) - real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) - real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) - real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) - real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) - real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) - real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) - real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) - real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) - real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) - real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) - real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) - real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) - real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) - real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) - real(RP) :: Gxz_M(elem%NfpTot), Gxz_P(elem%NfpTot) - real(RP) :: Gyz_M(elem%NfpTot), Gyz_P(elem%NfpTot) - - real(RP) :: gamm, rgamm - real(RP) :: rP0 - real(RP) :: RovP0, P0ovR - !------------------------------------------------------------------------ - - gamm = CPDry / CvDry - rgamm = CvDry / CpDry - rP0 = 1.0_RP / PRES00 - RovP0 = Rdry * rP0 - P0ovR = PRES00 / Rdry - - !$omp parallel do private( & - !$omp ke, iM, iP, ke2d, & - !$omp alpha, VelM, VelP, & - !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & - !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & - !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & - !$omp Phyd_M, Phyd_P, & - !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & - !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M ) - do ke=lmesh%NeS, lmesh%NeE - iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) - ke2D = lmesh%EMap3Dto2D(ke) - - Gsqrt_M(:) = Gsqrt(iM) - Gsqrt_P(:) = Gsqrt(iP) - GsqrtV_M(:) = Gsqrt_M(:) / GsqrtH(iM2Dto3D(:),ke2D) - GsqrtV_P(:) = Gsqrt_P(:) / GsqrtH(iM2Dto3D(:),ke2D) - - G13_M(:) = G13(iM) - G13_P(:) = G13(iP) - G23_M(:) = G23(iM) - G23_P(:) = G23(iP) - - GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) - GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) - GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) - GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) - GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) - GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) - GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) - GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) - GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) - GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) - Phyd_M(:) = PRES_hyd(iM) - Phyd_P(:) = PRES_hyd(iP) - - Gxz_M(:) = G11(iM2Dto3D(:),ke2D) * G13_M(:) + G12(iM2Dto3D(:),ke2D) * G23_M(:) - Gxz_P(:) = G11(iM2Dto3D(:),ke2D) * G13_P(:) + G12(iM2Dto3D(:),ke2D) * G23_P(:) - - Gyz_M(:) = G12(iM2Dto3D(:),ke2D) * G13_M(:) + G22(iM2Dto3D(:),ke2D) * G23_M(:) - Gyz_P(:) = G12(iM2Dto3D(:),ke2D) * G13_P(:) + G22(iM2Dto3D(:),ke2D) * G23_P(:) - - G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) - G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) - - Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & - + ( 1.0_RP / GsqrtV_M(:) + G13_M(:) * Gxz_M(:) + G23_M(:) * Gyz_M(:) ) * abs( nz(:,ke) ) - Gnn_P(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & - + ( 1.0_RP / GsqrtV_P(:) + G13_P(:) * Gxz_P(:) + G23_P(:) * Gyz_P(:) ) * abs( nz(:,ke) ) - - GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) - GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) - - GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) - GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) - - VelM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & - + ( ( GsqrtMOMZ_M(:) / GsqrtV_M(:) & - + G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) ) & - ) / GsqrtDensM(:) - VelP(:) = ( GsqrtMOMX_P(:) * nx(:,ke) + GsqrtMOMY_P(:) * ny(:,ke) & - + ( ( GsqrtMOMZ_P(:) / GsqrtV_P(:) & - + G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & - ) / GsqrtDensP(:) - - dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & - - Phyd_M(:) - dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & - - Phyd_P(:) - - alpha(:) = max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & - sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) - - del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & - ( GsqrtDensP(:) * VelP(:) - GsqrtDensM(:) * VelM(:) ) & - - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) - - del_flux(:,ke,VARS_MOMX_ID ) = 0.5_RP * ( & - ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & - + ( ( G1n_M(:) + Gxz_P(:) * nz(:,ke)) * dpresP(:) & - - ( G1n_M(:) + Gxz_M(:) * nz(:,ke)) * dpresM(:) ) & - - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) - - del_flux(:,ke,VARS_MOMY_ID ) = 0.5_RP * ( & - ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & - + ( ( G2n_M(:) + Gyz_P(:) * nz(:,ke) ) * dpresP(:) & - - ( G2n_M(:) + Gyz_M(:) * nz(:,ke) ) * dpresM(:) ) & - - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) - - del_flux(:,ke,VARS_MOMZ_ID ) = 0.5_RP * ( & - ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & - + ( dpresP(:) / GsqrtV_P(:) & - - dpresM(:) / GsqrtV_M(:) ) * nz(:,ke) & - - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) - - del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & - ( GsqrtRhotP(:) * VelP(:) - GsqrtRhotM(:) * VelM(:) ) & - - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) - - del_flux_hyd(:,ke,1) = 0.5_RP * ( & - GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & - - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) - - del_flux_hyd(:,ke,2) = 0.5_RP * ( & - GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & - - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) - end do - - return - end subroutine cal_del_flux_dyn - end module scale_atm_dyn_dgm_globalnonhydro3d_heve diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index efd4ef1e..ee2a249d 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -36,7 +36,13 @@ module scale_atm_dyn_dgm_globalnonhydro3d_hevi use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D - use, intrinsic :: ieee_arithmetic + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + atm_dyn_dgm_nonhydro3d_common_Init, & + atm_dyn_dgm_nonhydro3d_common_Final, & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM, & + IntrpMat_VPOrdM1, iM2Dto3D + !----------------------------------------------------------------------------- implicit none private @@ -60,72 +66,13 @@ module scale_atm_dyn_dgm_globalnonhydro3d_hevi ! !------------------- - integer, private, parameter :: DDENS_VID = 1 - integer, private, parameter :: MOMX_VID = 2 - integer, private, parameter :: MOMY_VID = 3 - integer, private, parameter :: MOMZ_VID = 4 - integer, private, parameter :: DRHOT_VID = 5 - integer, private, parameter :: PROG_VARS_NUM = 5 - - real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) - integer, private, allocatable :: iM2Dto3D(:) - - - private :: cal_del_flux_dyn - contains subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Init( mesh ) - implicit none class(MeshBase3D), intent(in) :: mesh - - integer :: p1, p2, p_ - type(ElementBase3D), pointer :: elem - real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) - - integer :: f_h, f_v - integer :: fp, fp_h1, fp_h2, fp_v - type(ElementBase2D), pointer :: elem2D - class(MeshBase2D), pointer :: mesh2D !-------------------------------------------- - elem => mesh%refElem3D - allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) - - InvV_VPOrdM1(:,:) = elem%invV - do p2=1, elem%Nnode_h1D - do p1=1, elem%Nnode_h1D - p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 - InvV_VPOrdM1(p_,:) = 0.0_RP - end do - end do - IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) - - !-- - - allocate( iM2Dto3D(elem%NfpTot) ) - call mesh%GetMesh2D( mesh2D ) - elem2D => mesh2D%refElem2D - - do f_h=1, 4 - do fp_v=1, elem%Nnode_v - do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h - iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) - end do - end do - end do - do f_v=1, 2 - do fp_h2=1, elem%Nnode_h1D - do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & - + (f_v-1) * elem%Nfp_v & - + 4 * elem%Nnode_h1D * elem%Nnode_v - iM2Dto3D(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D - end do - end do - end do - + call atm_dyn_dgm_nonhydro3d_common_Init( mesh ) return end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Init @@ -134,8 +81,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Final() implicit none !-------------------------------------------- - deallocate( IntrpMat_VPOrdM1 ) - + call atm_dyn_dgm_nonhydro3d_common_Final() return end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_Final @@ -148,6 +94,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + use scale_atm_dyn_dgm_nonhydro3d_hevi_numflux, only: & + atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalhvc use scale_atm_dyn_dgm_spongelayer, only: & atm_dyn_dgm_spongelayer_add_tend use scale_const, only: & @@ -202,14 +150,15 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & !------------------------------------------------------------------------ call PROF_rapstart('cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, del_flux_hyd, & ! (out) + call atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalhvc( & + del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) lmesh%GsqrtH, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) - lmesh%vmapM, lmesh%vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) + lmesh%vmapM, lmesh%vmapP, iM2Dto3D, lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) - + !----- call PROF_rapstart('cal_dyn_tend_interior', 3) gamm = CPDry / CvDry @@ -294,7 +243,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) & * ( wt_(:) - w_(:) * RGsqrtV(:) ), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DDENS_VID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx(:) & @@ -352,13 +301,19 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * RHOT_(:), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * RHOT_(:), Fy) call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) - w_(:) * RGsqrtV(:) ) * RHOT_(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DRHOT_VID), LiftDelFlx) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,RHOT_VID), LiftDelFlx) RHOT_dt(:,ke) = & - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + lmesh%Escale(:,ke,2,2) * Fy(:) & + lmesh%Escale(:,ke,3,3) * Fz(:) & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) + + ! DENS_dt(:,ke) = 0.0_RP + ! MOMX_dt(:,ke) = 0.0_RP + ! MOMY_dt(:,ke) = 0.0_RP + ! MOMZ_dt(:,ke) = 0.0_RP + ! RHOT_dt(:,ke) = 0.0_RP end do !$omp end parallel call PROF_rapend('cal_dyn_tend_interior', 3) @@ -376,188 +331,6 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & return end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend - !------ - -!OCL SERIAL - subroutine cal_del_flux_dyn( del_flux, del_flux_hyd, & - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - Gsqrt, G11, G12, G22, GsqrtH, G13, G23, nx, ny, nz, & - vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - class(LocalMesh2D), intent(in) :: lmesh2D - class(elementbase2D), intent(in) :: elem2D - real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) - real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) - real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) - real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) - real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) - - integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) - integer :: ke2D - real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot) - real(RP) :: VelhP(elem%NfpTot), VelhM(elem%NfpTot) - real(RP) :: alpha(elem%NfpTot) - real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) - real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) - real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) - real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) - real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) - real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) - real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) - real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) - real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) - real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) - real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) - real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) - real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) - real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) - real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) - real(RP) :: Gxz_M(elem%NfpTot), Gxz_P(elem%NfpTot) - real(RP) :: Gyz_M(elem%NfpTot), Gyz_P(elem%NfpTot) - real(RP) :: swV(elem%NfpTot) - - real(RP) :: gamm, rgamm - real(RP) :: rP0 - real(RP) :: RovP0, P0ovR - !------------------------------------------------------------------------ - - gamm = CPDry / CvDry - rgamm = CvDry / CpDry - rP0 = 1.0_RP / PRES00 - RovP0 = Rdry * rP0 - P0ovR = PRES00 / Rdry - - !$omp parallel do private( & - !$omp ke, iM, iP, ke2d, & - !$omp alpha, VelM, VelP, VelhM, VelhP, & - !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & - !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & - !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & - !$omp Phyd_M, Phyd_P, & - !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & - !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M, & - !$omp swV ) - do ke=lmesh%NeS, lmesh%NeE - iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) - ke2D = lmesh%EMap3Dto2D(ke) - - Gsqrt_M(:) = Gsqrt(iM) - Gsqrt_P(:) = Gsqrt(iP) - GsqrtV_M(:) = Gsqrt_M(:) / GsqrtH(iM2Dto3D(:),ke2D) - GsqrtV_P(:) = Gsqrt_P(:) / GsqrtH(iM2Dto3D(:),ke2D) - - G13_M(:) = G13(iM) - G13_P(:) = G13(iP) - G23_M(:) = G23(iM) - G23_P(:) = G23(iP) - - GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) - GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) - GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) - GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) - GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) - GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) - GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) - GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) - GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) - GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) - Phyd_M(:) = PRES_hyd(iM) - Phyd_P(:) = PRES_hyd(iP) - swV(:) = 1.0_RP - nz(:,ke)**2 - - Gxz_M(:) = G11(iM2Dto3D(:),ke2D) * G13_M(:) + G12(iM2Dto3D(:),ke2D) * G23_M(:) - Gxz_P(:) = G11(iM2Dto3D(:),ke2D) * G13_P(:) + G12(iM2Dto3D(:),ke2D) * G23_P(:) - - Gyz_M(:) = G12(iM2Dto3D(:),ke2D) * G13_M(:) + G22(iM2Dto3D(:),ke2D) * G23_M(:) - Gyz_P(:) = G12(iM2Dto3D(:),ke2D) * G13_P(:) + G22(iM2Dto3D(:),ke2D) * G23_P(:) - - G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) - G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) - - Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) - Gnn_P(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) - - GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) - GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) - - GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) - GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) - - VelhM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & - + ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) & - ) / GsqrtDensM(:) - - VelhP(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & - + ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) & - ) / GsqrtDensM(:) - - VelM(:) = VelhM(:) + GsqrtMOMZ_M(:) / ( GsqrtV_M(:) * GsqrtDensM(:) ) * nz(:,ke) - VelP(:) = VelhP(:) + GsqrtMOMZ_P(:) / ( GsqrtV_P(:) * GsqrtDensP(:) ) * nz(:,ke) - - dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & - - Phyd_M(:) - dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & - - Phyd_P(:) - - alpha(:) = swV(:) * max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & - sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) - - del_flux(:,ke,DDENS_VID) = 0.5_RP * ( & - ( GsqrtDensP(:) * VelhP(:) - GsqrtDensM(:) * VelhM(:) ) & - - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) - - del_flux(:,ke,MOMX_VID ) = 0.5_RP * ( & - ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & - + ( ( G1n_M(:) + Gxz_P(:) * nz(:,ke)) * dpresP(:) & - - ( G1n_M(:) + Gxz_M(:) * nz(:,ke)) * dpresM(:) ) & - - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) - - del_flux(:,ke,MOMY_VID ) = 0.5_RP * ( & - ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & - + ( ( G2n_M(:) + Gyz_P(:) * nz(:,ke) ) * dpresP(:) & - - ( G2n_M(:) + Gyz_M(:) * nz(:,ke) ) * dpresM(:) ) & - - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) - - del_flux(:,ke,MOMZ_VID ) = 0.5_RP * ( & - ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & - - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) - - del_flux(:,ke,DRHOT_VID) = 0.5_RP * ( & - ( GsqrtRhotP(:) * VelhP(:) - GsqrtRhotM(:) * VelhM(:) ) & - - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) - - del_flux_hyd(:,ke,1) = 0.5_RP * ( & - GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & - - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) - - del_flux_hyd(:,ke,2) = 0.5_RP * ( & - GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & - - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) - end do - - return - end subroutine cal_del_flux_dyn - !OCL SERIAL subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & @@ -568,6 +341,11 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & impl_fac, dt, & ! (in) lmesh, elem, lmesh2D, elem2D ) ! (in) + use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + implicit none class(LocalMesh3D), intent(in) :: lmesh @@ -612,15 +390,13 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & integer :: vmapP(elem%NfpTot,lmesh%NeZ) integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v integer :: itr_lin, itr_nlin - integer :: f, vs, ve, kl, ku, nz_1D + integer :: kl, ku, nz_1D integer :: ij, info logical :: is_converged - real(RP), allocatable :: PmatBnd(:,:,:) !------------------------------------------------------------------------ - call PROF_rapstart( 'hevi_cal_vi_prep', 3) nz_1D = elem%Nnode_v * PROG_VARS_NUM * lmesh%NeZ @@ -628,34 +404,9 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & ku = kl allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) - !$omp parallel private(f, vs, ve) - !$omp do - do ke_z=1, lmesh%NeZ - do f=1, elem%Nfaces_h - vs = 1 + (f-1)*elem%Nfp_h - ve = vs + elem%Nfp_h - 1 - vmapM(vs:ve,ke_z) = elem%Fmask_h(:,f) + (ke_z-1)*elem%Np - end do - do f=1, elem%Nfaces_v - vs = elem%Nfp_h*elem%Nfaces_h + 1 + (f-1)*elem%Nfp_v - ve = vs + elem%Nfp_v - 1 - vmapM(vs:ve,ke_z) = elem%Fmask_v(:,f) + (ke_z-1)*elem%Np - end do - vmapP(:,ke_z) = vmapM(:,ke_z) - end do - !$omp do - do ke_z=1, lmesh%NeZ - vs = elem%Nfp_h*elem%Nfaces_h + 1 - ve = vs + elem%Nfp_v - 1 - if (ke_z > 1) & - vmapP(vs:ve,ke_z) = elem%Fmask_v(:,2) + (ke_z-2)*elem%Np + call vi_gen_vmap( vmapM, vmapP, & ! (out) + lmesh, elem ) ! (in) - vs = elem%Nfp_h*elem%Nfaces_h + elem%Nfp_v + 1 - ve = vs + elem%Nfp_v - 1 - if (ke_z < lmesh%NeZ) & - vmapP(vs:ve,ke_z) = elem%Fmask_v(:,1) + ke_z*elem%Np - end do - !$omp end parallel call PROF_rapend( 'hevi_cal_vi_prep', 3) do ke_y=1, lmesh%NeY @@ -668,15 +419,15 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY ke2D = lmesh%EMap3Dto2D(ke) - PROG_VARS(:,DDENS_VID,ke_z) = DDENS_(:,ke) + PROG_VARS(:,DENS_VID,ke_z) = DDENS_(:,ke) PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) - PROG_VARS(:,DRHOT_VID,ke_z) = DRHOT_(:,ke) + PROG_VARS(:,RHOT_VID,ke_z) = DRHOT_(:,ke) DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) - PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) + PROG_VARS0 (:,:,ke_z) = PROG_VARS(:,:,ke_z) PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) nz(:,ke_z) = lmesh%normal_fn(:,ke,3) @@ -685,7 +436,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) GnnM_z(:,ke_z) = ( & - 1.0_RP / lmesh%Gsqrt(:,ke) & + 1.0_RP / GsqrtV_z(:,ke_z)**2 & + G13_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,1) * G13_z(:,ke_z) & + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G23_z(:,ke_z) ) & + G23_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G13_z(:,ke_z) & @@ -702,7 +453,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) @@ -718,8 +469,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & call vi_construct_matbnd( PmatBnd, & ! (out) kl, ku, nz_1D, & ! (in) PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - alph, & ! (in) - Dz, Lift, & ! (in) + G13_z, G23_z, GsqrtV_z, alph, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -737,20 +488,6 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & end do end do - ! if ( lmesh%PRC_myrank==11 .and. ke_x==3 .and. ke_y==3 .and. ij == 1) then - ! LOG_INFO("check_check_vi",*) "V1", PROG_VARS(elem%Colmask(:,ij),1,:) - ! LOG_INFO("check_check_vi",*) "V2", PROG_VARS(elem%Colmask(:,ij),2,:) - ! LOG_INFO("check_check_vi",*) "V3", PROG_VARS(elem%Colmask(:,ij),3,:) - ! LOG_INFO("check_check_vi",*) "V4", PROG_VARS(elem%Colmask(:,ij),4,:) - ! LOG_INFO("check_check_vi",*) "V5", PROG_VARS(elem%Colmask(:,ij),5,:) - ! LOG_INFO("check_check_vi",*) "b1D1", b1D(:,1,:,ij) - ! LOG_INFO("check_check_vi",*) "b1D2", b1D(:,2,:,ij) - ! LOG_INFO("check_check_vi",*) "b1D3", b1D(:,3,:,ij) - ! LOG_INFO("check_check_vi",*) "b1D4", b1D(:,4,:,ij) - ! LOG_INFO("check_check_vi",*) "b1D5", b1D(:,5,:,ij) - ! LOG_INFO("check_check_vi",*) "PmatBand", PmatBnd(:,:,ij) - ! end if - call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij), nz_1D, info) do ke_z=1, lmesh%NeZ @@ -774,12 +511,12 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & if ( abs(impl_fac) > 0.0_RP) then !$omp parallel do do ke_z=1, lmesh%NeZ - tend(:,:,ke_z) = (- PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z))/impl_fac + tend(:,:,ke_z) = ( - PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z) ) / impl_fac end do else call vi_eval_Ax( tend(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) @@ -787,26 +524,14 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & nz, vmapM, vmapP, ke_x, ke_y, .true. ) ! (in) end if -! if (lmesh%PRC_myrank==11) then - ! do ke_z=1, lmesh%NeZ - ! ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - ! do p=1, elem%Np - ! if ( IEEE_IS_NAN(tend(p,DDENS_VID,ke_z)) .and. ke_x==3 .and. ke_y==3 .and. p==1 .and. ke_z == 1) then - ! LOG_INFO("check_nan_vi",*) impl_fac, lmesh%PRC_myrank, "Nan:", lmesh%pos_en(p,ke,:), ":", MOMX_(p,ke), MOMY_(p,ke), MOMZ_(p,ke), DRHOT_(p,ke) - ! LOG_INFO("check_nan_vi",*) p, ke_x, ke_y, " Nan_tend:", tend(p,:,ke_z) - ! end if - ! end do - ! end do -! end if - !$omp parallel do private(ke) do ke_z=1, lmesh%NeZ ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - DENS_dt(:,ke) = - tend(:,DDENS_VID,ke_z) - MOMX_dt(:,ke) = - tend(:,MOMX_VID ,ke_z) - MOMY_dt(:,ke) = - tend(:,MOMY_VID ,ke_z) - MOMZ_dt(:,ke) = - tend(:,MOMZ_VID ,ke_z) - RHOT_dt(:,ke) = - tend(:,DRHOT_VID,ke_z) + DENS_dt(:,ke) = - tend(:,DENS_VID,ke_z) + MOMX_dt(:,ke) = - tend(:,MOMX_VID,ke_z) + MOMY_dt(:,ke) = - tend(:,MOMY_VID,ke_z) + MOMZ_dt(:,ke) = - tend(:,MOMZ_VID,ke_z) + RHOT_dt(:,ke) = - tend(:,RHOT_VID,ke_z) end do call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) end do @@ -815,477 +540,4 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & return end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi - !------------------------------------------------ - -!OCL SERIAL - subroutine vi_eval_Ax( Ax, alph, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - Dz, Lift, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, cal_tend_flag ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(out) :: alph(elem%NfpTot,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) - class(SparseMat), intent(in) :: Dz, Lift - real(RP), intent(in) :: GnnM_z(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: G13_z(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: G23_z(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: GsqrtV_z(elem%Np,lmesh%NeZ) - logical, intent(in) :: modalFilterFlag - real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) - real(RP), intent(in) :: impl_fac - real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - logical, intent(in) :: cal_tend_flag - - real(RP) :: RGsqrtV(elem%Np) - real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) - real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) - real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) - real(RP) :: DPRES(elem%Np) - integer :: ke_z - integer :: ke, ke2d - integer :: v - integer :: ij - real(RP) :: gamm, rgamm - !-------------------------------------------------------- - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - call vi_cal_del_flux_dyn( del_flux, alph, & ! (out) - PROG_VARS(:,DDENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) - PROG_VARS(:,MOMY_VID ,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) - PROG_VARS(:,DRHOT_VID,:), & ! (in) - PROG_VARS0(:,DDENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) - PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) - PROG_VARS0(:,DRHOT_VID,:), & ! (in) - DENS_hyd, PRES_hyd, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, nz, vmapM, vmapP, & ! (in) - lmesh, elem ) ! (in) - - !$omp parallel do private( & - !$omp ke, ke2d, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & - !$omp v, ij, RGsqrtV & - !$omp ) - do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - ke2d = lmesh%EMap3Dto2D(ke) - - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm - - DPRES(:) = PRES_hyd(:,ke_z) * ( (1.0_RP + PROG_VARS(:,DRHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP ) - POT(:) = ( RHOT_hyd(:) + PROG_VARS(:,DRHOT_VID,ke_z) ) / ( DENS_hyd(:,ke_z) + PROG_VARS(:,DDENS_VID,ke_z) ) - - RGsqrtV(:) = 1.0_RP / GsqrtV_z(:,ke_z) - - !- DENS - call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DDENS_VID), LiftDelFlx) - Ax(:,DDENS_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) - - !- MOMX - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) - Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) - - !-MOMY - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) - Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) - - !-MOMZ - call sparsemat_matmul(Dz, DPRES(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) - Ax(:,MOMZ_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) & - + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DDENS_VID,ke_z)) - - !-RHOT - call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DRHOT_VID), LiftDelFlx) - Ax(:,DRHOT_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) - - !-- Modal filtering in the vertical direction - if ( modalFilterFlag ) then - do v=1, PROG_VARS_NUM - do ij=1, elem%Nnode_h1D**2 - Ax(elem%Colmask(:,ij),v,ke_z) = Ax(elem%Colmask(:,ij),v,ke_z) & - - matmul(VModalFilter, PROG_VARS(elem%Colmask(:,ij),v,ke_z) ) / dt - end do - end do - end if - - !-- - if ( .not. cal_tend_flag ) then - Ax(:,:,ke_z) = PROG_VARS(:,:,ke_z) + impl_fac * Ax(:,:,ke_z) - end if - - end do - - return - end subroutine vi_eval_Ax - -!OCL SERIAL - subroutine vi_cal_del_flux_dyn( del_flux, alph, & ! (out) - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) - DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) - DENS_hyd, PRES_hyd, & ! (in) - Gnn_, G13_, G23_, GsqrtV_, nz, vmapM, vmapP, lmesh, elem ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) - real(RP), intent(out) :: alph(elem%NfpTot*lmesh%NeZ) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DDENS0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: Gnn_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: G13_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: G23_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: GsqrtV_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) - - integer :: i, p, ke_z, iP, iM, iM2D - real(RP) :: alpha0 - real(RP) :: MOMZ_P - real(RP) :: wt0M, wt0P - real(RP) :: rhot_hyd_M, rhot_hyd_P - real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP - real(RP) :: pres0M, pres0P, dens0M, dens0P - real(RP) :: gamm, rgamm - !------------------------------------------------------------------------ - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - !$omp parallel do private( p, i, iM, iP, & - !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & - !$omp dpresM, dpresP, MOMZ_P, wt0M, wt0P, & - !$omp dens0M, dens0P, pres0M, pres0P ) - do ke_z=1, lmesh%NeZ - do p=1, elem%NfpTot - i = p + (ke_z-1)*elem%NfpTot - iM = vmapM(i); iP = vmapP(i) - iM2D = iM2Dto3D(p) - - !- - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm - - densM = DENS_hyd(iM) + DDENS_(iM) - densP = DENS_hyd(iP) + DDENS_(iP) - - pottM = (rhot_hyd_M + DRHOT_(iM)) / densM - pottP = (rhot_hyd_P + DRHOT_(iP)) / densP - - dpresM = PRES_hyd(iM) * ((1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - 1.0_RP) - dpresP = PRES_hyd(iP) * ((1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - 1.0_RP) - - !- - dens0M = DENS_hyd(iM) + DDENS0_(iM) - dens0P = DENS_hyd(iP) + DDENS0_(iP) - - pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm - pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm - - wt0M = ( MOMZ0_(iM) / GsqrtV_(iM) + G13_(iM) * MOMX0_(iM) + G23_(iM) * MOMY0_(iM) ) / dens0M - wt0P = ( MOMZ0_(iP) / GsqrtV_(iP) + G13_(iP) * MOMX0_(iP) + G23_(iP) * MOMY0_(iP) ) / dens0M - - alph(i) = nz(i)**2 * max( abs( wt0M ) + sqrt( Gnn_(iM) * gamm * pres0M / dens0M ), & - abs( wt0P ) + sqrt( Gnn_(iP) * gamm * pres0M / dens0M ) ) - - !---- - if (iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ)) then - MOMZ_P = - MOMZ_(iM) - !alph(i) = 0.0_RP - else - MOMZ_P = MOMZ_(iP) - end if - - del_flux(i,DDENS_VID) = 0.5_RP * ( & - + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & - - alph(i) * ( DDENS_(iP) - DDENS_(iM) ) ) - - del_flux(i,MOMX_VID) = 0.5_RP * ( & - - alph(i) * ( MOMX_(iP) - MOMX_(iM) ) ) - - del_flux(i,MOMY_VID) = 0.5_RP * ( & - - alph(i) * ( MOMY_(iP) - MOMY_(iM) ) ) - - del_flux(i,MOMZ_VID) = 0.5_RP * ( & - + ( dpresP - dpresM ) * nz(i) & - - alph(i) * ( MOMZ_P - MOMZ_(iM) ) ) - - del_flux(i,DRHOT_VID) = 0.5_RP * ( & - + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & - - alph(i) * ( DRHOT_(iP) - DRHOT_(iM) ) ) - end do - end do - - return - end subroutine vi_cal_del_flux_dyn - -!OCL SERIAL - subroutine vi_construct_matbnd( PmatBnd, & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - alph, & ! (in) - Dz, Lift, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - integer, intent(in) :: kl, ku, nz_1D - real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: alph(elem%NfpTot,lmesh%NeZ) - class(SparseMat), intent(in) :: Dz, Lift - logical, intent(in) :: modalFilterFlag - real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) - real(RP), intent(in) :: impl_fac - real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - - real(RP) :: RHOT_hyd(elem%Nnode_v) - real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - integer :: ke_z, ke_z2 - integer :: v, ke, p, f1, f2, fp, fp2, FmV - real(RP) :: gamm, rgamm - real(RP) :: fac_dz_p(elem%Nnode_v) - real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - real(RP) :: PmatL(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - real(RP) :: PmatU(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - integer :: Colmask(elem%Nnode_v) - real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) - real(RP) :: Dd(elem%Nnode_v) - real(RP) :: tmp1 - real(RP) :: fac - - integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 - logical :: bc_flag - logical :: eval_flag(PROG_VARS_NUM,PROG_VARS_NUM) - !-------------------------------------------------------- - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - eval_flag(:,:) = .false. - do v=1, PROG_VARS_NUM - eval_flag(v,v) = .true. - end do - eval_flag(DDENS_VID,MOMZ_VID) = .true. - eval_flag(MOMZ_VID,DDENS_VID) = .true. - eval_flag(MOMZ_VID,DRHOT_VID) = .true. - eval_flag(DRHOT_VID,MOMZ_VID) = .true. - eval_flag(DRHOT_VID,DDENS_VID) = .true. - - Id(:,:) = 0.0_RP - do p=1, elem%Nnode_v - Id(p,p) = 1.0_RP - end do - - !$omp parallel private(RHOT_hyd, Colmask) - !$omp do - do v=1, PROG_VARS_NUM - PmatD(:,:,:,v) = 0.0_RP - PmatL(:,:,:,v) = 0.0_RP - PmatU(:,:,:,v) = 0.0_RP - end do - !$omp do - do ij=1, elem%Nnode_h1D**2 - PmatBnd(:,:,:,:,ij) = 0.0_RP - end do - !$omp do collapse(2) - do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - Colmask(:) = elem%Colmask(:,ij) - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm - - DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**(gamm-1) - - DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DDENS_VID,ke_z) - POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) - W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) - end do - end do - !$omp end parallel - - !$omp parallel do private(ke_z, ke, ColMask, p, fp, fp2, v, f1, f2, ke_z2, fac_dz_p, & - !$omp fac, tmp1, FmV, & - !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & - !$omp Dd ) & - !$omp firstprivate(PmatD, PmatL, PmatU) - do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - Colmask(:) = elem%Colmask(:,ij) - - !----- - do p=1, elem%Nnode_v - fac_dz_p(:) = impl_fac * lmesh%Escale(Colmask(:),ke,3,3) * elem%Dx3(Colmask(:),Colmask(p)) - if (modalFilterFlag) then - Dd(:) = Id(:,p) - VModalFilter(:,p) * impl_fac / dt - else - Dd(:) = Id(:,p) - end if - - ! DDENS - PmatD(:,p,DDENS_VID,DDENS_VID) = Dd(:) - PmatD(:,p,DDENS_VID,MOMZ_VID) = fac_dz_p(:) - - ! MOMX - PmatD(:,p,MOMX_VID,MOMX_VID) = Dd(:) - - ! MOMY - PmatD(:,p,MOMY_VID,MOMY_VID) = Dd(:) - - ! MOMZ - PmatD(:,p,MOMZ_VID,MOMZ_VID) = Dd(:) - PmatD(:,p,MOMZ_VID,DDENS_VID) = impl_fac * Grav * IntrpMat_VPOrdM1(Colmask(:),Colmask(p)) - PmatD(:,p,MOMZ_VID,DRHOT_VID) = fac_dz_p(:) * DPDRHOT0(p,ke_z,ij) - - !DRHOT - PmatD(:,p,DRHOT_VID,DDENS_VID) = - fac_dz_p(:) * POT0(p,ke_z,ij) * W0(p,ke_z,ij) - PmatD(:,p,DRHOT_VID,MOMZ_VID ) = fac_dz_p(:) * POT0(p,ke_z,ij) - PmatD(:,p,DRHOT_VID,DRHOT_VID) = Dd(:) + fac_dz_p(:) * W0(p,ke_z,ij) - end do - - do f1=1, 2 - if (f1==1) then - ke_z2 = max(ke_z-1,1) - pv1 = 1; pv2 = elem%Nnode_v - f2 = 2 - else - ke_z2 = min(ke_z+1,lmesh%NeZ) - pv1 = elem%Nnode_v; pv2 = 1 - f2 = 1 - end if - fac = 0.5_RP * impl_fac - if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then - bc_flag = .true. - pv2 = pv1; f2 = f1 - else - bc_flag = .false. - end if - - FmV = elem%Fmask_v(ij,f1) - fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij - fp2 = elem%Nfp_h * elem%Nfaces_h + (f2-1)*elem%Nfp_v + ij - - !-- - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) & - * max( alph(fp,ke_z), alph(fp2,ke_z2) ) - if (bc_flag) then - PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 - else - do v=1, PROG_VARS_NUM - PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 - if (f1 == 1) then - PmatL(pv1,pv2,v,v) = - tmp1 - else - PmatU(pv1,pv2,v,v) = - tmp1 - end if - end do - end if - - !-- - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * nz(fp,ke_z) - - if (bc_flag) then - PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - 2.0_RP * tmp1 - PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - 2.0_RP * tmp1 * W0(pv1,ke_z,ij) - else - PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - tmp1 - PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) = PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) - tmp1 * DPDRHOT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - tmp1 * POT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - tmp1 * W0(pv1,ke_z,ij) - - if (f1 == 1) then - PmatL(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 - PmatL(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) & - + tmp1 * W0(pv2,ke_z2,ij) - else - PmatU(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 - PmatU(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) & - + tmp1 * W0(pv2,ke_z2,ij) - end if - end if - end do - - do v2=1, PROG_VARS_NUM - do v1=1, PROG_VARS_NUM - if ( eval_flag(v1,v2) ) then - do pv2=1, elem%Nnode_v - g_kj = pv2 + (v2-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM - g_kjm1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z-2)*elem%Nnode_v*PROG_VARS_NUM - g_kjp1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z )*elem%Nnode_v*PROG_VARS_NUM - - do pv1=1, elem%Nnode_v - pb1 = pv1 + (v1-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM - if (ke_z > 1) then - PmatBnd(kl+ku+1+pb1-g_kjm1, pv2,v2,ke_z-1, ij) = PmatL(pv1,pv2,v1,v2) - end if - PmatBnd(kl+ku+1+pb1-g_kj, pv2,v2,ke_z, ij) = PmatD(pv1,pv2,v1,v2) - if (ke_z < lmesh%NeZ) then - PmatBnd(kl+ku+1+pb1-g_kjp1, pv2,v2,ke_z+1, ij) = PmatU(pv1,pv2,v1,v2) - end if - end do - end do - end if - end do - end do - end do - end do - - return - end subroutine vi_construct_matbnd - end module scale_atm_dyn_dgm_globalnonhydro3d_hevi diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 new file mode 100644 index 00000000..0aeade3f --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 @@ -0,0 +1,137 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / Dynamics common +!! +!! @par Description +!! HEVE DGM scheme for Atmospheric dynamical process. +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_nonhydro3d_common + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_nonhydro3d_common_Init + public :: atm_dyn_dgm_nonhydro3d_common_Final + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + integer, public, parameter :: DENS_VID = 1 + integer, public, parameter :: MOMX_VID = 2 + integer, public, parameter :: MOMY_VID = 3 + integer, public, parameter :: MOMZ_VID = 4 + integer, public, parameter :: RHOT_VID = 5 + integer, public, parameter :: PROG_VARS_NUM = 5 + + real(RP), public, allocatable :: IntrpMat_VPOrdM1(:,:) + integer, public, allocatable :: iM2Dto3D(:) + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + +contains + subroutine atm_dyn_dgm_nonhydro3d_common_Init( mesh ) + + implicit none + class(MeshBase3D), intent(in) :: mesh + + integer :: p1, p2, p_ + type(ElementBase3D), pointer :: elem + real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) + + integer :: f_h, f_v + integer :: fp, fp_h1, fp_h2, fp_v + type(ElementBase2D), pointer :: elem2D + class(MeshBase2D), pointer :: mesh2D + !-------------------------------------------- + + elem => mesh%refElem3D + allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) + + InvV_VPOrdM1(:,:) = elem%invV + do p2=1, elem%Nnode_h1D + do p1=1, elem%Nnode_h1D + p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 + InvV_VPOrdM1(p_,:) = 0.0_RP + end do + end do + IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) + + !-- + + allocate( iM2Dto3D(elem%NfpTot) ) + call mesh%GetMesh2D( mesh2D ) + elem2D => mesh2D%refElem2D + + do f_h=1, 4 + do fp_v=1, elem%Nnode_v + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h + iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) + end do + end do + end do + do f_v=1, 2 + do fp_h2=1, elem%Nnode_h1D + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & + + (f_v-1) * elem%Nfp_v & + + 4 * elem%Nnode_h1D * elem%Nnode_v + iM2Dto3D(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D + end do + end do + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_common_Init + + + subroutine atm_dyn_dgm_nonhydro3d_common_Final() + implicit none + !-------------------------------------------- + + deallocate( IntrpMat_VPOrdM1 ) + deallocate( iM2Dto3D ) + + return + end subroutine atm_dyn_dgm_nonhydro3d_common_Final + +end module scale_atm_dyn_dgm_nonhydro3d_common diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 index 91a94a53..363a2242 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 @@ -34,6 +34,12 @@ module scale_atm_dyn_dgm_nonhydro3d_heve use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + atm_dyn_dgm_nonhydro3d_common_Init, & + atm_dyn_dgm_nonhydro3d_common_Final, & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM, & + IntrpMat_VPOrdM1, iM2Dto3D !----------------------------------------------------------------------------- implicit none @@ -57,41 +63,13 @@ module scale_atm_dyn_dgm_nonhydro3d_heve ! !------------------- - integer, private, parameter :: VARS_DDENS_ID = 1 - integer, private, parameter :: VARS_MOMX_ID = 2 - integer, private, parameter :: VARS_MOMY_ID = 3 - integer, private, parameter :: VARS_MOMZ_ID = 4 - integer, private, parameter :: VARS_DRHOT_ID = 5 - integer, private, parameter :: PROG_VARS_NUM = 5 - - real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) - - private :: cal_del_flux_dyn - contains subroutine atm_dyn_dgm_nonhydro3d_heve_Init( mesh ) - implicit none class(MeshBase3D), intent(in) :: mesh - - integer :: p1, p2, p_ - type(ElementBase3D), pointer :: elem - real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) !-------------------------------------------- - elem => mesh%refElem3D - allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) - - InvV_VPOrdM1(:,:) = elem%invV - do p2=1, elem%Nnode_h1D - do p1=1, elem%Nnode_h1D - p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 - InvV_VPOrdM1(p_,:) = 0.0_RP - end do - end do - IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) - - !-- + call atm_dyn_dgm_nonhydro3d_common_Init( mesh ) return end subroutine atm_dyn_dgm_nonhydro3d_heve_Init @@ -100,8 +78,7 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_Final() implicit none !-------------------------------------------- - deallocate( IntrpMat_VPOrdM1 ) - + call atm_dyn_dgm_nonhydro3d_common_Final() return end subroutine atm_dyn_dgm_nonhydro3d_heve_Final @@ -114,6 +91,9 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + use scale_atm_dyn_dgm_nonhydro3d_heve_numflux, only: & + atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc + use scale_atm_dyn_dgm_spongelayer, only: & atm_dyn_dgm_spongelayer_add_tend @@ -143,12 +123,15 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP) :: PRES_(elem%Np) + real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP) :: DPRES_(elem%Np) real(RP) :: RHOT_(elem%Np) - real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), wt_(elem%Np) real(RP) :: Cori(elem%Np) real(RP) :: drho(elem%Np) + real(RP) :: GsqrtV(elem%Np), RGsqrtV(elem%Np) integer :: ke, ke2d @@ -158,11 +141,13 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & !------------------------------------------------------------------------ call PROF_rapstart('cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, & ! (out) + call atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc( & + del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + lmesh%Gsqrt, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) lmesh%vmapM, lmesh%vmapP, & ! (in) - lmesh, elem ) ! (in) + lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) !----- @@ -173,88 +158,115 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & RovP0 = Rdry * rP0 P0ovR = PRES00 / Rdry - !$omp parallel do private( & - !$omp RHOT_, PRES_, rdens_, u_, v_, w_, ke2d, Cori, drho, & + !$omp parallel do private( ke, ke2d, Cori, & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, wt_, & + !$omp drho, GradPhyd_x, GradPhyd_y, & + !$omp GsqrtV, RGsqrtV, & !$omp Fx, Fy, Fz, LiftDelFlx ) do ke = lmesh%NeS, lmesh%NeE + !-- + ke2d = lmesh%EMap3Dto2D(ke) + Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) + + GsqrtV(:) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2d) + RGsqrtV(:) = 1.0_RP / GsqrtV(:) + !-- RHOT_(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT_(:,ke) - PRES_(:) = PRES00 * (RovP0 * RHOT_(:))**gamm + DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & + - PRES_hyd(:,ke) rdens_(:) = 1.0_RP / (DDENS_(:,ke) + DENS_hyd(:,ke)) u_ (:) = MOMX_(:,ke) * rdens_(:) v_ (:) = MOMY_(:,ke) * rdens_(:) w_ (:) = MOMZ_(:,ke) * rdens_(:) - - ke2d = lmesh%EMap3Dto2D(ke) - Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) + wt_(:) = w_(:) * RGsqrtV(:) + lmesh%GI3(:,ke,1) * u_(:) + lmesh%GI3(:,ke,2) * v_(:) drho(:) = matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) + !-- Gradient hydrostatic pressure + + call sparsemat_matmul(Dx, GsqrtV(:) * PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,1) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + + call sparsemat_matmul(Dy, GsqrtV(:) * PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,2) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + !-- DENS - call sparsemat_matmul(Dx, MOMX_(:,ke), Fx) - call sparsemat_matmul(Dy, MOMY_(:,ke), Fy) - call sparsemat_matmul(Dz, MOMZ_(:,ke), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DDENS_ID), LiftDelFlx) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) * wt_(:), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) + lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- MOMX - call sparsemat_matmul(Dx, u_(:) * MOMX_(:,ke) + PRES_(:), Fx) - call sparsemat_matmul(Dy, v_(:) * MOMX_(:,ke) , Fy) - call sparsemat_matmul(Dz, w_(:) * MOMX_(:,ke) , Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMX_ID), LiftDelFlx) - - MOMX_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) & - - Cori(:) * MOMY_(:,ke) & - ) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMX_(:,ke) , Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + + lmesh%GI3(:,ke,1) * DPRES_(:) ), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) + + MOMX_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_x(:) * RGsqrtV(:) & + + Cori(:) * MOMY_(:,ke) !-- MOMY - call sparsemat_matmul(Dx, u_(:) * MOMY_(:,ke) , Fx) - call sparsemat_matmul(Dy, v_(:) * MOMY_(:,ke) + PRES_(:), Fy) - call sparsemat_matmul(Dz, w_(:) * MOMY_(:,ke) , Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMY_ID), LiftDelFlx) - - MOMY_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) & - + Cori(:) * MOMX_(:,ke) & - ) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMY_(:,ke) , Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & + + lmesh%GI3(:,ke,2) * DPRES_(:) ), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) + + MOMY_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_y(:) * RGsqrtV(:) & + - Cori(:) * MOMX_(:,ke) !-- MOMZ - call sparsemat_matmul(Dx, u_(:) * MOMZ_(:,ke), Fx) - call sparsemat_matmul(Dy, v_(:) * MOMZ_(:,ke), Fy) - call sparsemat_matmul(Dz, w_(:) * MOMZ_(:,ke) + PRES_(:) - PRES_hyd(:,ke), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_MOMZ_ID), LiftDelFlx) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMZ_(:,ke) & + + RGsqrtV(:) * DPRES_(:) ), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) - MOMZ_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) & + MOMZ_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & - Grav * drho(:) !-- RHOT - call sparsemat_matmul(Dx, u_(:) * RHOT_(:), Fx) - call sparsemat_matmul(Dy, v_(:) * RHOT_(:), Fy) - call sparsemat_matmul(Dz, w_(:) * RHOT_(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_DRHOT_ID), LiftDelFlx) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * RHOT_(:), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * RHOT_(:), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * wt_(:) * RHOT_(:), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,RHOT_VID), LiftDelFlx) - RHOT_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) + RHOT_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) end do call PROF_rapend('cal_dyn_tend_interior', 3) @@ -272,119 +284,4 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & return end subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend - !------ - -!OCL SERIAL - subroutine cal_del_flux_dyn( del_flux, & - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - nx, ny, nz, vmapM, vmapP, lmesh, elem ) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) - real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) - - integer :: ke, i, iP(elem%NfpTot), iM(elem%NfpTot) - real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) - real(RP) :: dpres(elem%NfpTot), presM(elem%NfpTot), presP(elem%NfpTot) - real(RP) :: densM(elem%NfpTot), densP(elem%NfpTot) - real(RP) :: rhotM(elem%NfpTot), rhotP(elem%NfpTot) - real(RP) :: DDENS_P(elem%NfpTot), DDENS_M(elem%NfpTot) - real(RP) :: MOMX_P(elem%NfpTot), MOMX_M(elem%NfpTot) - real(RP) :: MOMY_P(elem%NfpTot), MOMY_M(elem%NfpTot) - real(RP) :: MOMZ_P(elem%NfpTot), MOMZ_M(elem%NfpTot) - real(RP) :: DRHOT_P(elem%NfpTot), DRHOT_M(elem%NfpTot) - real(RP) :: PRES_hyd_P(elem%NfpTot), PRES_hyd_M(elem%NfpTot) - - real(RP) :: gamm, rgamm - real(RP) :: rP0 - real(RP) :: RovP0, P0ovR - !------------------------------------------------------------------------ - - gamm = CPDry / CvDry - rgamm = CvDry / CpDry - rP0 = 1.0_RP / PRES00 - RovP0 = Rdry * rP0 - P0ovR = PRES00 / Rdry - - !$omp parallel do private( i, iM, iP, & - !$omp alpha, VelM, VelP, & - !$omp dpres, presM, presP, densM, densP, rhotM, rhotP, & - !$omp MOMX_M, MOMX_P, MOMY_M, MOMY_P, MOMZ_M, MOMZ_P, & - !$omp DDENS_M, DDENS_P, DRHOT_M, DRHOT_P, & - !$omp PRES_hyd_M, PRES_hyd_P ) - do ke=lmesh%NeS, lmesh%NeE - iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) - - DDENS_M(:) = DDENS_(iM) - DDENS_P(:) = DDENS_(iP) - MOMX_M(:) = MOMX_(iM) - MOMX_P(:) = MOMX_(iP) - MOMY_M(:) = MOMY_(iM) - MOMY_P(:) = MOMY_(iP) - MOMZ_M(:) = MOMZ_(iM) - MOMZ_P(:) = MOMZ_(iP) - DRHOT_M(:) = DRHOT_(iM) - DRHOT_P(:) = DRHOT_(iP) - PRES_hyd_M(:) = PRES_hyd(iM) - PRES_hyd_P(:) = PRES_hyd(iP) - - densM(:) = DDENS_M(:) + DENS_hyd(iM) - densP(:) = DDENS_P(:) + DENS_hyd(iP) - - VelM(:) = ( MOMX_M(:) * nx(:,ke) + MOMY_M(:) * ny(:,ke) + MOMZ_M(:) * nz(:,ke) ) / densM(:) - VelP(:) = ( MOMX_P(:) * nx(:,ke) + MOMY_P(:) * ny(:,ke) + MOMZ_P(:) * nz(:,ke) ) / densP(:) - - rhotM(:) = P0ovR * (PRES_hyd_M(:) * rP0)**rgamm + DRHOT_M(:) - rhotP(:) = P0ovR * (PRES_hyd_P(:) * rP0)**rgamm + DRHOT_P(:) - - presM(:) = PRES00 * (RovP0 * rhotM(:))**gamm - presP(:) = PRES00 * (RovP0 * rhotP(:))**gamm - - dpres(:) = presP(:) - presM(:) & - - ( PRES_hyd_P(:) - PRES_hyd_M(:) ) * abs(nz(:,ke)) - - alpha(:) = max( sqrt(gamm * presM(:) / densM(:)) + abs(VelM(:)), & - sqrt(gamm * presP(:) / densP(:)) + abs(VelP(:)) ) - - del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & - ( densP(:) * VelP(:) - densM(:) * VelM(:) ) & - - alpha(:) * ( DDENS_P(:) - DDENS_M(:) ) ) - - del_flux(:,ke,VARS_MOMX_ID) = 0.5_RP * ( & - ( MOMX_P(:) * VelP(:) - MOMX_M(:) * VelM(:) ) & - + dpres(:) * nx(:,ke) & - - alpha(:) * ( MOMX_P(:) - MOMX_M(:) ) ) - - del_flux(:,ke,VARS_MOMY_ID) = 0.5_RP * ( & - ( MOMY_P(:) * VelP(:) - MOMY_M(:) * VelM(:) ) & - + dpres(:) * ny(:,ke) & - - alpha(:) * ( MOMY_P(:) - MOMY_M(:) ) ) - - del_flux(:,ke,VARS_MOMZ_ID) = 0.5_RP * ( & - ( MOMZ_P(:) * VelP(:) - MOMZ_M(:) * VelM(:)) & - + dpres(:) * nz(:,ke) & - - alpha(:) * ( MOMZ_P(:) - MOMZ_M(:) ) ) - - del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & - ( rhotP(:) * VelP(:) - rhotM(:) * VelM(:) ) & - - alpha(:) * ( DRHOT_P(:) - DRHOT_M(:) ) ) - end do - - return - end subroutine cal_del_flux_dyn - end module scale_atm_dyn_dgm_nonhydro3d_heve diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 new file mode 100644 index 00000000..37a5eae9 --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 @@ -0,0 +1,421 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / Dynamics HEVE numflux +!! +!! @par Description +!! HEVE DGM scheme for Atmospheric dynamical process. +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_nonhydro3d_heve_numflux + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc + public :: atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + integer, private, parameter :: VARS_DDENS_ID = 1 + integer, private, parameter :: VARS_MOMX_ID = 2 + integer, private, parameter :: VARS_MOMY_ID = 3 + integer, private, parameter :: VARS_MOMZ_ID = 4 + integer, private, parameter :: VARS_DRHOT_ID = 5 + integer, private, parameter :: PROG_VARS_NUM = 5 + +contains + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc( & + del_flux, del_flux_hyd, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + Gsqrt, G13, G23, nx, ny, nz, & ! (in) + vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + + integer :: ke, i, iP(elem%NfpTot), iM(elem%NfpTot) + integer :: ke2D + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) + real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) + real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) + real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) + real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) + real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) + real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) + real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) + real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) + real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) + real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) + real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) + real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) + real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + !------------------------------------------------------------------------ + + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( & + !$omp ke, iM, iP, ke2D, & + !$omp alpha, VelM, VelP, & + !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & + !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & + !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & + !$omp Phyd_M, Phyd_P, & + !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & + !$omp Gnn_P, Gnn_M ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + ke2D = lmesh%EMap3Dto2D(ke) + + Gsqrt_M(:) = Gsqrt(iM) + Gsqrt_P(:) = Gsqrt(iP) + GsqrtV_M(:) = Gsqrt_M(:) + GsqrtV_P(:) = Gsqrt_P(:) + + G13_M(:) = G13(iM) + G13_P(:) = G13(iP) + G23_M(:) = G23(iM) + G23_P(:) = G23(iP) + + GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) + GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) + GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) + GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) + GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) + GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) + GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) + GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) + GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) + GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) + Phyd_M(:) = PRES_hyd(iM) + Phyd_P(:) = PRES_hyd(iP) + + Gnn_M(:) = abs( nx(:,ke) ) + abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_M(:)**2 + G13_M(:)**2 + G23_M(:)**2 ) * abs( nz(:,ke) ) + Gnn_P(:) = abs( nx(:,ke) ) + abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_P(:)**2 + G13_P(:)**2 + G23_P(:)**2 ) * abs( nz(:,ke) ) + + GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) + GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) + + GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) + GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) + + VelM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( ( GsqrtMOMZ_M(:) / GsqrtV_M(:) & + + G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) ) & + ) / GsqrtDensM(:) + VelP(:) = ( GsqrtMOMX_P(:) * nx(:,ke) + GsqrtMOMY_P(:) * ny(:,ke) & + + ( ( GsqrtMOMZ_P(:) / GsqrtV_P(:) & + + G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & + ) / GsqrtDensP(:) + + ! Tentative treatment + where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) + VelP(:) = - VelM(:) + GsqrtMOMZ_P(:) = - GsqrtMOMZ_M(:) - 2.0_RP * ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) + end where + + dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & + - Phyd_M(:) + dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & + - Phyd_P(:) + + alpha(:) = max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & + sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) + + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & + ( GsqrtDensP(:) * VelP(:) - GsqrtDensM(:) * VelM(:) ) & + - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) + + del_flux(:,ke,VARS_MOMX_ID ) = 0.5_RP * ( & + ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke)) * dpresP(:) & + - Gsqrt_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) + + del_flux(:,ke,VARS_MOMY_ID ) = 0.5_RP * ( & + ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke)) * dpresP(:) & + - Gsqrt_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) + + del_flux(:,ke,VARS_MOMZ_ID ) = 0.5_RP * ( & + ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * dpresP(:) / GsqrtV_P(:) & + - Gsqrt_M(:) * dpresM(:) / GsqrtV_M(:) ) * nz(:,ke) & + - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) + + del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & + ( GsqrtRhotP(:) * VelP(:) - GsqrtRhotM(:) * VelM(:) ) & + - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( & + GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) + + del_flux_hyd(:,ke,2) = 0.5_RP * ( & + GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc( & + del_flux, del_flux_hyd, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + Gsqrt, G11, G12, G22, GsqrtH, G13, G23, nx, ny, nz, & ! (in) + vmapM, vmapP, iM2Dto3D, lmesh, elem, lmesh2D, elem2D ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: iM2Dto3D(elem%NfpTot) + + integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) + integer :: ke2D + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) + real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) + real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) + real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) + real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) + real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) + real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) + real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) + real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) + real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) + real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) + real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) + real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) + real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) + real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) + real(RP) :: Gxz_M(elem%NfpTot), Gxz_P(elem%NfpTot) + real(RP) :: Gyz_M(elem%NfpTot), Gyz_P(elem%NfpTot) + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + !------------------------------------------------------------------------ + + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( & + !$omp ke, iM, iP, ke2d, & + !$omp alpha, VelM, VelP, & + !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & + !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & + !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & + !$omp Phyd_M, Phyd_P, & + !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & + !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + ke2D = lmesh%EMap3Dto2D(ke) + + Gsqrt_M(:) = Gsqrt(iM) + Gsqrt_P(:) = Gsqrt(iP) + GsqrtV_M(:) = Gsqrt_M(:) / GsqrtH(iM2Dto3D(:),ke2D) + GsqrtV_P(:) = Gsqrt_P(:) / GsqrtH(iM2Dto3D(:),ke2D) + + G13_M(:) = G13(iM) + G13_P(:) = G13(iP) + G23_M(:) = G23(iM) + G23_P(:) = G23(iP) + + GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) + GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) + GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) + GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) + GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) + GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) + GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) + GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) + GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) + GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) + Phyd_M(:) = PRES_hyd(iM) + Phyd_P(:) = PRES_hyd(iP) + + Gxz_M(:) = G11(iM2Dto3D(:),ke2D) * G13_M(:) + G12(iM2Dto3D(:),ke2D) * G23_M(:) + Gxz_P(:) = G11(iM2Dto3D(:),ke2D) * G13_P(:) + G12(iM2Dto3D(:),ke2D) * G23_P(:) + + Gyz_M(:) = G12(iM2Dto3D(:),ke2D) * G13_M(:) + G22(iM2Dto3D(:),ke2D) * G23_M(:) + Gyz_P(:) = G12(iM2Dto3D(:),ke2D) * G13_P(:) + G22(iM2Dto3D(:),ke2D) * G23_P(:) + + G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) + G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) + + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_M(:)**2 + G13_M(:) * Gxz_M(:) + G23_M(:) * Gyz_M(:) ) * abs( nz(:,ke) ) + Gnn_P(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_P(:)**2 + G13_P(:) * Gxz_P(:) + G23_P(:) * Gyz_P(:) ) * abs( nz(:,ke) ) + + GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) + GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) + + GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) + GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) + + VelM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( ( GsqrtMOMZ_M(:) / GsqrtV_M(:) & + + G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) ) & + ) / GsqrtDensM(:) + VelP(:) = ( GsqrtMOMX_P(:) * nx(:,ke) + GsqrtMOMY_P(:) * ny(:,ke) & + + ( ( GsqrtMOMZ_P(:) / GsqrtV_P(:) & + + G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & + ) / GsqrtDensP(:) + + ! Tentative treatment + where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) + VelP(:) = - VelM(:) + GsqrtMOMZ_P(:) = - GsqrtMOMZ_M(:) - 2.0_RP * ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) + end where + + dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & + - Phyd_M(:) + dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & + - Phyd_P(:) + + alpha(:) = max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & + sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) + + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & + ( GsqrtDensP(:) * VelP(:) - GsqrtDensM(:) * VelM(:) ) & + - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) + + del_flux(:,ke,VARS_MOMX_ID ) = 0.5_RP * ( & + ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( G1n_M(:) + Gxz_P(:) * nz(:,ke)) * dpresP(:) & + - Gsqrt_M(:) * ( G1n_M(:) + Gxz_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) + + del_flux(:,ke,VARS_MOMY_ID ) = 0.5_RP * ( & + ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( G2n_M(:) + Gyz_P(:) * nz(:,ke) ) * dpresP(:) & + - Gsqrt_M(:) * ( G2n_M(:) + Gyz_M(:) * nz(:,ke) ) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) + + del_flux(:,ke,VARS_MOMZ_ID ) = 0.5_RP * ( & + ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * dpresP(:) / GsqrtV_P(:) & + - Gsqrt_M(:) * dpresM(:) / GsqrtV_M(:) ) * nz(:,ke) & + - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) + + del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & + ( GsqrtRhotP(:) * VelP(:) - GsqrtRhotM(:) * VelM(:) ) & + - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( & + GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) + + del_flux_hyd(:,ke,2) = 0.5_RP * ( & + GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc + +end module scale_atm_dyn_dgm_nonhydro3d_heve_numflux diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 index 6a954baa..47170e46 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 @@ -35,6 +35,12 @@ module scale_atm_dyn_dgm_nonhydro3d_hevi use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + atm_dyn_dgm_nonhydro3d_common_Init, & + atm_dyn_dgm_nonhydro3d_common_Final, & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM, & + IntrpMat_VPOrdM1, iM2Dto3D !----------------------------------------------------------------------------- implicit none @@ -59,44 +65,14 @@ module scale_atm_dyn_dgm_nonhydro3d_hevi ! !------------------- - integer, private, parameter :: DDENS_VID = 1 - integer, private, parameter :: MOMX_VID = 2 - integer, private, parameter :: MOMY_VID = 3 - integer, private, parameter :: MOMZ_VID = 4 - integer, private, parameter :: DRHOT_VID = 5 - integer, private, parameter :: PROG_VARS_NUM = 5 - - real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) - - private :: cal_del_flux_dyn - private :: vi_cal_del_flux_dyn - contains subroutine atm_dyn_dgm_nonhydro3d_hevi_Init( mesh ) implicit none class(MeshBase3D), intent(in) :: mesh - - integer :: p1, p2, p3, p_, p_intrp - type(ElementBase3D), pointer :: elem - real(RP) :: invV_POrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) - - real(RP), allocatable :: InvV_(:,:) !-------------------------------------------- - elem => mesh%refElem3D - allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) - - invV_POrdM1(:,:) = elem%invV - do p2=1, elem%Nnode_h1D - do p1=1, elem%Nnode_h1D - p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 - invV_POrdM1(p_,:) = 0.0_RP - end do - end do - IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_POrdM1) - - !--- + call atm_dyn_dgm_nonhydro3d_common_Init( mesh ) return end subroutine atm_dyn_dgm_nonhydro3d_hevi_Init @@ -105,7 +81,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_Final() implicit none !-------------------------------------------- - deallocate( IntrpMat_VPOrdM1 ) + call atm_dyn_dgm_nonhydro3d_common_Final() return end subroutine atm_dyn_dgm_nonhydro3d_hevi_Final @@ -118,6 +94,9 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + use scale_atm_dyn_dgm_nonhydro3d_hevi_numflux, only: & + atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc + use scale_atm_dyn_dgm_spongelayer, only: & atm_dyn_dgm_spongelayer_add_tend @@ -147,107 +126,146 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP) :: dens_(elem%Np), RHOT_hyd(elem%Np), RHOT_(elem%Np) - real(RP) :: pres_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), pot_(elem%Np) + real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP) :: DPRES_(elem%Np) + real(RP) :: RHOT_(elem%Np) + real(RP) :: rdens_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), wt_(elem%Np) + real(RP) :: GsqrtV(elem%Np), RGsqrtV(elem%Np) real(RP) :: Cori(elem%Np) - real(RP) :: tmp(elem%Np) integer :: ke, ke2d - real(RP) :: gamm, rgamm + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR !------------------------------------------------------------------------ call PROF_rapstart( 'cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, & ! (out) + call atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc( & + del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + lmesh%Gsqrt, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) lmesh%vmapM, lmesh%vmapP, & ! (in) - lmesh, elem ) ! (in) + lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend( 'cal_dyn_tend_bndflux', 3) !----- call PROF_rapstart( 'cal_dyn_tend_interior', 3) gamm = CPDry / CvDry rgamm = CvDry / CpDry - - !$omp parallel do private( & - !$omp RHOT_hyd, RHOT_, pres_, dens_, u_, v_, w_, pot_, ke2d, Cori, & + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( ke2d, Cori, & + !$omp RHOT_, DPRES_, rdens_, u_, v_, w_, wt_, & + !$omp GradPhyd_x, GradPhyd_y, & + !$omp GsqrtV, RGsqrtV, & !$omp Fx, Fy, Fz, LiftDelFlx ) do ke = lmesh%NeS, lmesh%NeE !-- - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**rgamm + ke2d = lmesh%EMap3Dto2D(ke) + Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) - RHOT_(:) = RHOT_hyd(:) + DRHOT_(:,ke) - pres_(:) = PRES_hyd(:,ke) * (1.0_RP + DRHOT_(:,ke)/RHOT_hyd(:))**gamm - dens_(:) = DDENS_(:,ke) + DENS_hyd(:,ke) + GsqrtV(:) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2d) + RGsqrtV(:) = 1.0_RP / GsqrtV(:) - u_ (:) = MOMX_(:,ke) / dens_(:) - v_ (:) = MOMY_(:,ke) / dens_(:) - w_ (:) = MOMZ_(:,ke) / dens_(:) - pot_(:) = RHOT_(:) / dens_(:) + !-- + RHOT_(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT_(:,ke) + DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & + - PRES_hyd(:,ke) - ke2d = lmesh%EMap3Dto2D(ke) - Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) + rdens_(:) = 1.0_RP / (DDENS_(:,ke) + DENS_hyd(:,ke)) + u_ (:) = MOMX_(:,ke) * rdens_(:) + v_ (:) = MOMY_(:,ke) * rdens_(:) + w_ (:) = MOMZ_(:,ke) * rdens_(:) + wt_(:) = w_(:) * RGsqrtV(:) + lmesh%GI3(:,ke,1) * u_(:) + lmesh%GI3(:,ke,2) * v_(:) + !-- Gradient hydrostatic pressure + + call sparsemat_matmul(Dx, GsqrtV(:) * PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,1) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + + call sparsemat_matmul(Dy, GsqrtV(:) * PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,2) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + !-- DENS - call sparsemat_matmul(Dx, MOMX_(:,ke), Fx) - call sparsemat_matmul(Dy, MOMY_(:,ke), Fy) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DDENS_VID), LiftDelFlx) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * MOMX_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * MOMY_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) & + * ( wt_(:) - w_(:) * RGsqrtV(:) ), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + LiftDelFlx(:) ) + lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- MOMX - call sparsemat_matmul(Dx, u_(:) * MOMX_(:,ke) + pres_(:), Fx) - call sparsemat_matmul(Dy, v_(:) * MOMX_(:,ke) , Fy) - call sparsemat_matmul(Dz, w_(:) * MOMX_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + DPRES_(:) ), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMX_(:,ke) , Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + lmesh%GI3(:,ke,1) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) - MOMX_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) & - - Cori(:) * MOMY_(:,ke) & - ) + MOMX_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_x(:) * RGsqrtV(:) & + + Cori(:) * MOMY_(:,ke) !-- MOMY - call sparsemat_matmul(Dx, u_(:) * MOMY_(:,ke) , Fx) - call sparsemat_matmul(Dy, v_(:) * MOMY_(:,ke) + pres_(:), Fy) - call sparsemat_matmul(Dz, w_(:) * MOMY_(:,ke) , Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMY_(:,ke) , Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + DPRES_(:) ), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & + + lmesh%GI3(:,ke,2) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) - MOMY_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) & - + Cori(:) * MOMX_(:,ke) & - ) + MOMY_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_y(:) * RGsqrtV(:) & + - Cori(:) * MOMX_(:,ke) !-- MOMZ - call sparsemat_matmul(Dx, u_(:) * MOMZ_(:,ke), Fx) - call sparsemat_matmul(Dy, v_(:) * MOMZ_(:,ke), Fy) - call sparsemat_matmul(Dz, w_(:) * MOMZ_(:,ke), Fz) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMZ_(:,ke), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMZ_(:,ke), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * wt_(:) * MOMZ_(:,ke), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) - MOMZ_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + lmesh%Escale(:,ke,3,3) * Fz(:) & - + LiftDelFlx(:) ) + MOMZ_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) !-- RHOT - call sparsemat_matmul(Dx, pot_(:) * MOMX_(:,ke), Fx) - call sparsemat_matmul(Dy, pot_(:) * MOMY_(:,ke), Fy) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DRHOT_VID), LiftDelFlx) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_ (:) * RHOT_(:), Fx) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_ (:) * RHOT_(:), Fy) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) - w_(:) * RGsqrtV(:) ) * RHOT_(:), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,RHOT_VID), LiftDelFlx) - RHOT_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx(:) & - + lmesh%Escale(:,ke,2,2) * Fy(:) & - + LiftDelFlx(:) ) + RHOT_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) end do call PROF_rapend( 'cal_dyn_tend_interior', 3) @@ -266,94 +284,6 @@ end subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend !------ -!OCL SERIAL - subroutine cal_del_flux_dyn( del_flux, & ! (out) - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) - nx, ny, nz, vmapM, vmapP, lmesh, elem ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%Ne,PROG_VARS_NUM) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) - real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) - integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) - integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) - - integer :: i, iP, iM - real(RP) :: VelP, VelM, MOMZ_P, alpha, swV - real(RP) :: presM, presP, dpresM, dpresP, densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P - real(RP) :: gamm, rgamm - !------------------------------------------------------------------------ - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - !$omp parallel do private( iM, iP, alpha, swV, & - !$omp VelP, VelM, MOMZ_P, presM, presP, dpresM, dpresP, & - !$omp densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P ) - do i=1, elem%NfpTot*lmesh%Ne - iM = vmapM(i); iP = vmapP(i) - - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm - - rhotM = rhot_hyd_M + DRHOT_(iM) - presM = PRES_hyd(iM) * (1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - dpresM = presM - PRES_hyd(iM)*abs(nz(i)) - - rhotP = rhot_hyd_P + DRHOT_(iP) - presP = PRES_hyd(iP) * (1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - dpresP = presP - PRES_hyd(iP)*abs(nz(i)) - - densM = DDENS_(iM) + DENS_hyd(iM) - densP = DDENS_(iP) + DENS_hyd(iP) - - swV = 1.0_RP - nz(i)**2 - VelM = (MOMX_(iM)*nx(i) + MOMY_(iM)*ny(i) + MOMZ_(iM)*nz(i))/densM - VelP = (MOMX_(iP)*nx(i) + MOMY_(iP)*ny(i) + MOMZ_(iP)*nz(i))/densP - MOMZ_P = MOMZ_(iP) - - alpha = swV*max( sqrt(gamm * presM / densM) + abs(VelM), & - sqrt(gamm * presP / densP) + abs(VelP) ) - - del_flux(i,DDENS_VID) = 0.5_RP*( & - (MOMX_(iP) - MOMX_(iM))*nx(i) & - + (MOMY_(iP) - MOMY_(iM))*ny(i) & - - alpha * (DDENS_(iP) - DDENS_(iM)) ) - - del_flux(i,MOMX_VID) = 0.5_RP*( & - ( MOMX_(iP)*VelP - MOMX_(iM)*VelM ) & - + ( dpresP - dpresM )*nx(i) & - - alpha * (MOMX_(iP) - MOMX_(iM)) ) - - del_flux(i,MOMY_VID) = 0.5_RP*( & - ( MOMY_(iP)*VelP - MOMY_(iM)*VelM ) & - + ( dpresP - dpresM )*ny(i) & - - alpha * (MOMY_(iP) - MOMY_(iM)) ) - - del_flux(i,MOMZ_VID) = 0.5_RP*( & - ( MOMZ_P*VelP - MOMZ_(iM)*VelM ) & - - alpha * (MOMZ_(iP) - MOMZ_(iM)) ) - - del_flux(i,DRHOT_VID) = 0.5_RP*( & - swV*( rhotP*VelP - rhotM*VelM ) & - - alpha * (DRHOT_(iP) - DRHOT_(iM)) ) - - end do - - return - end subroutine cal_del_flux_dyn - !OCL SERIAL subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) @@ -363,6 +293,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & impl_fac, dt, & ! (in) lmesh, elem, lmesh2D, elem2D ) ! (in) + use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + implicit none class(LocalMesh3D), intent(in) :: lmesh @@ -394,22 +329,25 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: alph(elem%NfpTot,lmesh%NeZ) real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) + real(RP) :: GnnM_z(elem%Np,lmesh%NeZ) + real(RP) :: G13_z(elem%Np,lmesh%NeZ) + real(RP) :: G23_z(elem%Np,lmesh%NeZ) + real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ) real(RP) :: nz(elem%NfpTot,lmesh%NeZ) integer :: vmapM(elem%NfpTot,lmesh%NeZ) integer :: vmapP(elem%NfpTot,lmesh%NeZ) - integer :: ke_x, ke_y, ke_z, ke, p, v + integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v integer :: itr_lin, itr_nlin - integer :: f, vs, ve, kl, ku, nz_1D + integer :: kl, ku, nz_1D integer :: ij, info logical :: is_converged - real(RP), allocatable :: PmatBnd(:,:,:) !------------------------------------------------------------------------ - call PROF_rapstart( 'hevi_cal_vi_prep', 3) @@ -418,34 +356,9 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & ku = kl allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) - !$omp parallel private(f, vs, ve) - !$omp do - do ke_z=1, lmesh%NeZ - do f=1, elem%Nfaces_h - vs = 1 + (f-1)*elem%Nfp_h - ve = vs + elem%Nfp_h - 1 - vmapM(vs:ve,ke_z) = elem%Fmask_h(:,f) + (ke_z-1)*elem%Np - end do - do f=1, elem%Nfaces_v - vs = elem%Nfp_h*elem%Nfaces_h + 1 + (f-1)*elem%Nfp_v - ve = vs + elem%Nfp_v - 1 - vmapM(vs:ve,ke_z) = elem%Fmask_v(:,f) + (ke_z-1)*elem%Np - end do - vmapP(:,ke_z) = vmapM(:,ke_z) - end do - !$omp do - do ke_z=1, lmesh%NeZ - vs = elem%Nfp_h*elem%Nfaces_h + 1 - ve = vs + elem%Nfp_v - 1 - if (ke_z > 1) & - vmapP(vs:ve,ke_z) = elem%Fmask_v(:,2) + (ke_z-2)*elem%Np - - vs = elem%Nfp_h*elem%Nfaces_h + elem%Nfp_v + 1 - ve = vs + elem%Nfp_v - 1 - if (ke_z < lmesh%NeZ) & - vmapP(vs:ve,ke_z) = elem%Fmask_v(:,1) + ke_z*elem%Np - end do - !$omp end parallel + call vi_gen_vmap( vmapM, vmapP, & ! (out) + lmesh, elem ) ! (in) + call PROF_rapend( 'hevi_cal_vi_prep', 3) do ke_y=1, lmesh%NeY @@ -453,21 +366,29 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & call PROF_rapstart( 'hevi_cal_vi_get_var', 3) - !$omp parallel do private(ke) + !$omp parallel do private( ke, ke2D ) do ke_z=1, lmesh%NeZ ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2D = lmesh%EMap3Dto2D(ke) - PROG_VARS(:,DDENS_VID,ke_z) = DDENS_(:,ke) + PROG_VARS(:,DENS_VID,ke_z) = DDENS_(:,ke) PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) - PROG_VARS(:,DRHOT_VID,ke_z) = DRHOT_(:,ke) + PROG_VARS(:,RHOT_VID,ke_z) = DRHOT_(:,ke) DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) - PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) + PROG_VARS0 (:,:,ke_z) = PROG_VARS(:,:,ke_z) PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) + nz(:,ke_z) = lmesh%normal_fn(:,ke,3) + G13_z(:,ke_z) = lmesh%GI3(:,ke,1) + G23_z(:,ke_z) = lmesh%GI3(:,ke,2) + GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) + + GnnM_z(:,ke_z) = & + 1.0_RP / GsqrtV_z(:,ke_z)**2 + G13_z(:,ke_z)**2 + G23_z(:,ke_z)**2 end do call PROF_rapend( 'hevi_cal_vi_get_var', 3) @@ -478,9 +399,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & ! dG/dq^n+1 del[q] = - G(q^n*) do itr_nlin = 1, 1 - call vi_eval_Ax( Ax(:,:,:), & ! (out) + call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -495,7 +417,8 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & call vi_construct_matbnd( PmatBnd, & ! (out) kl, ku, nz_1D, & ! (in) PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + G13_z, G23_z, GsqrtV_z, alph, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -539,9 +462,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & tend(:,:,ke_z) = (- PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z))/impl_fac end do else - call vi_eval_Ax( tend(:,:,:), & ! (out) + call vi_eval_Ax( tend(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -551,11 +475,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & !$omp parallel do private(ke) do ke_z=1, lmesh%NeZ ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - DENS_dt(:,ke) = - tend(:,DDENS_VID,ke_z) - MOMX_dt(:,ke) = - tend(:,MOMX_VID ,ke_z) - MOMY_dt(:,ke) = - tend(:,MOMY_VID ,ke_z) - MOMZ_dt(:,ke) = - tend(:,MOMZ_VID ,ke_z) - RHOT_dt(:,ke) = - tend(:,DRHOT_VID,ke_z) + DENS_dt(:,ke) = - tend(:,DENS_VID,ke_z) + MOMX_dt(:,ke) = - tend(:,MOMX_VID,ke_z) + MOMY_dt(:,ke) = - tend(:,MOMY_VID,ke_z) + MOMZ_dt(:,ke) = - tend(:,MOMZ_VID,ke_z) + RHOT_dt(:,ke) = - tend(:,RHOT_VID,ke_z) end do call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) end do @@ -564,458 +488,4 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & return end subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi - !------------------------------------------------ - -!OCL SERIAL - subroutine vi_eval_Ax( Ax, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - Dz, Lift, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, cal_tend_flag ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) - class(SparseMat), intent(in) :: Dz, Lift - logical, intent(in) :: modalFilterFlag - real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) - real(RP), intent(in) :: impl_fac - real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - logical, intent(in) :: cal_tend_flag - - real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) - real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) - real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) - real(RP) :: DPRES(elem%Np) - real(RP) :: tmpV1D(elem%Nnode_v) - integer :: ke_z - integer :: ke - integer :: v - integer :: ij - real(RP) :: gamm, rgamm - !-------------------------------------------------------- - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - call vi_cal_del_flux_dyn( del_flux, & ! (out) - PROG_VARS(:,DDENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) - PROG_VARS(:,MOMY_VID ,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) - PROG_VARS(:,DRHOT_VID,:), & ! (in) - PROG_VARS0(:,DDENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) - PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) - PROG_VARS0(:,DRHOT_VID,:), & ! (in) - DENS_hyd, PRES_hyd, nz, vmapM, vmapP, & ! (in) - lmesh, elem ) ! (in) - - !$omp parallel do private( & - !$omp ke, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & - !$omp v, ij, tmpV1D & - !$omp ) - do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm - - DPRES(:) = PRES_hyd(:,ke_z) * ((1.0_RP + PROG_VARS(:,DRHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP) - POT(:) = (RHOT_hyd(:) + PROG_VARS(:,DRHOT_VID,ke_z))/(DENS_hyd(:,ke_z) + PROG_VARS(:,DDENS_VID,ke_z)) - - !- DENS - call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DDENS_VID), LiftDelFlx) - Ax(:,DDENS_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) - - !- MOMX - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) - Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) - - !-MOMY - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) - Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) - - !-MOMZ - call sparsemat_matmul(Dz, DPRES(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) - Ax(:,MOMZ_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) & - + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DDENS_VID,ke_z)) - - !-RHOT - call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DRHOT_VID), LiftDelFlx) - Ax(:,DRHOT_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) - - !-- Modal filtering in the vertical direction - if ( modalFilterFlag ) then - do v=1, PROG_VARS_NUM - do ij=1, elem%Nnode_h1D**2 - Ax(elem%Colmask(:,ij),v,ke_z) = Ax(elem%Colmask(:,ij),v,ke_z) & - - matmul(VModalFilter, PROG_VARS(elem%Colmask(:,ij),v,ke_z) ) / dt - end do - end do - end if - - !-- - if ( .not. cal_tend_flag ) then - Ax(:,:,ke_z) = PROG_VARS(:,:,ke_z) + impl_fac * Ax(:,:,ke_z) - end if - - end do - - return - end subroutine vi_eval_Ax - -!OCL SERIAL - subroutine vi_cal_del_flux_dyn( del_flux, & ! (out) - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) - DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) - DENS_hyd, PRES_hyd, nz, vmapM, vmapP, lmesh, elem ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DDENS0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) - - integer :: i, p, ke_z, iP, iM - real(RP) :: alpha0, swV - real(RP) :: MOMZ_P - real(RP) :: rhot_hyd_M, rhot_hyd_P - real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP - real(RP) :: pres0M, pres0P, dens0M, dens0P - real(RP) :: gamm, rgamm - !------------------------------------------------------------------------ - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - !$omp parallel do private( p, i, iM, iP, & - !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & - !$omp dpresM, dpresP, MOMZ_P, & - !$omp dens0M, dens0P, pres0M, pres0P, & - !$omp swV, alpha0 ) - do ke_z=1, lmesh%NeZ - do p=1, elem%NfpTot - i = p + (ke_z-1)*elem%NfpTot - iM = vmapM(i); iP = vmapP(i) - - !- - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm - - densM = DENS_hyd(iM) + DDENS_(iM) - densP = DENS_hyd(iP) + DDENS_(iP) - - pottM = (rhot_hyd_M + DRHOT_(iM)) / densM - pottP = (rhot_hyd_P + DRHOT_(iP)) / densP - - dpresM = PRES_hyd(iM) * ((1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - 1.0_RP) - dpresP = PRES_hyd(iP) * ((1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - 1.0_RP) - - !- - dens0M = DENS_hyd(iM) + DDENS0_(iM) - dens0P = DENS_hyd(iP) + DDENS0_(iP) - - pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm - pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm - - swV = nz(i)**2 - alpha0 = swV * max( abs(MOMZ0_(iM)/dens0M) + sqrt(gamm * pres0M/dens0M), & - abs(MOMZ0_(iP)/dens0P) + sqrt(gamm * pres0P/dens0P) ) - - if (iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ)) then - MOMZ_P = - MOMZ_(iM) - alpha0 = 0.0_RP - else - MOMZ_P = MOMZ_(iP) - end if - - del_flux(i,DDENS_VID) = 0.5_RP * ( & - + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & - - alpha0 * ( DDENS_(iP) - DDENS_(iM) ) ) - - del_flux(i,MOMX_VID) = 0.5_RP * ( & - - alpha0 * ( MOMX_(iP) - MOMX_(iM) ) ) - - del_flux(i,MOMY_VID) = 0.5_RP * ( & - - alpha0 * ( MOMY_(iP) - MOMY_(iM) ) ) - - del_flux(i,MOMZ_VID) = 0.5_RP * ( & - + ( dpresP - dpresM ) * nz(i) & - - alpha0 * ( MOMZ_P - MOMZ_(iM) ) ) - - del_flux(i,DRHOT_VID) = 0.5_RP * ( & - + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & - - alpha0 * ( DRHOT_(iP) - DRHOT_(iM) ) ) - end do - end do - - return - end subroutine vi_cal_del_flux_dyn - -!OCL SERIAL - subroutine vi_construct_matbnd( PmatBnd, & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - Dz, Lift, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - integer, intent(in) :: kl, ku, nz_1D - real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) - class(SparseMat), intent(in) :: Dz, Lift - logical, intent(in) :: modalFilterFlag - real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) - real(RP), intent(in) :: impl_fac - real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - - real(RP) :: RHOT_hyd(elem%Nnode_v) - real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: Cs0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - integer :: ke_z, ke_z2 - integer :: v, ke, p, f1, fp, FmV - real(RP) :: gamm, rgamm - real(RP) :: fac_dz_p(elem%Nnode_v) - real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - real(RP) :: PmatL(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - real(RP) :: PmatU(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - integer :: Colmask(elem%Nnode_v) - real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) - real(RP) :: Dd(elem%Nnode_v) - real(RP) :: tmp1 - real(RP) :: alphaM, alphaP - real(RP) :: fac - - integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 - logical :: bc_flag - logical :: eval_flag(PROG_VARS_NUM,PROG_VARS_NUM) - !-------------------------------------------------------- - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - eval_flag(:,:) = .false. - do v=1, PROG_VARS_NUM - eval_flag(v,v) = .true. - end do - eval_flag(DDENS_VID,MOMZ_VID) = .true. - eval_flag(MOMZ_VID,DDENS_VID) = .true. - eval_flag(MOMZ_VID,DRHOT_VID) = .true. - eval_flag(DRHOT_VID,MOMZ_VID) = .true. - eval_flag(DRHOT_VID,DDENS_VID) = .true. - - Id(:,:) = 0.0_RP - do p=1, elem%Nnode_v - Id(p,p) = 1.0_RP - end do - - !$omp parallel private(RHOT_hyd, Colmask) - !$omp do - do v=1, PROG_VARS_NUM - PmatD(:,:,:,v) = 0.0_RP - PmatL(:,:,:,v) = 0.0_RP - PmatU(:,:,:,v) = 0.0_RP - end do - !$omp do - do ij=1, elem%Nnode_h1D**2 - PmatBnd(:,:,:,:,ij) = 0.0_RP - end do - !$omp do collapse(2) - do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - Colmask(:) = elem%Colmask(:,ij) - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm - - DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**(gamm-1) - - DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DDENS_VID,ke_z) - POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) - W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) - Cs0(:,ke_z,ij) = sqrt( gamm * PRES_hyd(Colmask(:),ke_z) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**gamm / DENS0(:,ke_z,ij) ) - end do - end do - !$omp end parallel - - !$omp parallel do private(ke_z, ke, ColMask, p, fp, v, f1, ke_z2, fac_dz_p, & - !$omp fac, tmp1, alphaM, alphaP, FmV, & - !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & - !$omp Dd ) & - !$omp firstprivate(PmatD, PmatL, PmatU) - do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - Colmask(:) = elem%Colmask(:,ij) - - !----- - do p=1, elem%Nnode_v - fac_dz_p(:) = impl_fac * lmesh%Escale(Colmask(:),ke,3,3) * elem%Dx3(Colmask(:),Colmask(p)) - if (modalFilterFlag) then - Dd(:) = Id(:,p) - VModalFilter(:,p) * impl_fac / dt - else - Dd(:) = Id(:,p) - end if - - ! DDENS - PmatD(:,p,DDENS_VID,DDENS_VID) = Dd(:) - PmatD(:,p,DDENS_VID,MOMZ_VID) = fac_dz_p(:) - - ! MOMX - PmatD(:,p,MOMX_VID,MOMX_VID) = Dd(:) - - ! MOMY - PmatD(:,p,MOMY_VID,MOMY_VID) = Dd(:) - - ! MOMZ - PmatD(:,p,MOMZ_VID,MOMZ_VID) = Dd(:) - PmatD(:,p,MOMZ_VID,DDENS_VID) = impl_fac * Grav * IntrpMat_VPOrdM1(Colmask(:),Colmask(p)) - PmatD(:,p,MOMZ_VID,DRHOT_VID) = fac_dz_p(:) * DPDRHOT0(p,ke_z,ij) - - !DRHOT - PmatD(:,p,DRHOT_VID,DDENS_VID) = - fac_dz_p(:) * POT0(p,ke_z,ij) * W0(p,ke_z,ij) - PmatD(:,p,DRHOT_VID,MOMZ_VID ) = fac_dz_p(:) * POT0(p,ke_z,ij) - PmatD(:,p,DRHOT_VID,DRHOT_VID) = Dd(:) + fac_dz_p(:) * W0(p,ke_z,ij) - end do - - do f1=1, 2 - if (f1==1) then - ke_z2 = max(ke_z-1,1) - pv1 = 1; pv2 = elem%Nnode_v - else - ke_z2 = min(ke_z+1,lmesh%NeZ) - pv1 = elem%Nnode_v; pv2 = 1 - end if - fac = 0.5_RP * impl_fac - if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then - bc_flag = .true. - pv2 = pv1 - else - bc_flag = .false. - end if - - FmV = elem%Fmask_v(ij,f1) - fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij - - !-- - alphaM = abs( W0(pv1,ke_z ,ij) ) + Cs0(pv1,ke_z ,ij) - alphaP = abs( W0(pv2,ke_z2,ij) ) + Cs0(pv2,ke_z2,ij) - - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * max(alphaM, alphaP) - if (bc_flag) then - !PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 - else - do v=1, PROG_VARS_NUM - PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 - if (f1 == 1) then - PmatL(pv1,pv2,v,v) = - tmp1 - else - PmatU(pv1,pv2,v,v) = - tmp1 - end if - end do - end if - - !-- - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * nz(fp,ke_z) - - if (bc_flag) then - PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - 2.0_RP * tmp1 - PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - 2.0_RP * tmp1 * W0(pv1,ke_z,ij) - else - PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - tmp1 - PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) = PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) - tmp1 * DPDRHOT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - tmp1 * POT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - tmp1 * W0(pv1,ke_z,ij) - - if (f1 == 1) then - PmatL(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 - PmatL(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) & - + tmp1 * W0(pv2,ke_z2,ij) - else - PmatU(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 - PmatU(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) & - + tmp1 * W0(pv2,ke_z2,ij) - end if - end if - end do - - do v2=1, PROG_VARS_NUM - do v1=1, PROG_VARS_NUM - if ( eval_flag(v1,v2) ) then - do pv2=1, elem%Nnode_v - g_kj = pv2 + (v2-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM - g_kjm1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z-2)*elem%Nnode_v*PROG_VARS_NUM - g_kjp1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z )*elem%Nnode_v*PROG_VARS_NUM - - do pv1=1, elem%Nnode_v - pb1 = pv1 + (v1-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM - if (ke_z > 1) then - PmatBnd(kl+ku+1+pb1-g_kjm1, pv2,v2,ke_z-1, ij) = PmatL(pv1,pv2,v1,v2) - end if - PmatBnd(kl+ku+1+pb1-g_kj, pv2,v2,ke_z, ij) = PmatD(pv1,pv2,v1,v2) - if (ke_z < lmesh%NeZ) then - PmatBnd(kl+ku+1+pb1-g_kjp1, pv2,v2,ke_z+1, ij) = PmatU(pv1,pv2,v1,v2) - end if - end do - end do - end if - end do - end do - end do - end do - - return - end subroutine vi_construct_matbnd - end module scale_atm_dyn_dgm_nonhydro3d_hevi diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 new file mode 100644 index 00000000..f6302665 --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 @@ -0,0 +1,597 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / Dynamics HEVI common +!! +!! @par Description +!! HEVI DGM scheme for Atmospheric dynamical process +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_nonhydro3d_hevi_common + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_modalfilter, only: ModalFilter + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap + public :: atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax + public :: atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + private :: vi_cal_del_flux_dyn + +contains + !------------------------------------------------ + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap( & + vmapM, vmapP, & ! (out) + lmesh, elem ) ! (in) + implicit none + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + integer, intent(out) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(out) :: vmapP(elem%NfpTot,lmesh%NeZ) + + integer :: ke_z + integer :: f + integer :: vs, ve + !------------------------------------------------------- + + !$omp parallel private(f, vs, ve) + !$omp do + do ke_z=1, lmesh%NeZ + do f=1, elem%Nfaces_h + vs = 1 + (f-1)*elem%Nfp_h + ve = vs + elem%Nfp_h - 1 + vmapM(vs:ve,ke_z) = elem%Fmask_h(:,f) + (ke_z-1)*elem%Np + end do + do f=1, elem%Nfaces_v + vs = elem%Nfp_h*elem%Nfaces_h + 1 + (f-1)*elem%Nfp_v + ve = vs + elem%Nfp_v - 1 + vmapM(vs:ve,ke_z) = elem%Fmask_v(:,f) + (ke_z-1)*elem%Np + end do + vmapP(:,ke_z) = vmapM(:,ke_z) + end do + !$omp do + do ke_z=1, lmesh%NeZ + vs = elem%Nfp_h*elem%Nfaces_h + 1 + ve = vs + elem%Nfp_v - 1 + if (ke_z > 1) & + vmapP(vs:ve,ke_z) = elem%Fmask_v(:,2) + (ke_z-2)*elem%Np + + vs = elem%Nfp_h*elem%Nfaces_h + elem%Nfp_v + 1 + ve = vs + elem%Nfp_v - 1 + if (ke_z < lmesh%NeZ) & + vmapP(vs:ve,ke_z) = elem%Fmask_v(:,1) + ke_z*elem%Np + end do + !$omp end parallel + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax( & + Ax, alph, & ! (out) + PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y, cal_tend_flag ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(out) :: alph(elem%NfpTot,lmesh%NeZ) + real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + class(SparseMat), intent(in) :: Dz, Lift + real(RP), intent(in) :: IntrpMat_VPOrdM1(elem%Np,elem%Np) + real(RP), intent(in) :: GnnM_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G13_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G23_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: GsqrtV_z(elem%Np,lmesh%NeZ) + logical, intent(in) :: modalFilterFlag + real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: ke_x, ke_y + logical, intent(in) :: cal_tend_flag + + real(RP) :: RGsqrtV(elem%Np) + real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) + real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) + real(RP) :: DPRES(elem%Np) + integer :: ke_z + integer :: ke, ke2d + integer :: v + integer :: ij + real(RP) :: gamm, rgamm + !-------------------------------------------------------- + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + call vi_cal_del_flux_dyn( del_flux, alph, & ! (out) + PROG_VARS(:,DENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) + PROG_VARS(:,MOMY_VID,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) + PROG_VARS(:,RHOT_VID,:), & ! (in) + PROG_VARS0(:,DENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) + PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) + PROG_VARS0(:,RHOT_VID,:), & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, nz, vmapM, vmapP, & ! (in) + lmesh, elem ) ! (in) + + !$omp parallel do private( & + !$omp ke, ke2d, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & + !$omp v, ij, RGsqrtV & + !$omp ) + do ke_z=1, lmesh%NeZ + ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2d = lmesh%EMap3Dto2D(ke) + + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm + + DPRES(:) = PRES_hyd(:,ke_z) * ( (1.0_RP + PROG_VARS(:,RHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP ) + POT(:) = ( RHOT_hyd(:) + PROG_VARS(:,RHOT_VID,ke_z) ) / ( DENS_hyd(:,ke_z) + PROG_VARS(:,DENS_VID,ke_z) ) + + RGsqrtV(:) = 1.0_RP / GsqrtV_z(:,ke_z) + + !- DENS + call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DENS_VID), LiftDelFlx) + Ax(:,DENS_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + + !- MOMX + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) + Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) + + !-MOMY + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) + Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) + + !-MOMZ + call sparsemat_matmul(Dz, DPRES(:), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) + Ax(:,MOMZ_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) & + + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DENS_VID,ke_z)) + + !-RHOT + call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,RHOT_VID), LiftDelFlx) + Ax(:,RHOT_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + + !-- Modal filtering in the vertical direction + if ( modalFilterFlag ) then + do v=1, PROG_VARS_NUM + do ij=1, elem%Nnode_h1D**2 + Ax(elem%Colmask(:,ij),v,ke_z) = Ax(elem%Colmask(:,ij),v,ke_z) & + - matmul(VModalFilter, PROG_VARS(elem%Colmask(:,ij),v,ke_z) ) / dt + end do + end do + end if + + !-- + if ( .not. cal_tend_flag ) then + Ax(:,:,ke_z) = PROG_VARS(:,:,ke_z) + impl_fac * Ax(:,:,ke_z) + end if + + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax + + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & + PmatBnd, & ! (out) + kl, ku, nz_1D, & ! (in) + PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) + G13, G23, GsqrtV, alph, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + integer, intent(in) :: kl, ku, nz_1D + real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G13(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G23(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: GsqrtV(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: alph(elem%NfpTot,lmesh%NeZ) + class(SparseMat), intent(in) :: Dz, Lift + real(RP), intent(in) :: IntrpMat_VPOrdM1(elem%Np,elem%Np) + logical, intent(in) :: modalFilterFlag + real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: ke_x, ke_y + + real(RP) :: RHOT_hyd(elem%Nnode_v) + real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + integer :: ke_z, ke_z2 + integer :: v, ke, p, f1, f2, fp, fp2, FmV + real(RP) :: gamm, rgamm + real(RP) :: fac_dz_p(elem%Nnode_v) + real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) + real(RP) :: PmatL(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) + real(RP) :: PmatU(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) + integer :: Colmask(elem%Nnode_v) + real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) + real(RP) :: Dd(elem%Nnode_v) + real(RP) :: tmp1 + real(RP) :: fac + + integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 + logical :: bc_flag + logical :: eval_flag(PROG_VARS_NUM,PROG_VARS_NUM) + !-------------------------------------------------------- + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + eval_flag(:,:) = .false. + do v=1, PROG_VARS_NUM + eval_flag(v,v) = .true. + end do + eval_flag(DENS_VID,MOMZ_VID ) = .true. + eval_flag(MOMZ_VID,DENS_VID ) = .true. + eval_flag(MOMZ_VID,RHOT_VID ) = .true. + eval_flag(RHOT_VID,MOMZ_VID ) = .true. + eval_flag(RHOT_VID,DENS_VID) = .true. + + Id(:,:) = 0.0_RP + do p=1, elem%Nnode_v + Id(p,p) = 1.0_RP + end do + + !$omp parallel private(RHOT_hyd, Colmask) + !$omp do + do v=1, PROG_VARS_NUM + PmatD(:,:,:,v) = 0.0_RP + PmatL(:,:,:,v) = 0.0_RP + PmatU(:,:,:,v) = 0.0_RP + end do + !$omp do + do ij=1, elem%Nnode_h1D**2 + PmatBnd(:,:,:,:,ij) = 0.0_RP + end do + !$omp do collapse(2) + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + Colmask(:) = elem%Colmask(:,ij) + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm + + DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & + * ( 1.0_RP + PROG_VARS0(Colmask(:),RHOT_VID,ke_z) / RHOT_hyd(:) )**(gamm-1) + + DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DENS_VID,ke_z) + POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),RHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) + W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) + end do + end do + !$omp end parallel + + !$omp parallel do private(ke_z, ke, ColMask, p, fp, fp2, v, f1, f2, ke_z2, fac_dz_p, & + !$omp fac, tmp1, FmV, & + !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & + !$omp Dd ) & + !$omp firstprivate(PmatD, PmatL, PmatU) + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + Colmask(:) = elem%Colmask(:,ij) + + !----- + do p=1, elem%Nnode_v + fac_dz_p(:) = impl_fac * lmesh%Escale(Colmask(:),ke,3,3) / GsqrtV(Colmask(:),ke_z) & + * elem%Dx3(Colmask(:),Colmask(p)) + + if (modalFilterFlag) then + Dd(:) = Id(:,p) - VModalFilter(:,p) * impl_fac / dt + else + Dd(:) = Id(:,p) + end if + + ! DDENS + PmatD(:,p,DENS_VID,DENS_VID) = Dd(:) + PmatD(:,p,DENS_VID,MOMZ_VID ) = fac_dz_p(:) + + ! MOMX + PmatD(:,p,MOMX_VID,MOMX_VID) = Dd(:) + + ! MOMY + PmatD(:,p,MOMY_VID,MOMY_VID) = Dd(:) + + ! MOMZ + PmatD(:,p,MOMZ_VID,MOMZ_VID ) = Dd(:) + PmatD(:,p,MOMZ_VID,DENS_VID) = impl_fac * Grav * IntrpMat_VPOrdM1(Colmask(:),Colmask(p)) + PmatD(:,p,MOMZ_VID,RHOT_VID) = fac_dz_p(:) * DPDRHOT0(p,ke_z,ij) + + !DRHOT + PmatD(:,p,RHOT_VID,DENS_VID) = - fac_dz_p(:) * POT0(p,ke_z,ij) * W0(p,ke_z,ij) + PmatD(:,p,RHOT_VID,MOMZ_VID ) = fac_dz_p(:) * POT0(p,ke_z,ij) + PmatD(:,p,RHOT_VID,RHOT_VID) = Dd(:) + fac_dz_p(:) * W0(p,ke_z,ij) + end do + + do f1=1, 2 + if (f1==1) then + ke_z2 = max(ke_z-1,1) + pv1 = 1; pv2 = elem%Nnode_v + f2 = 2 + else + ke_z2 = min(ke_z+1,lmesh%NeZ) + pv1 = elem%Nnode_v; pv2 = 1 + f2 = 1 + end if + fac = 0.5_RP * impl_fac / GsqrtV(Colmask(pv1),ke_z) + if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then + bc_flag = .true. + pv2 = pv1; f2 = f1 + else + bc_flag = .false. + end if + + FmV = elem%Fmask_v(ij,f1) + fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij + fp2 = elem%Nfp_h * elem%Nfaces_h + (f2-1)*elem%Nfp_v + ij + + !-- + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) & + * max( alph(fp,ke_z), alph(fp2,ke_z2) ) + if (bc_flag) then + PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 + else + do v=1, PROG_VARS_NUM + PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 + if (f1 == 1) then + PmatL(pv1,pv2,v,v) = - tmp1 + else + PmatU(pv1,pv2,v,v) = - tmp1 + end if + end do + end if + + !-- + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * nz(fp,ke_z) + + if (bc_flag) then + PmatD(pv1,pv1,DENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DENS_VID,MOMZ_VID ) - 2.0_RP * tmp1 + PmatD(pv1,pv1,RHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,RHOT_VID,MOMZ_VID ) - 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID,DENS_VID) = PmatD(pv1,pv1,RHOT_VID,DENS_VID) + 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID,RHOT_VID) = PmatD(pv1,pv1,RHOT_VID,RHOT_VID) - 2.0_RP * tmp1 * W0(pv1,ke_z,ij) + else + PmatD(pv1,pv1,DENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DENS_VID,MOMZ_VID ) - tmp1 + PmatD(pv1,pv1,MOMZ_VID ,RHOT_VID) = PmatD(pv1,pv1,MOMZ_VID ,RHOT_VID) - tmp1 * DPDRHOT0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,RHOT_VID,MOMZ_VID ) - tmp1 * POT0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID,DENS_VID) = PmatD(pv1,pv1,RHOT_VID,DENS_VID) + tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID,RHOT_VID) = PmatD(pv1,pv1,RHOT_VID,RHOT_VID) - tmp1 * W0(pv1,ke_z,ij) + + if (f1 == 1) then + PmatL(pv1,pv2,DENS_VID,MOMZ_VID ) = + tmp1 + PmatL(pv1,pv2,MOMZ_VID,RHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) + PmatL(pv1,pv2,RHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) + PmatL(pv1,pv2,RHOT_VID,DENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) + PmatL(pv1,pv2,RHOT_VID,RHOT_VID) = PmatL(pv1,pv2,RHOT_VID,RHOT_VID) & + + tmp1 * W0(pv2,ke_z2,ij) + else + PmatU(pv1,pv2,DENS_VID,MOMZ_VID ) = + tmp1 + PmatU(pv1,pv2,MOMZ_VID,RHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) + PmatU(pv1,pv2,RHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) + PmatU(pv1,pv2,RHOT_VID,DENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) + PmatU(pv1,pv2,RHOT_VID,RHOT_VID) = PmatU(pv1,pv2,RHOT_VID,RHOT_VID) & + + tmp1 * W0(pv2,ke_z2,ij) + end if + end if + end do + + do v2=1, PROG_VARS_NUM + do v1=1, PROG_VARS_NUM + if ( eval_flag(v1,v2) ) then + do pv2=1, elem%Nnode_v + g_kj = pv2 + (v2-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM + g_kjm1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z-2)*elem%Nnode_v*PROG_VARS_NUM + g_kjp1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z )*elem%Nnode_v*PROG_VARS_NUM + + do pv1=1, elem%Nnode_v + pb1 = pv1 + (v1-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM + if (ke_z > 1) then + PmatBnd(kl+ku+1+pb1-g_kjm1, pv2,v2,ke_z-1, ij) = PmatL(pv1,pv2,v1,v2) + end if + PmatBnd(kl+ku+1+pb1-g_kj, pv2,v2,ke_z, ij) = PmatD(pv1,pv2,v1,v2) + if (ke_z < lmesh%NeZ) then + PmatBnd(kl+ku+1+pb1-g_kjp1, pv2,v2,ke_z+1, ij) = PmatU(pv1,pv2,v1,v2) + end if + end do + end do + end if + end do + end do + end do + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + +!-- private ---------------- + +!OCL SERIAL + subroutine vi_cal_del_flux_dyn( del_flux, alph, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + Gnn_, G13_, G23_, GsqrtV_, nz, vmapM, vmapP, lmesh, elem ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) + real(RP), intent(out) :: alph(elem%NfpTot*lmesh%NeZ) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DDENS0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMX0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMY0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: MOMZ0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: Gnn_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: G13_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: G23_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: GsqrtV_(elem%Np*lmesh%NeZ) + real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) + + integer :: i, p, ke_z, iP, iM + real(RP) :: MOMZ_P + real(RP) :: wt0M, wt0P + real(RP) :: rhot_hyd_M, rhot_hyd_P + real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP + real(RP) :: pres0M, pres0P, dens0M, dens0P + real(RP) :: gamm, rgamm + !------------------------------------------------------------------------ + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + !$omp parallel do private( p, i, iM, iP, & + !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & + !$omp dpresM, dpresP, MOMZ_P, wt0M, wt0P, & + !$omp dens0M, dens0P, pres0M, pres0P ) + do ke_z=1, lmesh%NeZ + do p=1, elem%NfpTot + i = p + (ke_z-1)*elem%NfpTot + iM = vmapM(i); iP = vmapP(i) + + !- + rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm + rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm + + densM = DENS_hyd(iM) + DDENS_(iM) + densP = DENS_hyd(iP) + DDENS_(iP) + + pottM = (rhot_hyd_M + DRHOT_(iM)) / densM + pottP = (rhot_hyd_P + DRHOT_(iP)) / densP + + dpresM = PRES_hyd(iM) * ( (1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - 1.0_RP ) + dpresP = PRES_hyd(iP) * ( (1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - 1.0_RP ) + + !- + dens0M = DENS_hyd(iM) + DDENS0_(iM) + dens0P = DENS_hyd(iP) + DDENS0_(iP) + + pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm + pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm + + wt0M = ( MOMZ0_(iM) / GsqrtV_(iM) + G13_(iM) * MOMX0_(iM) + G23_(iM) * MOMY0_(iM) ) / dens0M + wt0P = ( MOMZ0_(iP) / GsqrtV_(iP) + G13_(iP) * MOMX0_(iP) + G23_(iP) * MOMY0_(iP) ) / dens0P + + alph(i) = nz(i)**2 * max( abs( wt0M ) + sqrt( Gnn_(iM) * gamm * pres0M / dens0M ), & + abs( wt0P ) + sqrt( Gnn_(iP) * gamm * pres0P / dens0P ) ) + + !---- + if ( iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ) ) then + MOMZ_P = - GsqrtV_(iM) * ( dens0M * wt0M + G13_(iM) * MOMX0_(iM) + G23_(iM) * MOMY0_(iM) ) + !alph(i) = 0.0_RP + else + MOMZ_P = MOMZ0_(iP) + end if + + del_flux(i,DENS_VID) = 0.5_RP * ( & + + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & + - alph(i) * ( DDENS_(iP) - DDENS_(iM) ) ) + + del_flux(i,MOMX_VID) = 0.5_RP * ( & + - alph(i) * ( MOMX_(iP) - MOMX_(iM) ) ) + + del_flux(i,MOMY_VID) = 0.5_RP * ( & + - alph(i) * ( MOMY_(iP) - MOMY_(iM) ) ) + + del_flux(i,MOMZ_VID) = 0.5_RP * ( & + + ( dpresP - dpresM ) * nz(i) & + - alph(i) * ( MOMZ_P - MOMZ_(iM) ) ) + + del_flux(i,RHOT_VID) = 0.5_RP * ( & + + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & + - alph(i) * ( DRHOT_(iP) - DRHOT_(iM) ) ) + end do + end do + + return + end subroutine vi_cal_del_flux_dyn + +end module scale_atm_dyn_dgm_nonhydro3d_hevi_common diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 new file mode 100644 index 00000000..3690633c --- /dev/null +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 @@ -0,0 +1,417 @@ +!------------------------------------------------------------------------------- +!> module Atmosphere / Dynamics HEVI numerical flux +!! +!! @par Description +!! HEVE DGM scheme for Atmospheric dynamical process. +!! +!! @author Team SCALE +!< +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module scale_atm_dyn_dgm_nonhydro3d_hevi_numflux + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + use scale_prc + use scale_prof + use scale_const, only: & + GRAV => CONST_GRAV, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & + PRES00 => CONST_PRE00 + + use scale_sparsemat + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshField3D + use scale_meshfield_base, only: MeshField3D + + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedures + ! + public :: atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc + public :: atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalhvc + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures & variables + ! + !------------------- + + integer, private, parameter :: VARS_DDENS_ID = 1 + integer, private, parameter :: VARS_MOMX_ID = 2 + integer, private, parameter :: VARS_MOMY_ID = 3 + integer, private, parameter :: VARS_MOMZ_ID = 4 + integer, private, parameter :: VARS_DRHOT_ID = 5 + integer, private, parameter :: PROG_VARS_NUM = 5 + +contains + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc( & + del_flux, del_flux_hyd, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + Gsqrt, G13, G23, nx, ny, nz, & ! (in) + vmapM, vmapP, lmesh, elem, lmesh2D, elem2D ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + + integer :: ke, i, iP(elem%NfpTot), iM(elem%NfpTot) + integer :: ke2D + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: VelhP(elem%NfpTot), VelhM(elem%NfpTot) + real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) + real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) + real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) + real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) + real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) + real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) + real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) + real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) + real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) + real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) + real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) + real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) + real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) + real(RP) :: swV(elem%NfpTot) + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + !------------------------------------------------------------------------ + + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( & + !$omp ke, iM, iP, ke2d, & + !$omp alpha, VelM, VelP, VelhM, VelhP, & + !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & + !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & + !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & + !$omp Phyd_M, Phyd_P, & + !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & + !$omp swV ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + ke2D = lmesh%EMap3Dto2D(ke) + + Gsqrt_M(:) = Gsqrt(iM) + Gsqrt_P(:) = Gsqrt(iP) + GsqrtV_M(:) = Gsqrt_M(:) + GsqrtV_P(:) = Gsqrt_P(:) + + G13_M(:) = G13(iM) + G13_P(:) = G13(iP) + G23_M(:) = G23(iM) + G23_P(:) = G23(iP) + + GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) + GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) + GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) + GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) + GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) + GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) + GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) + GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) + GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) + GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) + Phyd_M(:) = PRES_hyd(iM) + Phyd_P(:) = PRES_hyd(iP) + swV(:) = 1.0_RP - nz(:,ke)**2 + + GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) + GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) + + GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) + GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) + + VelhM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) ) & + / GsqrtDensM(:) + VelhP(:) = ( GsqrtMOMX_P(:) * nx(:,ke) + GsqrtMOMY_P(:) * ny(:,ke) & + + ( G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & + / GsqrtDensP(:) + + VelM(:) = VelhM(:) + GsqrtMOMZ_M(:) / ( GsqrtV_M(:) * GsqrtDensM(:) ) * nz(:,ke) + VelP(:) = VelhP(:) + GsqrtMOMZ_P(:) / ( GsqrtV_P(:) * GsqrtDensP(:) ) * nz(:,ke) + + ! Tentative treatment + where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) + VelP(:) = - VelM(:) + end where + + dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & + - Phyd_M(:) + dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & + - Phyd_P(:) + + alpha(:) = swV(:) * max( sqrt( gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & + sqrt( gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) + + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & + ( GsqrtDensP(:) * VelhP(:) - GsqrtDensM(:) * VelhM(:) ) & + - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) + + del_flux(:,ke,VARS_MOMX_ID ) = 0.5_RP * ( & + ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke)) * dpresP(:) & + - Gsqrt_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) + + del_flux(:,ke,VARS_MOMY_ID ) = 0.5_RP * ( & + ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke)) * dpresP(:) & + - Gsqrt_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) + + del_flux(:,ke,VARS_MOMZ_ID ) = 0.5_RP * ( & + ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & + - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) + + del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & + ( GsqrtRhotP(:) * VelhP(:) - GsqrtRhotM(:) * VelhM(:) ) & + - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( & + GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) + + del_flux_hyd(:,ke,2) = 0.5_RP * ( & + GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalhvc( & + del_flux, del_flux_hyd, & ! (out) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + Gsqrt, G11, G12, G22, GsqrtH, G13, G23, nx, ny, nz, & ! (in) + vmapM, vmapP, iM2Dto3D, lmesh, elem, lmesh2D, elem2D ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(elementbase2D), intent(in) :: elem2D + real(RP), intent(out) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) + real(RP), intent(out) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G11(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G12(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G22(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) + real(RP), intent(in) :: nx(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: ny(elem%NfpTot,lmesh%Ne) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%Ne) + integer, intent(in) :: iM2Dto3D(elem%NfpTot) + + integer :: ke, iP(elem%NfpTot), iM(elem%NfpTot) + integer :: ke2D + real(RP) :: VelP(elem%NfpTot), VelM(elem%NfpTot), alpha(elem%NfpTot) + real(RP) :: VelhP(elem%NfpTot), VelhM(elem%NfpTot) + real(RP) :: dpresP(elem%NfpTot), dpresM(elem%NfpTot) + real(RP) :: GsqrtDensM(elem%NfpTot), GsqrtDensP(elem%NfpTot) + real(RP) :: GsqrtRhotM(elem%NfpTot), GsqrtRhotP(elem%NfpTot) + real(RP) :: GsqrtDDENS_P(elem%NfpTot), GsqrtDDENS_M(elem%NfpTot) + real(RP) :: GsqrtMOMX_P(elem%NfpTot), GsqrtMOMX_M(elem%NfpTot) + real(RP) :: GsqrtMOMY_P(elem%NfpTot), GsqrtMOMY_M(elem%NfpTot) + real(RP) :: GsqrtMOMZ_P(elem%NfpTot), GsqrtMOMZ_M(elem%NfpTot) + real(RP) :: GsqrtDRHOT_P(elem%NfpTot), GsqrtDRHOT_M(elem%NfpTot) + real(RP) :: Phyd_P(elem%NfpTot), Phyd_M(elem%NfpTot) + real(RP) :: Gsqrt_P(elem%NfpTot), Gsqrt_M(elem%NfpTot) + real(RP) :: GsqrtV_P(elem%NfpTot), GsqrtV_M(elem%NfpTot) + real(RP) :: G13_M(elem%NfpTot), G13_P(elem%NfpTot) + real(RP) :: G23_M(elem%NfpTot), G23_P(elem%NfpTot) + real(RP) :: G1n_M(elem%NfpTot), G2n_M(elem%NfpTot) + real(RP) :: Gnn_M(elem%NfpTot), Gnn_P(elem%NfpTot) + real(RP) :: Gxz_M(elem%NfpTot), Gxz_P(elem%NfpTot) + real(RP) :: Gyz_M(elem%NfpTot), Gyz_P(elem%NfpTot) + real(RP) :: swV(elem%NfpTot) + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR + !------------------------------------------------------------------------ + + gamm = CPDry / CvDry + rgamm = CvDry / CpDry + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( & + !$omp ke, iM, iP, ke2d, & + !$omp alpha, VelM, VelP, VelhM, VelhP, & + !$omp dpresM, dpresP, GsqrtDensM, GsqrtDensP, GsqrtRhotM, GsqrtRhotP, & + !$omp GsqrtMOMX_M, GsqrtMOMX_P, GsqrtMOMY_M, GsqrtMOMY_P, GsqrtMOMZ_M, GsqrtMOMZ_P, & + !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & + !$omp Phyd_M, Phyd_P, & + !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & + !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M, swV ) + do ke=lmesh%NeS, lmesh%NeE + iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) + ke2D = lmesh%EMap3Dto2D(ke) + + Gsqrt_M(:) = Gsqrt(iM) + Gsqrt_P(:) = Gsqrt(iP) + GsqrtV_M(:) = Gsqrt_M(:) / GsqrtH(iM2Dto3D(:),ke2D) + GsqrtV_P(:) = Gsqrt_P(:) / GsqrtH(iM2Dto3D(:),ke2D) + + G13_M(:) = G13(iM) + G13_P(:) = G13(iP) + G23_M(:) = G23(iM) + G23_P(:) = G23(iP) + + GsqrtDDENS_M(:) = Gsqrt_M(:) * DDENS_(iM) + GsqrtDDENS_P(:) = Gsqrt_P(:) * DDENS_(iP) + GsqrtMOMX_M (:) = Gsqrt_M(:) * MOMX_ (iM) + GsqrtMOMX_P (:) = Gsqrt_P(:) * MOMX_ (iP) + GsqrtMOMY_M (:) = Gsqrt_M(:) * MOMY_ (iM) + GsqrtMOMY_P (:) = Gsqrt_P(:) * MOMY_ (iP) + GsqrtMOMZ_M (:) = Gsqrt_M(:) * MOMZ_ (iM) + GsqrtMOMZ_P (:) = Gsqrt_P(:) * MOMZ_ (iP) + GsqrtDRHOT_M(:) = Gsqrt_M(:) * DRHOT_(iM) + GsqrtDRHOT_P(:) = Gsqrt_P(:) * DRHOT_(iP) + Phyd_M(:) = PRES_hyd(iM) + Phyd_P(:) = PRES_hyd(iP) + swV(:) = 1.0_RP - nz(:,ke)**2 + + Gxz_M(:) = G11(iM2Dto3D(:),ke2D) * G13_M(:) + G12(iM2Dto3D(:),ke2D) * G23_M(:) + Gxz_P(:) = G11(iM2Dto3D(:),ke2D) * G13_P(:) + G12(iM2Dto3D(:),ke2D) * G23_P(:) + + Gyz_M(:) = G12(iM2Dto3D(:),ke2D) * G13_M(:) + G22(iM2Dto3D(:),ke2D) * G23_M(:) + Gyz_P(:) = G12(iM2Dto3D(:),ke2D) * G13_P(:) + G22(iM2Dto3D(:),ke2D) * G23_P(:) + + G1n_M(:) = G11(iM2Dto3D(:),ke2D) * nx(:,ke) + G12(iM2Dto3D(:),ke2D) * ny(:,ke) + G2n_M(:) = G12(iM2Dto3D(:),ke2D) * nx(:,ke) + G22(iM2Dto3D(:),ke2D) * ny(:,ke) + + Gnn_M(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_M(:)**2 + G13_M(:) * Gxz_M(:) + G23_M(:) * Gyz_M(:) ) * abs( nz(:,ke) ) + Gnn_P(:) = G11(iM2Dto3D(:),ke2D) * abs( nx(:,ke) ) + G22(iM2Dto3D(:),ke2D) * abs( ny(:,ke) ) & + + ( 1.0_RP / GsqrtV_P(:)**2 + G13_P(:) * Gxz_P(:) + G23_P(:) * Gyz_P(:) ) * abs( nz(:,ke) ) + + GsqrtDensM(:) = GsqrtDDENS_M(:) + Gsqrt_M(:) * DENS_hyd(iM) + GsqrtDensP(:) = GsqrtDDENS_P(:) + Gsqrt_P(:) * DENS_hyd(iP) + + GsqrtRhotM(:) = Gsqrt_M(:) * P0ovR * (Phyd_M(:) * rP0)**rgamm + GsqrtDRHOT_M(:) + GsqrtRhotP(:) = Gsqrt_P(:) * P0ovR * (Phyd_P(:) * rP0)**rgamm + GsqrtDRHOT_P(:) + + VelhM(:) = ( GsqrtMOMX_M(:) * nx(:,ke) + GsqrtMOMY_M(:) * ny(:,ke) & + + ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) * nz(:,ke) ) & + / GsqrtDensM(:) + VelhP(:) = ( GsqrtMOMX_P(:) * nx(:,ke) + GsqrtMOMY_P(:) * ny(:,ke) & + + ( G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & + / GsqrtDensP(:) + + VelM(:) = VelhM(:) + GsqrtMOMZ_M(:) / ( GsqrtV_M(:) * GsqrtDensM(:) ) * nz(:,ke) + VelP(:) = VelhP(:) + GsqrtMOMZ_P(:) / ( GsqrtV_P(:) * GsqrtDensP(:) ) * nz(:,ke) + + ! Tentative treatment + where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) + VelP(:) = - VelM(:) + end where + + dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & + - Phyd_M(:) + dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & + - Phyd_P(:) + + alpha(:) = swV(:) * max( sqrt( Gnn_M(:) * gamm * ( Phyd_M(:) + dpresM(:) ) * Gsqrt_M(:) / GsqrtDensM(:) ) + abs(VelM(:)), & + sqrt( Gnn_P(:) * gamm * ( Phyd_P(:) + dpresP(:) ) * Gsqrt_P(:) / GsqrtDensP(:) ) + abs(VelP(:)) ) + + del_flux(:,ke,VARS_DDENS_ID) = 0.5_RP * ( & + ( GsqrtDensP(:) * VelhP(:) - GsqrtDensM(:) * VelhM(:) ) & + - alpha(:) * ( GsqrtDDENS_P(:) - GsqrtDDENS_M(:) ) ) + + del_flux(:,ke,VARS_MOMX_ID ) = 0.5_RP * ( & + ( GsqrtMOMX_P(:) * VelP(:) - GsqrtMOMX_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( G1n_M(:) + Gxz_P(:) * nz(:,ke) ) * dpresP(:) & + - Gsqrt_M(:) * ( G1n_M(:) + Gxz_M(:) * nz(:,ke) ) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMX_P(:) - GsqrtMOMX_M(:) ) ) + + del_flux(:,ke,VARS_MOMY_ID ) = 0.5_RP * ( & + ( GsqrtMOMY_P(:) * VelP(:) - GsqrtMOMY_M(:) * VelM(:) ) & + + ( Gsqrt_P(:) * ( G2n_M(:) + Gyz_P(:) * nz(:,ke)) * dpresP(:) & + - Gsqrt_M(:) * ( G2n_M(:) + Gyz_M(:) * nz(:,ke)) * dpresM(:) ) & + - alpha(:) * ( GsqrtMOMY_P(:) - GsqrtMOMY_M(:) ) ) + + del_flux(:,ke,VARS_MOMZ_ID ) = 0.5_RP * ( & + ( GsqrtMOMZ_P(:) * VelP(:) - GsqrtMOMZ_M(:) * VelM(:) ) & + - alpha(:) * ( GsqrtMOMZ_P(:) - GsqrtMOMZ_M(:) ) ) + + del_flux(:,ke,VARS_DRHOT_ID) = 0.5_RP * ( & + ( GsqrtRhotP(:) * VelhP(:) - GsqrtRhotM(:) * VelhM(:) ) & + - alpha(:) * ( GsqrtDRHOT_P(:) - GsqrtDRHOT_M(:) ) ) + + del_flux_hyd(:,ke,1) = 0.5_RP * ( & + GsqrtV_P(:) * ( nx(:,ke) + G13_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( nx(:,ke) + G13_M(:) * nz(:,ke) ) * Phyd_M(:) ) + + del_flux_hyd(:,ke,2) = 0.5_RP * ( & + GsqrtV_P(:) * ( ny(:,ke) + G23_P(:) * nz(:,ke) ) * Phyd_P(:) & + - GsqrtV_M(:) * ( ny(:,ke) + G23_M(:) * nz(:,ke) ) * Phyd_M(:) ) + end do + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalhvc + +end module scale_atm_dyn_dgm_nonhydro3d_hevi_numflux diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 index 2c36d31c..49203786 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_heve.F90 @@ -37,7 +37,13 @@ module scale_atm_dyn_dgm_nonhydro3d_splitform_heve use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D - + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + atm_dyn_dgm_nonhydro3d_common_Init, & + atm_dyn_dgm_nonhydro3d_common_Final, & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM, & + IntrpMat_VPOrdM1, iM2Dto3D + !----------------------------------------------------------------------------- implicit none private @@ -60,48 +66,24 @@ module scale_atm_dyn_dgm_nonhydro3d_splitform_heve ! !------------------- - integer, private, parameter :: DDENS_VID = 1 - integer, private, parameter :: MOMX_VID = 2 - integer, private, parameter :: MOMY_VID = 3 - integer, private, parameter :: MOMZ_VID = 4 - integer, private, parameter :: DRHOT_VID = 5 - integer, private, parameter :: PROG_VARS_NUM = 5 - - real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) real(RP), private, allocatable :: DxT1D_(:,:) real(RP), private, allocatable :: DyT1D_(:,:) real(RP), private, allocatable :: DzT1D_(:,:) - private :: cal_del_flux_dyn private :: dx_ab, dy_ab, dz_ab private :: dx_abc, dy_abc, dz_abc contains subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_Init( mesh ) - implicit none class(MeshBase3D), intent(in) :: mesh - integer :: p1, p2, p3, p_, p_intrp + integer :: p1, p2, p3, p_ type(ElementBase3D), pointer :: elem - real(RP) :: invV_POrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) - - real(RP), allocatable :: InvV_(:,:) !-------------------------------------------- + call atm_dyn_dgm_nonhydro3d_common_Init( mesh ) elem => mesh%refElem3D - allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) - - invV_POrdM1(:,:) = elem%invV - do p2=1, elem%Nnode_h1D - do p1=1, elem%Nnode_h1D - p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 - invV_POrdM1(p_,:) = 0.0_RP - end do - end do - IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_POrdM1) - - !--- allocate( DxT1D_(elem%Nnode_h1D,elem%Nnode_h1D) ) allocate( DyT1D_(elem%Nnode_h1D,elem%Nnode_h1D) ) @@ -129,9 +111,9 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_Final() implicit none !-------------------------------------------- - deallocate( IntrpMat_VPOrdM1 ) deallocate( DxT1D_, DyT1D_, DzT1D_ ) - + call atm_dyn_dgm_nonhydro3d_common_Final() + return end subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_Final @@ -143,6 +125,9 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + use scale_atm_dyn_dgm_nonhydro3d_heve_numflux, only: & + atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc + use scale_atm_dyn_dgm_spongelayer, only: & atm_dyn_dgm_spongelayer_add_tend @@ -172,57 +157,92 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) - real(RP) :: Fx_sp(elem%Np), Fy_sp(elem%Np), Fz_sp(elem%Np) + real(RP) :: Fx_sp(elem%Np), Fy_sp(elem%Np), Fz_sp(elem%Np) + real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP) :: dens_(elem%Np), RHOT_hyd(elem%Np), RHOT_(elem%Np) - real(RP) :: pres_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), pot_(elem%Np) - real(RP) :: Cori(elem%Np) - real(RP) :: drho(elem%Np) + real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP) :: GsqrtDens_(elem%Np), rdens_(elem%Np), RHOT_hyd(elem%Np), RHOT_(elem%Np) + real(RP) :: dpres_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), wt_(elem%Np), pot_(elem%Np) + real(RP) :: drho(elem%Np), Cori(elem%Np) + real(RP) :: GsqrtV(elem%Np), RGsqrtV(elem%Np) - real(RP) :: tmp(elem%Np) integer :: ke, ke2d - real(RP) :: gamm, rgamm + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR !------------------------------------------------------------------------ call PROF_rapstart( 'cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, & ! (out) + call atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc( & + del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + lmesh%Gsqrt, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) lmesh%vmapM, lmesh%vmapP, & ! (in) - lmesh, elem ) ! (in) + lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend( 'cal_dyn_tend_bndflux', 3) !----- call PROF_rapstart( 'cal_dyn_tend_interior', 3) - gamm = CPDry / CvDry + gamm = CPDry / CvDry rgamm = CvDry / CpDry - - !$omp parallel do private( & - !$omp RHOT_hyd, RHOT_, pres_, dens_, drho, u_, v_, w_, pot_, ke2d, Cori, & + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( ke2d, Cori, & + !$omp RHOT_, DPRES_, GsqrtDens_, rdens_, u_, v_, w_, wt_, & + !$omp GradPhyd_x, GradPhyd_y, drho, & + !$omp GsqrtV, RGsqrtV, & !$omp Fx, Fy, Fz, Fx_sp, Fy_sp, Fz_sp, LiftDelFlx ) do ke = lmesh%NeS, lmesh%NeE !-- - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**rgamm + ke2d = lmesh%EMap3Dto2D(ke) + Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) - RHOT_(:) = RHOT_hyd(:) + DRHOT_(:,ke) - pres_(:) = PRES_hyd(:,ke) * (1.0_RP + DRHOT_(:,ke)/RHOT_hyd(:))**gamm - dens_(:) = DDENS_(:,ke) + DENS_hyd(:,ke) + GsqrtV(:) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2d) + RGsqrtV(:) = 1.0_RP / GsqrtV(:) - u_ (:) = MOMX_(:,ke) / dens_(:) - v_ (:) = MOMY_(:,ke) / dens_(:) - w_ (:) = MOMZ_(:,ke) / dens_(:) - pot_(:) = RHOT_(:) / dens_(:) + !-- + RHOT_(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT_(:,ke) + DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & + - PRES_hyd(:,ke) + + GsqrtDens_(:) = lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) + rdens_(:) = 1.0_RP / GsqrtDens_(:) + u_ (:) = MOMX_(:,ke) * rdens_(:) + v_ (:) = MOMY_(:,ke) * rdens_(:) + w_ (:) = MOMZ_(:,ke) * rdens_(:) + wt_(:) = w_(:) * RGsqrtV(:) + lmesh%GI3(:,ke,1) * u_(:) + lmesh%GI3(:,ke,2) * v_(:) + pot_(:) = RHOT_(:) * rdens_(:) ke2d = lmesh%EMap3Dto2D(ke) Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) drho(:) = matmul(IntrpMat_VPOrdM1, DDENS_(:,ke)) + !-- Gradient hydrostatic pressure + + call sparsemat_matmul(Dx, GsqrtV(:) * PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,1) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + + call sparsemat_matmul(Dy, GsqrtV(:) * PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,2) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + !-- DENS - call dx_ab( DxT1D_, dens_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_ab( DyT1D_, dens_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_ab( DzT1D_, dens_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DDENS_VID), LiftDelFlx) + call dx_ab( DxT1D_, GsqrtDens_(:), u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_ab( DyT1D_, GsqrtDens_(:), v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_ab( DzT1D_, GsqrtDens_(:), wt_(:), elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx_sp(:) & @@ -231,54 +251,54 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & + LiftDelFlx(:) ) !-- MOMX - call dx_abc( DxT1D_, dens_, u_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, u_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, u_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Dx, pres_(:) , Fx) + call dx_abc( DxT1D_, GsqrtDens_, u_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, u_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, u_, wt_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * dpres_(:) , Fx) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) - MOMX_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * (Fx_sp(:) + Fx(:)) & - + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & - + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & - + LiftDelFlx(:) & - - Cori(:) * MOMY_(:,ke) & - ) + MOMX_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * ( Fx_sp(:) + Fx(:) ) & + + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & + + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_x(:) * RGsqrtV(:) & + + Cori(:) * MOMY_(:,ke) !-- MOMY - call dx_abc( DxT1D_, dens_, v_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, v_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, v_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Dy, pres_(:) , Fy) + call dx_abc( DxT1D_, GsqrtDens_, v_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, v_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, v_, wt_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * dpres_(:) , Fy) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) - MOMY_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx_sp(:) & - + lmesh%Escale(:,ke,2,2) * (Fy_sp(:) + Fy(:)) & - + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & - + LiftDelFlx(:) & - + Cori(:) * MOMX_(:,ke) & - ) + MOMY_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx_sp(:) & + + lmesh%Escale(:,ke,2,2) * ( Fy_sp(:) + Fy(:) ) & + + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_y(:) * RGsqrtV(:) & + - Cori(:) * MOMX_(:,ke) !-- MOMZ - call dx_abc( DxT1D_, dens_, w_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, w_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, w_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Dz, pres_(:) - PRES_hyd(:,ke), Fz) + call dx_abc( DxT1D_, GsqrtDens_, w_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, w_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, w_, wt_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * RGsqrtV(:) * dpres_(:) , Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) MOMZ_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx_sp(:) & - + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & - + lmesh%Escale(:,ke,3,3) * (Fz_sp(:) + Fz(:)) & - + LiftDelFlx(:) ) & - - Grav * drho(:) + lmesh%Escale(:,ke,1,1) * Fx_sp(:) & + + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & + + lmesh%Escale(:,ke,3,3) * ( Fz_sp(:) + Fz(:) ) & + + LiftDelFlx(:) ) & + - Grav * drho(:) !-- RHOT - call dx_abc( DxT1D_, dens_, pot_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, pot_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, pot_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DRHOT_VID), LiftDelFlx) + call dx_abc( DxT1D_, GsqrtDens_, pot_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, pot_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, pot_, wt_(:), elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,RHOT_VID), LiftDelFlx) RHOT_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx_sp(:) & @@ -301,97 +321,6 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend( & return end subroutine atm_dyn_dgm_nonhydro3d_heve_splitform_cal_tend - !------ - - subroutine cal_del_flux_dyn( del_flux, & - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - nx, ny, nz, vmapM, vmapP, lmesh, elem ) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%Ne,PROG_VARS_NUM) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) - real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) - integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) - integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) - - integer :: i, iP, iM - real(RP) :: VelP, VelM, alpha - real(RP) :: presM, presP, dpresM, dpresP, densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P - real(RP) :: gamm, rgamm - - !------------------------------------------------------------------------ - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - !$omp parallel do private( iM, iP, alpha, & - !$omp VelP, VelM, presM, presP, dpresM, dpresP, & - !$omp densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P & - !$omp ) - do i=1, elem%NfpTot*lmesh%Ne - iM = vmapM(i); iP = vmapP(i) - - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm - - rhotM = rhot_hyd_M + DRHOT_(iM) - presM = PRES_hyd(iM) * (1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - dpresM = presM - PRES_hyd(iM)*abs(nz(i)) - - rhotP = rhot_hyd_P + DRHOT_(iP) - presP = PRES_hyd(iP) * (1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - dpresP = presP - PRES_hyd(iP)*abs(nz(i)) - - densM = DDENS_(iM) + DENS_hyd(iM) - densP = DDENS_(iP) + DENS_hyd(iP) - - VelM = (MOMX_(iM)*nx(i) + MOMY_(iM)*ny(i) + MOMZ_(iM)*nz(i))/densM - VelP = (MOMX_(iP)*nx(i) + MOMY_(iP)*ny(i) + MOMZ_(iP)*nz(i))/densP - - alpha = max( sqrt(gamm * presM / densM) + abs(VelM), & - sqrt(gamm * presP / densP) + abs(VelP) ) - - del_flux(i,DDENS_VID) = 0.5_RP * ( & - ( MOMX_(iP) - MOMX_(iM) ) * nx(i) & - + ( MOMY_(iP) - MOMY_(iM) ) * ny(i) & - + ( MOMZ_(iP) - MOMZ_(iM) ) * nz(i) & - - alpha * ( DDENS_(iP) - DDENS_(iM) ) ) - - del_flux(i,MOMX_VID) = 0.5_RP * ( & - ( MOMX_(iP) * VelP - MOMX_(iM) * VelM ) & - + ( dpresP - dpresM ) * nx(i) & - - alpha * ( MOMX_(iP) - MOMX_(iM) ) ) - - del_flux(i,MOMY_VID) = 0.5_RP* ( & - ( MOMY_(iP) * VelP - MOMY_(iM) * VelM ) & - + ( dpresP - dpresM ) * ny(i) & - - alpha * ( MOMY_(iP) - MOMY_(iM) ) ) - - del_flux(i,MOMZ_VID) = 0.5_RP * ( & - ( MOMZ_(iP) * VelP - MOMZ_(iM) * VelM ) & - + ( dpresP - dpresM ) * nz(i) & - - alpha * ( MOMZ_(iP) - MOMZ_(iM) ) ) - - del_flux(i,DRHOT_VID) = 0.5_RP * ( & - ( rhotP * VelP - rhotM * VelM ) & - - alpha * ( DRHOT_(iP) - DRHOT_(iM) ) ) - - end do - - return - end subroutine cal_del_flux_dyn - !----------------------------------------- subroutine dx_ab(DxT1D, a, b, Nnode_h1D, Nnode_v, fx) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 index b717d179..ea817d85 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 @@ -37,6 +37,12 @@ module scale_atm_dyn_dgm_nonhydro3d_splitform_hevi use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D + use scale_atm_dyn_dgm_nonhydro3d_common, only: & + atm_dyn_dgm_nonhydro3d_common_Init, & + atm_dyn_dgm_nonhydro3d_common_Final, & + DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & + PROG_VARS_NUM, & + IntrpMat_VPOrdM1, iM2Dto3D !----------------------------------------------------------------------------- implicit none @@ -61,19 +67,10 @@ module scale_atm_dyn_dgm_nonhydro3d_splitform_hevi ! !------------------- - integer, private, parameter :: DDENS_VID = 1 - integer, private, parameter :: MOMX_VID = 2 - integer, private, parameter :: MOMY_VID = 3 - integer, private, parameter :: MOMZ_VID = 4 - integer, private, parameter :: DRHOT_VID = 5 - integer, private, parameter :: PROG_VARS_NUM = 5 - - real(RP), private, allocatable :: IntrpMat_VPOrdM1(:,:) real(RP), private, allocatable :: DxT1D_(:,:) real(RP), private, allocatable :: DyT1D_(:,:) real(RP), private, allocatable :: DzT1D_(:,:) - private :: cal_del_flux_dyn private :: dx_ab, dy_ab, dz_ab private :: dx_abc, dy_abc, dz_abc @@ -83,26 +80,13 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_Init( mesh ) implicit none class(MeshBase3D), intent(in) :: mesh - integer :: p1, p2, p3, p_, p_intrp + integer :: p1, p2, p3, p_ type(ElementBase3D), pointer :: elem - real(RP) :: invV_POrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) - - real(RP), allocatable :: InvV_(:,:) !-------------------------------------------- - elem => mesh%refElem3D - allocate( IntrpMat_VPOrdM1(elem%Np,elem%Np) ) - - invV_POrdM1(:,:) = elem%invV - do p2=1, elem%Nnode_h1D - do p1=1, elem%Nnode_h1D - p_ = p1 + (p2-1)*elem%Nnode_h1D + (elem%Nnode_v-1)*elem%Nnode_h1D**2 - invV_POrdM1(p_,:) = 0.0_RP - end do - end do - IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_POrdM1) + call atm_dyn_dgm_nonhydro3d_common_Init( mesh ) - !--- + elem => mesh%refElem3D allocate( DxT1D_(elem%Nnode_h1D,elem%Nnode_h1D) ) allocate( DyT1D_(elem%Nnode_h1D,elem%Nnode_h1D) ) @@ -130,7 +114,8 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_Final() implicit none !-------------------------------------------- - deallocate( IntrpMat_VPOrdM1 ) + call atm_dyn_dgm_nonhydro3d_common_Final() + deallocate( DxT1D_, DyT1D_, DzT1D_ ) return @@ -144,6 +129,9 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend( & SL_flag, wdamp_tau, wdamp_height, hveldamp_flag, & ! (in) Dx, Dy, Dz, Sx, Sy, Sz, Lift, lmesh, elem, lmesh2D, elem2D ) + use scale_atm_dyn_dgm_nonhydro3d_hevi_numflux, only: & + atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc + use scale_atm_dyn_dgm_spongelayer, only: & atm_dyn_dgm_spongelayer_add_tend @@ -173,93 +161,131 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend( & logical, intent(in) :: hveldamp_flag real(RP) :: Fx(elem%Np), Fy(elem%Np), Fz(elem%Np), LiftDelFlx(elem%Np) - real(RP) :: Fx_sp(elem%Np), Fy_sp(elem%Np), Fz_sp(elem%Np) + real(RP) :: Fx_sp(elem%Np), Fy_sp(elem%Np), Fz_sp(elem%Np) + real(RP) :: GradPhyd_x(elem%Np), GradPhyd_y(elem%Np) real(RP) :: del_flux(elem%NfpTot,lmesh%Ne,PROG_VARS_NUM) - real(RP) :: dens_(elem%Np), RHOT_hyd(elem%Np), RHOT_(elem%Np) - real(RP) :: pres_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), pot_(elem%Np) + real(RP) :: del_flux_hyd(elem%NfpTot,lmesh%Ne,2) + real(RP) :: GsqrtDens_(elem%Np), rdens_(elem%Np), RHOT_hyd(elem%Np), RHOT_(elem%Np) + real(RP) :: dpres_(elem%Np), u_(elem%Np), v_(elem%Np), w_(elem%Np), wt_(elem%Np), pot_(elem%Np) real(RP) :: Cori(elem%Np) + real(RP) :: GsqrtV(elem%Np), RGsqrtV(elem%Np) - real(RP) :: tmp(elem%Np) integer :: ke, ke2d - real(RP) :: gamm, rgamm + + real(RP) :: gamm, rgamm + real(RP) :: rP0 + real(RP) :: RovP0, P0ovR !------------------------------------------------------------------------ call PROF_rapstart( 'cal_dyn_tend_bndflux', 3) - call cal_del_flux_dyn( del_flux, & ! (out) + call atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc( & + del_flux, del_flux_hyd, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) + lmesh%Gsqrt, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) lmesh%vmapM, lmesh%vmapP, & ! (in) - lmesh, elem ) ! (in) + lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend( 'cal_dyn_tend_bndflux', 3) !----- call PROF_rapstart( 'cal_dyn_tend_interior', 3) - gamm = CPDry / CvDry + gamm = CPDry / CvDry rgamm = CvDry / CpDry - - !$omp parallel do private( & - !$omp RHOT_hyd, RHOT_, pres_, dens_, u_, v_, w_, pot_, ke2d, Cori, & + rP0 = 1.0_RP / PRES00 + RovP0 = Rdry * rP0 + P0ovR = PRES00 / Rdry + + !$omp parallel do private( ke2d, Cori, & + !$omp RHOT_, DPRES_, GsqrtDens_, rdens_, u_, v_, w_, wt_, & + !$omp GradPhyd_x, GradPhyd_y, & + !$omp GsqrtV, RGsqrtV, & !$omp Fx, Fy, Fz, Fx_sp, Fy_sp, Fz_sp, LiftDelFlx ) do ke = lmesh%NeS, lmesh%NeE !-- - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke)/PRES00)**rgamm + ke2d = lmesh%EMap3Dto2D(ke) + Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) - RHOT_(:) = RHOT_hyd(:) + DRHOT_(:,ke) - pres_(:) = PRES_hyd(:,ke) * (1.0_RP + DRHOT_(:,ke)/RHOT_hyd(:))**gamm - dens_(:) = DDENS_(:,ke) + DENS_hyd(:,ke) + GsqrtV(:) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2d) + RGsqrtV(:) = 1.0_RP / GsqrtV(:) - u_ (:) = MOMX_(:,ke) / dens_(:) - v_ (:) = MOMY_(:,ke) / dens_(:) - w_ (:) = MOMZ_(:,ke) / dens_(:) - pot_(:) = RHOT_(:) / dens_(:) + !-- + RHOT_(:) = P0ovR * (PRES_hyd(:,ke) * rP0)**rgamm + DRHOT_(:,ke) + DPRES_(:) = PRES00 * ( RovP0 * RHOT_(:) )**gamm & + - PRES_hyd(:,ke) + + GsqrtDens_(:) = lmesh%Gsqrt(:,ke) * ( DDENS_(:,ke) + DENS_hyd(:,ke) ) + rdens_(:) = 1.0_RP / GsqrtDens_(:) + u_ (:) = MOMX_(:,ke) * rdens_(:) + v_ (:) = MOMY_(:,ke) * rdens_(:) + w_ (:) = MOMZ_(:,ke) * rdens_(:) + wt_(:) = w_(:) * RGsqrtV(:) + lmesh%GI3(:,ke,1) * u_(:) + lmesh%GI3(:,ke,2) * v_(:) + pot_(:) = RHOT_(:) * rdens_(:) ke2d = lmesh%EMap3Dto2D(ke) Cori(:) = CORIOLIS(elem%IndexH2Dto3D(:),ke2d) + !-- Gradient hydrostatic pressure + + call sparsemat_matmul(Dx, GsqrtV(:) * PRES_hyd(:,ke), Fx) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,1) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,1), LiftDelFlx) + GradPhyd_x(:) = lmesh%Escale(:,ke,1,1) * Fx(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + + call sparsemat_matmul(Dy, GsqrtV(:) * PRES_hyd(:,ke), Fy) + call sparsemat_matmul(Dz, GsqrtV(:) * lmesh%GI3(:,ke,2) * PRES_hyd(:,ke), Fz) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux_hyd(:,ke,2), LiftDelFlx) + GradPhyd_y(:) = lmesh%Escale(:,ke,2,2) * Fy(:) & + + lmesh%Escale(:,ke,3,3) * Fz(:) & + + LiftDelFlx(:) + !-- DENS - call dx_ab( DxT1D_, dens_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_ab( DyT1D_, dens_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DDENS_VID), LiftDelFlx) + call dx_ab( DxT1D_, GsqrtDens_(:), u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_ab( DyT1D_, GsqrtDens_(:), v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_ab( DzT1D_, GsqrtDens_(:), wt_(:) - w_(:) * RGsqrtV(:), elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DENS_VID), LiftDelFlx) DENS_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx_sp(:) & + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & + + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & + LiftDelFlx(:) ) !-- MOMX - call dx_abc( DxT1D_, dens_, u_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, u_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, u_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Dx, pres_(:) , Fx) + call dx_abc( DxT1D_, GsqrtDens_, u_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, u_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, u_, wt_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * dpres_(:) , Fx) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) - MOMX_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * (Fx_sp(:) + Fx(:)) & - + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & - + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & - + LiftDelFlx(:) & - - Cori(:) * MOMY_(:,ke) & - ) + MOMX_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * ( Fx_sp(:) + Fx(:) ) & + + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & + + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_x(:) * RGsqrtV(:) & + + Cori(:) * MOMY_(:,ke) !-- MOMY - call dx_abc( DxT1D_, dens_, v_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, v_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, v_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) - call sparsemat_matmul(Dy, pres_(:) , Fy) + call dx_abc( DxT1D_, GsqrtDens_, v_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, v_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, v_, wt_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * dpres_(:) , Fy) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) - MOMY_dt(:,ke) = - ( & - lmesh%Escale(:,ke,1,1) * Fx_sp(:) & - + lmesh%Escale(:,ke,2,2) * (Fy_sp(:) + Fy(:)) & - + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & - + LiftDelFlx(:) & - + Cori(:) * MOMX_(:,ke) & - ) + MOMY_dt(:,ke) = & + - ( lmesh%Escale(:,ke,1,1) * Fx_sp(:) & + + lmesh%Escale(:,ke,2,2) * ( Fy_sp(:) + Fy(:) ) & + + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & + + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) & + - GradPhyd_y(:) * RGsqrtV(:) & + - Cori(:) * MOMX_(:,ke) !-- MOMZ - call dx_abc( DxT1D_, dens_, w_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, w_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call dz_abc( DzT1D_, dens_, w_, w_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call dx_abc( DxT1D_, GsqrtDens_, w_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, w_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, w_, wt_, elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMZ_VID), LiftDelFlx) MOMZ_dt(:,ke) = - ( & @@ -269,13 +295,15 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend( & + LiftDelFlx(:) ) !-- RHOT - call dx_abc( DxT1D_, dens_, pot_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) - call dy_abc( DyT1D_, dens_, pot_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,DRHOT_VID), LiftDelFlx) + call dx_abc( DxT1D_, GsqrtDens_, pot_, u_, elem%Nnode_h1D, elem%Nnode_v, Fx_sp ) + call dy_abc( DyT1D_, GsqrtDens_, pot_, v_, elem%Nnode_h1D, elem%Nnode_v, Fy_sp ) + call dz_abc( DzT1D_, GsqrtDens_, pot_, wt_(:) - w_(:) * RGsqrtV(:), elem%Nnode_h1D, elem%Nnode_v, Fz_sp ) + call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,RHOT_VID), LiftDelFlx) RHOT_dt(:,ke) = - ( & lmesh%Escale(:,ke,1,1) * Fx_sp(:) & + lmesh%Escale(:,ke,2,2) * Fy_sp(:) & + + lmesh%Escale(:,ke,3,3) * Fz_sp(:) & + LiftDelFlx(:) ) end do call PROF_rapend( 'cal_dyn_tend_interior', 3) @@ -295,105 +323,6 @@ end subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_tend !------ - subroutine cal_del_flux_dyn( del_flux, & - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & - nx, ny, nz, vmapM, vmapP, lmesh, elem ) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%Ne,PROG_VARS_NUM) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeA) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) - real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) - integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) - integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) - - integer :: i, iP, iM - real(RP) :: VelP, VelM, MOMZ_P, alpha, swV - real(RP) :: presM, presP, dpresM, dpresP, densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P - real(RP) :: dens, u, v, w, pot, velh, vel - real(RP) :: gamm, rgamm - - !------------------------------------------------------------------------ - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - !$omp parallel do private( iM, iP, alpha, swV, & - !$omp VelP, VelM, MOMZ_P, presM, presP, dpresM, dpresP, & - !$omp densM, densP, rhotM, rhotP, rhot_hyd_M, rhot_hyd_P, & - !$omp dens, u, v, w, pot, velh, vel ) - do i=1, elem%NfpTot*lmesh%Ne - iM = vmapM(i); iP = vmapP(i) - - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm - - rhotM = rhot_hyd_M + DRHOT_(iM) - presM = PRES_hyd(iM) * (1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - dpresM = presM - PRES_hyd(iM)*abs(nz(i)) - - rhotP = rhot_hyd_P + DRHOT_(iP) - presP = PRES_hyd(iP) * (1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - dpresP = presP - PRES_hyd(iP)*abs(nz(i)) - - densM = DDENS_(iM) + DENS_hyd(iM) - densP = DDENS_(iP) + DENS_hyd(iP) - dens = 0.5_RP*(densM + densP) - - swV = 1.0_RP - nz(i)**2 - VelM = (MOMX_(iM)*nx(i) + MOMY_(iM)*ny(i) + MOMZ_(iM)*nz(i))/densM - VelP = (MOMX_(iP)*nx(i) + MOMY_(iP)*ny(i) + MOMZ_(iP)*nz(i))/densP - MOMZ_P = MOMZ_(iP) - - u = 0.5_RP * (MOMX_(iM) + MOMX_(iP)) / dens - v = 0.5_RP * (MOMY_(iM) + MOMY_(iP)) / dens - w = 0.5_RP * (MOMZ_(iM) + MOMZ_P ) / dens - velh = u*nx(i) + v*ny(i) - vel = velh + w*nz(i) - - pot = 0.5_RP * (rhotM + rhotP) / dens - - alpha = swV*max( sqrt(gamm * presM / densM) + abs(VelM), & - sqrt(gamm * presP / densP) + abs(VelP) ) - - del_flux(i,DDENS_VID) = & - (dens*u - MOMX_(iM)) * nx(i) & - + (dens*v - MOMY_(iM)) * ny(i) & - - 0.5_RP * alpha * (DDENS_(iP) - DDENS_(iM)) - - del_flux(i,MOMX_VID) = & - ( dens*u*vel - MOMX_(iM)*VelM ) & - + ( dpresP - dpresM )*nx(i) & - - 0.5_RP * alpha * (MOMX_(iP) - MOMX_(iM)) - - del_flux(i,MOMY_VID) = & - ( dens*v*vel - MOMY_(iM)*VelM ) & - + ( dpresP - dpresM )*ny(i) & - - 0.5_RP * alpha * (MOMY_(iP) - MOMY_(iM)) - - del_flux(i,MOMZ_VID) = & - ( dens*w*vel - MOMZ_(iM)*VelM ) & - - 0.5_RP * alpha * (MOMZ_(iP) - MOMZ_(iM)) - - del_flux(i,DRHOT_VID) = & - swV*( dens*pot*vel - rhotM*VelM) & - - 0.5_RP * alpha * (DRHOT_(iP) - DRHOT_(iM)) - - end do - - return - end subroutine cal_del_flux_dyn - subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, DENS_hyd, PRES_hyd, & ! (in) @@ -402,6 +331,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & impl_fac, dt, & ! (in) lmesh, elem, lmesh2D, elem2D ) ! (in) + use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + implicit none class(LocalMesh3D), intent(in) :: lmesh @@ -433,21 +367,25 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP) :: alph(elem%NfpTot,lmesh%NeZ) real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) + real(RP) :: GnnM_z(elem%Np,lmesh%NeZ) + real(RP) :: G13_z(elem%Np,lmesh%NeZ) + real(RP) :: G23_z(elem%Np,lmesh%NeZ) + real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ) real(RP) :: nz(elem%NfpTot,lmesh%NeZ) integer :: vmapM(elem%NfpTot,lmesh%NeZ) integer :: vmapP(elem%NfpTot,lmesh%NeZ) - integer :: ke_x, ke_y, ke_z, ke, p, v + integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v integer :: itr_lin, itr_nlin - integer :: f, vs, ve, kl, ku, nz_1D + integer :: kl, ku, nz_1D integer :: ij, info logical :: is_converged real(RP), allocatable :: PmatBnd(:,:,:) - !------------------------------------------------------------------------ @@ -458,34 +396,9 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & ku = kl allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) - !$omp parallel private(f, vs, ve) - !$omp do - do ke_z=1, lmesh%NeZ - do f=1, elem%Nfaces_h - vs = 1 + (f-1)*elem%Nfp_h - ve = vs + elem%Nfp_h - 1 - vmapM(vs:ve,ke_z) = elem%Fmask_h(:,f) + (ke_z-1)*elem%Np - end do - do f=1, elem%Nfaces_v - vs = elem%Nfp_h*elem%Nfaces_h + 1 + (f-1)*elem%Nfp_v - ve = vs + elem%Nfp_v - 1 - vmapM(vs:ve,ke_z) = elem%Fmask_v(:,f) + (ke_z-1)*elem%Np - end do - vmapP(:,ke_z) = vmapM(:,ke_z) - end do - !$omp do - do ke_z=1, lmesh%NeZ - vs = elem%Nfp_h*elem%Nfaces_h + 1 - ve = vs + elem%Nfp_v - 1 - if (ke_z > 1) & - vmapP(vs:ve,ke_z) = elem%Fmask_v(:,2) + (ke_z-2)*elem%Np - - vs = elem%Nfp_h*elem%Nfaces_h + elem%Nfp_v + 1 - ve = vs + elem%Nfp_v - 1 - if (ke_z < lmesh%NeZ) & - vmapP(vs:ve,ke_z) = elem%Fmask_v(:,1) + ke_z*elem%Np - end do - !$omp end parallel + call vi_gen_vmap( vmapM, vmapP, & ! (out) + lmesh, elem ) ! (in) + call PROF_rapend( 'hevi_cal_vi_prep', 3) do ke_y=1, lmesh%NeY @@ -493,32 +406,47 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & call PROF_rapstart( 'hevi_cal_vi_get_var', 3) - !$omp parallel do private(ke) + !$omp parallel do private( ke, ke2D ) do ke_z=1, lmesh%NeZ ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2D = lmesh%EMap3Dto2D(ke) - PROG_VARS(:,DDENS_VID,ke_z) = DDENS_(:,ke) + PROG_VARS(:,DENS_VID,ke_z) = DDENS_(:,ke) PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) - PROG_VARS(:,DRHOT_VID,ke_z) = DRHOT_(:,ke) + PROG_VARS(:,RHOT_VID,ke_z) = DRHOT_(:,ke) DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) + nz(:,ke_z) = lmesh%normal_fn(:,ke,3) + G13_z(:,ke_z) = lmesh%GI3(:,ke,1) + G23_z(:,ke_z) = lmesh%GI3(:,ke,2) + GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) + + GnnM_z(:,ke_z) = ( & + 1.0_RP / GsqrtV_z(:,ke_z)**2 & + + G13_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,1) * G13_z(:,ke_z) & + + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G23_z(:,ke_z) ) & + + G23_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G13_z(:,ke_z) & + + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,2,2) * G23_z(:,ke_z) ) ) end do call PROF_rapend( 'hevi_cal_vi_get_var', 3) if ( abs(impl_fac) > 0.0_RP ) then call PROF_rapstart( 'hevi_cal_vi_itr', 3) + ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 + ! dG/dq^n+1 del[q] = - G(q^n*) do itr_nlin = 1, 1 - call vi_eval_Ax( Ax(:,:,:), & ! (out) + call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -533,7 +461,8 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & call vi_construct_matbnd( PmatBnd, & ! (out) kl, ku, nz_1D, & ! (in) PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + G13_z, G23_z, GsqrtV_z, alph, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -574,12 +503,13 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & if ( abs(impl_fac) > 0.0_RP) then !$omp parallel do do ke_z=1, lmesh%NeZ - tend(:,:,ke_z) = (- PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z))/impl_fac + tend(:,:,ke_z) = ( - PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z) ) / impl_fac end do else - call vi_eval_Ax( tend(:,:,:), & ! (out) + call vi_eval_Ax( tend(:,:,:), alph, & ! (out) PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, & ! (in) @@ -589,11 +519,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & !$omp parallel do private(ke) do ke_z=1, lmesh%NeZ ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - DENS_dt(:,ke) = - tend(:,DDENS_VID,ke_z) - MOMX_dt(:,ke) = - tend(:,MOMX_VID,ke_z) - MOMY_dt(:,ke) = - tend(:,MOMY_VID,ke_z) - MOMZ_dt(:,ke) = - tend(:,MOMZ_VID,ke_z) - RHOT_dt(:,ke) = - tend(:,DRHOT_VID,ke_z) + DENS_dt(:,ke) = - tend(:,DENS_VID,ke_z) + MOMX_dt(:,ke) = - tend(:,MOMX_VID ,ke_z) + MOMY_dt(:,ke) = - tend(:,MOMY_VID ,ke_z) + MOMZ_dt(:,ke) = - tend(:,MOMZ_VID ,ke_z) + RHOT_dt(:,ke) = - tend(:,RHOT_VID,ke_z) end do call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) end do @@ -602,459 +532,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & return end subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi - !------------------------------------------------ - - !--- - subroutine vi_eval_Ax( Ax, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - Dz, Lift, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, cal_tend_flag ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) - class(SparseMat), intent(in) :: Dz, Lift - logical, intent(in) :: modalFilterFlag - real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) - real(RP), intent(in) :: impl_fac - real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - logical, intent(in) :: cal_tend_flag - - real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) - real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) - real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) - real(RP) :: DPRES(elem%Np) - real(RP) :: tmpV1D(elem%Nnode_v) - integer :: ke_z - integer :: ke - integer :: v - integer :: ij - real(RP) :: gamm, rgamm - !-------------------------------------------------------- - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - call vi_cal_del_flux_dyn( del_flux, & ! (out) - PROG_VARS(:,DDENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) - PROG_VARS(:,MOMY_VID ,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) - PROG_VARS(:,DRHOT_VID,:), & ! (in) - PROG_VARS0(:,DDENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) - PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) - PROG_VARS0(:,DRHOT_VID,:), & ! (in) - DENS_hyd, PRES_hyd, nz, vmapM, vmapP, & ! (in) - lmesh, elem ) ! (in) - - !$omp parallel do private( & - !$omp ke, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & - !$omp v, ij, tmpV1D & - !$omp ) - do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm - - DPRES(:) = PRES_hyd(:,ke_z) * ((1.0_RP + PROG_VARS(:,DRHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP) - POT(:) = (RHOT_hyd(:) + PROG_VARS(:,DRHOT_VID,ke_z))/(DENS_hyd(:,ke_z) + PROG_VARS(:,DDENS_VID,ke_z)) - - !- DENS - call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DDENS_VID), LiftDelFlx) - Ax(:,DDENS_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) - - !- MOMX - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) - Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) - - !-MOMY - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) - Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) - - !-MOMZ - call sparsemat_matmul(Dz, DPRES(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) - Ax(:,MOMZ_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) & - + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DDENS_VID,ke_z)) - - - !-RHOT - call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DRHOT_VID), LiftDelFlx) - Ax(:,DRHOT_VID,ke_z) = lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) - - !-- Modal filtering in the vertical direction - if ( modalFilterFlag ) then - do v=1, PROG_VARS_NUM - do ij=1, elem%Nnode_h1D**2 - Ax(elem%Colmask(:,ij),v,ke_z) = Ax(elem%Colmask(:,ij),v,ke_z) & - - matmul(VModalFilter, PROG_VARS(elem%Colmask(:,ij),v,ke_z) ) / dt - end do - end do - end if - - !-- - if ( .not. cal_tend_flag ) then - Ax(:,:,ke_z) = PROG_VARS(:,:,ke_z) + impl_fac * Ax(:,:,ke_z) - end if - - end do - - return - end subroutine vi_eval_Ax - - subroutine vi_cal_del_flux_dyn( del_flux, & - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & - DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & - DENS_hyd, PRES_hyd, nz, vmapM, vmapP, lmesh, elem ) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DDENS0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) - - integer :: i, p, ke_z, iP, iM - real(RP) :: alpha0, swV - real(RP) :: MOMZ_P - real(RP) :: rhot_hyd_M, rhot_hyd_P - real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP - real(RP) :: pres0M, pres0P, dens0M, dens0P - real(RP) :: gamm, rgamm - !------------------------------------------------------------------------ - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - !$omp parallel do private( p, i, iM, iP, & - !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & - !$omp dpresM, dpresP, MOMZ_P, & - !$omp dens0M, dens0P, pres0M, pres0P, & - !$omp swV, alpha0 ) - do ke_z=1, lmesh%NeZ - do p=1, elem%NfpTot - i = p + (ke_z-1)*elem%NfpTot - iM = vmapM(i); iP = vmapP(i) - - !- - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm - - densM = DENS_hyd(iM) + DDENS_(iM) - densP = DENS_hyd(iP) + DDENS_(iP) - - pottM = (rhot_hyd_M + DRHOT_(iM)) / densM - pottP = (rhot_hyd_P + DRHOT_(iP)) / densP - - dpresM = PRES_hyd(iM) * ((1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - 1.0_RP) - dpresP = PRES_hyd(iP) * ((1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - 1.0_RP) - - !- - dens0M = DENS_hyd(iM) + DDENS0_(iM) - dens0P = DENS_hyd(iP) + DDENS0_(iP) - - pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm - pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm - - swV = nz(i)**2 - alpha0 = swV * max( abs(MOMZ0_(iM)/dens0M) + sqrt(gamm * pres0M/dens0M), & - abs(MOMZ0_(iP)/dens0P) + sqrt(gamm * pres0P/dens0P) ) - - if (iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ)) then - MOMZ_P = - MOMZ_(iM) - else - MOMZ_P = MOMZ_(iP) - end if - - del_flux(i,DDENS_VID) = 0.5_RP * ( & - + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & - - alpha0 * ( DDENS_(iP) - DDENS_(iM) ) ) - - del_flux(i,MOMX_VID) = 0.5_RP * ( & - - alpha0 * ( MOMX_(iP) - MOMX_(iM) ) ) - - del_flux(i,MOMY_VID) = 0.5_RP * ( & - - alpha0 * ( MOMY_(iP) - MOMY_(iM) ) ) - - del_flux(i,MOMZ_VID) = 0.5_RP * ( & - + ( dpresP - dpresM ) * nz(i) & - - alpha0 * ( MOMZ_P - MOMZ_(iM) ) ) - - del_flux(i,DRHOT_VID) = 0.5_RP * ( & - + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & - - alpha0 * ( DRHOT_(iP) - DRHOT_(iM) ) ) - end do - end do - - return - end subroutine vi_cal_del_flux_dyn - - subroutine vi_construct_matbnd( PmatBnd, & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - Dz, Lift, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y ) ! (in) - - implicit none - - class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem - integer, intent(in) :: kl, ku, nz_1D - real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) - class(SparseMat), intent(in) :: Dz, Lift - logical, intent(in) :: modalFilterFlag - real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) - real(RP), intent(in) :: impl_fac - real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - - real(RP) :: RHOT_hyd(elem%Nnode_v) - real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: Cs0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) - integer :: ke_z, ke_z2 - integer :: v, ke, p, f1, fp, FmV - real(RP) :: gamm, rgamm - real(RP) :: fac_dz_p(elem%Nnode_v) - real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - real(RP) :: PmatL(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - real(RP) :: PmatU(elem%Nnode_v,elem%Nnode_v,PROG_VARS_NUM,PROG_VARS_NUM) - integer :: Colmask(elem%Nnode_v) - real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) - real(RP) :: Dd(elem%Nnode_v) - real(RP) :: tmp1 - real(RP) :: alphaM, alphaP - real(RP) :: fac - - integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 - logical :: bc_flag - logical :: eval_flag(PROG_VARS_NUM,PROG_VARS_NUM) - !-------------------------------------------------------- - - gamm = CpDry/CvDry - rgamm = CvDry/CpDry - - eval_flag(:,:) = .false. - do v=1, PROG_VARS_NUM - eval_flag(v,v) = .true. - end do - eval_flag(DDENS_VID,MOMZ_VID) = .true. - eval_flag(MOMZ_VID,DDENS_VID) = .true. - eval_flag(MOMZ_VID,DRHOT_VID) = .true. - eval_flag(DRHOT_VID,MOMZ_VID) = .true. - eval_flag(DRHOT_VID,DDENS_VID) = .true. - - Id(:,:) = 0.0_RP - do p=1, elem%Nnode_v - Id(p,p) = 1.0_RP - end do - - !$omp parallel private(RHOT_hyd, Colmask) - !$omp do - do v=1, PROG_VARS_NUM - PmatD(:,:,:,v) = 0.0_RP - PmatL(:,:,:,v) = 0.0_RP - PmatU(:,:,:,v) = 0.0_RP - end do - !$omp do - do ij=1, elem%Nnode_h1D**2 - PmatBnd(:,:,:,:,ij) = 0.0_RP - end do - !$omp do collapse(2) - do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - Colmask(:) = elem%Colmask(:,ij) - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm - - DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**(gamm-1) - - DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DDENS_VID,ke_z) - POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) - W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) - Cs0(:,ke_z,ij) = sqrt( gamm * PRES_hyd(Colmask(:),ke_z) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),DRHOT_VID,ke_z) / RHOT_hyd(:) )**gamm / DENS0(:,ke_z,ij) ) - end do - end do - !$omp end parallel - - !$omp parallel do private(ke_z, ke, ColMask, p, fp, v, f1, ke_z2, fac_dz_p, & - !$omp fac, tmp1, alphaM, alphaP, FmV, & - !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & - !$omp Dd ) & - !$omp firstprivate(PmatD, PmatL, PmatU) - do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - Colmask(:) = elem%Colmask(:,ij) - - !----- - do p=1, elem%Nnode_v - fac_dz_p(:) = impl_fac * lmesh%Escale(Colmask(:),ke,3,3) * elem%Dx3(Colmask(:),Colmask(p)) - if (modalFilterFlag) then - Dd(:) = Id(:,p) - VModalFilter(:,p) * impl_fac / dt - else - Dd(:) = Id(:,p) - end if - - ! DDENS - PmatD(:,p,DDENS_VID,DDENS_VID) = Dd(:) - PmatD(:,p,DDENS_VID,MOMZ_VID) = fac_dz_p(:) - - ! MOMX - PmatD(:,p,MOMX_VID,MOMX_VID) = Dd(:) - - ! MOMY - PmatD(:,p,MOMY_VID,MOMY_VID) = Dd(:) - - ! MOMZ - PmatD(:,p,MOMZ_VID,MOMZ_VID) = Dd(:) - PmatD(:,p,MOMZ_VID,DDENS_VID) = impl_fac * Grav * IntrpMat_VPOrdM1(Colmask(:),Colmask(p)) - PmatD(:,p,MOMZ_VID,DRHOT_VID) = fac_dz_p(:) * DPDRHOT0(p,ke_z,ij) - - !DRHOT - PmatD(:,p,DRHOT_VID,DDENS_VID) = - fac_dz_p(:) * POT0(p,ke_z,ij) * W0(p,ke_z,ij) - PmatD(:,p,DRHOT_VID,MOMZ_VID ) = fac_dz_p(:) * POT0(p,ke_z,ij) - PmatD(:,p,DRHOT_VID,DRHOT_VID) = Dd(:) + fac_dz_p(:) * W0(p,ke_z,ij) - end do - - do f1=1, 2 - if (f1==1) then - ke_z2 = max(ke_z-1,1) - pv1 = 1; pv2 = elem%Nnode_v - else - ke_z2 = min(ke_z+1,lmesh%NeZ) - pv1 = elem%Nnode_v; pv2 = 1 - end if - fac = 0.5_RP * impl_fac - if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then - bc_flag = .true. - pv2 = pv1 - else - bc_flag = .false. - end if - - FmV = elem%Fmask_v(ij,f1) - fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij - - !-- - alphaM = abs( W0(pv1,ke_z ,ij) ) + Cs0(pv1,ke_z ,ij) - alphaP = abs( W0(pv2,ke_z2,ij) ) + Cs0(pv2,ke_z2,ij) - - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * max(alphaM, alphaP) - if (bc_flag) then - !PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) = PmatD(pv1,pv1,MOMZ_VID,MOMZ_VID) + 2.0_RP * tmp1 - else - do v=1, PROG_VARS_NUM - PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 - if (f1 == 1) then - PmatL(pv1,pv2,v,v) = - tmp1 - else - PmatU(pv1,pv2,v,v) = - tmp1 - end if - end do - end if - - !-- - tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * nz(fp,ke_z) - - if (bc_flag) then - PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - 2.0_RP * tmp1 - PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - 2.0_RP * tmp1 * W0(pv1,ke_z,ij) - else - PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) = PmatD(pv1,pv1,DDENS_VID,MOMZ_VID ) - tmp1 - PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) = PmatD(pv1,pv1,MOMZ_VID ,DRHOT_VID) - tmp1 * DPDRHOT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) = PmatD(pv1,pv1,DRHOT_VID,MOMZ_VID ) - tmp1 * POT0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) = PmatD(pv1,pv1,DRHOT_VID,DDENS_VID) + tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) - PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) = PmatD(pv1,pv1,DRHOT_VID,DRHOT_VID) - tmp1 * W0(pv1,ke_z,ij) - - if (f1 == 1) then - PmatL(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 - PmatL(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) - PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatL(pv1,pv2,DRHOT_VID,DRHOT_VID) & - + tmp1 * W0(pv2,ke_z2,ij) - else - PmatU(pv1,pv2,DDENS_VID,MOMZ_VID ) = + tmp1 - PmatU(pv1,pv2,MOMZ_VID,DRHOT_VID ) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,MOMZ_VID ) = + tmp1 * POT0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,DDENS_VID) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) - PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) = PmatU(pv1,pv2,DRHOT_VID,DRHOT_VID) & - + tmp1 * W0(pv2,ke_z2,ij) - end if - end if - end do - - do v2=1, PROG_VARS_NUM - do v1=1, PROG_VARS_NUM - if ( eval_flag(v1,v2) ) then - do pv2=1, elem%Nnode_v - g_kj = pv2 + (v2-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM - g_kjm1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z-2)*elem%Nnode_v*PROG_VARS_NUM - g_kjp1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z )*elem%Nnode_v*PROG_VARS_NUM - - do pv1=1, elem%Nnode_v - pb1 = pv1 + (v1-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*PROG_VARS_NUM - if (ke_z > 1) then - PmatBnd(kl+ku+1+pb1-g_kjm1, pv2,v2,ke_z-1, ij) = PmatL(pv1,pv2,v1,v2) - end if - PmatBnd(kl+ku+1+pb1-g_kj, pv2,v2,ke_z, ij) = PmatD(pv1,pv2,v1,v2) - if (ke_z < lmesh%NeZ) then - PmatBnd(kl+ku+1+pb1-g_kjp1, pv2,v2,ke_z+1, ij) = PmatU(pv1,pv2,v1,v2) - end if - end do - end do - end if - end do - end do - end do - end do - - return - end subroutine vi_construct_matbnd - -!----------------------------------------- + !----------------------------------------- subroutine dx_ab(DxT1D, a, b, Nnode_h1D, Nnode_v, fx) integer, intent(in) :: Nnode_h1D, Nnode_v diff --git a/FElib/src/mesh/scale_localmesh_3d.F90 b/FElib/src/mesh/scale_localmesh_3d.F90 index c00a13e3..b2328f3a 100644 --- a/FElib/src/mesh/scale_localmesh_3d.F90 +++ b/FElib/src/mesh/scale_localmesh_3d.F90 @@ -34,6 +34,7 @@ module scale_localmesh_3d real(DP), allocatable :: Sz(:,:) real(DP), allocatable :: zS(:,:) real(RP), allocatable :: GI3(:,:,:) !< The contravariant component of metric tensor with vertical general coordinate + real(RP), allocatable :: GsqrtH(:,:) !< The Jacobian of horizontal transformation in the computational coordinate real(RP), allocatable :: zlev(:,:) class(LocalMesh2D), pointer :: lcmesh2D @@ -91,7 +92,7 @@ subroutine LocalMesh3D_Final( this, is_generated ) call LocalMeshBase_Final( this, is_generated ) if (is_generated) then deallocate( this%zS, this%Sz ) - deallocate( this%GI3, this%Gsqrt ) + deallocate( this%GI3, this%GsqrtH ) deallocate( this%zlev ) deallocate( this%lon2D, this%lat2D ) deallocate( this%EMap3Dto2D ) diff --git a/FElib/src/mesh/scale_localmesh_base.F90 b/FElib/src/mesh/scale_localmesh_base.F90 index eae0a390..c71d63bc 100644 --- a/FElib/src/mesh/scale_localmesh_base.F90 +++ b/FElib/src/mesh/scale_localmesh_base.F90 @@ -61,7 +61,6 @@ module scale_localmesh_base real(RP), allocatable :: G_ij(:,:,:,:) !< The covariant component of metric tensor with horizontal general curvilinear coordinate real(RP), allocatable :: GIJ(:,:,:,:) !< The contravariant component of metric tensor with horizontal general curvilinear coordinate - real(RP), allocatable :: GsqrtH(:,:) !< The Jacobian of horizontal transformation in the computational coordinate real(RP), allocatable :: Gsqrt(:,:) !< The Jacobian of 3D transformation in the computational coordinate (=GsqrtH * GsqrtV) end type LocalMeshBase @@ -138,7 +137,7 @@ subroutine LocalMeshBase_Final( this, is_generated ) end if if ( allocated(this%G_ij) ) then deallocate( this%G_ij, this%GIJ ) - deallocate( this%Gsqrt, this%GsqrtH ) + deallocate( this%Gsqrt ) end if end if diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index d717062a..1d4db1c5 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -32,7 +32,6 @@ module scale_mesh_base3d procedure(MeshBase3D_generate), deferred :: Generate procedure(MeshBase3D_getMesh2D), deferred :: GetMesh2D procedure :: GetLocalMesh => MeshBase3D_get_localmesh - procedure :: SetVCoordinate_lcdom => MeshBase3D_set_vcoordinate_lcdom end type MeshBase3D interface @@ -143,36 +142,6 @@ subroutine MeshBase3D_get_localmesh( this, id, ptr_lcmesh ) return end subroutine MeshBase3D_get_localmesh - subroutine MeshBase3D_set_vcoordinate_lcdom( this, & - vcoord_name, domid, topo, zTop, Dx2D, Dy2D, Lift2D ) - - use scale_sparsemat, only: SparseMat - use scale_meshutil_vcoord, only: MeshUtil_VCoord_GetMetric - implicit none - - class(MeshBase3D), target, intent(in) :: this - character(len=*), intent(in) :: vcoord_name - integer, intent(in) :: domid - real(RP), intent(in) :: topo(this%lcmesh_list(domid)%refElem3D%Nfp_v,this%lcmesh_list(domid)%lcmesh2D%NeA) - real(RP), intent(in) :: zTop - type(SparseMat), intent(in) :: Dx2D, Dy2D, Lift2D - - class(LocalMesh3D), pointer :: lcmesh - class(LocalMesh2D), pointer :: lcmesh2D - integer :: n - !------------------------------------------------------------- - - lcmesh => this%lcmesh_list(domid) - lcmesh2D => lcmesh%lcmesh2D - call MeshUtil_VCoord_GetMetric( & - lcmesh%GI3(:,:,1), lcmesh%GI3(:,:,2), lcmesh%zlev(:,:), & ! (out) - lcmesh%Gsqrt(:,:), & ! (inout) - topo(:,:), zTop, vcoord_name, lcmesh, lcmesh%refElem3D, lcmesh2D, lcmesh2D%refElem2D, & ! (in - Dx2D, Dy2D, Lift2D ) ! (in) - - return - end subroutine MeshBase3D_set_vcoordinate_lcdom - subroutine MeshBase3D_setGeometricInfo( lcmesh, coord_conv, calc_normal ) implicit none diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 63b8b235..7541f836 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -154,9 +154,15 @@ subroutine MeshCubeDom3D_Init( this, & call MeshBase3D_Init( this, refElem, NLocalMeshPerPrc, 6, & nproc, myrank ) - !--- + !--- 2D mesh call this%refElem2D%Init( this%refElem3D%PolyOrder_h, refElem%IsLumpedMatrix() ) + + this%mesh2D%isPeriodicX = isPeriodicX + this%mesh2D%isPeriodicY = isPeriodicY + this%mesh2D%NprcX = NprcX + this%mesh2D%NprcY = NprcY + call MeshBase2D_Init( this%mesh2D, this%refElem2D, NLocalMeshPerPrc, & nproc, myrank ) @@ -223,7 +229,7 @@ subroutine MeshCubeDom3D_generate( this ) call MesshCubeDom3D_assignDomID( this, & ! (in) tileID_table, panelID_table, & ! (out) - pi_table, pj_table, pk_table ) ! (out) + pi_table, pj_table, pk_table ) ! (out) !--- Setup local meshes managed by my process @@ -257,6 +263,11 @@ subroutine MeshCubeDom3D_generate( this ) ! write(*,*) " [X], [Y]:", mesh%xmin, mesh%xmax, ":", mesh%ymin, mesh%ymax end do + ! To set rcdomIJP2LCMeshID, call AssignDomID for 2D mesh + call this%mesh2D%AssignDomID( & + tileID_table, panelID_table, & ! (out) + pi_table, pj_table ) ! (out) + this%isGenerated = .true. this%mesh2D%isGenerated = .true. diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 index edabf5f0..85ca7c29 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom2d.F90 @@ -41,7 +41,7 @@ module scale_mesh_cubedspheredom2d procedure :: Init => MeshCubedSphereDom2D_Init procedure :: Final => MeshCubedSphereDom2D_Final procedure :: Generate => MeshCubedSphereDom2D_generate - procedure :: AssignDomID => MesshCubedSphereDom2D_assignDomID + procedure :: AssignDomID => MeshCubedSphereDom2D_assignDomID end type MeshCubedSphereDom2D public :: MeshCubedSphereDom2D_check_division_params @@ -344,7 +344,7 @@ end subroutine MeshCubedSphereDom2D_setupLocalDom !- private ------------------------------ - subroutine MesshCubedSphereDom2D_assignDomID( this, & + subroutine MeshCubedSphereDom2D_assignDomID( this, & NprcX_lc, NprcY_lc, & tileID_table, panelID_table, & pi_table, pj_table ) @@ -414,7 +414,7 @@ subroutine MesshCubedSphereDom2D_assignDomID( this, & end do return - end subroutine MesshCubedSphereDom2D_assignDomID + end subroutine MeshCubedSphereDom2D_assignDomID subroutine MeshCubedSphereDom2D_coord_conv( x, y, xr, xs, yr, ys, & vx, vy, elem ) diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 index 0e960772..1b194860 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 @@ -69,7 +69,12 @@ module scale_mesh_cubedspheredom3d ! !++ Private procedure ! - + + private :: MeshCubedSphereDom3D_calc_normal + private :: MeshCubedSphereDom3D_coord_conv + private :: MeshCubedSphereDom3D_set_metric + private :: fill_halo_metric + !----------------------------------------------------------------------------- ! !++ Private parameters & variables @@ -183,18 +188,12 @@ end subroutine MeshCubedSphereDom3D_getMesh2D subroutine MeshCubedSphereDom3D_generate( this ) use scale_mesh_cubedspheredom2d, only: & MeshCubedSphereDom2D_check_division_params - use scale_cubedsphere_cnv, only: & - CubedSphereCnv_CS2LonLatCoord, & - CubedSphereCnv_GetMetric implicit none class(MeshCubedSphereDom3D), intent(inout), target :: this integer :: n type(LocalMesh3D), pointer :: mesh - type(LocalMesh2D), pointer :: lcmesh2D - type(ElementBase3D), pointer :: elem3D - type(ElementBase2D), pointer :: elem2D integer :: tileID_table(this%LOCAL_MESH_NUM, this%PRC_NUM) integer :: panelID_table(this%LOCAL_MESH_NUM*this%PRC_NUM) @@ -203,9 +202,7 @@ subroutine MeshCubedSphereDom3D_generate( this ) integer :: pk_table(this%LOCAL_MESH_NUM*this%PRC_NUM) integer :: NprcX_lc, NprcY_lc, NprcZ_lc - integer :: tileID - - integer :: ke, ke2D + integer :: tileID !----------------------------------------------------------------------------- call MeshCubedSphereDom2D_check_division_params( & @@ -224,7 +221,6 @@ subroutine MeshCubedSphereDom3D_generate( this ) do n=1, this%LOCAL_MESH_NUM mesh => this%lcmesh_list(n) - elem3D => mesh%refElem3D tileID = tileID_table(n, mesh%PRC_myrank+1) call MeshCubedSphereDom3D_setupLocalDom( mesh, & @@ -244,23 +240,6 @@ subroutine MeshCubedSphereDom3D_generate( this ) call mesh%SetLocalMesh2D( this%mesh2D%lcmesh_list(n) ) - lcmesh2D => this%mesh2D%lcmesh_list(n) - elem2D => lcmesh2D%refElem2D - call CubedSphereCnv_CS2LonLatCoord( & - lcmesh2D%panelID, lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), & - lcmesh2D%Ne * elem2D%Np, this%RPlanet, & - mesh%lon2D(:,:), mesh%lat2D(:,:) ) - - call CubedSphereCnv_GetMetric( & - lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), elem2D%Np * lcmesh2D%Ne, this%RPlanet, & ! (in) - mesh%G_ij, mesh%GIJ, mesh%GsqrtH ) ! (out) - - !$omp parallel do private(ke2D) - do ke=mesh%NeS, mesh%NeE - ke2D = mesh%EMap3Dto2D(ke) - mesh%Gsqrt(:,ke) = mesh%GsqrtH(elem3D%IndexH2Dto3D(:),ke2D) - end do - !--- ! write(*,*) "** my_rank=", mesh%PRC_myrank ! write(*,*) " tileID:", mesh%tileID @@ -274,6 +253,15 @@ subroutine MeshCubedSphereDom3D_generate( this ) ! write(*,*) " [X], [Y]:", mesh%xmin, mesh%xmax, ":", mesh%ymin, mesh%ymax end do + ! Set lon&lat position and metrics with the cubed sphere mesh + call MeshCubedSphereDom3D_set_metric( this ) + + ! To set rcdomIJP2LCMeshID, call AssignDomID for 2D mesh + call this%mesh2D%AssignDomID( & + NprcX_lc, NprcY_lc, & ! (in) + tileID_table, panelID_table, & ! (out) + pi_table, pj_table ) ! (out) + this%isGenerated = .true. this%mesh2D%isGenerated = .true. @@ -542,4 +530,70 @@ subroutine MeshCubedSphereDom3D_calc_normal( normal_fn, & return end subroutine MeshCubedSphereDom3D_calc_normal + !-- + +!OCL SERIAL + subroutine MeshCubedSphereDom3D_set_metric( this ) + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_CS2LonLatCoord, & + CubedSphereCnv_GetMetric + + implicit none + class(MeshCubedSphereDom3D), intent(inout), target :: this + + integer :: n + integer :: ke, ke2D + + class(LocalMesh3D), pointer :: lcmesh + class(LocalMesh2D), pointer :: lcmesh2D + class(ElementBase2D), pointer :: elem2D + !---------------------------------------------------- + + do n=1, this%mesh2D%LOCAL_MESH_NUM + lcmesh => this%lcmesh_list(n) + lcmesh2D => this%mesh2D%lcmesh_list(n) + elem2D => lcmesh2D%refElem2D + call CubedSphereCnv_CS2LonLatCoord( & + lcmesh2D%panelID, lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), & ! (in) + lcmesh2D%Ne * elem2D%Np, this%RPlanet, & ! (in) + lcmesh%lon2D(:,:), lcmesh%lat2D(:,:) ) ! (out) + + call CubedSphereCnv_GetMetric( & + lcmesh2D%pos_en(:,:,1), lcmesh2D%pos_en(:,:,2), elem2D%Np * lcmesh2D%Ne, this%RPlanet, & ! (in) + lcmesh%G_ij, lcmesh%GIJ, lcmesh%GsqrtH ) ! (out) + + !$omp parallel do private(ke2D) + do ke=lcmesh%NeS, lcmesh%NeE + ke2D = lcmesh%EMap3Dto2D(ke) + lcmesh%Gsqrt(:,ke) = lcmesh%GsqrtH(lcmesh%refElem3D%IndexH2Dto3D(:),ke2D) + end do + + call fill_halo_metric( lcmesh%Gsqrt, lcmesh%VMapM, lcmesh%VMapP, lcmesh, lcmesh%refElem3D ) + end do + + return + end subroutine MeshCubedSphereDom3D_set_metric + +!OCL SERIAL + subroutine fill_halo_metric( Gsqrt, vmapM, vmapP, lmesh, elem ) + implicit none + class(LocalMesh3D), intent(in) :: lmesh + class(ElementBase3D), intent(in) :: elem + integer, intent(in) :: vmapM(elem%NfpTot*lmesh%Ne) + integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) + real(RP), intent(inout) :: Gsqrt(elem%Np*lmesh%NeA) + + integer :: i, iM, iP + !------------------------------------------------ + + !$omp parallel do private(i, iM, iP) + do i=1, elem%NfpTot*lmesh%Ne + iM = vmapM(i); iP = vmapP(i) + if ( iP > elem%Np * lmesh%Ne ) then + Gsqrt(iP) = Gsqrt(iM) + end if + end do + return + end subroutine fill_halo_metric + end module scale_mesh_cubedspheredom3d \ No newline at end of file diff --git a/FElib/src/mesh/scale_mesh_rectdom2d.F90 b/FElib/src/mesh/scale_mesh_rectdom2d.F90 index 465edafb..40871cc6 100644 --- a/FElib/src/mesh/scale_mesh_rectdom2d.F90 +++ b/FElib/src/mesh/scale_mesh_rectdom2d.F90 @@ -41,6 +41,7 @@ module scale_mesh_rectdom2d procedure :: Init => MeshRectDom2D_Init procedure :: Final => MeshRectDom2D_Final procedure :: Generate => MeshRectDom2D_generate + procedure :: AssignDomID => MeshRectDom2D_assignDomID end type MeshRectDom2D public :: MeshRectDom2D_coord_conv @@ -140,7 +141,6 @@ subroutine MeshRectDom2D_generate( this ) integer :: pj_table(this%LOCAL_MESH_NUM*this%PRC_NUM) integer :: TILE_NUM_PER_PANEL - integer :: NprcX, NprcY real(RP) :: delx, dely integer :: tileID @@ -151,10 +151,9 @@ subroutine MeshRectDom2D_generate( this ) !--- Construct the connectivity of patches (only master node) - call MesshRectDom2D_assignDomID( this, & ! (in) - & NprcX, NprcY, & ! (out) - & tileID_table, panelID_table, & ! (out) - & pi_table, pj_table ) ! (out) + call this%AssignDomID( & + tileID_table, panelID_table, & ! (out) + pi_table, pj_table ) ! (out) !--- Setup local meshes managed by my process @@ -163,10 +162,10 @@ subroutine MeshRectDom2D_generate( this ) tileID = tileID_table(n, mesh%PRC_myrank+1) call MeshRectDom2D_setupLocalDom( mesh, & - & tileID, panelID_table(tileID), & - & pi_table(tileID), pj_table(tileID), NprcX, NprcY, & - & this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & - & this%NeGX/NprcX, this%NeGY/NprcY ) + tileID, panelID_table(tileID), & + pi_table(tileID), pj_table(tileID), this%NprcX, this%NprcY, & + this%xmin_gl, this%xmax_gl, this%ymin_gl, this%ymax_gl, & + this%NeGX/this%NprcX, this%NeGY/this%NprcY ) !--- ! write(*,*) "** my_rank=", mesh%PRC_myrank @@ -278,8 +277,7 @@ subroutine MeshRectDom2D_setupLocalDom( lcmesh, & return end subroutine MeshRectDom2D_setupLocalDom - subroutine MesshRectDom2D_assignDomID( this, & - NprcX, NprcY, & + subroutine MeshRectDom2D_assignDomID( this, & tileID_table, panelID_table, & pi_table, pj_table ) @@ -288,9 +286,7 @@ subroutine MesshRectDom2D_assignDomID( this, & implicit none - type(MeshRectDom2D), target, intent(inout) :: this - integer, intent(out) :: NprcX - integer, intent(out) :: NprcY + class(MeshRectDom2D), target, intent(inout) :: this integer, intent(out) :: tileID_table(this%LOCAL_MESH_NUM, this%PRC_NUM) integer, intent(out) :: panelID_table(this%LOCAL_MESH_NUM*this%PRC_NUM) integer, intent(out) :: pi_table(this%LOCAL_MESH_NUM*this%PRC_NUM) @@ -309,10 +305,8 @@ subroutine MesshRectDom2D_assignDomID( this, & call MeshUtil2D_buildGlobalMap( & panelID_table, pi_table, pj_table, & ! (out) this%tileID_globalMap, this%tileFaceID_globalMap, this%tilePanelID_globalMap, & ! (out) - this%LOCAL_MESH_NUM_global, this%isPeriodicX, this%isPeriodicY ) ! (in) ! (in) - - NprcX = maxval(pi_table) - NprcY = maxval(pj_table) + this%LOCAL_MESH_NUM_global, this%isPeriodicX, this%isPeriodicY, & ! (in) + this%NprcX, this%NprcY ) ! (in) !---- @@ -345,7 +339,7 @@ subroutine MesshRectDom2D_assignDomID( this, & end do return - end subroutine MesshRectDom2D_assignDomID + end subroutine MeshRectDom2D_assignDomID subroutine MeshRectDom2D_coord_conv( x, y, xr, xs, yr, ys, & vx, vy, elem ) diff --git a/FElib/src/mesh/scale_mesh_topography.F90 b/FElib/src/mesh/scale_mesh_topography.F90 index 0420967a..09d25b31 100644 --- a/FElib/src/mesh/scale_mesh_topography.F90 +++ b/FElib/src/mesh/scale_mesh_topography.F90 @@ -25,7 +25,7 @@ module scale_mesh_topography ! !++ Public type & procedure ! - type, abstract, public :: MeshTopography + type, public :: MeshTopography type(MeshField2D) :: topo contains procedure :: Init => MeshTopography_Init @@ -49,14 +49,21 @@ module scale_mesh_topography ! contains - subroutine MeshTopography_Init( this, mesh ) + subroutine MeshTopography_Init( this, varname, mesh ) implicit none class(MeshTopography), intent(inout) :: this + character(len=*), intent(in) :: varname class(MeshBase2D), intent(in), target :: mesh + + integer :: n !----------------------------------------------------------------------------- - call this%topo%Init( "TOPO", "m", mesh ) + call this%topo%Init( varname, "m", mesh ) + + do n=1, mesh%LOCAL_MESH_NUM + this%topo%local(n)%val(:,:) = 0.0_RP + end do return end subroutine MeshTopography_Init @@ -73,18 +80,18 @@ subroutine MeshTopography_Final( this ) end subroutine MeshTopography_Final subroutine MeshTopography_set_vcoordinate( this, mesh3D, & - vcoord_name, zTop, comm3D, comm2D ) + vcoord_id, zTop, comm3D, comm2D ) use scale_sparsemat, only: SparseMat use scale_meshutil_vcoord, only: MeshUtil_VCoord_GetMetric implicit none - class(MeshTopography), target, intent(in) :: this + class(MeshTopography), target, intent(inout) :: this class(MeshBase3D), intent(inout), target :: mesh3D - character(len=*), intent(in) :: vcoord_name + integer, intent(in) :: vcoord_id real(RP), intent(in) :: zTop - class(MeshFieldCommBase) :: comm3D - class(MeshFieldCommBase) :: comm2D + class(MeshFieldCommBase), intent(inout) :: comm3D + class(MeshFieldCommBase), intent(inout) :: comm2D type(SparseMat) :: Dx2D, Dy2D, Lift2D class(LocalMesh3D), pointer :: lcmesh @@ -105,7 +112,15 @@ subroutine MeshTopography_set_vcoordinate( this, mesh3D, & call Dy2D %Init( lcmesh2D%refElem2D%Dx2 ) call Lift2D%Init( lcmesh2D%refElem2D%Lift ) - !-- + ! Exchange topography data to fill halo + + comm2d_varlist(1)%field2d => this%topo + call comm2D%Put(comm2d_varlist, 1) + call comm2D%Exchange() + call comm2D%Get(comm2d_varlist, 1) + + ! Calculate metric factors associated with general vertical coordinates + call Gsqrt%Init( "Gsqrt", "", mesh3D ) call G13%Init( "G13", "", mesh3D ) call G23%Init( "G23", "", mesh3D ) @@ -118,21 +133,13 @@ subroutine MeshTopography_set_vcoordinate( this, mesh3D, & call MeshUtil_VCoord_GetMetric( & G13%local(n)%val, G23%local(n)%val, lcmesh%zlev(:,:), & ! (out) Gsqrt%local(n)%val, & ! (inout) - this%topo%local(n)%val(:,:), zTop, vcoord_name, & ! (in) + this%topo%local(n)%val(:,:), zTop, vcoord_id, & ! (in) lcmesh, lcmesh%refElem3D, lcmesh2D, lcmesh2D%refElem2D, & ! (in) Dx2D, Dy2D, Lift2D ) ! (in) end do - !-- Communicate halo data - - ! 2D + ! Exchange metric data to fill halo - comm2d_varlist(1)%field2d => this%topo - call comm2D%Put(comm2d_varlist, 1) - call comm2D%Exchange() - call comm2D%Get(comm2d_varlist, 1) - - ! 3D comm3d_varlist(1)%field3d => Gsqrt comm3d_varlist(2)%field3d => G13 comm3d_varlist(3)%field3d => G23 @@ -141,6 +148,8 @@ subroutine MeshTopography_set_vcoordinate( this, mesh3D, & call comm3D%Exchange() call comm3D%Get(comm3d_varlist, 1) + ! Update metric data managed by local mesh + do n=1, mesh3D%LOCAL_MESH_NUM lcmesh => mesh3D%lcmesh_list(n) !$omp parallel do @@ -152,6 +161,10 @@ subroutine MeshTopography_set_vcoordinate( this, mesh3D, & end do !--- + call Gsqrt%Final() + call G13%Final() + call G23%Final() + call Dx2D%Final() call Dy2D%Final() call Lift2D%Final() diff --git a/FElib/src/mesh/scale_meshutil_2d.F90 b/FElib/src/mesh/scale_meshutil_2d.F90 index fc475657..a0723469 100644 --- a/FElib/src/mesh/scale_meshutil_2d.F90 +++ b/FElib/src/mesh/scale_meshutil_2d.F90 @@ -430,9 +430,9 @@ end subroutine MeshUtil2D_genPatchBoundaryMap subroutine MeshUtil2D_buildGlobalMap( & panelID_table, pi_table, pj_table, & tileID_map, tileFaceID_map, tilePanelID_map, & - Ntile, isPeriodicX, isPeriodicY ) - - use scale_prc, only: PRC_isMaster + Ntile, isPeriodicX, isPeriodicY, & + Ne_x, Ne_y ) + implicit none integer, intent(in) :: Ntile @@ -444,9 +444,11 @@ subroutine MeshUtil2D_buildGlobalMap( & integer, intent(out) :: tilePanelID_map(4,Ntile) logical, intent(in) :: isPeriodicX logical, intent(in) :: isPeriodicY + integer, intent(in) :: Ne_x + integer, intent(in) :: Ne_y integer :: NtilePerPanel - integer :: NeX, NeY, NvX, NvY + integer :: NvX, NvY integer, allocatable :: nodesID_2d(:,:) integer, allocatable :: EToV(:,:) integer, allocatable :: EToE(:,:) @@ -459,11 +461,9 @@ subroutine MeshUtil2D_buildGlobalMap( & !----------------------------------------------------------------------------- NtilePerPanel = Ntile/1 - NeY = int( sqrt(dble(NtilePerPanel)) ) - NeX = NtilePerPanel/NeY - NvX = NeX + 1 - NvY = NeY + 1 - allocate( nodesID_2d(NvX,NvY) ) + NvX = Ne_x + 1 + NvY = Ne_y + 1 + allocate( nodesID_2d(NvX, NvY) ) allocate( EToV(Ntile,4), EToE(Ntile,4), EToF(Ntile,4) ) counter = 0 @@ -477,8 +477,8 @@ subroutine MeshUtil2D_buildGlobalMap( & !---- tileID = 0 - do j = 1, NeY - do i = 1, NeX + do j = 1, Ne_y + do i = 1, Ne_x tileID = tileID + 1 panelID_table(tileID) = 1 pi_table(tileID) = i; pj_table(tileID) = j @@ -502,11 +502,11 @@ subroutine MeshUtil2D_buildGlobalMap( & if (isPeriodicX) then do tileID=1, Ntile if (pi_table(tileID) == 1 .and. tileFaceID_map(4,tileID) == 4) then - tileID_map(4,tileID) = NeX + (pj_table(tileID) - 1)*NeX + tileID_map(4,tileID) = Ne_x + (pj_table(tileID) - 1)*Ne_x tileFaceID_map(4,tileID) = 2 end if - if (pi_table(tileID) == NeX .and. tileFaceID_map(2,tileID) == 2) then - tileID_map(2,tileID) = 1 + (pj_table(tileID) - 1)*NeX + if (pi_table(tileID) == Ne_x .and. tileFaceID_map(2,tileID) == 2) then + tileID_map(2,tileID) = 1 + (pj_table(tileID) - 1)*Ne_x tileFaceID_map(2,tileID) = 4 end if end do @@ -515,10 +515,10 @@ subroutine MeshUtil2D_buildGlobalMap( & if (isPeriodicY) then do tileID=1, Ntile if (pj_table(tileID) == 1 .and. tileFaceID_map(1,tileID) == 1) then - tileID_map(1,tileID) = pi_table(tileID) + (NeY - 1)*NeX + tileID_map(1,tileID) = pi_table(tileID) + (Ne_y - 1)*Ne_x tileFaceID_map(1,tileID) = 3 end if - if (pj_table(tileID) == NeY .and. tileFaceID_map(3,tileID) == 3) then + if (pj_table(tileID) == Ne_y .and. tileFaceID_map(3,tileID) == 3) then tileID_map(3,tileID) = pi_table(tileID) tileFaceID_map(3,tileID) = 1 end if diff --git a/FElib/src/mesh/scale_meshutil_vcoord.F90 b/FElib/src/mesh/scale_meshutil_vcoord.F90 index 4c76a758..84d3d569 100644 --- a/FElib/src/mesh/scale_meshutil_vcoord.F90 +++ b/FElib/src/mesh/scale_meshutil_vcoord.F90 @@ -26,6 +26,7 @@ module scale_meshutil_vcoord ! !++ Public type & procedure ! + public :: MeshUtil_get_VCoord_TypeID public :: MeshUtil_VCoord_GetMetric !----------------------------------------------------------------------------- @@ -33,6 +34,7 @@ module scale_meshutil_vcoord !++ Public parameters & variables ! character(*), public, parameter :: MESH_VCOORD_TERRAIN_FOLLOWING_NAME = "TERRAIN_FOLLOWING" + integer, public, parameter :: MESH_VCOORD_TERRAIN_FOLLOWING_ID = 1 !----------------------------------------------------------------------------- ! @@ -47,9 +49,28 @@ module scale_meshutil_vcoord !----------------------------------------------------------------------------- contains +!OCL SERIAL + function MeshUtil_get_VCoord_TypeID( vcoord_type ) result( vcoord_id ) + implicit none + + character(len=*), intent(in) :: vcoord_type + integer :: vcoord_id + + select case( vcoord_type ) + case( MESH_VCOORD_TERRAIN_FOLLOWING_NAME ) + vcoord_id = MESH_VCOORD_TERRAIN_FOLLOWING_ID + case default + LOG_ERROR("MeshUtil_VCoord_TypeID",*) "vcoord_type is inappropriate. Check!", vcoord_type + call PRC_abort + end select + + return + end function MeshUtil_get_VCoord_TypeID + +!OCL SERIAL subroutine MeshUtil_VCoord_GetMetric( G13, G23, zlev, & Gsqrt, & - topo, zTop, vcoord_type, lcmesh, elem, lcmesh2D, elem2D, & + topo, zTop, vcoord_id, lcmesh, elem, lcmesh2D, elem2D, & Dx2D, Dy2D, Lift2D ) implicit none @@ -61,22 +82,22 @@ subroutine MeshUtil_VCoord_GetMetric( G13, G23, zlev, & real(RP), intent(out) :: G23(elem%Np,lcmesh%NeA) real(RP), intent(out) :: zlev(elem%Np,lcmesh%Ne) real(RP), intent(inout) :: Gsqrt(elem%Np,lcmesh%NeA) - real(RP), intent(in) :: topo(elem2D%Np,lcmesh2D%Ne) - character(len=*), intent(in) :: vcoord_type + real(RP), intent(in) :: topo(elem2D%Np,lcmesh2D%NeA) + integer, intent(in) :: vcoord_id real(RP), intent(in) :: zTop type(SparseMat), intent(in) :: Dx2D type(SparseMat), intent(in) :: Dy2D type(SparseMat), intent(in) :: Lift2D integer :: ke, ke2D - real(RP) :: del_flux(elem2D%Np,lcmesh2D%Ne,2) - real(RP) :: Fx2D(elem2D%NP), Fy2D(elem2D%NP), LiftDelFlux2D(elem2D%NP) - real(RP) :: GsqrtV(elem%Np,lcmesh2D%Ne) + real(RP) :: del_flux(elem2D%NfpTot,lcmesh2D%Ne,2) + real(RP) :: Fx2D(elem2D%Np), Fy2D(elem2D%Np), LiftDelFlux2D(elem2D%Np) + real(RP) :: GsqrtV(elem2D%Np,lcmesh2D%Ne) real(RP) :: GradZs(elem2D%Np,lcmesh2D%Ne,2) real(RP) :: coef3D(elem%NP) !------------------------------------------------ - if ( vcoord_type == MESH_VCOORD_TERRAIN_FOLLOWING_NAME ) then + if ( vcoord_id == MESH_VCOORD_TERRAIN_FOLLOWING_ID ) then ! * z = topo + (1 - topo / zTop ) * zeta ! * zeta = zTop * (z - topo)/(zTop - topo) @@ -84,6 +105,10 @@ subroutine MeshUtil_VCoord_GetMetric( G13, G23, zlev, & ! = - (dz/dxi)_zeta * dzeta/dz ! = (GsqrtV)^-1 * [ - 1 + zeta / zTop ] * d topo /dxi (i=1, 2) + call cal_del_flux( del_flux, & + topo, lcmesh2D%normal_fn(:,:,1), lcmesh2D%normal_fn(:,:,2), & + lcmesh2D%VMapM, lcmesh2D%VMapP, lcmesh2D, elem2D ) + !$omp parallel private(ke2D, ke, & !$omp Fx2D, Fy2D, LiftDelFlux2D, coef3D ) @@ -99,8 +124,8 @@ subroutine MeshUtil_VCoord_GetMetric( G13, G23, zlev, & call sparsemat_matmul( Lift2D, lcmesh2D%Fscale(:,ke2D) * del_flux(:,ke2D,2), LiftDelFlux2D) GradZs(:,ke2D,2) = lcmesh2D%Escale(:,ke2D,2,2) * Fy2D(:) + LiftDelFlux2D(:) end do - !$omp end do + !$omp do do ke=1, lcmesh%Ne ke2D = lcmesh%EMap3Dto2D(ke) @@ -108,24 +133,25 @@ subroutine MeshUtil_VCoord_GetMetric( G13, G23, zlev, & zlev(:,ke) = lcmesh%pos_en(:,ke,3) & + coef3D(:) * topo(elem%IndexH2Dto3D,ke2D) - coef3D(:) = - coef3D(:) / GsqrtV(elem%IndexH2Dto3D,ke2D) - G13(:,ke) = coef3D(:) * GradZs(elem%IndexH2Dto3D,ke2D,1) - G23(:,ke) = coef3D(:) * GradZs(elem%IndexH2Dto3D,ke2D,2) + coef3D(:) = - coef3D(:) / GsqrtV(elem%IndexH2Dto3D(:),ke2D) + G13(:,ke) = coef3D(:) * GradZs(elem%IndexH2Dto3D(:),ke2D,1) + G23(:,ke) = coef3D(:) * GradZs(elem%IndexH2Dto3D(:),ke2D,2) - Gsqrt(:,ke) = Gsqrt(:,ke) * GsqrtV(elem%IndexH2Dto3D,ke2D) + Gsqrt(:,ke) = Gsqrt(:,ke) * GsqrtV(elem%IndexH2Dto3D(:),ke2D) end do !$omp end do !$omp end parallel else - LOG_ERROR("Mesh_VCoord_GetMetric",*) "vcoord_type is inappropriate. Check!", vcoord_type + LOG_ERROR("Mesh_VCoord_GetMetric",*) "vcoord_id is inappropriate. Check!", vcoord_id call PRC_abort end if return end subroutine MeshUtil_VCoord_GetMetric +!OCL SERIAL subroutine cal_del_flux( del_flux, & - topo, nx, ny, vmapM, vmapP,lmesh, elem ) + topo, nx, ny, vmapM, vmapP, lmesh, elem ) implicit none type(LocalMesh2D), intent(in) :: lmesh type(ElementBase2D), intent(in) :: elem @@ -146,6 +172,7 @@ subroutine cal_del_flux( del_flux, & iM = vmapM(i); iP = vmapP(i) dtopo = 0.5_RP * ( topo(iP) - topo(iM) ) + del_flux(i,1) = dtopo * nx(i) del_flux(i,2) = dtopo * ny(i) end do diff --git a/model/atm_nonhydro3d/src/scale-dg_init.F90 b/model/atm_nonhydro3d/src/scale-dg_pp.F90 similarity index 100% rename from model/atm_nonhydro3d/src/scale-dg_init.F90 rename to model/atm_nonhydro3d/src/scale-dg_pp.F90 From 52f6a48270d1fd62442579c68d643cd6a9fea560 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 23 Jun 2021 22:30:04 +0900 Subject: [PATCH 62/98] Modify source codes of scale-dg to treat topography. --- model/atm_nonhydro3d/src/Makefile | 19 +- .../atm_nonhydro3d/src/admin/mod_dg_prep.F90 | 19 +- .../src/atmos/mod_atmos_component.F90 | 2 +- .../src/atmos/mod_atmos_mesh.F90 | 48 +-- .../src/atmos/mod_atmos_mesh_gm.F90 | 71 ++-- .../src/atmos/mod_atmos_mesh_rm.F90 | 52 ++- model/atm_nonhydro3d/src/depend | 4 +- .../src/preprocess/mod_mktopo.F90 | 396 ++++++++++++++++++ model/atm_nonhydro3d/src/scale-dg_pp.F90 | 6 +- 9 files changed, 528 insertions(+), 89 deletions(-) create mode 100644 model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 diff --git a/model/atm_nonhydro3d/src/Makefile b/model/atm_nonhydro3d/src/Makefile index 66070b0f..606a8e53 100644 --- a/model/atm_nonhydro3d/src/Makefile +++ b/model/atm_nonhydro3d/src/Makefile @@ -14,9 +14,11 @@ include $(TOPDIR)/Mkinclude BINNAME = scale-dg INITNAME = scale-dg_init +PPNAME = scale-dg_pp BINS = $(BINDIR)/$(BINNAME)$(POSTFIX) \ - $(BINDIR)/$(INITNAME)$(POSTFIX) + $(BINDIR)/$(INITNAME)$(POSTFIX) \ + $(BINDIR)/$(PPNAME)$(POSTFIX) LIBS = $(LIBDIR)/libScaleFECore.a VERSION = $(shell git rev-parse --short HEAD 2> /dev/null) @@ -52,6 +54,7 @@ OBJS = \ mod_exp.o \ \ mod_dg_prep.o \ + mod_mktopo.o \ mod_mkinit_util.o \ mod_mkinit.o @@ -65,7 +68,7 @@ build: $(MAKE) makelib @echo;echo "Entering scale-dg...";echo "Current version is " $(VERSION) mkdir -p $(BUILD_DIR) - $(MAKE) $(subst $(BINDIR),$(BUILD_DIR),$(BINS)) + $(MAKE) makebin @echo "Complete making scale-dg." install: @@ -81,26 +84,32 @@ info: makelib: $(MAKE) -C $(SCALEFELIBDIR)/src +makebin: $(BUILD_DIR)/$(BINNAME)$(POSTFIX) $(BUILD_DIR)/$(PPNAME)$(POSTFIX) $(BUILD_DIR)/$(BINNAME)$(POSTFIX) : $(BUILD_DIR)/$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o $(LIBS) $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) -$(BUILD_DIR)/$(INITNAME)$(POSTFIX) : $(BUILD_DIR)/$(INITNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o $(LIBS) +$(BUILD_DIR)/$(PPNAME)$(POSTFIX) : $(BUILD_DIR)/$(PPNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o $(LIBS) $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(BUILD_DIR)/$(BINNAME).o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o -$(BUILD_DIR)/$(INITNAME).o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o +$(BUILD_DIR)/$(PPNAME).o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(BUILD_DIR)/mod_user.o $(BUILD_DIR)/mod_user.o : $(LIBS) $(patsubst %,$(BUILD_DIR)/%,$(SUB_OBJS)) $(BUILD_DIR)/mod_exp.o $(BUILD_DIR)/mod_mkinit_util.o $(BINDIR)/$(BINNAME)$(POSTFIX) : $(BUILD_DIR)/$(BINNAME)$(POSTFIX) install $< $@ -$(BINDIR)/$(INITNAME)$(POSTFIX) : $(BUILD_DIR)/$(INITNAME)$(POSTFIX) +$(BINDIR)/$(PPNAME)$(POSTFIX) : $(BUILD_DIR)/$(PPNAME)$(POSTFIX) install $< $@ +$(BINDIR)/$(INITNAME)$(POSTFIX) : $(BINDIR)/$(PPNAME)$(POSTFIX) + (cd $(BINDIR); ln -sf `basename $<` $@) + + distclean: clean rm -f $(BINDIR)/$(BINNAME)$(POSTFIX) rm -f $(BINDIR)/$(INITNAME)$(POSTFIX) + rm -f $(BINDIR)/$(PPNAME)$(POSTFIX) rm -rf ./.libs* clean: diff --git a/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 b/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 index 21fb8aa3..c4aa9dcf 100644 --- a/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 +++ b/model/atm_nonhydro3d/src/admin/mod_dg_prep.F90 @@ -33,6 +33,8 @@ module mod_dg_prep USER_setup, & USER_mkinit + use mod_mktopo, only: & + MKTOPO, MKTOPO_write use mod_mkinit, only: & MKINIT @@ -87,6 +89,7 @@ subroutine dg_prep( & logical :: ismaster logical :: output + logical :: output_topo !--------------------------------------------------------------------------- !########## Initial setup ########## @@ -121,11 +124,17 @@ subroutine dg_prep( & !- Execute preprocess !- Execute mktopo + call PROF_rapstart('MkTopo',1) + call MKTOPO( output_topo, & + atmos%mesh, atmos%mesh%topography ) + call PROF_rapend ('MkTopo',1) !- Re-setup + call atmos%mesh%Setup_vcoordinate() !- Execute mkinit call PROF_rapstart('MkInit',1) + call MKINIT( output, & atmos%mesh, atmos%vars%PROGVARS_manager, atmos%vars%AUXVARS_manager ) call USER_mkinit( atmos ) @@ -134,9 +143,9 @@ subroutine dg_prep( & !- Output - ! call TOPOGRAPHY_write + if ( output_topo ) call MKTOPO_write( atmos%mesh, atmos%mesh%topography ) - if (output) then + if ( output ) then call PROF_rapstart('MkInit_restart',1) call restart_write() call PROF_rapend ('MkInit_restart',1) @@ -161,6 +170,7 @@ subroutine initialize() use scale_time_manager, only: TIME_manager_Init use mod_user, only: USER_setup + use mod_mktopo, only: MKTOPO_setup use mod_mkinit, only: MKINIT_setup implicit none @@ -190,7 +200,10 @@ subroutine initialize() call FILE_restart_meshfield_setup ! setup submodels - call atmos%setup() + call atmos%setup() + + ! setup mktopo + call MKTOPO_setup ! setup mkinit call MKINIT_setup() diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 index 0569f782..6194f1ee 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_component.F90 @@ -112,7 +112,7 @@ subroutine Atmos_setup( this ) ATMOS_DYN_DO, & ATMOS_PHY_SF_DO, & ATMOS_PHY_TB_DO - + integer :: ierr !-------------------------------------------------- call PROF_rapstart( 'ATM_setup', 1) diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 index 9c250072..5568529e 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh.F90 @@ -33,18 +33,20 @@ module mod_atmos_mesh ! type, abstract, extends(ModelMesh3D), public :: AtmosMesh type(HexahedralElement) :: element + type(MeshTopography) :: topography + integer :: vcoord_type_id contains procedure :: AtmosMesh_Init procedure :: AtmosMesh_Final procedure(AtmosMesh_create_communicator), public, deferred :: Create_communicator - procedure(AtmosMesh_setup_restartfile1), public, deferred :: Setup_restartfile1 - procedure(AtmosMesh_setup_restartfile2), public, deferred :: Setup_restartfile2 + procedure(AtmosMesh_setup_restartfile1), public, deferred :: Setup_restartfile1 + procedure(AtmosMesh_setup_restartfile2), public, deferred :: Setup_restartfile2 procedure(AtmosMesh_calc_UVMet), public, deferred :: Calc_UVmet generic :: Setup_restartfile => Setup_restartfile1, Setup_restartfile2 + procedure(AtmosMesh_setup_vcoord), public, deferred :: Setup_vcoordinate procedure :: Construct_ModalFilter3D => AtmosMesh_construct_ModalFilter3D procedure :: Construct_ModalFilterHV => AtmosMesh_construct_ModalFilterHV - procedure :: Setup_vcoordinate => AtmosMesh_setup_vcoordinate end type AtmosMesh interface subroutine AtmosMesh_create_communicator( this, sfield_num, hvfield_num, var_manager, field_list, commid ) @@ -99,7 +101,12 @@ subroutine AtmosMesh_calc_UVMet( this, U, V, & type(MeshField3D), intent(inout) :: Vmet end subroutine AtmosMesh_calc_UVMet end interface - + interface + subroutine AtmosMesh_setup_vcoord( this ) + import AtmosMesh + class(AtmosMesh), target, intent(inout) :: this + end subroutine AtmosMesh_setup_vcoord + end interface integer, parameter, public :: ATM_MESH_MAX_COMMNUICATOR_NUM = 10 !----------------------------------------------------------------------------- @@ -150,7 +157,7 @@ subroutine AtmosMesh_Init( this, mesh ) !- call mesh%GetMesh2D( mesh2D ) - call this%topography%Init( mesh2D ) + call this%topography%Init( "topo", mesh2D ) return end subroutine AtmosMesh_Init @@ -167,37 +174,6 @@ subroutine AtmosMesh_Final(this) return end subroutine AtmosMesh_Final - subroutine AtmosMesh_setup_vcoordinate( this, & - vcoord_name, zTop, & - file_topo, in_basename, in_varname, & - comm3D, comm2D ) - - use scale_file_base_meshfield, only: FILE_base_meshfield - use scale_mesh_base2d, only: & - MFTYPE2D_XY => MeshBase2D_DIMTYPEID_XY - use scale_meshfieldcomm_base, only: MeshFieldCommBase - implicit none - - class(AtmosMesh), intent(inout), target :: this - character(len=*), intent(in) :: vcoord_name - real(RP), intent(in) :: zTop - type(FILE_base_meshfield), intent(inout) :: file_topo - character(len=*), intent(in) :: in_basename - character(len=*), intent(in) :: in_varname - class(MeshFieldCommBase) :: comm3D - class(MeshFieldCommBase) :: comm2D - !------------------------------------------- - - call file_topo%Open( in_basename ) - call file_topo%Read_Var( MFTYPE2D_XY, in_varname, this%topo ) - call file_topo%Close() - - call this%topography%SetVCoordinate( this%ptr_mesh, & - vcoord_name, zTop, comm3D, comm2D ) - - return - end subroutine AtmosMesh_setup_vcoordinate - subroutine AtmosMesh_construct_ModalFilter3D( this, & filter, & etac_h, alpha_h, ord_h, & diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 index 65baa40f..83eed72d 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_gm.F90 @@ -17,6 +17,7 @@ module mod_atmos_mesh_gm use scale_localmesh_3d, only: LocalMesh3D use scale_meshfieldcomm_cubedspheredom3d, only: MeshFieldCommCubedSphereDom3D use scale_sparsemat, only: sparsemat + use scale_file_base_meshfield, only: FILE_base_meshfield use scale_file_restart_meshfield, only: FILE_restart_meshfield_component use scale_model_var_manager, only: ModelVarManager @@ -43,6 +44,7 @@ module mod_atmos_mesh_gm procedure :: Setup_restartfile1 => AtmosMeshGM_setup_restartfile1 procedure :: Setup_restartfile2 => AtmosMeshGM_setup_restartfile2 procedure :: Calc_UVmet => AtmosMeshGM_calc_UVMet + procedure :: Setup_vcoordinate => AtmosMeshGM_setup_vcoordinate end type AtmosMeshGM !----------------------------------------------------------------------------- @@ -66,8 +68,10 @@ module mod_atmos_mesh_gm subroutine AtmosMeshGM_Init( this ) use scale_const, only: & RPlanet => CONST_RADIUS - use scale_file_base_meshfield, only: FILE_base_meshfield - use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + use scale_mesh_base2d, only: & + MFTYPE2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_meshutil_vcoord, only: & + MeshUtil_get_VCoord_TypeID implicit none class(AtmosMeshGM), target, intent(inout) :: this @@ -88,26 +92,24 @@ subroutine AtmosMeshGM_Init( this ) integer :: PolyOrder_h = 2 integer :: PolyOrder_v = 2 logical :: LumpedMassMatFlag = .false. - character(len=H_LONG) :: TOPO_IN_BASENAME = '' !< basename of the input file - character(len=H_MID) :: TOPO_IN_VARNAME = 'topo' !< variable name of topo in the input file character(len=H_MID) :: VERTICAL_COORD_NAME = "TERRAIN_FOLLOWING" - + character(len=H_LONG) :: TOPO_IN_BASENAME = '' !< basename of the input file + character(len=H_MID) :: TOPO_IN_VARNAME = 'topo' !< variable name of topo in the input file + namelist / PARAM_ATMOS_MESH / & dom_zmin, dom_zmax, & FZ, isPeriodicZ, & NeGX, NeGY, NeZ, NLocalMeshPerPrc, Nprc, & PolyOrder_h, PolyOrder_v, LumpedMassMatFlag, & - TOPO_IN_BASENAME, TOPO_IN_VARNAME, & - VERTICAL_COORD_NAME - + VERTICAL_COORD_NAME, & + TOPO_IN_BASENAME, TOPO_IN_VARNAME + integer :: k logical :: is_spec_FZ integer :: ierr type(FILE_base_meshfield) :: file_topo - type(MeshFieldCommCubedSphereDom3D) :: comm3D - type(MeshFieldCommCubedSphereDom2D) :: comm2D !------------------------------------------- LOG_NEWLINE @@ -118,10 +120,10 @@ subroutine AtmosMeshGM_Init( this ) rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_ATMOS_MESH,iostat=ierr) if( ierr < 0 ) then !--- missing - LOG_INFO("ATMOS_MESH_setup",*) 'Not found namelist. Default used.' + LOG_INFO("ATMOS_MESH_setup",*) 'Not found namelist. Default used.' elseif( ierr > 0 ) then !--- fatal error - LOG_ERROR("ATMOS_MESH_setup",*) 'Not appropriate names in namelist PARAM_ATM_MESH. Check!' - call PRC_abort + LOG_ERROR("ATMOS_MESH_setup",*) 'Not appropriate names in namelist PARAM_ATM_MESH. Check!' + call PRC_abort endif LOG_NML(PARAM_ATMOS_MESH) @@ -153,25 +155,24 @@ subroutine AtmosMeshGM_Init( this ) call this%mesh%Generate() !- + call this%AtmosMesh_Init( this%mesh ) !- Set topography & vertical coordinate + + if ( TOPO_IN_BASENAME /= '' ) then + LOG_INFO("ATMOS_MESH_setup",*) 'Read topography data' - if ( TOPO_IN_VARNAME /= '' ) then call file_topo%Init(1, meshcubedsphere2D=this%mesh%mesh2D ) - call comm2D%Init( 1, 0, this%mesh%mesh2D ) - call comm3D%Init( 1, 1, this%mesh ) - - call this%Setup_vcoordinate( & - VERTICAL_COORD_NAME, dom_zmax, & - file_topo, TOPO_IN_BASENAME, TOPO_IN_VARNAME, & - comm3D, comm2D ) - - call comm2D%Final() - call comm3D%Final() + call file_topo%Open( TOPO_IN_BASENAME, myrank=PRC_myrank ) + call file_topo%Read_Var( MFTYPE2D_XY, TOPO_IN_VARNAME, this%topography%topo ) + call file_topo%Close() call file_topo%Final() end if + this%vcoord_type_id = MeshUtil_get_VCoord_TypeID( VERTICAL_COORD_NAME ) + call this%Setup_vcoordinate() + return end subroutine AtmosMeshGM_Init @@ -242,7 +243,6 @@ subroutine AtmosMeshGM_setup_restartfile2( this, restart_file, & end subroutine AtmosMeshGM_setup_restartfile2 - subroutine AtmosMeshGM_calc_UVMet( this, U, V, & Umet, Vmet ) @@ -282,4 +282,25 @@ subroutine AtmosMeshGM_calc_UVMet( this, U, V, & return end subroutine AtmosMeshGM_calc_UVMet + subroutine AtmosMeshGM_setup_vcoordinate( this ) + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + implicit none + class(AtmosMeshGM), TARGET, INTENT(INOUT) :: this + + type(MeshFieldCommCubedSphereDom3D) :: comm3D + type(MeshFieldCommCubedSphereDom2D) :: comm2D + !------------------------------------------------- + + call comm2D%Init( 1, 0, this%mesh%mesh2D ) + call comm3D%Init( 1, 1, this%mesh ) + + call this%topography%SetVCoordinate( this%ptr_mesh, & + this%vcoord_type_id, this%mesh%zmax_gl, comm3D, comm2D ) + + call comm2D%Final() + call comm3D%Final() + + return + end SUBROUTINE AtmosMeshGM_setup_vcoordinate + end module mod_atmos_mesh_gm \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 index cbb09e36..fbb97998 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_mesh_rm.F90 @@ -42,6 +42,7 @@ module mod_atmos_mesh_rm procedure :: Setup_restartfile1 => AtmosMeshRM_setup_restartfile1 procedure :: Setup_restartfile2 => AtmosMeshRM_setup_restartfile2 procedure :: Calc_UVmet => AtmosMeshRM_calc_UVmet + procedure :: Setup_vcoordinate => AtmosMeshRM_setup_vcoordinate end type AtmosMeshRM !----------------------------------------------------------------------------- @@ -66,7 +67,11 @@ module mod_atmos_mesh_rm subroutine AtmosMeshRM_Init( this ) use scale_file_base_meshfield, only: FILE_base_meshfield - use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D + use scale_mesh_base2d, only: & + MFTYPE2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_meshutil_vcoord, only: & + MeshUtil_get_VCoord_TypeID + implicit none class(AtmosMeshRM), target, intent(inout) :: this @@ -115,8 +120,6 @@ subroutine AtmosMeshRM_Init( this ) integer :: ierr type(FILE_base_meshfield) :: file_topo - type(MeshFieldCommRectDom2D) :: comm2D - type(MeshFieldCommCubeDom3D) :: comm3D !------------------------------------------- LOG_NEWLINE @@ -170,21 +173,19 @@ subroutine AtmosMeshRM_Init( this ) !- Set topography & vertical coordinate - if ( TOPO_IN_VARNAME /= '' ) then - call file_topo%Init(1, mesh2D=this%mesh%mesh2D ) - call comm2D%Init( 1, 0, this%mesh%mesh2D ) - call comm3D%Init( 1, 1, this%mesh%mesh3D ) - - call this%Setup_vcoordinate( & - VERTICAL_COORD_NAME, dom_zmax, & - file_topo, TOPO_IN_BASENAME, TOPO_IN_VARNAME, & - comm3D, comm2D ) + if ( TOPO_IN_BASENAME /= '' ) then + LOG_INFO("ATMOS_MESH_setup",*) 'Read topography data' - call comm2D%Final() - call comm3D%Final() + call file_topo%Init(1, mesh2D=this%mesh%mesh2D ) + call file_topo%Open( TOPO_IN_BASENAME, myrank=PRC_myrank ) + call file_topo%Read_Var( MFTYPE2D_XY, TOPO_IN_VARNAME, this%topography%topo ) + call file_topo%Close() call file_topo%Final() end if + this%vcoord_type_id = MeshUtil_get_VCoord_TypeID( VERTICAL_COORD_NAME ) + call this%Setup_vcoordinate() + return end subroutine AtmosMeshRM_Init @@ -280,6 +281,27 @@ subroutine AtmosMeshRM_calc_UVMet( this, U, V, & end do return -end subroutine AtmosMeshRM_calc_UVMet + end subroutine AtmosMeshRM_calc_UVMet + + subroutine AtmosMeshRM_setup_vcoordinate( this ) + use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D + implicit none + class(AtmosMeshRM), TARGET, INTENT(INOUT) :: this + + type(MeshFieldCommCubeDom3D) :: comm3D + type(MeshFieldCommRectDom2D) :: comm2D + !------------------------------------------------- + + call comm2D%Init( 1, 0, this%mesh%mesh2D ) + call comm3D%Init( 1, 1, this%mesh ) + + call this%topography%SetVCoordinate( this%ptr_mesh, & + this%vcoord_type_id, this%mesh%zmax_gl, comm3D, comm2D ) + + call comm2D%Final() + call comm3D%Final() + + return + end SUBROUTINE AtmosMeshRM_setup_vcoordinate end module mod_atmos_mesh_rm \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/depend b/model/atm_nonhydro3d/src/depend index a1aee831..cc81ffd5 100644 --- a/model/atm_nonhydro3d/src/depend +++ b/model/atm_nonhydro3d/src/depend @@ -12,10 +12,11 @@ $(BUILD_DIR)/mod_atmos_phy_tb_vars.o: atmos/mod_atmos_phy_tb_vars.F90 $(DEPENDLI $(BUILD_DIR)/mod_atmos_vars.o: atmos/mod_atmos_vars.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_dg_driver.o: admin/mod_dg_driver.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_user.o $(BUILD_DIR)/mod_dg_launcher.o: admin/mod_dg_launcher.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_dg_driver.o $(BUILD_DIR)/mod_dg_prep.o -$(BUILD_DIR)/mod_dg_prep.o: admin/mod_dg_prep.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_mkinit.o $(BUILD_DIR)/mod_user.o +$(BUILD_DIR)/mod_dg_prep.o: admin/mod_dg_prep.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_mkinit.o $(BUILD_DIR)/mod_mktopo.o $(BUILD_DIR)/mod_user.o $(BUILD_DIR)/mod_exp.o: admin/mod_exp.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_mkinit.o: preprocess/mod_mkinit.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_atmos_vars.o $(BUILD_DIR)/mod_mkinit_util.o: preprocess/mod_mkinit_util.F90 $(DEPENDLIB) +$(BUILD_DIR)/mod_mktopo.o: preprocess/mod_mktopo.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o $(BUILD_DIR)/mod_atmos_mesh.o $(BUILD_DIR)/mod_user.o: user/mod_user.F90 $(DEPENDLIB) $(BUILD_DIR)/mod_atmos_component.o MODS = \ @@ -37,4 +38,5 @@ MODS = \ mod_exp.mod \ mod_mkinit.mod \ mod_mkinit_util.mod \ + mod_mktopo.mod \ mod_user.mod diff --git a/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 b/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 new file mode 100644 index 00000000..cc58e9ca --- /dev/null +++ b/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 @@ -0,0 +1,396 @@ +!------------------------------------------------------------------------------- +!> module INITIAL +!! +!! @par Description +!! subroutines for preparing topography data +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_mktopo + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc + + use scale_const, only: & + PI => CONST_PI, & + RPlanet => CONST_RADIUS + + use scale_element_base, only: & + ElementBase2D, ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmeshfield_base, only: LocalMeshFieldBase + use scale_meshfield_base, only: MeshField2D + use scale_mesh_topography, only: MeshTopography + + use mod_atmos_component, only: & + AtmosComponent + use mod_atmos_mesh, only: AtmosMesh + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: MKTOPO_setup + public :: MKTOPO + public :: MKTOPO_write + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + integer, public :: MKTOPO_TYPE = -1 + integer, parameter, public :: I_IGNORE = 0 + integer, parameter, public :: I_FLAT = 1 + integer, parameter, public :: I_BELLSHAPE = 2 + integer, parameter, public :: I_BELLSHAPE_GLOBAL = 3 + + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + + private :: MKTOPO_flat + private :: MKTOPO_bellshape_global + + !----------------------------------------------------------------------------- + ! + !++ Private variables + ! + character(len=H_LONG) :: OUT_BASENAME = '' !< basename of the output file + character(len=H_MID) :: OUT_VARNAME = 'topo' !< variable name of topo in the output file + character(len=H_MID) :: OUT_TITLE = 'SCALE-DG TOPOGRAPHY' !< title of the output file + character(len=H_SHORT) :: OUT_DTYPE = 'DEFAULT' !< REAL4 or REAL8 + !----------------------------------------------------------------------------- +contains + !----------------------------------------------------------------------------- + !> Setup + subroutine MKTOPO_setup + implicit none + + character(len=H_SHORT) :: toponame = 'NONE' + + namelist / PARAM_MKTOPO / & + toponame, & + OUT_BASENAME, OUT_VARNAME, & + OUT_TITLE, OUT_DTYPE + + + integer :: ierr + !--------------------------------------------------------------------------- + + LOG_NEWLINE + LOG_INFO("MKTOPO_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_MKTOPO,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("MKTOPO_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("MKTOPO_setup",*) 'Not appropriate names in namelist PARAM_MKTOPO. Check!' + call PRC_abort + endif + LOG_NML(PARAM_MKTOPO) + + select case(trim(toponame)) + case('NONE') + MKTOPO_TYPE = I_IGNORE + case('FLAT') + MKTOPO_TYPE = I_FLAT + case('BELLSHAPE') + MKTOPO_TYPE = I_BELLSHAPE + case('BELLSHAPE_GLOBAL') + MKTOPO_TYPE = I_BELLSHAPE_GLOBAL + case default + LOG_ERROR("MKTOPO_setup",*) 'Not appropriate toponame. Check!', toponame + call PRC_abort + end select + + return + end subroutine MKTOPO_setup + + !----------------------------------------------------------------------------- + !> Driver + subroutine MKTOPO( output, model_mesh, topography ) + + use scale_model_var_manager, only: ModelVarManager + + implicit none + logical, intent(out) :: output + class(AtmosMesh), target, intent(in) :: model_mesh + class(MeshTopography), intent(inout) :: topography + + integer :: n + integer :: ke + class(LocalMesh3D), pointer :: lcmesh3D + class(MeshBase3D), pointer :: mesh + class(LocalMesh2D), pointer :: lcmesh2D + class(MeshBase2D), pointer :: mesh2D + !--------------------------------------------------------------------------- + + mesh => model_mesh%ptr_mesh + + if ( MKTOPO_TYPE == I_IGNORE ) then + LOG_NEWLINE + LOG_PROGRESS(*) 'skip making topography data' + output = .false. + else + LOG_NEWLINE + LOG_PROGRESS(*) 'start making topography data' + + ! call PROF_rapstart('_MkTOPO_main',3) + + call mesh%GetMesh2D( mesh2D ) + + select case( MKTOPO_TYPE ) + case ( I_FLAT ) + call MKTOPO_flat( mesh2D, topography%topo ) + case ( I_BELLSHAPE ) + call MKTOPO_bellshape( mesh2D, topography%topo ) + case ( I_BELLSHAPE_GLOBAL ) + call MKTOPO_bellshape_global( mesh2D, topography%topo ) + end select + + ! call PROF_rapend ('_MkTOPO_main',3) + ! LOG_PROGRESS(*) 'end making topography data' + + output = .true. + end if + + return + end subroutine MKTOPO + + subroutine MKTOPO_write( model_mesh, topography ) + use scale_time, only: TIME_NOWDAYSEC + use scale_file_base_meshfield, only: FILE_base_meshfield + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_mesh_base2d, only: & + MFTYPE2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_prc, only: PRC_myrank + + implicit none + class(AtmosMesh), target, intent(in) :: model_mesh + class(MeshTopography), intent(inout) :: topography + + type(FILE_base_meshfield) :: file + class(MeshBase2D), pointer :: mesh + + integer :: vid + logical :: file_existed + !-------------------------------------------------- + + nullify( mesh ) + call model_mesh%ptr_mesh%GetMesh2D( mesh ) + select type( mesh ) + class is (MeshCubedSphereDom2D) + call file%Init( 1, meshcubedsphere2D=mesh ) + class is (MeshRectDom2D) + call file%Init( 1, mesh2D=mesh ) + end select + + call file%Create( OUT_BASENAME, OUT_TITLE, OUT_DTYPE, & + file_existed, & + myrank=PRC_myrank ) + call file%Def_Var( topography%topo, "TOPOGRAPHY", vid, MFTYPE2D_XY, 'XY' ) + call file%End_def() + call file%Write_var2D(vid, topography%topo, TIME_NOWDAYSEC, TIME_NOWDAYSEC) + call file%Close() + call file%Final() + + return + end subroutine MKTOPO_write + + !-- private--------------------------------------------------------------------- + + !----------------------------------------------------------------------------- + !> Make flat mountain + subroutine MKTOPO_flat( mesh, topo ) + implicit none + + class(MeshBase2D), intent(in), target :: mesh + class(MeshField2D), intent(inout) :: topo + + ! flat mountain parameter + real(RP) :: FLAT_HEIGHT = 100.0_RP ! height of mountain [m] + + namelist / PARAM_MKTOPO_FLAT / & + FLAT_HEIGHT + + integer :: ierr + integer :: n + integer :: ke2d + type(LocalMesh2D), pointer :: lmesh2D + !-------------------------------- + + LOG_INFO("MKTOPO_flat",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_MKTOPO_FLAT,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("MKTOPO_flat",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("MKTOPO_flat",*) 'Not appropriate names in namelist PARAM_MKTOPO_FLAT. Check!' + call PRC_abort + endif + LOG_NML(PARAM_MKTOPO_FLAT) + + do n=1, mesh%LOCAL_MESH_NUM + lmesh2D => mesh%lcmesh_list(n) + !$omp parallel do + do ke2D=lmesh2D%NeS, lmesh2D%NeE + topo%local(n)%val(:,ke2d) = FLAT_HEIGHT + end do + end do + + return + end subroutine MKTOPO_flat + + + !----------------------------------------------------------------------------- + !> Make mountain with bell shape (global) + subroutine MKTOPO_bellshape( mesh, topo ) + implicit none + + class(MeshBase2D), intent(in), target :: mesh + class(MeshField2D), intent(inout) :: topo + + ! bell-shaped mountain parameter + real(RP) :: BELL_cx = 0.0E0_RP ! center location [m]: x-coordinate + real(RP) :: BELL_cy = 0.0E3_RP ! center location [m]: y-coordinate + real(RP) :: BELL_R = 2.E3_RP ! half radius [m] + real(RP) :: BELL_HEIGHT = 100.0_RP ! height of mountain [m] + logical :: BELL_QUASI_2D = .false. + namelist / PARAM_MKTOPO_BELLSHAPE / & + BELL_cx, & + BELL_cy, & + BELL_R, & + BELL_HEIGHT, & + BELL_QUASI_2D + + integer :: ierr + integer :: n + integer :: ke2d + type(LocalMesh2D), pointer :: lmesh2D + class(ElementBase2D), pointer :: elem + + real(RP), allocatable :: r2(:) + real(RP) :: fac_y_quasi2D + !-------------------------------- + + LOG_INFO("MKTOPO_bellshape",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_MKTOPO_BELLSHAPE,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("MKTOPO_bellshape",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("MKTOPO_bellshape",*) 'Not appropriate names in namelist PARAM_MKTOPO_BELLSHAPE. Check!' + call PRC_abort + endif + LOG_NML(PARAM_MKTOPO_BELLSHAPE) + + if ( BELL_QUASI_2D ) then + fac_y_quasi2D = 0.0_RP + else + fac_y_quasi2D = 1.0_RP + end if + + do n=1, mesh%LOCAL_MESH_NUM + lmesh2D => mesh%lcmesh_list(n) + elem => lmesh2D%refElem2D + + allocate( r2(elem%Np) ) + !$omp parallel do private(r2) + do ke2D=lmesh2D%NeS, lmesh2D%NeE + r2(:) = ( ( lmesh2D%pos_en(:,ke2d,1) - BELL_cx )**2 & + + fac_y_quasi2D * ( lmesh2D%pos_en(:,ke2d,2) - BELL_cy )**2 ) & + / BELL_R**2 + topo%local(n)%val(:,ke2d) = BELL_HEIGHT / ( 1.0_RP + r2(:) ) + end do + deallocate( r2 ) + end do + + return + end subroutine MKTOPO_bellshape + + !----------------------------------------------------------------------------- + !> Make mountain with bell shape (global) + subroutine MKTOPO_bellshape_global( mesh, topo ) + use scale_const, only: & + RPlanet => CONST_RADIUS + implicit none + + class(MeshBase2D), intent(in), target :: mesh + class(MeshField2D), intent(inout) :: topo + + ! bell-shaped mountain parameter + real(RP) :: BELL_Clon = 0.0E0_RP ! center location [rad]: longitude + real(RP) :: BELL_Clat = 0.0E3_RP ! center location [rad]: latitude + real(RP) :: BELL_R = 2.E3_RP ! half radius [m] + real(RP) :: BELL_HEIGHT = 100.0_RP ! height of mountain [m] + namelist / PARAM_MKTOPO_BELLSHAPE_GLOBAL / & + BELL_Clon, & + BELL_Clat, & + BELL_R, & + BELL_HEIGHT + + integer :: ierr + integer :: n + integer :: ke2d + type(LocalMesh2D), pointer :: lmesh2D + class(ElementBase2D), pointer :: elem + + real(RP), allocatable :: r(:) + !-------------------------------- + + LOG_INFO("MKTOPO_bellshape",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_MKTOPO_BELLSHAPE_GLOBAL,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("MKTOPO_bellshape",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("MKTOPO_bellshape",*) 'Not appropriate names in namelist PARAM_MKTOPO_BELLSHAPE_GLOBAL. Check!' + call PRC_abort + endif + LOG_NML(PARAM_MKTOPO_BELLSHAPE_GLOBAL) + + do n=1, mesh%LOCAL_MESH_NUM + lmesh2D => mesh%lcmesh_list(n) + elem => lmesh2D%refElem2D + + allocate( r(elem%Np) ) + !$omp parallel do private(r) + do ke2D=lmesh2D%NeS, lmesh2D%NeE + r(:) = RPlanet / BELL_R & + * acos( sin(BELL_Clat) * sin(lmesh2D%lat(:,ke2d)) & + + cos(BELL_Clat) * cos(lmesh2D%lat(:,ke2d)) * cos(lmesh2D%lon(:,ke2d) - BELL_Clon) ) + topo%local(n)%val(:,ke2d) = BELL_HEIGHT / ( 1.0_RP + r(:)**2 ) + end do + deallocate( r ) + end do + + return + end subroutine MKTOPO_bellshape_global + +end module mod_mktopo \ No newline at end of file diff --git a/model/atm_nonhydro3d/src/scale-dg_pp.F90 b/model/atm_nonhydro3d/src/scale-dg_pp.F90 index 0ea60860..51db24bf 100755 --- a/model/atm_nonhydro3d/src/scale-dg_pp.F90 +++ b/model/atm_nonhydro3d/src/scale-dg_pp.F90 @@ -1,5 +1,5 @@ !------------------------------------------------------------------------------- -!> Program SCALE-DG_init (a launcher of main routine) +!> Program SCALE-DG_pp (a launcher of main routine) !! !! @par Description !! SCALE: Scalable Computing by Advanced Library and Environment @@ -9,7 +9,7 @@ !! !< !------------------------------------------------------------------------------- -program scaledg_init +program scaledg_pp !----------------------------------------------------------------------------- ! !++ used modules @@ -37,4 +37,4 @@ program scaledg_init EXECUTE_MODEL ) ! (in) stop -end program scaledg_init +end program scaledg_pp From 37d7de439a6998de4c3d0c8c2ea82cf5f14070b5 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 23 Jun 2021 22:32:16 +0900 Subject: [PATCH 63/98] Add test cases of mountain wave for atmospheric dynamical core of regional and global models. --- model/atm_nonhydro3d/test/Makefile.common | 6 +- .../test/case/mountain_wave/Makefile | 28 ++ .../test/case/mountain_wave/init.conf | 64 +++ .../linear_hydrostatic_case/init.conf | 65 +++ .../linear_hydrostatic_case/run.conf | 109 +++++ .../test/case/mountain_wave/mod_user.F90 | 312 ++++++++++++++ .../test/case/mountain_wave/run.conf | 108 +++++ .../test/case/mountain_wave_global/Makefile | 28 ++ .../case/mountain_wave_global/cs2lonlat.cnf | 36 ++ .../test/case/mountain_wave_global/init.conf | 58 +++ .../case/mountain_wave_global/mod_user.F90 | 390 ++++++++++++++++++ .../test/case/mountain_wave_global/run.conf | 103 +++++ 12 files changed, 1304 insertions(+), 3 deletions(-) create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave/Makefile create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave/init.conf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/init.conf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/run.conf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave/run.conf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/Makefile create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/mod_user.F90 create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf diff --git a/model/atm_nonhydro3d/test/Makefile.common b/model/atm_nonhydro3d/test/Makefile.common index 2eafb1d4..2ea9c259 100644 --- a/model/atm_nonhydro3d/test/Makefile.common +++ b/model/atm_nonhydro3d/test/Makefile.common @@ -44,15 +44,15 @@ else endif ifeq ($(origin PPNAME), undefined) - PPNAME = scale-rm_pp + PPNAME = scale-dg_pp endif ifeq ($(origin INITNAME), undefined) - INITNAME = scale-rm_init + INITNAME = scale-dg_init endif ifeq ($(origin BINNAME), undefined) - BINNAME = atm_nonhydro3d + BINNAME = scale-dg endif ifeq ($(origin N2GNAME), undefined) diff --git a/model/atm_nonhydro3d/test/case/mountain_wave/Makefile b/model/atm_nonhydro3d/test/case/mountain_wave/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/mountain_wave/init.conf b/model/atm_nonhydro3d/test/case/mountain_wave/init.conf new file mode 100644 index 00000000..aa9d4fda --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave/init.conf @@ -0,0 +1,64 @@ +#--- Configuration file for a test case of mountainy wave ------- +# Case 7 in Giraldo and Restelli (2008) +# 2D linear nonhydrostatic case +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'mountain_wave', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_MKTOPO + toponame = 'BELLSHAPE', + OUT_BASENAME = 'TOPO', +/ +&PARAM_MKTOPO_BELLSHAPE + BELL_CX = 72.D3, + BELL_CY = 0.D0, + BELL_R = 1.0D3, + BELL_HEIGHT = 1.D0, + BELL_QUASI_2D = .true., +/ +&PARAM_EXP + BruntVaisalaFreq = 1.0D-2, + U0 = 10.0D0, ! Wind speed at the equator +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + dom_xmin = 0.0D3, + dom_xmax = 144.0D3, + isPeriodicX = .true., + dom_ymin = 0.0D3, + dom_ymax = 3.0D3, + isPeriodicY = .true., + dom_zmin = 0D0, + dom_zmax = 30D3, + NprcX = 6, + NeX = 8, + NprcY = 1, + NeY = 1, + NeZ = 7, + PolyOrder_h = 5, + PolyOrder_v = 5, + LumpedMassMatFlag = .true., + Fz = 0D0, 4.0D3, 8.D3, 12D3, 16.D3, 20.D3, 25.D3, 30D3, +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/init.conf b/model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/init.conf new file mode 100644 index 00000000..3c7ec7a7 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/init.conf @@ -0,0 +1,65 @@ +#--- Configuration file for a test case of mountainy wave ------- +# Case 6 in Giraldo and Restelli (2008) +# 2D linear hydrostatic case +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'mountain_wave', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_MKTOPO + toponame = 'BELLSHAPE', + OUT_BASENAME = 'TOPO', +/ +&PARAM_MKTOPO_BELLSHAPE + BELL_CX = 120.D3, + BELL_CY = 0.D0, + BELL_R = 10.0D3, + BELL_HEIGHT = 1.D0, + BELL_QUASI_2D = .true., +/ +&PARAM_EXP + THETA0 = 250D0, ! isothermal atmosphere of 250 K + BruntVaisalaFreq = 1.9567954884127995E-2, ! for isothermal atmosphere, N=g/(Cp T0)^1/2 + U0 = 20.0D0, ! Wind speed at the equator +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + dom_xmin = 0.0D3, + dom_xmax = 240.0D3, + isPeriodicX = .true., + dom_ymin = 0.0D3, + dom_ymax = 10.0D3, + isPeriodicY = .true., + dom_zmin = 0D0, + dom_zmax = 30D3, + NprcX = 6, + NeX = 4, + NprcY = 1, + NeY = 1, + NeZ = 7, + PolyOrder_h = 5, + PolyOrder_v = 5, + LumpedMassMatFlag = .true., + Fz = 0D0, 4.0D3, 8.D3, 12D3, 16.D3, 20.D3, 25.D3, 30D3, +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/run.conf b/model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/run.conf new file mode 100644 index 00000000..390559ba --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave/linear_hydrostatic_case/run.conf @@ -0,0 +1,109 @@ +#--- Configuration file for a test case of mountainy wave ------- +# Case 7 in Giraldo and Restelli (2008) +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 10.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 10.0D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +&PARAM_USER + USER_do = .true., + U0 = 20.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ACTIVATE_FLAG = .true., + TIME_DT = 10.0D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + dom_xmin = 0.0D3, + dom_xmax = 240.0D3, + isPeriodicX = .true., + dom_ymin = 0.0D3, + dom_ymax = 10.0D3, + isPeriodicY = .true., + dom_zmin = 0D0, + dom_zmax = 30D3, + NprcX = 6, + NeX = 4, + NprcY = 1, + NeY = 1, + NeZ = 7, + PolyOrder_h = 5, + PolyOrder_v = 5, + LumpedMassMatFlag = .false., + TOPO_IN_BASENAME = 'TOPO', + Fz = 0D0, 4.0D3, 8.D3, 12D3, 16.D3, 20.D3, 25.D3, 30D3, +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "NONHYDRO3D_HEVE", + !- + TINTEG_TYPE = 'ERK_SSP_10s4o_2N', ! [IMEX_ARK_232, IMEX_ARK324, ERK_SSP_3s3o, ERK_SSP_10s4o_2N] + TIME_DT = 2.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 0.05D0, + MF_ORDER_h = 16, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 0.05D0, + MF_ORDER_v = 16, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 1.D0, + FILE_HISTORY_DEFAULT_TUNIT = "HOUR", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='PT_diff' / +!&HISTORY_ITEM name='DENS_hyd' / +&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + diff --git a/model/atm_nonhydro3d/test/case/mountain_wave/mod_user.F90 b/model/atm_nonhydro3d/test/case/mountain_wave/mod_user.F90 new file mode 100644 index 00000000..b3129b08 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave/mod_user.F90 @@ -0,0 +1,312 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfield_base, only: MeshField3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_mountain_wave + contains + procedure :: setInitCond_lc => exp_SetInitCond_mountain_wave + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_mountain_wave), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + real(RP), private :: U0 + real(RP), private :: zTop + real(RP), private :: SPONGE_HEIGHT + + type(MeshField3D), private :: PT_diff + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + call exp_manager%Init('mountain_wave') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do, & + U0, & + zTop, Sponge_Height + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + U0 = 10.0_RP + zTop = 30.E3_RP + SPONGE_HEIGHT = 15.E3_RP + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + if ( USER_do ) call PT_diff%Init( 'PT_diff', 'K', atm%mesh%ptr_mesh ) + + return + end subroutine USER_setup + + subroutine USER_calc_tendency( atm ) + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + + use scale_const, only: & + Rdry => CONST_Rdry, & + CpDry => CONST_CPdry, & + RPlanet => CONST_RADIUS, & + PI => CONST_PI + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + use mod_atmos_vars, only: & + AtmosVars_GetLocalMeshPrgVars, & + AtmosVars_GetLocalMeshPhyAuxVars, & + MOMX_p => ATMOS_PHYTEND_MOMX_ID, & + MOMY_p => ATMOS_PHYTEND_MOMY_ID, & + MOMZ_p => ATMOS_PHYTEND_MOMZ_ID, & + RHOH_p => ATMOS_PHYTEND_RHOH_ID + use scale_localmeshfield_base, only: LocalMeshFieldBase + + implicit none + + class(AtmosComponent), intent(inout) :: atm + + class(LocalMesh3D), pointer :: lcmesh + class(ElementBase3D), pointer :: elem + class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT + class(LocalMeshFieldBase), pointer :: DENS_hyd, PRES_hyd + class(LocalMeshFieldBase), pointer :: PRES, PT + + real(RP), parameter :: rtau = 1.0_RP / 600.0_RP + + integer :: n + integer :: ke + + real(RP), allocatable :: DENS(:) + real(RP), allocatable :: sfac(:) + !------------------------------------------ + + if ( USER_do ) then + call atm%vars%Calc_diagVar( 'PT_diff', PT_diff ) + call FILE_HISTORY_meshfield_in( PT_diff, "perturbation of potential temperature" ) + end if + + do n=1, atm%mesh%ptr_mesh%LOCAL_MESH_NUM + call AtmosVars_GetLocalMeshPrgVars( n, atm%mesh%ptr_mesh, & + atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager, & + DDENS, MOMX, MOMY, MOMZ, DRHOT, & + DENS_hyd, PRES_hyd, lcmesh ) + + call AtmosVars_GetLocalMeshPhyAuxVars( n, atm%mesh%ptr_mesh, & + atm%vars%AUXVARS_manager, PRES, PT ) + + elem => lcmesh%refElem3D + allocate( DENS(elem%Np), sfac(elem%Np) ) + + !$omp parallel do private(DENS, sfac) + do ke=lcmesh%NeS, lcmesh%NeE + DENS(:) = DENS_hyd%val(:,ke) + DDENS%val(:,ke) + sfac(:) = rtau * 0.5_RP * ( 1.0_RP - cos( PI * ( lcmesh%pos_en(:,ke,3) - SPONGE_HEIGHT ) / ( zTop - SPONGE_HEIGHT ) ) ) + + where ( lcmesh%pos_en(:,ke,3) > SPONGE_HEIGHT ) + atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) & + - sfac(:) * ( MOMX%val(:,ke) - DENS(:) * U0 ) + atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) & + - sfac(:) * MOMY%val(:,ke) + atm%vars%PHY_TEND(MOMZ_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMZ_p)%local(n)%val(:,ke) & + - sfac(:) * MOMZ%val(:,ke) + + atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) & + - DENS(:) * sfac(:) * CpDry * ( PRES%val(:,ke) / DENS(:) - PRES_hyd%val(:,ke) / DENS_hyd%val(:,ke) ) / Rdry + end where + end do + deallocate( DENS, sfac ) + end do + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_mountain_wave( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + OHM => CONST_OHM, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS + + use scale_atm_dyn_dgm_hydrostatic, only: & + hydrostatic_calc_basicstate_constBVFreq + + implicit none + + class(Exp_mountain_wave), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + real(RP) :: THETA0 = 280.0_RP + real(RP) :: BruntVaisalaFreq = 0.01_RP + namelist /PARAM_EXP/ & + U0, & + BruntVaisalaFreq, & + THETA0 + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 + + integer :: ke + integer :: ierr + + !----------------------------------------------------------------------------- + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("MOUNTAIN_WAVE_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("MOUNTAIN_WAVE_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + !--- + + call hydrostatic_calc_basicstate_constBVFreq( DENS_hyd, PRES_hyd, & ! (out) + BruntVaisalaFreq, THETA0, PRES00, & ! (in) + x, y, lcmesh%zlev, lcmesh, elem ) ! (in) + !--- + + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + MOMX(:,ke) = DENS_hyd(:,ke) * U0 + MOMY(:,ke) = 0.0_RP + end do + + return + end subroutine exp_SetInitCond_mountain_wave + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_mountain_wave), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + !--------------------------------------------------- + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/mountain_wave/run.conf b/model/atm_nonhydro3d/test/case/mountain_wave/run.conf new file mode 100644 index 00000000..f0fccc31 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave/run.conf @@ -0,0 +1,108 @@ +#--- Configuration file for a test case of mountainy wave ------- +# Case 7 in Giraldo and Restelli (2008) +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 5.0D0, !0.5D0, !24.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 12D0, !10D0, !300D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +&PARAM_USER + USER_do = .true., +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ACTIVATE_FLAG = .true., + TIME_DT = 12D0, !300D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + dom_xmin = 0.0D3, + dom_xmax = 144.0D3, + !isPeriodicX = .true., + dom_ymin = 0.0D3, + dom_ymax = 3.0D3, + !isPeriodicY = .false., + dom_zmin = 0D0, + dom_zmax = 30D3, + NprcX = 6, + NeX = 8, + NprcY = 1, + NeY = 1, + NeZ = 7, + PolyOrder_h = 5, + PolyOrder_v = 5, + LumpedMassMatFlag = .false., + TOPO_IN_BASENAME = 'TOPO', + Fz = 0D0, 4.0D3, 8.D3, 12D3, 16.D3, 20.D3, 25.D3, 30D3, +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "NONHYDRO3D_HEVE", + !- + TINTEG_TYPE = 'ERK_SSP_10s4o_2N', ! [IMEX_ARK_232, IMEX_ARK324, ERK_SSP_3s3o] + TIME_DT = 0.8D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 0.05D0, + MF_ORDER_h = 16, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 0.05D0, + MF_ORDER_v = 16, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 1.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "HOUR", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='U' / +&HISTORY_ITEM name='V' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='PT_diff' / +!&HISTORY_ITEM name='DENS_hyd' / +&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/Makefile b/model/atm_nonhydro3d/test/case/mountain_wave_global/Makefile new file mode 100644 index 00000000..220dffd4 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/Makefile @@ -0,0 +1,28 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../../../../..) +TESTDIR = ../.. + + +# user-defined source files +CODE_DIR = . +ORG_SRCS = mod_user.F90 + +# parameters for run +#INITCONF = init.conf +RUNCONF = run.conf +TPROC = 1 + +# required data (parameters,distributed files) +DATPARAM = +DATDISTS = + + + +# build, makedir, run, jobshell, allclean, clean is inside of common Makefile +include $(TESTDIR)/Makefile.common diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf new file mode 100644 index 00000000..e7e39f65 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf @@ -0,0 +1,36 @@ +&PARAM_IO + IO_LOG_BASENAME = "cs2lonlat_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="./history", + vars = "W", "Umet", "Vmet", "PT_diff", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_INTERP_MESH + !-- input ---------------- + in_Nprc = 6, + in_NeGX = 5, + in_NeGY = 5, + in_NeGZ = 6, + in_PolyOrder_h = 7, + in_PolyOrder_v = 7, + in_NLocalMeshPerPrc = 1, + dom_zmin = 0.0D0, + dom_zmax = 40.0D3, + in_Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, + !-- output ---------------- + out_NprcX = 2, + out_NeX = 64, + out_NprcY = 2, + out_NeY = 32, + out_NeZ = 15, + out_PolyOrder_h =3, + out_PolyOrder_v =2, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf b/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf new file mode 100644 index 00000000..8128dae1 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf @@ -0,0 +1,58 @@ +#--- Configuration file for a test case of mountainy wave ------- +# Test Case 3 in Tomita et al. (2004) +&PARAM_IO + IO_LOG_BASENAME = 'init_LOG', +/ +&PARAM_MKINIT + initname = 'mountain_wave', +/ +&PARAM_RESTART + OUTPUT_FLAG = .true., + OUT_BASENAME = 'init' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, +/ +&PARAM_MKTOPO + toponame = 'BELLSHAPE_GLOBAL', + OUT_BASENAME = 'TOPO', +/ +&PARAM_MKTOPO_BELLSHAPE_GLOBAL + BELL_Clon = 0.7853975D0, !0.D0, + BELL_Clat = 0.D0, + BELL_R = 1250D3, + BELL_HEIGHT = 1000.D0, ! mild nonlinear case (Case3-#1 in Tomita et al. (2004)) +! BELL_HEIGHT = 4000.D0, ! highly nonlinearcase (Case3-#2 in Tomita et al. (2004)) +/ +&PARAM_EXP + BruntVaisalaFreq = 1.87D-2, + U0 = 40.0D0, ! Wind speed at the equator +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + NeZ = 6, + dom_zmin = 0.0D0, + dom_zmax = 40.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + LumpedMassMatFlag = .true., + Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVE", + TINTEG_TYPE = 'ERK_SSP_3s3o', +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/mountain_wave_global/mod_user.F90 new file mode 100644 index 00000000..319b2eeb --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/mod_user.F90 @@ -0,0 +1,390 @@ +!------------------------------------------------------------------------------- +!> module USER +!! +!! @par Description +!! User defined module +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +module mod_user + + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use mod_exp, only: experiment + + use mod_atmos_component, only: & + AtmosComponent + + use scale_element_base, only: ElementBase3D + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_meshfield_base, only: MeshField3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public procedure + ! + public :: USER_mkinit + public :: USER_setup + public :: USER_calc_tendency + public :: USER_update + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + !----------------------------------------------------------------------------- + ! + !++ Private procedure + ! + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type, private, extends(experiment) :: Exp_mountain_wave_global + contains + procedure :: setInitCond_lc => exp_SetInitCond_mountain_wave + procedure :: geostrophic_balance_correction_lc => exp_geostrophic_balance_correction + end type + type(Exp_mountain_wave_global), private :: exp_manager + + logical, private :: USER_do = .false. !< do user step? + + type(MeshField3D), private :: PT_diff + + !----------------------------------------------------------------------------- +contains + subroutine USER_mkinit ( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + call exp_manager%Init('mountain_wave_global') + call exp_manager%SetInitCond( & + atm%mesh, atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager ) + call exp_manager%Final() + + return + end subroutine USER_mkinit + + subroutine USER_setup( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + + namelist / PARAM_USER / & + USER_do + + integer :: ierr + !------------------------------------------ + + + LOG_NEWLINE + LOG_INFO("USER_setup",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_USER,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("USER_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("USER_setup",*) 'Not appropriate names in namelist PARAM_USER. Check!' + call PRC_abort + endif + LOG_NML(PARAM_USER) + + !- + if ( USER_do ) call PT_diff%Init( 'PT_diff', 'K', atm%mesh%ptr_mesh ) + + return + end subroutine USER_setup + + subroutine USER_calc_tendency( atm ) + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + + use scale_const, only: & + Rdry => CONST_Rdry, & + CpDry => CONST_CPdry, & + RPlanet => CONST_RADIUS, & + PI => CONST_PI + + use scale_file_history_meshfield, only: & + FILE_HISTORY_meshfield_in + use mod_atmos_vars, only: & + AtmosVars_GetLocalMeshPrgVars, & + AtmosVars_GetLocalMeshPhyAuxVars, & + MOMX_p => ATMOS_PHYTEND_MOMX_ID, & + MOMY_p => ATMOS_PHYTEND_MOMY_ID, & + MOMZ_p => ATMOS_PHYTEND_MOMZ_ID, & + RHOH_p => ATMOS_PHYTEND_RHOH_ID + use scale_localmeshfield_base, only: LocalMeshFieldBase + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + + implicit none + + class(AtmosComponent), intent(inout) :: atm + + class(LocalMesh3D), pointer :: lcmesh + class(ElementBase3D), pointer :: elem + class(LocalMeshFieldBase), pointer :: DDENS, MOMX, MOMY, MOMZ, DRHOT + class(LocalMeshFieldBase), pointer :: DENS_hyd, PRES_hyd + class(LocalMeshFieldBase), pointer :: PRES, PT + + real(RP), parameter :: rtau = 1.0_RP / 1800.0_RP + + integer :: n + integer :: ke + + real(RP), allocatable :: DENS(:) + real(RP), allocatable :: sfac(:) + real(RP), allocatable :: UmetOvCosLat(:,:), Vmet(:,:) + real(RP), allocatable :: U0(:,:), V0(:,:) + !------------------------------------------ + + if ( USER_do ) then + call atm%vars%Calc_diagVar( 'PT_diff', PT_diff ) + call FILE_HISTORY_meshfield_in( PT_diff, "perturbation of potential temperature" ) + end if + + do n=1, atm%mesh%ptr_mesh%LOCAL_MESH_NUM + call AtmosVars_GetLocalMeshPrgVars( n, atm%mesh%ptr_mesh, & + atm%vars%PROGVARS_manager, atm%vars%AUXVARS_manager, & + DDENS, MOMX, MOMY, MOMZ, DRHOT, & + DENS_hyd, PRES_hyd, lcmesh ) + + call AtmosVars_GetLocalMeshPhyAuxVars( n, atm%mesh%ptr_mesh, & + atm%vars%AUXVARS_manager, PRES, PT ) + + elem => lcmesh%refElem3D + allocate( DENS(elem%Np), sfac(elem%Np) ) + allocate( U0(elem%Np,lcmesh%Ne), V0(elem%Np,lcmesh%Ne) ) + allocate( UmetOvCosLat(elem%Np,lcmesh%Ne), Vmet(elem%Np,lcmesh%Ne) ) + + !$omp parallel do + do ke=lcmesh%NeS, lcmesh%NeE + UmetOvCosLat(:,ke) = 40.0_RP + Vmet(:,ke) = 0.0_RP + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + UmetOvCosLat(:,:), Vmet(:,:), & + U0(:,:), V0(:,:) ) + + !$omp parallel do private(DENS, sfac) + do ke=lcmesh%NeS, lcmesh%NeE + DENS(:) = DENS_hyd%val(:,ke) + DDENS%val(:,ke) + sfac(:) = rtau * 0.5_RP * ( 1.0_RP - cos( PI * ( lcmesh%pos_en(:,ke,3) - 25.E3_RP ) / (40.E3_RP - 25.E3_RP) ) ) + + where ( lcmesh%pos_en(:,ke,3) > 25.E3_RP ) + atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) & + - sfac(:) * ( MOMX%val(:,ke) - DENS(:) * U0(:,ke) ) + atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) & + - sfac(:) * ( MOMY%val(:,ke) - DENS(:) * V0(:,ke) ) + atm%vars%PHY_TEND(MOMZ_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMZ_p)%local(n)%val(:,ke) & + - sfac(:) * MOMZ%val(:,ke) + + atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) & + - DENS(:) * sfac(:) * CpDry * ( PRES%val(:,ke) / DENS(:) - PRES_hyd%val(:,ke) / DENS_hyd%val(:,ke) ) / Rdry + end where + end do + deallocate( DENS, sfac ) + deallocate( UmetOvCosLat, Vmet, U0, V0 ) + end do + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_update + + !------ + subroutine exp_SetInitCond_mountain_wave( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + x, y, z, dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + lcmesh, elem ) + + use scale_const, only: & + PI => CONST_PI, & + GRAV => CONST_GRAV, & + OHM => CONST_OHM, & + Rdry => CONST_Rdry, & + CPdry => CONST_CPdry, & + PRES00 => CONST_PRE00, & + RPlanet => CONST_RADIUS + + use scale_atm_dyn_dgm_hydrostatic, only: & + hydrostatic_calc_basicstate_constBVFreq + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSVec + + implicit none + + class(Exp_mountain_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(out) :: DRHOT(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: x(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: y(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: z(elem%Np,lcmesh%Ne) + real(RP), intent(in) :: dom_xmin, dom_xmax + real(RP), intent(in) :: dom_ymin, dom_ymax + real(RP), intent(in) :: dom_zmin, dom_zmax + + real(RP) :: THETA0 = 300.0_RP + real(RP) :: BruntVaisalaFreq = 0.0187_RP + real(RP) :: U0 = 40.0_RP + namelist /PARAM_EXP/ & + U0, & + BruntVaisalaFreq + integer, parameter :: IntrpPolyOrder_h = 8 + integer, parameter :: IntrpPolyOrder_v = 8 + + real(RP) :: p_lat(elem%Nfp_v,lcmesh%lcmesh2D%Ne) + real(RP) :: G_(elem%Nfp_v), G0(elem%Nfp_v), lat0(elem%Nfp_v) + + real(RP) :: cos_lat(elem%Np) + real(RP) :: T(elem%Np) + real(RP) :: MOMX_met_ov_coslat(elem%Np,lcmesh%Ne) + real(RP) :: MOMY_met (elem%Np,lcmesh%Ne) + + integer :: ke, ke2d + integer :: ierr + + type(LocalMesh2D), pointer :: lmesh2D + real(RP) :: H0_pres + !----------------------------------------------------------------------------- + + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_EXP,iostat=ierr) + if( ierr < 0 ) then !--- missing + LOG_INFO("MOUNTAIN_WAVE_setup",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("MOUNTAIN_WAVE_setup",*) 'Not appropriate names in namelist PARAM_EXP. Check!' + call PRC_abort + endif + LOG_NML(PARAM_EXP) + !--- + + call hydrostatic_calc_basicstate_constBVFreq( DENS_hyd, PRES_hyd, & ! (out) + BruntVaisalaFreq, THETA0, PRES00, & ! (in) + x, y, z, lcmesh, elem ) ! (in) + + !--- + + H0_pres = Grav * Rdry / CPdry / BruntVaisalaFreq**2 + + lmesh2D => lcmesh%lcmesh2D + !$omp parallel do private(G0, G_, lat0) + do ke2D=lmesh2D%NeS, lmesh2D%NeE + lat0(:) = 0.0_RP + call calc_G( G0(:), & + U0, OHM, RPlanet, Grav, H0_pres, lat0, elem%Nfp_v ) + call calc_G( G_(:), & + U0, OHM, RPlanet, Grav, H0_pres, lcmesh%lat2D(:,ke2D), elem%Nfp_v ) + + p_lat(:,ke2d) = PRES00 * ( G0(:) / G_(:) )**( RPlanet * 0.25_RP / H0_pres ) + end do + + !$omp parallel do private( ke2d, cos_lat, T ) + do ke=lcmesh%NeS, lcmesh%NeE + ke2d = lcmesh%EMap3Dto2D(ke) + cos_lat(:) = cos(lcmesh%lat2D(elem%IndexH2Dto3D(:),ke2D)) + + PRES_hyd(:,ke) = p_lat(elem%IndexH2Dto3D,ke2d) * exp( - lcmesh%zlev(:,ke) / H0_pres ) + + T(:) = H0_pres / Rdry * ( Grav - U0 * cos_lat * ( U0 * cos_lat / RPlanet + 2.0_RP * OHM * cos_lat ) ) + DENS_hyd(:,ke) = p_lat(elem%IndexH2Dto3D,ke2d) / ( Rdry * T(:) ) * exp( - lcmesh%zlev(:,ke) / H0_pres ) + + MOMX_met_ov_coslat(:,ke) = DENS_hyd(:,ke) * U0 + MOMY_met(:,ke) = 0.0_RP + end do + + call CubedSphereCnv_LonLat2CSVec( & + lcmesh%panelID, lcmesh%pos_en(:,:,1), lcmesh%pos_en(:,:,2), elem%Np * lcmesh%Ne, RPlanet, & + MOMX_met_ov_coslat(:,:), MOMY_met(:,:), & + MOMX(:,lcmesh%NeS:lcmesh%NeE), MOMY(:,lcmesh%NeS:lcmesh%NeE) ) + + return + contains + subroutine calc_G( G, U, OMG, a, Grav, H0p, lat, np ) + implicit none + integer, intent(in) :: np + real(RP), intent(out) :: G(np) + real(RP), intent(in) :: U + real(RP), intent(in) :: OMG + real(RP), intent(in) :: a + real(RP), intent(in) :: Grav + real(RP), intent(in) :: H0p + real(RP), intent(in) :: lat(np) + + real(RP) :: cos_2lat(np) + real(RP) :: cos_4lat(np) + real(RP) :: g1(np), g2 + !---------------- + + cos_2lat(:) = cos(2.0_RP * lat(:)) + cos_4lat(:) = cos(4.0_RP * lat(:)) + + g1(:) = ( 3.0_RP + 4.0_RP * cos_2lat(:) + cos_4lat(:) ) * 2.0_RP * U**2 * ( U**2 + 4.0_RP * a * OMG * ( U + a * OMG ) ) & + - ( 1.0_RP + cos_2lat(:) ) * 16.0_RP * U * Grav * a * ( U + 2.0_RP * a * OMG ) & + + 16.0_RP * ( a * Grav )**2 + g2 = U**2 * ( U**2 + 4.0_RP * a * OMG * ( U + a * OMG ) ) + + G(:) = g1(:) / g2 + + return + end subroutine + end subroutine exp_SetInitCond_mountain_wave + + subroutine exp_geostrophic_balance_correction( this, & + DENS_hyd, PRES_hyd, DDENS, MOMX, MOMY, MOMZ, DRHOT, & + lcmesh, elem ) + + implicit none + + class(Exp_mountain_wave_global), intent(inout) :: this + type(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(inout) :: DENS_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(in) :: PRES_hyd(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DDENS(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMX(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMY(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: MOMZ(elem%Np,lcmesh%NeA) + real(RP), intent(inout) :: DRHOT(elem%Np,lcmesh%NeA) + + !--------------------------------------------------- + return + end subroutine exp_geostrophic_balance_correction + +end module mod_user diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf b/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf new file mode 100644 index 00000000..83db27fd --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf @@ -0,0 +1,103 @@ +#--- Configuration file for a test case of mountainy wave ------- +# Test Case 3 in Tomita et al. (2004) +&PARAM_RESTART + IN_BASENAME = "init_00000101-000000.000", + OUTPUT_FLAG = .true., + OUT_BASENAME = 'restart' +/ +&PARAM_TIME + TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, + TIME_STARTMS = 0.D0, + TIME_DURATION = 12.0D0, + TIME_DURATION_UNIT = 'HOUR', + TIME_DT = 300D0, + TIME_DT_UNIT = 'SEC', +/ +&PARAM_CONST + CONST_OHM = 0.0D0, +/ +&PARAM_USER + USER_do = .true., +/ +#** ATMOS ****************************************************** +&PARAM_ATMOS + ATMOS_MESH_TYPE = 'GLOBAL', + ACTIVATE_FLAG = .true., + TIME_DT = 300D0, + TIME_DT_UNIT = 'SEC', + ATMOS_DYN_DO = .true. +/ +&PARAM_ATMOS_MESH + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + NeZ = 6, + dom_zmin = 0.0D0, + dom_zmax = 40.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + LumpedMassMatFlag = .true., + TOPO_IN_BASENAME = 'TOPO', + Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, +/ +&PARAM_ATMOS_VARS + CHECK_RANGE = .true. , + CHECK_TOTAL = .false., +/ +#** ATMOS / DYN ****************************************************** +&PARAM_ATMOS_DYN + EQS_TYPE = "GLOBALNONHYDRO3D_HEVI", + !- + TINTEG_TYPE = 'IMEX_ARK324', ! [IMEX_ARK_232, IMEX_ARK324, ERK_SSP_3s3o] + TIME_DT = 75.0D0, + TIME_DT_UNIT = 'SEC', + !- + MODALFILTER_FLAG = .true., + NUMDIFF_FLAG = .false., +/ +&PARAM_ATMOS_DYN_MODALFILTER + MF_ETAC_h = 0.0D0, + MF_ALPHA_h = 0.2D0, + MF_ORDER_h = 16, + MF_ETAC_v = 0.0D0, + MF_ALPHA_v = 0.2D0, + MF_ORDER_v = 16, +/ +&PARAM_ATMOS_DYN_BND + btm_vel_bc = 'SLIP', + top_vel_bc = 'SLIP', + btm_thermal_bc = 'ADIABATIC', + top_thermal_bc = 'ADIABATIC', +/ + +#*** OUTPUT ******************************************* +&PARAM_FILE_HISTORY + FILE_HISTORY_DEFAULT_BASENAME = "history", + FILE_HISTORY_DEFAULT_TINTERVAL = 1.0D0, + FILE_HISTORY_DEFAULT_TUNIT = "HOUR", + FILE_HISTORY_DEFAULT_TAVERAGE = .false., + FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", + FILE_HISTORY_OUTPUT_STEP0 = .true., +/ +&HISTORY_ITEM name='Umet' / +&HISTORY_ITEM name='Vmet' / +&HISTORY_ITEM name='W' / +&HISTORY_ITEM name='PT_diff' / +!&HISTORY_ITEM name='DENS_hyd' / +&HISTORY_ITEM name='PRES_hyd' / + +#*** Statistics ******************************************* + +&PARAM_MESHFIELD_STATISTICS + use_globalcomm = .true., +/ +&PARAM_MONITOR + MONITOR_STEP_INTERVAL = 80 +/ +&MONITOR_ITEM name='DDENS' / +!&MONITOR_ITEM name='ENGT' / +!&MONITOR_ITEM name='ENGK' / +!&MONITOR_ITEM name='ENGI' / +!&MONITOR_ITEM name='ENGP' / + From 469ae6fdb04c26173a862875ed6a92746c70f79b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 23 Jun 2021 23:50:43 +0900 Subject: [PATCH 64/98] Modify parameters for a test case of mountain wave in a global model. --- .../scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 6 ------ .../test/case/mountain_wave_global/init.conf | 2 +- .../test/case/mountain_wave_global/run.conf | 10 +++++----- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index ee2a249d..bbacffc9 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -308,12 +308,6 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & + lmesh%Escale(:,ke,2,2) * Fy(:) & + lmesh%Escale(:,ke,3,3) * Fz(:) & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) - - ! DENS_dt(:,ke) = 0.0_RP - ! MOMX_dt(:,ke) = 0.0_RP - ! MOMY_dt(:,ke) = 0.0_RP - ! MOMZ_dt(:,ke) = 0.0_RP - ! RHOT_dt(:,ke) = 0.0_RP end do !$omp end parallel call PROF_rapend('cal_dyn_tend_interior', 3) diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf b/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf index 8128dae1..97d09cc7 100644 --- a/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/init.conf @@ -19,7 +19,7 @@ OUT_BASENAME = 'TOPO', / &PARAM_MKTOPO_BELLSHAPE_GLOBAL - BELL_Clon = 0.7853975D0, !0.D0, + BELL_Clon = 0.D0, BELL_Clat = 0.D0, BELL_R = 1250D3, BELL_HEIGHT = 1000.D0, ! mild nonlinear case (Case3-#1 in Tomita et al. (2004)) diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf b/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf index 83db27fd..f72a6e38 100644 --- a/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/run.conf @@ -8,8 +8,8 @@ &PARAM_TIME TIME_STARTDATE = 0000, 1, 1, 0, 0, 0, TIME_STARTMS = 0.D0, - TIME_DURATION = 12.0D0, - TIME_DURATION_UNIT = 'HOUR', + TIME_DURATION = 2.0D0, ! 6.0D0, + TIME_DURATION_UNIT = 'DAY', TIME_DT = 300D0, TIME_DT_UNIT = 'SEC', / @@ -58,10 +58,10 @@ / &PARAM_ATMOS_DYN_MODALFILTER MF_ETAC_h = 0.0D0, - MF_ALPHA_h = 0.2D0, + MF_ALPHA_h = 0.05D0, MF_ORDER_h = 16, MF_ETAC_v = 0.0D0, - MF_ALPHA_v = 0.2D0, + MF_ALPHA_v = 0.05D0, MF_ORDER_v = 16, / &PARAM_ATMOS_DYN_BND @@ -74,7 +74,7 @@ #*** OUTPUT ******************************************* &PARAM_FILE_HISTORY FILE_HISTORY_DEFAULT_BASENAME = "history", - FILE_HISTORY_DEFAULT_TINTERVAL = 1.0D0, + FILE_HISTORY_DEFAULT_TINTERVAL = 4.0D0, FILE_HISTORY_DEFAULT_TUNIT = "HOUR", FILE_HISTORY_DEFAULT_TAVERAGE = .false., FILE_HISTORY_DEFAULT_DATATYPE = "REAL4", From b28d2dc90cadad3bb75037cb22d0835ea6aadc88 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 24 Jun 2021 00:01:54 +0900 Subject: [PATCH 65/98] Modify multiple unary operators. --- .../scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 8 ++++---- .../scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 8 ++++---- .../scale_atm_dyn_dgm_nonhydro3d_heve.F90 | 4 ++-- .../scale_atm_dyn_dgm_nonhydro3d_hevi.F90 | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index c55e6976..0743d30f 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -254,8 +254,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !-- MOMX call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMX_(:,ke) + G11(:) * DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMX_(:,ke) + G12(:) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & - ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + + ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) MOMX_dt(:,ke) = & @@ -271,8 +271,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !-- MOMY call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMY_(:,ke) + G12(:) * DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMY_(:,ke) + G22(:) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & - ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) & + + ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) MOMY_dt(:,ke) = & diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index bbacffc9..adccad02 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -254,8 +254,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & !-- MOMX call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMX_(:,ke) + G11(:) * DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMX_(:,ke) + G12(:) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & - ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) & + + ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) MOMX_dt(:,ke) = & @@ -271,8 +271,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & !-- MOMY call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMY_(:,ke) + G12(:) * DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMY_(:,ke) + G22(:) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & - ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) & + + ( lmesh%GI3(:,ke,1) * G12(:) + lmesh%GI3(:,ke,2) * G22(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) MOMY_dt(:,ke) = & diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 index 363a2242..5e585224 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve.F90 @@ -215,7 +215,7 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & !-- MOMX call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMX_(:,ke) , Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) & + lmesh%GI3(:,ke,1) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) @@ -230,7 +230,7 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_cal_tend( & !-- MOMY call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMY_(:,ke) , Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) & + lmesh%GI3(:,ke,2) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 index 47170e46..fe3b6fc0 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 @@ -216,8 +216,8 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & !-- MOMX call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_(:) * MOMX_(:,ke) + DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * v_(:) * MOMX_(:,ke) , Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & - lmesh%GI3(:,ke,1) * DPRES_(:) ), Fz) + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) & + + lmesh%GI3(:,ke,1) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) MOMX_dt(:,ke) = & @@ -231,7 +231,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_tend( & !-- MOMY call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * u_(:) * MOMY_(:,ke) , Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_(:) * MOMY_(:,ke) + DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) + & + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMY_(:,ke) & + lmesh%GI3(:,ke,2) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMY_VID), LiftDelFlx) From 8f87c59eaf062af58eccd678697d99db22cfbdbc Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 24 Jun 2021 00:05:07 +0900 Subject: [PATCH 66/98] Modify multiple unary operators. --- .../scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 index 0743d30f..f09d55fb 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_heve.F90 @@ -254,7 +254,7 @@ subroutine atm_dyn_dgm_globalnonhydro3d_heve_cal_tend( & !-- MOMX call sparsemat_matmul(Dx, lmesh%Gsqrt(:,ke) * ( u_ (:) * MOMX_(:,ke) + G11(:) * DPRES_(:) ), Fx) call sparsemat_matmul(Dy, lmesh%Gsqrt(:,ke) * ( v_ (:) * MOMX_(:,ke) + G12(:) * DPRES_(:) ), Fy) - call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) + & + call sparsemat_matmul(Dz, lmesh%Gsqrt(:,ke) * ( wt_(:) * MOMX_(:,ke) & + ( lmesh%GI3(:,ke,1) * G11(:) + lmesh%GI3(:,ke,2) * G12(:) ) * DPRES_(:) ), Fz) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,MOMX_VID), LiftDelFlx) From 8e75c632e52db92004469ed58a66907cbcc402a5 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 27 Jun 2021 09:38:53 +0900 Subject: [PATCH 67/98] Modify source codes. --- .../fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 | 8 +------- .../test/case/equatorial_wave_global/mod_user.F90 | 11 +++++++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 index f4dc9109..35df45e8 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalsw.F90 @@ -147,13 +147,7 @@ subroutine atm_dyn_dgm_globalsw_cal_tend( & lmesh%Escale(:,ke,1,1) * Fx(:) & + lmesh%Escale(:,ke,2,2) * Fy(:) & + LiftDelFlx(:) ) / lmesh%Gsqrt(:,ke) - ! if (lmesh%panelID==1 .and. ke==1 )then - ! write(*,*) "Gsqrt:", lmesh%Gsqrt(:,ke) - ! write(*,*) "Fx:", Fx(:) - ! write(*,*) "Fy:", Fy(:) - ! write(*,*) "Lift:", LiftDelFlx(:) - ! write(*,*) "ht:", h_dt(:,ke) - ! end if + !-- u1 call sparsemat_matmul(Dx, E(:), Fx) call sparsemat_matmul(Lift, lmesh%Fscale(:,ke) * del_flux(:,ke,VARS_u1_ID), LiftDelFlx) diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 b/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 index 68e6747c..2da47b5f 100644 --- a/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/mod_user.F90 @@ -141,7 +141,7 @@ subroutine USER_calc_tendency( atm ) class(LocalMeshFieldBase), pointer :: DENS_hyd, PRES_hyd class(LocalMeshFieldBase), pointer :: PRES, PT - real(RP), parameter :: rtau = 1.0_RP / ( 10.0_RP * 864000.0_RP ) ! (10 day)^-1 + real(RP), parameter :: rtau = 1.0_RP / ( 10.0_RP * 86400.0_RP ) ! (10 day)^-1 integer :: n integer :: ke @@ -284,11 +284,14 @@ subroutine func_qheat( q_intrp, & real(RP), intent(in) :: lat(elem_intrp%Np) real(RP), intent(in) :: zlev(elem_intrp%Np) real(RP), intent(in) :: rplanet_ + + real(RP) :: lon_(elem_intrp%Np) !------------------------------------------ - where ( abs(lon(:)) < DLon .and. abs(lat(:)) < DLat ) - q_intrp(:) = CpDry * Q0 * cos(0.5_RP * PI * lon(:) / DLon)**2 & - * cos(0.5_RP * PI * lat(:) / DLat)**2 & + lon_(:) = PI - lon(:) + where ( abs(lon_(:)) < DLon .and. abs(lat(:)) < DLat ) + q_intrp(:) = CpDry * Q0 * cos(0.5_RP * PI * lon_(:) / DLon)**2 & + * cos(0.5_RP * PI * lat (:) / DLat)**2 & * sin( real(nv,kind=RP) * PI * zlev(:) / Zt ) elsewhere q_intrp(:) = 0.0_RP From f0777f6068cd49f7bf4c2dc954966df7ed10c79b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 7 Jul 2021 12:06:13 +0900 Subject: [PATCH 68/98] Modify modules for HEVI to improve the computational performance. --- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 248 ++++++------ .../scale_atm_dyn_dgm_nonhydro3d_hevi.F90 | 251 ++++++------- ...ale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 | 352 +++++++++++------- ..._atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 | 265 +++++++------ 4 files changed, 594 insertions(+), 522 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index adccad02..c67f9bed 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -142,7 +142,6 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & real(RP) :: s integer :: ke, ke2d - integer :: p, p12, p3 real(RP) :: gamm, rgamm real(RP) :: rP0 @@ -325,7 +324,6 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & return end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend - !OCL SERIAL subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & DENS_dt, MOMX_dt, MOMY_dt, MOMZ_dt, RHOT_dt, & ! (out) @@ -364,26 +362,23 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & real(RP), intent(in) :: impl_fac real(RP), intent(in) :: dt - real(RP) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: PROG_VARS00(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: b(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: alph(elem%NfpTot,lmesh%NeZ) - real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) - real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) - real(RP) :: GnnM_z(elem%Np,lmesh%NeZ) - real(RP) :: G13_z(elem%Np,lmesh%NeZ) - real(RP) :: G23_z(elem%Np,lmesh%NeZ) - real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ) - real(RP) :: nz(elem%NfpTot,lmesh%NeZ) + real(RP) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: GnnM_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: G13_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: G23_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: nz(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) integer :: vmapM(elem%NfpTot,lmesh%NeZ) - integer :: vmapP(elem%NfpTot,lmesh%NeZ) - integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v - integer :: itr_lin, itr_nlin + integer :: vmapP(elem%NfpTot,lmesh%NeZ) + integer :: ColMask(elem%Nnode_v) + integer :: ke_xy, ke_z, ke, ke2D, v + integer :: itr_nlin integer :: kl, ku, nz_1D integer :: ij, info logical :: is_converged @@ -401,135 +396,140 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & call vi_gen_vmap( vmapM, vmapP, & ! (out) lmesh, elem ) ! (in) + !- + + !$omp parallel private( ke_xy, ke_z, ke, ke2D ) + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2D = lmesh%EMap3Dto2D(ke) + + PROG_VARS(:,ke_z,DENS_VID,ke_xy) = DDENS_(:,ke) + PROG_VARS(:,ke_z,MOMX_VID,ke_xy) = MOMX_ (:,ke) + PROG_VARS(:,ke_z,MOMY_VID,ke_xy) = MOMY_ (:,ke) + PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) = MOMZ_ (:,ke) + PROG_VARS(:,ke_z,RHOT_VID,ke_xy) = DRHOT_(:,ke) + + DENS_hyd_z(:,ke_z,ke_xy) = DENS_hyd(:,ke) + PRES_hyd_z(:,ke_z,ke_xy) = PRES_hyd(:,ke) + + nz(:,ke_z,ke_xy) = lmesh%normal_fn(:,ke,3) + G13_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,1) + G23_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,2) + GsqrtV_z(:,ke_z,ke_xy) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) + + GnnM_z(:,ke_z,ke_xy) = ( & + 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & + + G13_z(:,ke_z,ke_xy) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,1) * G13_z(:,ke_z,ke_xy) & + + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G23_z(:,ke_z,ke_xy) ) & + + G23_z(:,ke_z,ke_xy) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G13_z(:,ke_z,ke_xy) & + + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,2,2) * G23_z(:,ke_z,ke_xy) ) ) + end do + end do + !$omp end do + !$omp workshare + PROG_VARS0 (:,:,:,:) = PROG_VARS(:,:,:,:) + !$omp end workshare + !$omp end parallel + call PROF_rapend( 'hevi_cal_vi_prep', 3) - do ke_y=1, lmesh%NeY - do ke_x=1, lmesh%NeX + !-- - call PROF_rapstart( 'hevi_cal_vi_get_var', 3) + if ( abs(impl_fac) > 0.0_RP ) then + call PROF_rapstart( 'hevi_cal_vi_itr', 3) - !$omp parallel do private( ke, ke2D ) - do ke_z=1, lmesh%NeZ - ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - ke2D = lmesh%EMap3Dto2D(ke) - - PROG_VARS(:,DENS_VID,ke_z) = DDENS_(:,ke) - PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) - PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) - PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) - PROG_VARS(:,RHOT_VID,ke_z) = DRHOT_(:,ke) - DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) - PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) - - PROG_VARS0 (:,:,ke_z) = PROG_VARS(:,:,ke_z) - PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) - - nz(:,ke_z) = lmesh%normal_fn(:,ke,3) - G13_z(:,ke_z) = lmesh%GI3(:,ke,1) - G23_z(:,ke_z) = lmesh%GI3(:,ke,2) - GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) - - GnnM_z(:,ke_z) = ( & - 1.0_RP / GsqrtV_z(:,ke_z)**2 & - + G13_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,1) * G13_z(:,ke_z) & - + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G23_z(:,ke_z) ) & - + G23_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G13_z(:,ke_z) & - + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,2,2) * G23_z(:,ke_z) ) ) - end do - call PROF_rapend( 'hevi_cal_vi_get_var', 3) - - if ( abs(impl_fac) > 0.0_RP ) then - call PROF_rapstart( 'hevi_cal_vi_itr', 3) - - ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 - ! dG/dq^n+1 del[q] = - G(q^n*) - do itr_nlin = 1, 1 - - call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, .false. ) ! (in) - - do ke_z=1, lmesh%NeZ - b(:,:,ke_z) = - Ax(:,:,ke_z) + PROG_VARS00(:,:,ke_z) - end do + ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 + ! dG/dq^n+1 del[q] = - G(q^n*) + do itr_nlin = 1, 1 + call PROF_rapstart( 'hevi_cal_vi_ax', 3) + + call vi_eval_Ax( & + DENS_dt(:,:), MOMX_dt(:,:), MOMY_dt(:,:), MOMZ_dt(:,:), RHOT_dt(:,:), & ! (out, dummy) + alph(:,:,:), & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz, vmapM, vmapP, & ! (in) + b1D(:,:,:,:,:) ) ! (out) + + call PROF_rapend( 'hevi_cal_vi_ax', 3) + do ke_xy=1, lmesh%NeX * lmesh%NeY call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) - call vi_construct_matbnd( PmatBnd, & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - G13_z, G23_z, GsqrtV_z, alph, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + call vi_construct_matbnd( PmatBnd(:,:,:), & ! (out) + kl, ku, nz_1D, & ! (in) + PROG_VARS0(:,:,:,ke_xy), & ! (in) + DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) + G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) + alph(:,:,ke_xy), & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) call PROF_rapend( 'hevi_cal_vi_matbnd', 3) call PROF_rapstart( 'hevi_cal_vi_lin', 3) - !$omp parallel private(ij, v, ke_z, info) + !$omp parallel private(ij, v, ke_z, info, ColMask) !$omp do do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - do v=1, PROG_VARS_NUM - b1D(:,v,ke_z,ij) = b(elem%Colmask(:,ij),v,ke_z) - end do - end do - - call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij), nz_1D, info) + call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij,ke_xy), nz_1D, info) + ColMask(:) = elem%Colmask(:,ij) do ke_z=1, lmesh%NeZ do v=1, PROG_VARS_NUM - PROG_VARS(elem%Colmask(:,ij),v,ke_z) = PROG_VARS(elem%Colmask(:,ij),v,ke_z) + b1D(:,v,ke_z,ij) + PROG_VARS(ColMask(:),ke_z,v,ke_xy) = PROG_VARS(Colmask(:),ke_z,v,ke_xy) & + + b1D(:,v,ke_z,ij,ke_xy) end do end do - end do - !$omp do - do ke_z=1, lmesh%NeZ - PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) - end do + end do ! for ij + !$omp end do + !$omp workshare + PROG_VARS0(:,:,:,ke_xy) = PROG_VARS(:,:,:,ke_xy) + !$omp end workshare !$omp end parallel call PROF_rapend( 'hevi_cal_vi_lin', 3) - end do ! itr nlin - call PROF_rapend( 'hevi_cal_vi_itr', 3) - end if + end do ! for ke_xy + end do ! itr nlin - call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) - if ( abs(impl_fac) > 0.0_RP) then - !$omp parallel do - do ke_z=1, lmesh%NeZ - tend(:,:,ke_z) = ( - PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z) ) / impl_fac - end do - else - call vi_eval_Ax( tend(:,:,:), alph, & ! (out) - PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, .true. ) ! (in) - end if + call PROF_rapend( 'hevi_cal_vi_itr', 3) + end if - !$omp parallel do private(ke) + call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) + if ( abs(impl_fac) > 0.0_RP) then + !$omp parallel do collapse(2) private(ke_xy, ke_z, ke) + do ke_xy=1, lmesh%NeX * lmesh%NeY do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - DENS_dt(:,ke) = - tend(:,DENS_VID,ke_z) - MOMX_dt(:,ke) = - tend(:,MOMX_VID,ke_z) - MOMY_dt(:,ke) = - tend(:,MOMY_VID,ke_z) - MOMZ_dt(:,ke) = - tend(:,MOMZ_VID,ke_z) - RHOT_dt(:,ke) = - tend(:,RHOT_VID,ke_z) + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + DENS_dt(:,ke) = ( PROG_VARS(:,ke_z,DENS_VID,ke_xy) - DDENS_(:,ke) ) / impl_fac + MOMX_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMX_VID,ke_xy) - MOMX_ (:,ke) ) / impl_fac + MOMY_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMY_VID,ke_xy) - MOMY_ (:,ke) ) / impl_fac + MOMZ_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) - MOMZ_ (:,ke) ) / impl_fac + RHOT_dt(:,ke) = ( PROG_VARS(:,ke_z,RHOT_VID,ke_xy) - DRHOT_(:,ke) ) / impl_fac end do - call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) - end do - end do + end do + else + call vi_eval_Ax( & + DENS_dt(:,:), MOMX_dt(:,:), MOMY_dt(:,:), MOMZ_dt(:,:), RHOT_dt(:,:), & ! (out) + alph(:,:,:), & ! (out, dummy) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz, vmapM, vmapP ) ! (in) + end if + call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) return end subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 index fe3b6fc0..f611afd1 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 @@ -322,26 +322,23 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & real(RP), intent(in) :: impl_fac real(RP), intent(in) :: dt - real(RP) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: PROG_VARS00(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: b(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: alph(elem%NfpTot,lmesh%NeZ) - real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) - real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) - real(RP) :: GnnM_z(elem%Np,lmesh%NeZ) - real(RP) :: G13_z(elem%Np,lmesh%NeZ) - real(RP) :: G23_z(elem%Np,lmesh%NeZ) - real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ) - real(RP) :: nz(elem%NfpTot,lmesh%NeZ) + real(RP) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: GnnM_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: G13_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: G23_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: nz(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) integer :: vmapM(elem%NfpTot,lmesh%NeZ) - integer :: vmapP(elem%NfpTot,lmesh%NeZ) - integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v - integer :: itr_lin, itr_nlin + integer :: vmapP(elem%NfpTot,lmesh%NeZ) + integer :: ColMask(elem%Nnode_v) + integer :: ke_xy, ke_z, ke, ke2D, v + integer :: itr_nlin integer :: kl, ku, nz_1D integer :: ij, info logical :: is_converged @@ -359,131 +356,135 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & call vi_gen_vmap( vmapM, vmapP, & ! (out) lmesh, elem ) ! (in) - call PROF_rapend( 'hevi_cal_vi_prep', 3) - - do ke_y=1, lmesh%NeY - do ke_x=1, lmesh%NeX - - call PROF_rapstart( 'hevi_cal_vi_get_var', 3) - - !$omp parallel do private( ke, ke2D ) - do ke_z=1, lmesh%NeZ - ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - ke2D = lmesh%EMap3Dto2D(ke) - - PROG_VARS(:,DENS_VID,ke_z) = DDENS_(:,ke) - PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) - PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) - PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) - PROG_VARS(:,RHOT_VID,ke_z) = DRHOT_(:,ke) - DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) - PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) - - PROG_VARS0 (:,:,ke_z) = PROG_VARS(:,:,ke_z) - PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) - - nz(:,ke_z) = lmesh%normal_fn(:,ke,3) - G13_z(:,ke_z) = lmesh%GI3(:,ke,1) - G23_z(:,ke_z) = lmesh%GI3(:,ke,2) - GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) - - GnnM_z(:,ke_z) = & - 1.0_RP / GsqrtV_z(:,ke_z)**2 + G13_z(:,ke_z)**2 + G23_z(:,ke_z)**2 - end do - call PROF_rapend( 'hevi_cal_vi_get_var', 3) + !- + + !$omp parallel private( ke_xy, ke_z, ke, ke2D ) + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2D = lmesh%EMap3Dto2D(ke) + + PROG_VARS(:,ke_z,DENS_VID,ke_xy) = DDENS_(:,ke) + PROG_VARS(:,ke_z,MOMX_VID,ke_xy) = MOMX_ (:,ke) + PROG_VARS(:,ke_z,MOMY_VID,ke_xy) = MOMY_ (:,ke) + PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) = MOMZ_ (:,ke) + PROG_VARS(:,ke_z,RHOT_VID,ke_xy) = DRHOT_(:,ke) + + DENS_hyd_z(:,ke_z,ke_xy) = DENS_hyd(:,ke) + PRES_hyd_z(:,ke_z,ke_xy) = PRES_hyd(:,ke) - if ( abs(impl_fac) > 0.0_RP ) then - call PROF_rapstart( 'hevi_cal_vi_itr', 3) - - ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 - ! dG/dq^n+1 del[q] = - G(q^n*) - do itr_nlin = 1, 1 - - call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, .false. ) ! (in) - - do ke_z=1, lmesh%NeZ - b(:,:,ke_z) = - Ax(:,:,ke_z) + PROG_VARS00(:,:,ke_z) - end do - + nz(:,ke_z,ke_xy) = lmesh%normal_fn(:,ke,3) + G13_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,1) + G23_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,2) + GsqrtV_z(:,ke_z,ke_xy) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) + + GnnM_z(:,ke_z,ke_xy) = ( & + 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & + + G13_z(:,ke_z,ke_xy) **2 + G23_z(:,ke_z,ke_xy) **2 ) + end do + end do + !$omp end do + !$omp workshare + PROG_VARS0 (:,:,:,:) = PROG_VARS(:,:,:,:) + !$omp end workshare + !$omp end parallel + + call PROF_rapend( 'hevi_cal_vi_prep', 3) + + if ( abs(impl_fac) > 0.0_RP ) then + call PROF_rapstart( 'hevi_cal_vi_itr', 3) + + ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 + ! dG/dq^n+1 del[q] = - G(q^n*) + do itr_nlin = 1, 1 + call PROF_rapstart( 'hevi_cal_vi_ax', 3) + + call vi_eval_Ax( & + DENS_dt(:,:), MOMX_dt(:,:), MOMY_dt(:,:), MOMZ_dt(:,:), RHOT_dt(:,:), & ! (out, dummy) + alph(:,:,:), & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz, vmapM, vmapP, & ! (in) + b1D(:,:,:,:,:) ) ! (out) + + call PROF_rapend( 'hevi_cal_vi_ax', 3) + + do ke_xy=1, lmesh%NeX * lmesh%NeY call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) - call vi_construct_matbnd( PmatBnd, & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - G13_z, G23_z, GsqrtV_z, alph, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + call vi_construct_matbnd( PmatBnd(:,:,:), & ! (out) + kl, ku, nz_1D, & ! (in) + PROG_VARS0(:,:,:,ke_xy), & ! (in) + DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) + G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) + alph(:,:,ke_xy), & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) call PROF_rapend( 'hevi_cal_vi_matbnd', 3) call PROF_rapstart( 'hevi_cal_vi_lin', 3) - !$omp parallel private(ij, v, ke_z, info) + !$omp parallel private(ij, v, ke_z, info, ColMask) !$omp do do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - do v=1, PROG_VARS_NUM - b1D(:,v,ke_z,ij) = b(elem%Colmask(:,ij),v,ke_z) - end do - end do - - call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij), nz_1D, info) + call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij,ke_xy), nz_1D, info) + ColMask(:) = elem%Colmask(:,ij) do ke_z=1, lmesh%NeZ do v=1, PROG_VARS_NUM - PROG_VARS(elem%Colmask(:,ij),v,ke_z) = PROG_VARS(elem%Colmask(:,ij),v,ke_z) + b1D(:,v,ke_z,ij) + PROG_VARS(ColMask(:),ke_z,v,ke_xy) = PROG_VARS(Colmask(:),ke_z,v,ke_xy) & + + b1D(:,v,ke_z,ij,ke_xy) end do end do - end do - !$omp do - do ke_z=1, lmesh%NeZ - PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) - end do + end do ! for ij + !$omp end do + !$omp workshare + PROG_VARS0(:,:,:,ke_xy) = PROG_VARS(:,:,:,ke_xy) + !$omp end workshare !$omp end parallel call PROF_rapend( 'hevi_cal_vi_lin', 3) - end do ! itr nlin - - call PROF_rapend( 'hevi_cal_vi_itr', 3) - end if - - call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) - if ( abs(impl_fac) > 0.0_RP) then - !$omp parallel do - do ke_z=1, lmesh%NeZ - tend(:,:,ke_z) = (- PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z))/impl_fac - end do - else - call vi_eval_Ax( tend(:,:,:), alph, & ! (out) - PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, .true. ) ! (in) - end if - - !$omp parallel do private(ke) + + end do ! for ke_xy + end do ! itr nlin + + call PROF_rapend( 'hevi_cal_vi_itr', 3) + end if + + call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) + if ( abs(impl_fac) > 0.0_RP) then + !$omp parallel do collapse(2) private(ke_xy, ke_z, ke) + do ke_xy=1, lmesh%NeX * lmesh%NeY do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - DENS_dt(:,ke) = - tend(:,DENS_VID,ke_z) - MOMX_dt(:,ke) = - tend(:,MOMX_VID,ke_z) - MOMY_dt(:,ke) = - tend(:,MOMY_VID,ke_z) - MOMZ_dt(:,ke) = - tend(:,MOMZ_VID,ke_z) - RHOT_dt(:,ke) = - tend(:,RHOT_VID,ke_z) + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + DENS_dt(:,ke) = ( PROG_VARS(:,ke_z,DENS_VID,ke_xy) - DDENS_(:,ke) ) / impl_fac + MOMX_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMX_VID,ke_xy) - MOMX_ (:,ke) ) / impl_fac + MOMY_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMY_VID,ke_xy) - MOMY_ (:,ke) ) / impl_fac + MOMZ_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) - MOMZ_ (:,ke) ) / impl_fac + RHOT_dt(:,ke) = ( PROG_VARS(:,ke_z,RHOT_VID,ke_xy) - DRHOT_(:,ke) ) / impl_fac end do - call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) - end do - end do + end do + else + call vi_eval_Ax( & + DENS_dt(:,:), MOMX_dt(:,:), MOMY_dt(:,:), MOMZ_dt(:,:), RHOT_dt(:,:), & ! (out) + alph(:,:,:), & ! (out, dummy) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz, vmapM, vmapP ) ! (in) + end if + call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) return end subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 index f6302665..42859e70 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 @@ -113,124 +113,193 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap( & return end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap + !OCL SERIAL subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax( & - Ax, alph, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, cal_tend_flag ) ! (in) + DENS_t, MOMX_t, MOMY_t, MOMZ_t, RHOT_t, & ! (out) + alph, & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS00, MOMX00, MOMY00, MOMZ00, DRHOT00, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM, G13, G23, GsqrtV, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, & ! (in) + b1D_ij ) ! (out) implicit none class(LocalMesh3D), intent(in) :: lmesh class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(out) :: alph(elem%NfpTot,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(out) :: DENS_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMX_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMY_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMZ_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: RHOT_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PROG_VARS0 (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: DDENS00(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMX00 (elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMY00 (elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMZ00 (elem%Np,lmesh%NeA) + real(RP), intent(in) :: DRHOT00(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) class(SparseMat), intent(in) :: Dz, Lift real(RP), intent(in) :: IntrpMat_VPOrdM1(elem%Np,elem%Np) - real(RP), intent(in) :: GnnM_z(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: G13_z(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: G23_z(elem%Np,lmesh%NeZ) - real(RP), intent(in) :: GsqrtV_z(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: GnnM(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: G13 (elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: G23 (elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: GsqrtV(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) logical, intent(in) :: modalFilterFlag real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) real(RP), intent(in) :: impl_fac real(RP), intent(in) :: dt - real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) - integer, intent(in) :: ke_x, ke_y - logical, intent(in) :: cal_tend_flag + real(RP), intent(out), optional :: b1D_ij(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) - real(RP) :: RGsqrtV(elem%Np) + real(RP) :: RGsqrtV(elem%Np) + real(RP) :: Fscale(elem%NfpTot), Escale33(elem%Np) real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) - real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,PROG_VARS_NUM) - real(RP) :: RHOT_hyd(elem%Np), POT(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY,PROG_VARS_NUM) + real(RP) :: MOMZ(elem%Np), DDENS(elem%Np), RHOT_hyd(elem%Np), RHOT(elem%Np) real(RP) :: DPRES(elem%Np) - integer :: ke_z + integer :: ke_xy, ke_z integer :: ke, ke2d integer :: v integer :: ij + integer :: ColMask(elem%Nnode_v) + real(RP) :: rdt + real(RP) :: drho(elem%Np) + + integer :: kk, kkk, p, pp + real(RP) :: vmf_v + real(RP) :: gamm, rgamm !-------------------------------------------------------- gamm = CpDry/CvDry rgamm = CvDry/CpDry + rdt = 1.0_RP / dt + + call vi_cal_del_flux_dyn( del_flux, alph, & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + GnnM, G13, G23, GsqrtV, nz, vmapM, vmapP, & ! (in) + lmesh, elem ) ! (in) - call vi_cal_del_flux_dyn( del_flux, alph, & ! (out) - PROG_VARS(:,DENS_VID,:), PROG_VARS(:,MOMX_VID,:), & ! (in) - PROG_VARS(:,MOMY_VID,:), PROG_VARS(:,MOMZ_VID,:), & ! (in) - PROG_VARS(:,RHOT_VID,:), & ! (in) - PROG_VARS0(:,DENS_VID,:), PROG_VARS0(:,MOMX_VID,:), & ! (in) - PROG_VARS0(:,MOMY_VID ,:), PROG_VARS0(:,MOMZ_VID,:), & ! (in) - PROG_VARS0(:,RHOT_VID,:), & ! (in) - DENS_hyd, PRES_hyd, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, nz, vmapM, vmapP, & ! (in) - lmesh, elem ) ! (in) - - !$omp parallel do private( & - !$omp ke, ke2d, RHOT_hyd, DPRES, POT, Fz, LiftDelFlx, & - !$omp v, ij, RGsqrtV & - !$omp ) + !$omp parallel private( ke_xy, ke_z, ke, ke2d, ij, v, & + !$omp MOMZ, DDENS, RHOT_hyd, DPRES, RHOT, Fz, LiftDelFlx, & + !$omp RGsqrtV, ColMask, Fscale, Escale33, drho, & + !$omp kk, p, kkk, vmf_v, pp ) + + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke = Ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY ke2d = lmesh%EMap3Dto2D(ke) - RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z)/PRES00)**rgamm + DDENS(:) = PROG_VARS(:,ke_z,DENS_VID,ke_xy) + drho(:) = matmul(IntrpMat_VPOrdM1, DDENS(:)) - DPRES(:) = PRES_hyd(:,ke_z) * ( (1.0_RP + PROG_VARS(:,RHOT_VID,ke_z)/RHOT_hyd(:))**gamm - 1.0_RP ) - POT(:) = ( RHOT_hyd(:) + PROG_VARS(:,RHOT_VID,ke_z) ) / ( DENS_hyd(:,ke_z) + PROG_VARS(:,DENS_VID,ke_z) ) + MOMZ (:) = PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) - RGsqrtV(:) = 1.0_RP / GsqrtV_z(:,ke_z) + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z,ke_xy)/PRES00)**rgamm + RHOT(:) = RHOT_hyd(:) + PROG_VARS(:,ke_z,RHOT_VID,ke_xy) + DPRES(:) = PRES_hyd(:,ke_z,ke_xy) * ( ( RHOT(:) / RHOT_hyd(:) )**gamm - 1.0_RP ) + + RGsqrtV(:) = 1.0_RP / GsqrtV(:,ke_z,ke_xy) + Fscale(:) = lmesh%Fscale(:,ke) + Escale33(:) = lmesh%Escale(:,ke,3,3) !- DENS - call sparsemat_matmul(Dz, PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,DENS_VID), LiftDelFlx) - Ax(:,DENS_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + call sparsemat_matmul(Dz, MOMZ(:), Fz) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,DENS_VID), LiftDelFlx) + DENS_t(:,ke) = - ( Escale33(:) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) !- MOMX - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMX_VID), LiftDelFlx) - Ax(:,MOMX_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,MOMX_VID), LiftDelFlx) + MOMX_t(:,ke) = - LiftDelFlx(:) * RGsqrtV(:) !-MOMY - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMY_VID), LiftDelFlx) - Ax(:,MOMY_VID,ke_z) = LiftDelFlx(:) * RGsqrtV(:) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,MOMY_VID), LiftDelFlx) + MOMY_t(:,ke) = - LiftDelFlx(:) * RGsqrtV(:) !-MOMZ call sparsemat_matmul(Dz, DPRES(:), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,MOMZ_VID), LiftDelFlx) - Ax(:,MOMZ_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) & - + Grav * matmul(IntrpMat_VPOrdM1, PROG_VARS(:,DENS_VID,ke_z)) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,MOMZ_VID), LiftDelFlx) + MOMZ_t(:,ke) = - ( Escale33(:) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) & + - Grav * drho(:) !-RHOT - call sparsemat_matmul(Dz, POT(:)*PROG_VARS(:,MOMZ_VID,ke_z), Fz) - call sparsemat_matmul(Lift, lmesh%Fscale(:,ke)*del_flux(:,ke_z,RHOT_VID), LiftDelFlx) - Ax(:,RHOT_VID,ke_z) = ( lmesh%Escale(:,ke,3,3) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + call sparsemat_matmul(Dz, RHOT(:) * MOMZ(:) / ( DENS_hyd(:,ke_z,ke_xy) + DDENS(:) ), Fz) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,RHOT_VID), LiftDelFlx) + RHOT_t(:,ke) = - ( Escale33(:) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + + end do + end do + !$omp end do + + if ( modalFilterFlag ) then + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY - !-- Modal filtering in the vertical direction - if ( modalFilterFlag ) then - do v=1, PROG_VARS_NUM + !-- Modal filtering in the vertical direction + do kk=1, elem%Nnode_v do ij=1, elem%Nnode_h1D**2 - Ax(elem%Colmask(:,ij),v,ke_z) = Ax(elem%Colmask(:,ij),v,ke_z) & - - matmul(VModalFilter, PROG_VARS(elem%Colmask(:,ij),v,ke_z) ) / dt + p = elem%Colmask(kk,ij) + do kkk=1, elem%Nnode_v + pp = elem%Colmask(kkk,ij) + vmf_v = rdt * VModalFilter(kk,kkk) + DENS_t(p,ke) = DENS_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,DENS_VID,ke_xy) + MOMX_t(p,ke) = MOMX_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,MOMX_VID,ke_xy) + MOMY_t(p,ke) = MOMY_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,MOMY_VID,ke_xy) + MOMZ_t(p,ke) = MOMZ_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,MOMZ_VID,ke_xy) + RHOT_t(p,ke) = RHOT_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,RHOT_VID,ke_xy) + end do end do + end do + end do + end do + !$omp end do + end if + + if ( present( b1D_ij ) ) then + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + + do ij=1, elem%Nnode_h1D**2 + ColMask(:) = elem%Colmask(:,ij) + b1D_ij(:,DENS_VID,ke_z,ij,ke_xy) = impl_fac * DENS_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,DENS_VID,ke_xy) & + + DDENS00(ColMask(:),ke) + b1D_ij(:,MOMX_VID,ke_z,ij,ke_xy) = impl_fac * MOMX_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,MOMX_VID,ke_xy) & + + MOMX00(ColMask(:),ke) + b1D_ij(:,MOMY_VID,ke_z,ij,ke_xy) = impl_fac * MOMY_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,MOMY_VID,ke_xy) & + + MOMY00(ColMask(:),ke) + b1D_ij(:,MOMZ_VID,ke_z,ij,ke_xy) = impl_fac * MOMZ_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,MOMZ_VID,ke_xy) & + + MOMZ00(ColMask(:),ke) + b1D_ij(:,RHOT_VID,ke_z,ij,ke_xy) = impl_fac * RHOT_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,RHOT_VID,ke_xy) & + + DRHOT00(ColMask(:),ke) end do - end if - - !-- - if ( .not. cal_tend_flag ) then - Ax(:,:,ke_z) = PROG_VARS(:,:,ke_z) + impl_fac * Ax(:,:,ke_z) - end if - - end do + end do + end do + !$omp end do + end if + !$omp end parallel return end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax @@ -254,7 +323,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & class(elementbase3D), intent(in) :: elem integer, intent(in) :: kl, ku, nz_1D real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) - real(RP), intent(in) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) + real(RP), intent(in) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM) real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) real(RP), intent(in) :: G13(elem%Np,lmesh%NeZ) @@ -290,7 +359,7 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & real(RP) :: tmp1 real(RP) :: fac - integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb, pb1 + integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb1 logical :: bc_flag logical :: eval_flag(PROG_VARS_NUM,PROG_VARS_NUM) !-------------------------------------------------------- @@ -331,20 +400,22 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & - * ( 1.0_RP + PROG_VARS0(Colmask(:),RHOT_VID,ke_z) / RHOT_hyd(:) )**(gamm-1) + * ( 1.0_RP + PROG_VARS0(Colmask(:),ke_z,RHOT_VID) / RHOT_hyd(:) )**(gamm-1) - DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),DENS_VID,ke_z) - POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),RHOT_VID,ke_z) ) / DENS0(:,ke_z,ij) - W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),MOMZ_VID,ke_z) / DENS0(:,ke_z,ij) + DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),ke_z,DENS_VID) + POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),ke_z,RHOT_VID) ) / DENS0(:,ke_z,ij) + W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),ke_z,MOMZ_VID) / DENS0(:,ke_z,ij) end do end do !$omp end parallel - !$omp parallel do private(ke_z, ke, ColMask, p, fp, fp2, v, f1, f2, ke_z2, fac_dz_p, & + !$omp parallel private(ke_z, ke, ColMask, p, fp, fp2, v, f1, f2, ke_z2, fac_dz_p, & !$omp fac, tmp1, FmV, & !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & !$omp Dd ) & !$omp firstprivate(PmatD, PmatL, PmatU) + + !$omp do collapse(2) do ij=1, elem%Nnode_h1D**2 do ke_z=1, lmesh%NeZ ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY @@ -475,9 +546,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & end if end do end do - end do end do - + end do + !$omp end do + !$omp end parallel + return end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd @@ -485,8 +558,7 @@ end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd !OCL SERIAL subroutine vi_cal_del_flux_dyn( del_flux, alph, & ! (out) - DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) - DDENS0_, MOMX0_, MOMY0_, MOMZ0_, DRHOT0_, & ! (in) + PVARS_, PVARS0_, & ! (in) DENS_hyd, PRES_hyd, & ! (in) Gnn_, G13_, G23_, GsqrtV_, nz, vmapM, vmapP, lmesh, elem ) ! (in) @@ -494,102 +566,106 @@ subroutine vi_cal_del_flux_dyn( del_flux, alph, & ! (out) class(LocalMesh3D), intent(in) :: lmesh class(elementbase3D), intent(in) :: elem - real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,PROG_VARS_NUM) - real(RP), intent(out) :: alph(elem%NfpTot*lmesh%NeZ) - real(RP), intent(in) :: DDENS_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DDENS0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMX0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMY0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: MOMZ0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DRHOT0_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: Gnn_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: G13_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: G23_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: GsqrtV_(elem%Np*lmesh%NeZ) - real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ) + real(RP), intent(out) :: del_flux(elem%NfpTot*lmesh%NeZ,lmesh%NeX*lmesh%NeY,PROG_VARS_NUM) + real(RP), intent(out) :: alph(elem%NfpTot*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PVARS_ (elem%Np*lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PVARS0_(elem%Np*lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: Gnn_(elem%Np*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: G13_(elem%Np*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: G23_(elem%Np*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: GsqrtV_(elem%Np*lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: nz(elem%NfpTot*lmesh%NeZ,lmesh%NeX*lmesh%NeY) integer, intent(in) :: vmapM(elem%NfpTot*lmesh%NeZ) integer, intent(in) :: vmapP(elem%NfpTot*lmesh%NeZ) integer :: i, p, ke_z, iP, iM + integer :: ij real(RP) :: MOMZ_P real(RP) :: wt0M, wt0P real(RP) :: rhot_hyd_M, rhot_hyd_P real(RP) :: dpresM, dpresP, densM, densP, pottM, pottP real(RP) :: pres0M, pres0P, dens0M, dens0P - real(RP) :: gamm, rgamm + + real(RP) :: gamm, rgamm, PRES0ovRdry !------------------------------------------------------------------------ - gamm = CpDry/CvDry - rgamm = CvDry/CpDry + gamm = CpDry / CvDry + rgamm = CvDry / CpDry + PRES0ovRdry = PRES00 / Rdry - !$omp parallel do private( p, i, iM, iP, & + !$omp parallel private( ij, ke_z, p, i, iM, iP, & !$omp rhot_hyd_M, rhot_hyd_P, densM, densP, pottM, pottP, & !$omp dpresM, dpresP, MOMZ_P, wt0M, wt0P, & - !$omp dens0M, dens0P, pres0M, pres0P ) + !$omp dens0M, dens0P, pres0M, pres0P ) + + !$omp do collapse(2) + do ij=1, lmesh%NeX*lmesh%NeY do ke_z=1, lmesh%NeZ do p=1, elem%NfpTot i = p + (ke_z-1)*elem%NfpTot iM = vmapM(i); iP = vmapP(i) !- - rhot_hyd_M = PRES00/Rdry * (PRES_hyd(iM)/PRES00)**rgamm - rhot_hyd_P = PRES00/Rdry * (PRES_hyd(iP)/PRES00)**rgamm + rhot_hyd_M = PRES0ovRdry * (PRES_hyd(iM,ij)/PRES00)**rgamm + rhot_hyd_P = PRES0ovRdry * (PRES_hyd(iP,ij)/PRES00)**rgamm - densM = DENS_hyd(iM) + DDENS_(iM) - densP = DENS_hyd(iP) + DDENS_(iP) + densM = DENS_hyd(iM,ij) + PVARS_(iM,DENS_VID,ij) + densP = DENS_hyd(iP,ij) + PVARS_(iP,DENS_VID,ij) - pottM = (rhot_hyd_M + DRHOT_(iM)) / densM - pottP = (rhot_hyd_P + DRHOT_(iP)) / densP + pottM = ( rhot_hyd_M + PVARS_(iM,RHOT_VID,ij) ) / densM + pottP = ( rhot_hyd_P + PVARS_(iP,RHOT_VID,ij) ) / densP - dpresM = PRES_hyd(iM) * ( (1.0_RP + DRHOT_(iM)/rhot_hyd_M)**gamm - 1.0_RP ) - dpresP = PRES_hyd(iP) * ( (1.0_RP + DRHOT_(iP)/rhot_hyd_P)**gamm - 1.0_RP ) + dpresM = PRES_hyd(iM,ij) * ( (1.0_RP + PVARS_(iM,RHOT_VID,ij) / rhot_hyd_M)**gamm - 1.0_RP ) + dpresP = PRES_hyd(iP,ij) * ( (1.0_RP + PVARS_(iP,RHOT_VID,ij) / rhot_hyd_P)**gamm - 1.0_RP ) !- - dens0M = DENS_hyd(iM) + DDENS0_(iM) - dens0P = DENS_hyd(iP) + DDENS0_(iP) - - pres0M = PRES_hyd(iM) * (1.0_RP + DRHOT0_(iM)/rhot_hyd_M)**gamm - pres0P = PRES_hyd(iP) * (1.0_RP + DRHOT0_(iP)/rhot_hyd_P)**gamm + dens0M = DENS_hyd(iM,ij) + PVARS0_(iM,DENS_VID,ij) + dens0P = DENS_hyd(iP,ij) + PVARS0_(iP,DENS_VID,ij) - wt0M = ( MOMZ0_(iM) / GsqrtV_(iM) + G13_(iM) * MOMX0_(iM) + G23_(iM) * MOMY0_(iM) ) / dens0M - wt0P = ( MOMZ0_(iP) / GsqrtV_(iP) + G13_(iP) * MOMX0_(iP) + G23_(iP) * MOMY0_(iP) ) / dens0P + pres0M = PRES_hyd(iM,ij) * (1.0_RP + PVARS0_(iM,RHOT_VID,ij) / rhot_hyd_M)**gamm + pres0P = PRES_hyd(iP,ij) * (1.0_RP + PVARS0_(iP,RHOT_VID,ij) / rhot_hyd_P)**gamm - alph(i) = nz(i)**2 * max( abs( wt0M ) + sqrt( Gnn_(iM) * gamm * pres0M / dens0M ), & - abs( wt0P ) + sqrt( Gnn_(iP) * gamm * pres0P / dens0P ) ) + wt0M = ( PVARS0_(iM,MOMZ_VID,ij) / GsqrtV_(iM,ij) + G13_(iM,ij) * PVARS0_(iM,MOMX_VID,ij) & + + G23_(iM,ij) * PVARS0_(iM,MOMY_VID,ij) ) / dens0M + wt0P = ( PVARS0_(iP,MOMZ_VID,ij) / GsqrtV_(iP,ij) + G13_(iP,ij) * PVARS0_(iP,MOMX_VID,ij) & + + G23_(iP,ij) * PVARS0_(iP,MOMY_VID,ij) ) / dens0P + + alph(i,ij) = nz(i,ij)**2 * max( abs( wt0M ) + sqrt( Gnn_(iM,ij) * gamm * pres0M / dens0M ), & + abs( wt0P ) + sqrt( Gnn_(iP,ij) * gamm * pres0P / dens0P ) ) !---- if ( iM==iP .and. (ke_z == 1 .or. ke_z == lmesh%NeZ) ) then - MOMZ_P = - GsqrtV_(iM) * ( dens0M * wt0M + G13_(iM) * MOMX0_(iM) + G23_(iM) * MOMY0_(iM) ) + MOMZ_P = - GsqrtV_(iM,ij) * ( dens0M * wt0M + G13_(iM,ij) * PVARS0_(iM,MOMX_VID,ij) & + + G23_(iM,ij) * PVARS0_(iM,MOMY_VID,ij) ) !alph(i) = 0.0_RP else - MOMZ_P = MOMZ0_(iP) + MOMZ_P = PVARS0_(iP,MOMZ_VID,ij) end if - del_flux(i,DENS_VID) = 0.5_RP * ( & - + ( MOMZ_P - MOMZ_(iM) ) * nz(i) & - - alph(i) * ( DDENS_(iP) - DDENS_(iM) ) ) + del_flux(i,ij,DENS_VID) = 0.5_RP * ( & + + ( MOMZ_P - PVARS_(iM,MOMZ_VID,ij) ) * nz(i,ij) & + - alph(i,ij) * ( PVARS_(iP,DENS_VID,ij) - PVARS_(iM,DENS_VID,ij) ) ) - del_flux(i,MOMX_VID) = 0.5_RP * ( & - - alph(i) * ( MOMX_(iP) - MOMX_(iM) ) ) + del_flux(i,ij,MOMX_VID) = 0.5_RP * ( & + - alph(i,ij) * ( PVARS_(iP,MOMX_VID,ij) - PVARS_(iM,MOMX_VID,ij) ) ) - del_flux(i,MOMY_VID) = 0.5_RP * ( & - - alph(i) * ( MOMY_(iP) - MOMY_(iM) ) ) + del_flux(i,ij,MOMY_VID) = 0.5_RP * ( & + - alph(i,ij) * ( PVARS_(iP,MOMY_VID,ij) - PVARS_(iM,MOMY_VID,ij) ) ) - del_flux(i,MOMZ_VID) = 0.5_RP * ( & - + ( dpresP - dpresM ) * nz(i) & - - alph(i) * ( MOMZ_P - MOMZ_(iM) ) ) + del_flux(i,ij,MOMZ_VID) = 0.5_RP * ( & + + ( dpresP - dpresM ) * nz(i,ij) & + - alph(i,ij) * ( MOMZ_P - PVARS_(iM,MOMZ_VID,ij) ) ) - del_flux(i,RHOT_VID) = 0.5_RP * ( & - + ( pottP * MOMZ_P - pottM * MOMZ_(iM) ) * nz(i) & - - alph(i) * ( DRHOT_(iP) - DRHOT_(iM) ) ) + del_flux(i,ij,RHOT_VID) = 0.5_RP * ( & + + ( pottP * MOMZ_P - pottM * PVARS_(iM,MOMZ_VID,ij) ) * nz(i,ij) & + - alph(i,ij) * ( PVARS_(iP,RHOT_VID,ij) - PVARS_(iM,RHOT_VID,ij) ) ) end do end do + end do + !$omp end do + !$omp end parallel return end subroutine vi_cal_del_flux_dyn diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 index ea817d85..ef401fdc 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 @@ -332,10 +332,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & lmesh, elem, lmesh2D, elem2D ) ! (in) use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & - vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & - vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & - vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd - + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + implicit none class(LocalMesh3D), intent(in) :: lmesh @@ -360,34 +360,29 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & real(RP), intent(in) :: impl_fac real(RP), intent(in) :: dt - real(RP) :: PROG_VARS(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: PROG_VARS0(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: PROG_VARS00(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: b(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) - real(RP) :: Ax(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: alph(elem%NfpTot,lmesh%NeZ) - real(RP) :: tend(elem%Np,PROG_VARS_NUM,lmesh%NeZ) - real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ) - real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ) - real(RP) :: GnnM_z(elem%Np,lmesh%NeZ) - real(RP) :: G13_z(elem%Np,lmesh%NeZ) - real(RP) :: G23_z(elem%Np,lmesh%NeZ) - real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ) - real(RP) :: nz(elem%NfpTot,lmesh%NeZ) + real(RP) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: GnnM_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: G13_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: G23_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: GsqrtV_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP) :: nz(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) integer :: vmapM(elem%NfpTot,lmesh%NeZ) - integer :: vmapP(elem%NfpTot,lmesh%NeZ) - integer :: ke_x, ke_y, ke_z, ke, ke2D, p, v - integer :: itr_lin, itr_nlin + integer :: vmapP(elem%NfpTot,lmesh%NeZ) + integer :: ColMask(elem%Nnode_v) + integer :: ke_xy, ke_z, ke, ke2D, v + integer :: itr_nlin integer :: kl, ku, nz_1D integer :: ij, info logical :: is_converged - real(RP), allocatable :: PmatBnd(:,:,:) !------------------------------------------------------------------------ - call PROF_rapstart( 'hevi_cal_vi_prep', 3) @@ -399,135 +394,135 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & call vi_gen_vmap( vmapM, vmapP, & ! (out) lmesh, elem ) ! (in) - call PROF_rapend( 'hevi_cal_vi_prep', 3) - - do ke_y=1, lmesh%NeY - do ke_x=1, lmesh%NeX - - call PROF_rapstart( 'hevi_cal_vi_get_var', 3) - - !$omp parallel do private( ke, ke2D ) - do ke_z=1, lmesh%NeZ - ke = ke_x + (ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - ke2D = lmesh%EMap3Dto2D(ke) - - PROG_VARS(:,DENS_VID,ke_z) = DDENS_(:,ke) - PROG_VARS(:,MOMX_VID,ke_z) = MOMX_(:,ke) - PROG_VARS(:,MOMY_VID,ke_z) = MOMY_(:,ke) - PROG_VARS(:,MOMZ_VID,ke_z) = MOMZ_(:,ke) - PROG_VARS(:,RHOT_VID,ke_z) = DRHOT_(:,ke) - DENS_hyd_z(:,ke_z) = DENS_hyd(:,ke) - PRES_hyd_z(:,ke_z) = PRES_hyd(:,ke) - - PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) - PROG_VARS00(:,:,ke_z) = PROG_VARS(:,:,ke_z) - - nz(:,ke_z) = lmesh%normal_fn(:,ke,3) - G13_z(:,ke_z) = lmesh%GI3(:,ke,1) - G23_z(:,ke_z) = lmesh%GI3(:,ke,2) - GsqrtV_z(:,ke_z) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) - - GnnM_z(:,ke_z) = ( & - 1.0_RP / GsqrtV_z(:,ke_z)**2 & - + G13_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,1) * G13_z(:,ke_z) & - + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G23_z(:,ke_z) ) & - + G23_z(:,ke_z) * ( lmesh%GIJ(elem%IndexH2Dto3D,ke2D,1,2) * G13_z(:,ke_z) & - + lmesh%GIJ(elem%IndexH2Dto3D,ke2D,2,2) * G23_z(:,ke_z) ) ) - end do - call PROF_rapend( 'hevi_cal_vi_get_var', 3) + !- + + !$omp parallel private( ke_xy, ke_z, ke, ke2D ) + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2D = lmesh%EMap3Dto2D(ke) + + PROG_VARS(:,ke_z,DENS_VID,ke_xy) = DDENS_(:,ke) + PROG_VARS(:,ke_z,MOMX_VID,ke_xy) = MOMX_ (:,ke) + PROG_VARS(:,ke_z,MOMY_VID,ke_xy) = MOMY_ (:,ke) + PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) = MOMZ_ (:,ke) + PROG_VARS(:,ke_z,RHOT_VID,ke_xy) = DRHOT_(:,ke) + + DENS_hyd_z(:,ke_z,ke_xy) = DENS_hyd(:,ke) + PRES_hyd_z(:,ke_z,ke_xy) = PRES_hyd(:,ke) - if ( abs(impl_fac) > 0.0_RP ) then - call PROF_rapstart( 'hevi_cal_vi_itr', 3) - - ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 - ! dG/dq^n+1 del[q] = - G(q^n*) - do itr_nlin = 1, 1 - - call vi_eval_Ax( Ax(:,:,:), alph, & ! (out) - PROG_VARS, PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, .false. ) ! (in) - - do ke_z=1, lmesh%NeZ - b(:,:,ke_z) = - Ax(:,:,ke_z) + PROG_VARS00(:,:,ke_z) - end do - + nz(:,ke_z,ke_xy) = lmesh%normal_fn(:,ke,3) + G13_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,1) + G23_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,2) + GsqrtV_z(:,ke_z,ke_xy) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) + + GnnM_z(:,ke_z,ke_xy) = ( & + 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & + + G13_z(:,ke_z,ke_xy) **2 + G23_z(:,ke_z,ke_xy) **2 ) + end do + end do + !$omp end do + !$omp workshare + PROG_VARS0 (:,:,:,:) = PROG_VARS(:,:,:,:) + !$omp end workshare + !$omp end parallel + + call PROF_rapend( 'hevi_cal_vi_prep', 3) + + if ( abs(impl_fac) > 0.0_RP ) then + call PROF_rapstart( 'hevi_cal_vi_itr', 3) + + ! G = (q^n+1 - q^n*) + impl_fac * A(q^n+1) = 0 + ! dG/dq^n+1 del[q] = - G(q^n*) + do itr_nlin = 1, 1 + call PROF_rapstart( 'hevi_cal_vi_ax', 3) + + call vi_eval_Ax( & + DENS_dt(:,:), MOMX_dt(:,:), MOMY_dt(:,:), MOMZ_dt(:,:), RHOT_dt(:,:), & ! (out, dummy) + alph(:,:,:), & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz, vmapM, vmapP, & ! (in) + b1D(:,:,:,:,:) ) ! (out) + + call PROF_rapend( 'hevi_cal_vi_ax', 3) + + do ke_xy=1, lmesh%NeX * lmesh%NeY call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) - call vi_construct_matbnd( PmatBnd, & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0, DENS_hyd_z, PRES_hyd_z, & ! (in) - G13_z, G23_z, GsqrtV_z, alph, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + call vi_construct_matbnd( PmatBnd(:,:,:), & ! (out) + kl, ku, nz_1D, & ! (in) + PROG_VARS0(:,:,:,ke_xy), & ! (in) + DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) + G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) + alph(:,:,ke_xy), & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) call PROF_rapend( 'hevi_cal_vi_matbnd', 3) call PROF_rapstart( 'hevi_cal_vi_lin', 3) - !$omp parallel private(ij, v, ke_z, info) + !$omp parallel private(ij, v, ke_z, info, ColMask) !$omp do do ij=1, elem%Nnode_h1D**2 - do ke_z=1, lmesh%NeZ - do v=1, PROG_VARS_NUM - b1D(:,v,ke_z,ij) = b(elem%Colmask(:,ij),v,ke_z) - end do - end do - - call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij), nz_1D, info) + call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij,ke_xy), nz_1D, info) + ColMask(:) = elem%Colmask(:,ij) do ke_z=1, lmesh%NeZ do v=1, PROG_VARS_NUM - PROG_VARS(elem%Colmask(:,ij),v,ke_z) = PROG_VARS(elem%Colmask(:,ij),v,ke_z) + b1D(:,v,ke_z,ij) + PROG_VARS(ColMask(:),ke_z,v,ke_xy) = PROG_VARS(Colmask(:),ke_z,v,ke_xy) & + + b1D(:,v,ke_z,ij,ke_xy) end do end do - end do - !$omp do - do ke_z=1, lmesh%NeZ - PROG_VARS0(:,:,ke_z) = PROG_VARS(:,:,ke_z) - end do + end do ! for ij + !$omp end do + !$omp workshare + PROG_VARS0(:,:,:,ke_xy) = PROG_VARS(:,:,:,ke_xy) + !$omp end workshare !$omp end parallel call PROF_rapend( 'hevi_cal_vi_lin', 3) - end do ! itr nlin - - call PROF_rapend( 'hevi_cal_vi_itr', 3) - end if - - call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) - if ( abs(impl_fac) > 0.0_RP) then - !$omp parallel do - do ke_z=1, lmesh%NeZ - tend(:,:,ke_z) = ( - PROG_VARS(:,:,ke_z) + PROG_VARS00(:,:,ke_z) ) / impl_fac - end do - else - call vi_eval_Ax( tend(:,:,:), alph, & ! (out) - PROG_VARS, PROG_VARS, DENS_hyd_z, PRES_hyd_z, & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, & ! (in) - nz, vmapM, vmapP, ke_x, ke_y, .true. ) ! (in) - end if - - !$omp parallel do private(ke) + + end do ! for ke_xy + end do ! itr nlin + + call PROF_rapend( 'hevi_cal_vi_itr', 3) + end if + + call PROF_rapstart( 'hevi_cal_vi_retrun_var', 3) + if ( abs(impl_fac) > 0.0_RP) then + !$omp parallel do collapse(2) private(ke_xy, ke_z, ke) + do ke_xy=1, lmesh%NeX * lmesh%NeY do ke_z=1, lmesh%NeZ - ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY - DENS_dt(:,ke) = - tend(:,DENS_VID,ke_z) - MOMX_dt(:,ke) = - tend(:,MOMX_VID ,ke_z) - MOMY_dt(:,ke) = - tend(:,MOMY_VID ,ke_z) - MOMZ_dt(:,ke) = - tend(:,MOMZ_VID ,ke_z) - RHOT_dt(:,ke) = - tend(:,RHOT_VID,ke_z) + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + DENS_dt(:,ke) = ( PROG_VARS(:,ke_z,DENS_VID,ke_xy) - DDENS_(:,ke) ) / impl_fac + MOMX_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMX_VID,ke_xy) - MOMX_ (:,ke) ) / impl_fac + MOMY_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMY_VID,ke_xy) - MOMY_ (:,ke) ) / impl_fac + MOMZ_dt(:,ke) = ( PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) - MOMZ_ (:,ke) ) / impl_fac + RHOT_dt(:,ke) = ( PROG_VARS(:,ke_z,RHOT_VID,ke_xy) - DRHOT_(:,ke) ) / impl_fac end do - call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) - end do - end do + end do + else + call vi_eval_Ax( & + DENS_dt(:,:), MOMX_dt(:,:), MOMY_dt(:,:), MOMZ_dt(:,:), RHOT_dt(:,:), & ! (out) + alph(:,:,:), & ! (out, dummy) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS_, MOMX_, MOMY_, MOMZ_, DRHOT_, & ! (in) + DENS_hyd_z, PRES_hyd_z, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM_z, G13_z, G23_z, GsqrtV_z, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz, vmapM, vmapP ) ! (in) + end if + call PROF_rapend( 'hevi_cal_vi_retrun_var', 3) return end subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi From c29962e655260ba85a81e9359c5534ec971b3ba2 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 7 Jul 2021 12:06:38 +0900 Subject: [PATCH 69/98] Fix a bug. --- model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 index dd77170d..7b939371 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_phy_tb.F90 @@ -126,10 +126,10 @@ subroutine AtmosPhyTb_setup( this, model_mesh, tm_parent_comp ) !- get mesh -------------------------------------------------- call model_mesh%GetModelMesh( ptr_mesh ) - ! select type(model_mesh) - ! class is (AtmosMesh) - ! atm_mesh => model_mesh - ! end select + select type(model_mesh) + class is (AtmosMesh) + atm_mesh => model_mesh + end select !--- Regist this compoent in the time manager From b06a286fcb139f1f936cb797c16f790c281a04fb Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 7 Jul 2021 17:32:23 +0900 Subject: [PATCH 70/98] Improve the computational performance of HEVI solver on fugaku. --- ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 56 +- .../scale_atm_dyn_dgm_nonhydro3d_hevi.F90 | 70 +-- ...ale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 | 483 ++++++++++++++++++ ..._atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 | 70 +-- 4 files changed, 596 insertions(+), 83 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index c67f9bed..d747a5fd 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -334,9 +334,9 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & lmesh, elem, lmesh2D, elem2D ) ! (in) use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & - vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & - vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & - vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax_2, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd_2 implicit none @@ -364,8 +364,10 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & real(RP) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) real(RP) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) - real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) - integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: b1D(elem%Nnode_v,3,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + integer :: ipiv(elem%Nnode_v*3*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: b1D_uv(elem%Nnode_v,lmesh%NeZ,2,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + integer :: ipiv_uv(elem%Nnode_v*1*lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) @@ -380,18 +382,24 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & integer :: ke_xy, ke_z, ke, ke2D, v integer :: itr_nlin integer :: kl, ku, nz_1D + integer :: kl_uv, ku_uv, nz_1D_uv integer :: ij, info logical :: is_converged real(RP), allocatable :: PmatBnd(:,:,:) + real(RP), allocatable :: PmatBnd_uv(:,:,:) !------------------------------------------------------------------------ call PROF_rapstart( 'hevi_cal_vi_prep', 3) - nz_1D = elem%Nnode_v * PROG_VARS_NUM * lmesh%NeZ - kl = 2 * elem%Nnode_v * PROG_VARS_NUM - 1 + nz_1D = elem%Nnode_v * 3 * lmesh%NeZ + kl = 2 * elem%Nnode_v * 3 - 1 ku = kl - allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + nz_1D_uv = elem%Nnode_v * 1 * lmesh%NeZ + kl_uv = 2 * elem%Nnode_v * 1 - 1 + ku_uv = kl_uv + allocate( PmatBnd (2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + allocate( PmatBnd_uv(2*kl_uv+ku_uv+1,nz_1D_uv,elem%Nnode_h1D**2) ) call vi_gen_vmap( vmapM, vmapP, & ! (out) lmesh, elem ) ! (in) @@ -456,23 +464,23 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, nz, vmapM, vmapP, & ! (in) - b1D(:,:,:,:,:) ) ! (out) + b1D(:,:,:,:,:), b1D_uv(:,:,:,:,:) ) ! (out) call PROF_rapend( 'hevi_cal_vi_ax', 3) do ke_xy=1, lmesh%NeX * lmesh%NeY call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) - call vi_construct_matbnd( PmatBnd(:,:,:), & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0(:,:,:,ke_xy), & ! (in) - DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) - G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) - alph(:,:,ke_xy), & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) + call vi_construct_matbnd( PmatBnd(:,:,:), PmatBnd_uv(:,:,:), & ! (out) + kl, ku, nz_1D, kl_uv, ku_uv, nz_1D, & ! (in) + PROG_VARS0(:,:,:,ke_xy), & ! (in) + DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) + G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) + alph(:,:,ke_xy), & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) call PROF_rapend( 'hevi_cal_vi_matbnd', 3) @@ -481,13 +489,15 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_vi( & !$omp do do ij=1, elem%Nnode_h1D**2 call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij,ke_xy), nz_1D, info) + call dgbsv( nz_1D_uv, kl_uv, ku_uv, 2, PmatBnd_uv(:,:,ij), 2*kl_uv+ku_uv+1, ipiv_uv(:,ij), b1D_uv(:,:,:,ij,ke_xy), nz_1D_uv, info) ColMask(:) = elem%Colmask(:,ij) do ke_z=1, lmesh%NeZ - do v=1, PROG_VARS_NUM - PROG_VARS(ColMask(:),ke_z,v,ke_xy) = PROG_VARS(Colmask(:),ke_z,v,ke_xy) & - + b1D(:,v,ke_z,ij,ke_xy) - end do + PROG_VARS(ColMask(:),ke_z,DENS_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,DENS_VID,ke_xy) + b1D(:,1,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMZ_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMZ_VID,ke_xy) + b1D(:,2,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,RHOT_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,RHOT_VID,ke_xy) + b1D(:,3,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMX_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMX_VID,ke_xy) + b1D_uv(:,ke_z,1,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMY_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMY_VID,ke_xy) + b1D_uv(:,ke_z,2,ij,ke_xy) end do end do ! for ij !$omp end do diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 index f611afd1..ea1b1a0b 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi.F90 @@ -292,12 +292,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & modalFilterFlag, VModalFilter, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, lmesh2D, elem2D ) ! (in) - use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & - vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & - vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & - vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd - + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax_2, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd_2 + implicit none class(LocalMesh3D), intent(in) :: lmesh @@ -324,8 +323,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & real(RP) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) real(RP) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) - real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) - integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: b1D(elem%Nnode_v,3,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + integer :: ipiv(elem%Nnode_v*3*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: b1D_uv(elem%Nnode_v,lmesh%NeZ,2,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + integer :: ipiv_uv(elem%Nnode_v*1*lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) @@ -340,18 +341,24 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & integer :: ke_xy, ke_z, ke, ke2D, v integer :: itr_nlin integer :: kl, ku, nz_1D + integer :: kl_uv, ku_uv, nz_1D_uv integer :: ij, info logical :: is_converged real(RP), allocatable :: PmatBnd(:,:,:) + real(RP), allocatable :: PmatBnd_uv(:,:,:) !------------------------------------------------------------------------ - + call PROF_rapstart( 'hevi_cal_vi_prep', 3) - nz_1D = elem%Nnode_v * PROG_VARS_NUM * lmesh%NeZ - kl = 2 * elem%Nnode_v * PROG_VARS_NUM - 1 + nz_1D = elem%Nnode_v * 3 * lmesh%NeZ + kl = 2 * elem%Nnode_v * 3 - 1 ku = kl - allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + nz_1D_uv = elem%Nnode_v * 1 * lmesh%NeZ + kl_uv = 2 * elem%Nnode_v * 1 - 1 + ku_uv = kl_uv + allocate( PmatBnd (2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + allocate( PmatBnd_uv(2*kl_uv+ku_uv+1,nz_1D_uv,elem%Nnode_h1D**2) ) call vi_gen_vmap( vmapM, vmapP, & ! (out) lmesh, elem ) ! (in) @@ -379,9 +386,8 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & G23_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,2) GsqrtV_z(:,ke_z,ke_xy) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) - GnnM_z(:,ke_z,ke_xy) = ( & - 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & - + G13_z(:,ke_z,ke_xy) **2 + G23_z(:,ke_z,ke_xy) **2 ) + GnnM_z(:,ke_z,ke_xy) = ( 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & + + G13_z(:,ke_z,ke_xy)**2 + G23_z(:,ke_z,ke_xy) ) end do end do !$omp end do @@ -391,7 +397,9 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & !$omp end parallel call PROF_rapend( 'hevi_cal_vi_prep', 3) - + + !-- + if ( abs(impl_fac) > 0.0_RP ) then call PROF_rapstart( 'hevi_cal_vi_itr', 3) @@ -411,23 +419,23 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, nz, vmapM, vmapP, & ! (in) - b1D(:,:,:,:,:) ) ! (out) + b1D(:,:,:,:,:), b1D_uv(:,:,:,:,:) ) ! (out) call PROF_rapend( 'hevi_cal_vi_ax', 3) do ke_xy=1, lmesh%NeX * lmesh%NeY call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) - call vi_construct_matbnd( PmatBnd(:,:,:), & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0(:,:,:,ke_xy), & ! (in) - DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) - G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) - alph(:,:,ke_xy), & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) + call vi_construct_matbnd( PmatBnd(:,:,:), PmatBnd_uv(:,:,:), & ! (out) + kl, ku, nz_1D, kl_uv, ku_uv, nz_1D, & ! (in) + PROG_VARS0(:,:,:,ke_xy), & ! (in) + DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) + G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) + alph(:,:,ke_xy), & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) call PROF_rapend( 'hevi_cal_vi_matbnd', 3) @@ -436,13 +444,15 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_cal_vi( & !$omp do do ij=1, elem%Nnode_h1D**2 call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij,ke_xy), nz_1D, info) + call dgbsv( nz_1D_uv, kl_uv, ku_uv, 2, PmatBnd_uv(:,:,ij), 2*kl_uv+ku_uv+1, ipiv_uv(:,ij), b1D_uv(:,:,:,ij,ke_xy), nz_1D_uv, info) ColMask(:) = elem%Colmask(:,ij) do ke_z=1, lmesh%NeZ - do v=1, PROG_VARS_NUM - PROG_VARS(ColMask(:),ke_z,v,ke_xy) = PROG_VARS(Colmask(:),ke_z,v,ke_xy) & - + b1D(:,v,ke_z,ij,ke_xy) - end do + PROG_VARS(ColMask(:),ke_z,DENS_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,DENS_VID,ke_xy) + b1D(:,1,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMZ_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMZ_VID,ke_xy) + b1D(:,2,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,RHOT_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,RHOT_VID,ke_xy) + b1D(:,3,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMX_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMX_VID,ke_xy) + b1D_uv(:,ke_z,1,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMY_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMY_VID,ke_xy) + b1D_uv(:,ke_z,2,ij,ke_xy) end do end do ! for ij !$omp end do diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 index 42859e70..3789a579 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_common.F90 @@ -46,9 +46,14 @@ module scale_atm_dyn_dgm_nonhydro3d_hevi_common ! !++ Public procedures ! + + + public :: atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap public :: atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax public :: atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + public :: atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax_2 + public :: atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd_2 !----------------------------------------------------------------------------- ! @@ -304,6 +309,196 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax( & return end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax_2( & + DENS_t, MOMX_t, MOMY_t, MOMZ_t, RHOT_t, & ! (out) + alph, & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DDENS00, MOMX00, MOMY00, MOMZ00, DRHOT00, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + GnnM, G13, G23, GsqrtV, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, & ! (in) + b1D_ij, b1D_ij_uv ) ! (out) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + real(RP), intent(out) :: DENS_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMX_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMY_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: MOMZ_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: RHOT_t(elem%Np,lmesh%NeA) + real(RP), intent(out) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PROG_VARS0 (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: DDENS00(elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMX00 (elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMY00 (elem%Np,lmesh%NeA) + real(RP), intent(in) :: MOMZ00 (elem%Np,lmesh%NeA) + real(RP), intent(in) :: DRHOT00(elem%Np,lmesh%NeA) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + class(SparseMat), intent(in) :: Dz, Lift + real(RP), intent(in) :: IntrpMat_VPOrdM1(elem%Np,elem%Np) + real(RP), intent(in) :: GnnM(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: G13 (elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: G23 (elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + real(RP), intent(in) :: GsqrtV(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + logical, intent(in) :: modalFilterFlag + real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) + real(RP), intent(out), optional :: b1D_ij(elem%Nnode_v,3,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + real(RP), intent(out), optional :: b1D_ij_uv(elem%Nnode_v,lmesh%NeZ,2,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + + real(RP) :: RGsqrtV(elem%Np) + real(RP) :: Fscale(elem%NfpTot), Escale33(elem%Np) + real(RP) :: Fz(elem%Np), LiftDelFlx(elem%Np) + real(RP) :: del_flux(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY,PROG_VARS_NUM) + real(RP) :: MOMZ(elem%Np), DDENS(elem%Np), RHOT_hyd(elem%Np), RHOT(elem%Np) + real(RP) :: DPRES(elem%Np) + integer :: ke_xy, ke_z + integer :: ke, ke2d + integer :: v + integer :: ij + integer :: ColMask(elem%Nnode_v) + real(RP) :: rdt + real(RP) :: drho(elem%Np) + + integer :: kk, kkk, p, pp + real(RP) :: vmf_v + + real(RP) :: gamm, rgamm + !-------------------------------------------------------- + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + rdt = 1.0_RP / dt + + call vi_cal_del_flux_dyn( del_flux, alph, & ! (out) + PROG_VARS, PROG_VARS0, & ! (in) + DENS_hyd, PRES_hyd, & ! (in) + GnnM, G13, G23, GsqrtV, nz, vmapM, vmapP, & ! (in) + lmesh, elem ) ! (in) + + !$omp parallel private( ke_xy, ke_z, ke, ke2d, ij, v, & + !$omp MOMZ, DDENS, RHOT_hyd, DPRES, RHOT, Fz, LiftDelFlx, & + !$omp RGsqrtV, ColMask, Fscale, Escale33, drho, & + !$omp kk, p, kkk, vmf_v, pp ) + + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = Ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + ke2d = lmesh%EMap3Dto2D(ke) + + DDENS(:) = PROG_VARS(:,ke_z,DENS_VID,ke_xy) + drho(:) = matmul(IntrpMat_VPOrdM1, DDENS(:)) + + MOMZ (:) = PROG_VARS(:,ke_z,MOMZ_VID,ke_xy) + + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(:,ke_z,ke_xy)/PRES00)**rgamm + RHOT(:) = RHOT_hyd(:) + PROG_VARS(:,ke_z,RHOT_VID,ke_xy) + DPRES(:) = PRES_hyd(:,ke_z,ke_xy) * ( ( RHOT(:) / RHOT_hyd(:) )**gamm - 1.0_RP ) + + RGsqrtV(:) = 1.0_RP / GsqrtV(:,ke_z,ke_xy) + Fscale(:) = lmesh%Fscale(:,ke) + Escale33(:) = lmesh%Escale(:,ke,3,3) + + !- DENS + call sparsemat_matmul(Dz, MOMZ(:), Fz) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,DENS_VID), LiftDelFlx) + DENS_t(:,ke) = - ( Escale33(:) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + + !- MOMX + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,MOMX_VID), LiftDelFlx) + MOMX_t(:,ke) = - LiftDelFlx(:) * RGsqrtV(:) + + !-MOMY + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,MOMY_VID), LiftDelFlx) + MOMY_t(:,ke) = - LiftDelFlx(:) * RGsqrtV(:) + + !-MOMZ + call sparsemat_matmul(Dz, DPRES(:), Fz) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,MOMZ_VID), LiftDelFlx) + MOMZ_t(:,ke) = - ( Escale33(:) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) & + - Grav * drho(:) + + !-RHOT + call sparsemat_matmul(Dz, RHOT(:) * MOMZ(:) / ( DENS_hyd(:,ke_z,ke_xy) + DDENS(:) ), Fz) + call sparsemat_matmul(Lift, Fscale(:) * del_flux(:,ke_z,ke_xy,RHOT_VID), LiftDelFlx) + RHOT_t(:,ke) = - ( Escale33(:) * Fz(:) + LiftDelFlx(:) ) * RGsqrtV(:) + + end do + end do + !$omp end do + + if ( modalFilterFlag ) then + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + + !-- Modal filtering in the vertical direction + do kk=1, elem%Nnode_v + do ij=1, elem%Nnode_h1D**2 + p = elem%Colmask(kk,ij) + do kkk=1, elem%Nnode_v + pp = elem%Colmask(kkk,ij) + vmf_v = rdt * VModalFilter(kk,kkk) + DENS_t(p,ke) = DENS_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,DENS_VID,ke_xy) + MOMX_t(p,ke) = MOMX_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,MOMX_VID,ke_xy) + MOMY_t(p,ke) = MOMY_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,MOMY_VID,ke_xy) + MOMZ_t(p,ke) = MOMZ_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,MOMZ_VID,ke_xy) + RHOT_t(p,ke) = RHOT_t(p,ke) + vmf_v * PROG_VARS(pp,ke_z,RHOT_VID,ke_xy) + end do + end do + end do + end do + end do + !$omp end do + end if + + if ( present( b1D_ij ) ) then + !$omp do collapse(2) + do ke_xy=1, lmesh%NeX*lmesh%NeY + do ke_z=1, lmesh%NeZ + ke = ke_xy + (ke_z-1)*lmesh%NeX*lmesh%NeY + + do ij=1, elem%Nnode_h1D**2 + ColMask(:) = elem%Colmask(:,ij) + b1D_ij(:,1,ke_z,ij,ke_xy) = impl_fac * DENS_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,DENS_VID,ke_xy) & + + DDENS00(ColMask(:),ke) + b1D_ij(:,2,ke_z,ij,ke_xy) = impl_fac * MOMZ_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,MOMZ_VID,ke_xy) & + + MOMZ00(ColMask(:),ke) + b1D_ij(:,3,ke_z,ij,ke_xy) = impl_fac * RHOT_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,RHOT_VID,ke_xy) & + + DRHOT00(ColMask(:),ke) + b1D_ij_uv(:,ke_z,1,ij,ke_xy) = impl_fac * MOMX_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,MOMX_VID,ke_xy) & + + MOMX00(ColMask(:),ke) + b1D_ij_uv(:,ke_z,2,ij,ke_xy) = impl_fac * MOMY_t(ColMask(:),ke) & + - PROG_VARS (ColMask(:),ke_z,MOMY_VID,ke_xy) & + + MOMY00(ColMask(:),ke) + end do + end do + end do + !$omp end do + end if + !$omp end parallel + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax_2 !OCL SERIAL subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & @@ -554,6 +749,294 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd( & return end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd + +!OCL SERIAL + subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd_2( & + PmatBnd, PmatBnd_uv, & ! (out) + kl, ku, nz_1D, & ! (in) + kl_uv, ku_uv, nz_1D_uv, & ! (in) + PROG_VARS0, DENS_hyd, PRES_hyd, & ! (in) + G13, G23, GsqrtV, alph, & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, & ! (in) + nz, vmapM, vmapP, ke_x, ke_y ) ! (in) + + implicit none + + class(LocalMesh3D), intent(in) :: lmesh + class(elementbase3D), intent(in) :: elem + integer, intent(in) :: kl, ku, nz_1D + real(RP), intent(out) :: PmatBnd(2*kl+ku+1,elem%Nnode_v,3,lmesh%NeZ,elem%Nnode_h1D**2) + integer, intent(in) :: kl_uv, ku_uv, nz_1D_uv + real(RP), intent(out) :: PmatBnd_uv(2*kl_uv+ku_uv+1,elem%Nnode_v,1,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP), intent(in) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM) + real(RP), intent(in) :: DENS_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: PRES_hyd(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G13(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: G23(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: GsqrtV(elem%Np,lmesh%NeZ) + real(RP), intent(in) :: alph(elem%NfpTot,lmesh%NeZ) + class(SparseMat), intent(in) :: Dz, Lift + real(RP), intent(in) :: IntrpMat_VPOrdM1(elem%Np,elem%Np) + logical, intent(in) :: modalFilterFlag + real(RP), intent(in) :: VModalFilter(elem%Nnode_v,elem%Nnode_v) + real(RP), intent(in) :: impl_fac + real(RP), intent(in) :: dt + real(RP), intent(in) :: nz(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapM(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: vmapP(elem%NfpTot,lmesh%NeZ) + integer, intent(in) :: ke_x, ke_y + + real(RP) :: RHOT_hyd(elem%Nnode_v) + real(RP) :: POT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: W0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: DENS0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: DPDRHOT0(elem%Nnode_v,lmesh%NeZ,elem%Nnode_h1D**2) + integer :: ke_z, ke_z2 + integer :: v, ke, p, f1, f2, fp, fp2, FmV + real(RP) :: gamm, rgamm + real(RP) :: fac_dz_p(elem%Nnode_v) + real(RP) :: PmatD(elem%Nnode_v,elem%Nnode_v,3,3) + real(RP) :: PmatL(elem%Nnode_v,elem%Nnode_v,3,3) + real(RP) :: PmatU(elem%Nnode_v,elem%Nnode_v,3,3) + real(RP) :: PmatD_uv(elem%Nnode_v,elem%Nnode_v) + real(RP) :: PmatL_uv(elem%Nnode_v,elem%Nnode_v) + real(RP) :: PmatU_uv(elem%Nnode_v,elem%Nnode_v) + + integer :: Colmask(elem%Nnode_v) + real(RP) :: Id(elem%Nnode_v,elem%Nnode_v) + real(RP) :: Dd(elem%Nnode_v) + real(RP) :: tmp1 + real(RP) :: fac + + integer :: ij, v1, v2, pv1, pv2, g_kj, g_kjp1, g_kjm1, pb1 + logical :: bc_flag + logical :: eval_flag(3,3) + + integer, parameter :: DENS_VID_LC = 1 + integer, parameter :: MOMZ_VID_LC = 2 + integer, parameter :: RHOT_VID_LC = 3 + + !-------------------------------------------------------- + + gamm = CpDry/CvDry + rgamm = CvDry/CpDry + + eval_flag(:,:) = .false. + do v=1, 3 + eval_flag(v,v) = .true. + end do + eval_flag(DENS_VID_LC,MOMZ_VID_LC) = .true. + eval_flag(MOMZ_VID_LC,DENS_VID_LC) = .true. + eval_flag(MOMZ_VID_LC,RHOT_VID_LC) = .true. + eval_flag(RHOT_VID_LC,MOMZ_VID_LC) = .true. + eval_flag(RHOT_VID_LC,DENS_VID_LC) = .true. + + Id(:,:) = 0.0_RP + do p=1, elem%Nnode_v + Id(p,p) = 1.0_RP + end do + + !$omp parallel private(RHOT_hyd, Colmask) + !$omp workshare + PmatD(:,:,:,:) = 0.0_RP + PmatL(:,:,:,:) = 0.0_RP + PmatU(:,:,:,:) = 0.0_RP + PmatD_uv(:,:) = 0.0_RP + PmatL_uv(:,:) = 0.0_RP + PmatU_uv(:,:) = 0.0_RP + !$omp end workshare + !$omp do + do ij=1, elem%Nnode_h1D**2 + PmatBnd (:,:,:,:,ij) = 0.0_RP + PmatBnd_uv(:,:,:,:,ij) = 0.0_RP + end do + !$omp do collapse(2) + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + Colmask(:) = elem%Colmask(:,ij) + RHOT_hyd(:) = PRES00/Rdry * (PRES_hyd(Colmask(:),ke_z)/PRES00)**rgamm + + DPDRHOT0(:,ke_z,ij) = gamm * PRES_hyd(Colmask(:),ke_z) / RHOT_hyd(:) & + * ( 1.0_RP + PROG_VARS0(Colmask(:),ke_z,RHOT_VID) / RHOT_hyd(:) )**(gamm-1) + + DENS0(:,ke_z,ij) = DENS_hyd(Colmask(:),ke_z) + PROG_VARS0(Colmask(:),ke_z,DENS_VID) + POT0(:,ke_z,ij) = ( RHOT_hyd(:) + PROG_VARS0(Colmask(:),ke_z,RHOT_VID) ) / DENS0(:,ke_z,ij) + W0(:,ke_z,ij) = PROG_VARS0(Colmask(:),ke_z,MOMZ_VID) / DENS0(:,ke_z,ij) + end do + end do + !$omp end parallel + + !$omp parallel private(ke_z, ke, ColMask, p, fp, fp2, v, f1, f2, ke_z2, fac_dz_p, & + !$omp fac, tmp1, FmV, & + !$omp ij, v1, v2, pv1, pv2, pb1, g_kj, g_kjp1, g_kjm1, bc_flag, & + !$omp Dd ) & + !$omp firstprivate(PmatD, PmatL, PmatU, PmatD_uv, PmatL_uv, PmatU_uv) + + !$omp do collapse(2) + do ij=1, elem%Nnode_h1D**2 + do ke_z=1, lmesh%NeZ + ke = Ke_x + (Ke_y-1)*lmesh%NeX + (ke_z-1)*lmesh%NeX*lmesh%NeY + Colmask(:) = elem%Colmask(:,ij) + + !----- + do p=1, elem%Nnode_v + fac_dz_p(:) = impl_fac * lmesh%Escale(Colmask(:),ke,3,3) / GsqrtV(Colmask(:),ke_z) & + * elem%Dx3(Colmask(:),Colmask(p)) + + if (modalFilterFlag) then + Dd(:) = Id(:,p) - VModalFilter(:,p) * impl_fac / dt + else + Dd(:) = Id(:,p) + end if + + ! DDENS + PmatD(:,p,DENS_VID_LC,DENS_VID_LC) = Dd(:) + PmatD(:,p,DENS_VID_LC,MOMZ_VID_LC) = fac_dz_p(:) + + ! MOMX, MOMY + PmatD_uv(:,p) = Dd(:) + + ! MOMZ + PmatD(:,p,MOMZ_VID_LC,MOMZ_VID_LC) = Dd(:) + PmatD(:,p,MOMZ_VID_LC,DENS_VID_LC) = impl_fac * Grav * IntrpMat_VPOrdM1(Colmask(:),Colmask(p)) + PmatD(:,p,MOMZ_VID_LC,RHOT_VID_LC) = fac_dz_p(:) * DPDRHOT0(p,ke_z,ij) + + !DRHOT + PmatD(:,p,RHOT_VID_LC,DENS_VID_LC) = - fac_dz_p(:) * POT0(p,ke_z,ij) * W0(p,ke_z,ij) + PmatD(:,p,RHOT_VID_LC,MOMZ_VID_LC) = fac_dz_p(:) * POT0(p,ke_z,ij) + PmatD(:,p,RHOT_VID_LC,RHOT_VID_LC) = Dd(:) + fac_dz_p(:) * W0(p,ke_z,ij) + end do + + do f1=1, 2 + if (f1==1) then + ke_z2 = max(ke_z-1,1) + pv1 = 1; pv2 = elem%Nnode_v + f2 = 2 + else + ke_z2 = min(ke_z+1,lmesh%NeZ) + pv1 = elem%Nnode_v; pv2 = 1 + f2 = 1 + end if + fac = 0.5_RP * impl_fac / GsqrtV(Colmask(pv1),ke_z) + if ( (ke_z == 1 .and. f1==1) .or. (ke_z == lmesh%NeZ .and. f1==elem%Nfaces_v) ) then + bc_flag = .true. + pv2 = pv1; f2 = f1 + else + bc_flag = .false. + end if + + FmV = elem%Fmask_v(ij,f1) + fp = elem%Nfp_h * elem%Nfaces_h + (f1-1)*elem%Nfp_v + ij + fp2 = elem%Nfp_h * elem%Nfaces_h + (f2-1)*elem%Nfp_v + ij + + !-- + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) & + * max( alph(fp,ke_z), alph(fp2,ke_z2) ) + if (bc_flag) then + PmatD(pv1,pv1,MOMZ_VID_LC,MOMZ_VID_LC) = PmatD(pv1,pv1,MOMZ_VID_LC,MOMZ_VID_LC) + 2.0_RP * tmp1 + else + do v=1, 3 + PmatD(pv1,pv1,v,v) = PmatD(pv1,pv1,v,v) + tmp1 + if (f1 == 1) then + PmatL(pv1,pv2,v,v) = - tmp1 + else + PmatU(pv1,pv2,v,v) = - tmp1 + end if + end do + + PmatD_uv(pv1,pv1) = PmatD_uv(pv1,pv1) + tmp1 + if (f1 == 1) then + PmatL_uv(pv1,pv2) = - tmp1 + else + PmatU_uv(pv1,pv2) = - tmp1 + end if + end if + + !-- + tmp1 = fac * elem%Lift(FmV,fp) * lmesh%Fscale(fp,ke) * nz(fp,ke_z) + + if (bc_flag) then + PmatD(pv1,pv1,DENS_VID_LC,MOMZ_VID_LC) = PmatD(pv1,pv1,DENS_VID_LC,MOMZ_VID_LC) - 2.0_RP * tmp1 + PmatD(pv1,pv1,RHOT_VID_LC,MOMZ_VID_LC) = PmatD(pv1,pv1,RHOT_VID_LC,MOMZ_VID_LC) - 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID_LC,DENS_VID_LC) = PmatD(pv1,pv1,RHOT_VID_LC,DENS_VID_LC) + 2.0_RP * tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID_LC,RHOT_VID_LC) = PmatD(pv1,pv1,RHOT_VID_LC,RHOT_VID_LC) - 2.0_RP * tmp1 * W0(pv1,ke_z,ij) + else + PmatD(pv1,pv1,DENS_VID_LC,MOMZ_VID_LC) = PmatD(pv1,pv1,DENS_VID_LC,MOMZ_VID_LC) - tmp1 + PmatD(pv1,pv1,MOMZ_VID_LC,RHOT_VID_LC) = PmatD(pv1,pv1,MOMZ_VID_LC,RHOT_VID_LC) - tmp1 * DPDRHOT0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID_LC,MOMZ_VID_LC) = PmatD(pv1,pv1,RHOT_VID_LC,MOMZ_VID_LC) - tmp1 * POT0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID_LC,DENS_VID_LC) = PmatD(pv1,pv1,RHOT_VID_LC,DENS_VID_LC) + tmp1 * POT0(pv1,ke_z,ij) * W0(pv1,ke_z,ij) + PmatD(pv1,pv1,RHOT_VID_LC,RHOT_VID_LC) = PmatD(pv1,pv1,RHOT_VID_LC,RHOT_VID_LC) - tmp1 * W0(pv1,ke_z,ij) + + if (f1 == 1) then + PmatL(pv1,pv2,DENS_VID_LC,MOMZ_VID_LC) = + tmp1 + PmatL(pv1,pv2,MOMZ_VID_LC,RHOT_VID_LC) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) + PmatL(pv1,pv2,RHOT_VID_LC,MOMZ_VID_LC) = + tmp1 * POT0(pv2,ke_z2,ij) + PmatL(pv1,pv2,RHOT_VID_LC,DENS_VID_LC) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) + PmatL(pv1,pv2,RHOT_VID_LC,RHOT_VID_LC) = PmatL(pv1,pv2,RHOT_VID_LC,RHOT_VID_LC) & + + tmp1 * W0(pv2,ke_z2,ij) + else + PmatU(pv1,pv2,DENS_VID_LC,MOMZ_VID_LC) = + tmp1 + PmatU(pv1,pv2,MOMZ_VID_LC,RHOT_VID_LC) = + tmp1 * DPDRHOT0(pv2,ke_z2,ij) + PmatU(pv1,pv2,RHOT_VID_LC,MOMZ_VID_LC) = + tmp1 * POT0(pv2,ke_z2,ij) + PmatU(pv1,pv2,RHOT_VID_LC,DENS_VID_LC) = - tmp1 * POT0(pv2,ke_z2,ij) * W0(pv2,ke_z2,ij) + PmatU(pv1,pv2,RHOT_VID_LC,RHOT_VID_LC) = PmatU(pv1,pv2,RHOT_VID_LC,RHOT_VID_LC) & + + tmp1 * W0(pv2,ke_z2,ij) + end if + end if + end do + + do v2=1, 3 + do v1=1, 3 + if ( eval_flag(v1,v2) ) then + do pv2=1, elem%Nnode_v + g_kj = pv2 + (v2-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*3 + g_kjm1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z-2)*elem%Nnode_v*3 + g_kjp1 = pv2 + (v2-1)*elem%Nnode_v + (ke_z )*elem%Nnode_v*3 + + do pv1=1, elem%Nnode_v + pb1 = pv1 + (v1-1)*elem%Nnode_v + (ke_z-1)*elem%Nnode_v*3 + if (ke_z > 1) then + PmatBnd(kl+ku+1+pb1-g_kjm1, pv2,v2,ke_z-1, ij) = PmatL(pv1,pv2,v1,v2) + end if + PmatBnd(kl+ku+1+pb1-g_kj, pv2,v2,ke_z, ij) = PmatD(pv1,pv2,v1,v2) + if (ke_z < lmesh%NeZ) then + PmatBnd(kl+ku+1+pb1-g_kjp1, pv2,v2,ke_z+1, ij) = PmatU(pv1,pv2,v1,v2) + end if + end do + end do + end if + end do + end do + + ! uv + do pv2=1, elem%Nnode_v + g_kj = pv2 + (ke_z-1)*elem%Nnode_v + g_kjm1 = pv2 + (ke_z-2)*elem%Nnode_v + g_kjp1 = pv2 + (ke_z )*elem%Nnode_v + + do pv1=1, elem%Nnode_v + pb1 = pv1 + (ke_z-1)*elem%Nnode_v + if (ke_z > 1) then + PmatBnd_uv(kl_uv+ku_uv+1+pb1-g_kjm1, pv2,1,ke_z-1, ij) = PmatL_uv(pv1,pv2) + end if + PmatBnd_uv(kl_uv+ku_uv+1+pb1-g_kj, pv2,1,ke_z, ij) = PmatD_uv(pv1,pv2) + if (ke_z < lmesh%NeZ) then + PmatBnd_uv(kl_uv+ku_uv+1+pb1-g_kjp1, pv2,1,ke_z+1, ij) = PmatU_uv(pv1,pv2) + end if + end do + end do + + end do + end do + !$omp end do + !$omp end parallel + + return + end subroutine atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd_2 + !-- private ---------------- !OCL SERIAL diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 index ef401fdc..8f3811a7 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_splitform_hevi.F90 @@ -330,12 +330,11 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & modalFilterFlag, VModalFilter, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, lmesh2D, elem2D ) ! (in) - use scale_atm_dyn_dgm_nonhydro3d_hevi_common, only: & - vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & - vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax, & - vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd - + vi_gen_vmap => atm_dyn_dgm_nonhydro3d_hevi_common_gen_vmap, & + vi_eval_Ax => atm_dyn_dgm_nonhydro3d_hevi_common_eval_Ax_2, & + vi_construct_matbnd => atm_dyn_dgm_nonhydro3d_hevi_common_construct_matbnd_2 + implicit none class(LocalMesh3D), intent(in) :: lmesh @@ -362,8 +361,10 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & real(RP) :: PROG_VARS (elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) real(RP) :: PROG_VARS0(elem%Np,lmesh%NeZ,PROG_VARS_NUM,lmesh%NeX*lmesh%NeY) - real(RP) :: b1D(elem%Nnode_v,PROG_VARS_NUM,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) - integer :: ipiv(elem%Nnode_v*PROG_VARS_NUM*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: b1D(elem%Nnode_v,3,lmesh%NeZ,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + integer :: ipiv(elem%Nnode_v*3*lmesh%NeZ,elem%Nnode_h1D**2) + real(RP) :: b1D_uv(elem%Nnode_v,lmesh%NeZ,2,elem%Nnode_h1D**2,lmesh%NeX*lmesh%NeY) + integer :: ipiv_uv(elem%Nnode_v*1*lmesh%NeZ,elem%Nnode_h1D**2) real(RP) :: alph(elem%NfpTot,lmesh%NeZ,lmesh%NeX*lmesh%NeY) real(RP) :: DENS_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) real(RP) :: PRES_hyd_z(elem%Np,lmesh%NeZ,lmesh%NeX*lmesh%NeY) @@ -378,18 +379,24 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & integer :: ke_xy, ke_z, ke, ke2D, v integer :: itr_nlin integer :: kl, ku, nz_1D + integer :: kl_uv, ku_uv, nz_1D_uv integer :: ij, info logical :: is_converged real(RP), allocatable :: PmatBnd(:,:,:) + real(RP), allocatable :: PmatBnd_uv(:,:,:) !------------------------------------------------------------------------ - + call PROF_rapstart( 'hevi_cal_vi_prep', 3) - nz_1D = elem%Nnode_v * PROG_VARS_NUM * lmesh%NeZ - kl = 2 * elem%Nnode_v * PROG_VARS_NUM - 1 + nz_1D = elem%Nnode_v * 3 * lmesh%NeZ + kl = 2 * elem%Nnode_v * 3 - 1 ku = kl - allocate( PmatBnd(2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + nz_1D_uv = elem%Nnode_v * 1 * lmesh%NeZ + kl_uv = 2 * elem%Nnode_v * 1 - 1 + ku_uv = kl_uv + allocate( PmatBnd (2*kl+ku+1,nz_1D,elem%Nnode_h1D**2) ) + allocate( PmatBnd_uv(2*kl_uv+ku_uv+1,nz_1D_uv,elem%Nnode_h1D**2) ) call vi_gen_vmap( vmapM, vmapP, & ! (out) lmesh, elem ) ! (in) @@ -417,9 +424,8 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & G23_z (:,ke_z,ke_xy) = lmesh%GI3(:,ke,2) GsqrtV_z(:,ke_z,ke_xy) = lmesh%Gsqrt(:,ke) / lmesh%GsqrtH(elem%IndexH2Dto3D,ke2D) - GnnM_z(:,ke_z,ke_xy) = ( & - 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & - + G13_z(:,ke_z,ke_xy) **2 + G23_z(:,ke_z,ke_xy) **2 ) + GnnM_z(:,ke_z,ke_xy) = ( 1.0_RP / GsqrtV_z(:,ke_z,ke_xy)**2 & + + G13_z(:,ke_z,ke_xy)**2 + G23_z(:,ke_z,ke_xy) ) end do end do !$omp end do @@ -429,7 +435,9 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & !$omp end parallel call PROF_rapend( 'hevi_cal_vi_prep', 3) - + + !-- + if ( abs(impl_fac) > 0.0_RP ) then call PROF_rapstart( 'hevi_cal_vi_itr', 3) @@ -449,23 +457,23 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & modalFilterFlag, VModalFilter%FilterMat, & ! (in) impl_fac, dt, & ! (in) lmesh, elem, nz, vmapM, vmapP, & ! (in) - b1D(:,:,:,:,:) ) ! (out) + b1D(:,:,:,:,:), b1D_uv(:,:,:,:,:) ) ! (out) call PROF_rapend( 'hevi_cal_vi_ax', 3) do ke_xy=1, lmesh%NeX * lmesh%NeY call PROF_rapstart( 'hevi_cal_vi_matbnd', 3) - call vi_construct_matbnd( PmatBnd(:,:,:), & ! (out) - kl, ku, nz_1D, & ! (in) - PROG_VARS0(:,:,:,ke_xy), & ! (in) - DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) - G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) - alph(:,:,ke_xy), & ! (in) - Dz, Lift, IntrpMat_VPOrdM1, & ! (in) - modalFilterFlag, VModalFilter%FilterMat, & ! (in) - impl_fac, dt, & ! (in) - lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) + call vi_construct_matbnd( PmatBnd(:,:,:), PmatBnd_uv(:,:,:), & ! (out) + kl, ku, nz_1D, kl_uv, ku_uv, nz_1D, & ! (in) + PROG_VARS0(:,:,:,ke_xy), & ! (in) + DENS_hyd_z(:,:,ke_xy), PRES_hyd_z(:,:,ke_xy), & ! (in) + G13_z(:,:,ke_xy), G23_z(:,:,ke_xy), GsqrtV_z(:,:,ke_xy), & ! (in) + alph(:,:,ke_xy), & ! (in) + Dz, Lift, IntrpMat_VPOrdM1, & ! (in) + modalFilterFlag, VModalFilter%FilterMat, & ! (in) + impl_fac, dt, & ! (in) + lmesh, elem, nz(:,:,ke_xy), vmapM, vmapP, ke_xy, 1 ) ! (in) call PROF_rapend( 'hevi_cal_vi_matbnd', 3) @@ -474,13 +482,15 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_splitform_cal_vi( & !$omp do do ij=1, elem%Nnode_h1D**2 call dgbsv( nz_1D, kl, ku, 1, PmatBnd(:,:,ij), 2*kl+ku+1, ipiv(:,ij), b1D(:,:,:,ij,ke_xy), nz_1D, info) + call dgbsv( nz_1D_uv, kl_uv, ku_uv, 2, PmatBnd_uv(:,:,ij), 2*kl_uv+ku_uv+1, ipiv_uv(:,ij), b1D_uv(:,:,:,ij,ke_xy), nz_1D_uv, info) ColMask(:) = elem%Colmask(:,ij) do ke_z=1, lmesh%NeZ - do v=1, PROG_VARS_NUM - PROG_VARS(ColMask(:),ke_z,v,ke_xy) = PROG_VARS(Colmask(:),ke_z,v,ke_xy) & - + b1D(:,v,ke_z,ij,ke_xy) - end do + PROG_VARS(ColMask(:),ke_z,DENS_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,DENS_VID,ke_xy) + b1D(:,1,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMZ_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMZ_VID,ke_xy) + b1D(:,2,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,RHOT_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,RHOT_VID,ke_xy) + b1D(:,3,ke_z,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMX_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMX_VID,ke_xy) + b1D_uv(:,ke_z,1,ij,ke_xy) + PROG_VARS(ColMask(:),ke_z,MOMY_VID,ke_xy) = PROG_VARS(Colmask(:),ke_z,MOMY_VID,ke_xy) + b1D_uv(:,ke_z,2,ij,ke_xy) end do end do ! for ij !$omp end do From 7664a6dd5efcf490c53c63d52769e194138e98e3 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 25 Jul 2021 01:20:54 +0900 Subject: [PATCH 71/98] Support vertical interpolation (model -> pressure or height coordinate ) in convert_cs2lonlat and interp tools. --- .github/workflows/FEProject_build.yml | 3 + FElib/src/Makefile | 1 + FElib/src/common/scale_polygon.F90 | 59 ++ FElib/src/depend | 4 +- .../src/mesh/scale_meshutil_cubedsphere2d.F90 | 66 ++ .../util/convert_cs2lonlat/Makefile | 2 + .../mod_cs2lonlat_interp_field.F90 | 3 +- .../mod_cs2lonlat_interp_mesh.F90 | 216 ++----- .../mod_cs2lonlat_interp_vcoord.F90 | 586 ++++++++++++++++++ .../prg_convert_cs2lonlat.F90 | 32 +- model/atm_nonhydro3d/util/interp/Makefile | 7 +- .../util/interp/mod_interp_mesh.F90 | 52 +- .../util/interp/mod_interp_vcoord.F90 | 578 +++++++++++++++++ .../atm_nonhydro3d/util/interp/prg_interp.F90 | 27 +- 14 files changed, 1396 insertions(+), 240 deletions(-) create mode 100644 FElib/src/common/scale_polygon.F90 create mode 100644 model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 create mode 100644 model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index bf202e8c..89d8c1de 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -137,6 +137,9 @@ jobs: echo "Build 3D nonhydrostatic atmospheric model" make -C atm_nonhydro3d/src + echo "Build 3D nonhydrostatic atmospheric model / utils" + make -C atm_nonhydro3d/util/interp + make -C atm_nonhydro3d/util/convert_cs2lonlat diff --git a/FElib/src/Makefile b/FElib/src/Makefile index 68f31564..d4575ab9 100644 --- a/FElib/src/Makefile +++ b/FElib/src/Makefile @@ -30,6 +30,7 @@ endif OBJS_NAME_COMMON = \ scale_polynominal.o \ + scale_polygon.o \ scale_sparsemat.o \ scale_linalgebra.o \ scale_time_manager.o \ diff --git a/FElib/src/common/scale_polygon.F90 b/FElib/src/common/scale_polygon.F90 new file mode 100644 index 00000000..2fb25b46 --- /dev/null +++ b/FElib/src/common/scale_polygon.F90 @@ -0,0 +1,59 @@ +#include "scaleFElib.h" +module scale_polygon + !----------------------------------------------------------------------------- + ! + !++ Used modules + ! + use scale_precision + use scale_io + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + public :: polygon_inpoly + +contains + + !> Check whether the point is located inside a polyngon +!OCL SERIAL + function polygon_inpoly( pt_x, pt_y, num_node, v_x, v_y ) result(ret) + implicit none + real(RP), intent(in) :: pt_x + real(RP), intent(in) :: pt_y + integer, intent(in) :: num_node + real(RP), intent(in) :: v_x(num_node) + real(RP), intent(in) :: v_y(num_node) + logical :: ret + + integer :: wn + integer :: i, ii + !------------------------------------------ + + wn = 0 + do i=1, num_node + ii = mod(i, num_node) + 1 + if ( v_y(i) <= pt_y .and. pt_y < v_y(ii)) then + if( pt_x < v_x(i) + (pt_y - v_y(i)) * (v_x(ii) - v_x(i))/(v_y(ii) - v_y(i)) ) then + wn = wn + 1 + end if + else if ( v_y(i) > pt_y .and. v_y(ii) <= pt_y ) then + if( pt_x < v_x(i) + (pt_y - v_y(i)) * (v_x(ii) - v_x(i))/(v_y(ii) - v_y(i)) ) then + wn = wn - 1 + end if + end if + end do + + if (wn == 0) then + ret = .false. + else + ret = .true. + end if + + return + end function polygon_inpoly + +end module scale_polygon \ No newline at end of file diff --git a/FElib/src/depend b/FElib/src/depend index e9ea08f5..f052aca3 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -58,13 +58,14 @@ $(OBJ_DIR)/scale_meshfieldcomm_rectdom2d.o: data/scale_meshfieldcomm_rectdom2d.F $(OBJ_DIR)/scale_meshutil_1d.o: mesh/scale_meshutil_1d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_2d.o: mesh/scale_meshutil_2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_quicksort.o $(OBJ_DIR)/scale_meshutil_3d.o: mesh/scale_meshutil_3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_quicksort.o -$(OBJ_DIR)/scale_meshutil_cubedsphere2d.o: mesh/scale_meshutil_cubedsphere2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_2d.o +$(OBJ_DIR)/scale_meshutil_cubedsphere2d.o: mesh/scale_meshutil_cubedsphere2d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o $(OBJ_DIR)/scale_meshutil_2d.o $(OBJ_DIR)/scale_meshutil_cubedsphere3d.o: mesh/scale_meshutil_cubedsphere3d.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_meshutil_3d.o $(OBJ_DIR)/scale_meshutil_cubedsphere2d.o $(OBJ_DIR)/scale_meshutil_vcoord.o: mesh/scale_meshutil_vcoord.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_localmesh_2d.o $(OBJ_DIR)/scale_localmesh_3d.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_model_component.o: model_framework/scale_model_component.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_time_manager.o $(OBJ_DIR)/scale_model_component_proc.o: model_framework/scale_model_component_proc.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_model_mesh_manager.o $(OBJ_DIR)/scale_model_var_manager.o $(OBJ_DIR)/scale_time_manager.o $(OBJ_DIR)/scale_model_mesh_manager.o: model_framework/scale_model_mesh_manager.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_mesh_base.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_sparsemat.o $(OBJ_DIR)/scale_model_var_manager.o: model_framework/scale_model_var_manager.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_file_monitor_meshfield.o $(OBJ_DIR)/scale_linkedlist.o $(OBJ_DIR)/scale_mesh_base1d.o $(OBJ_DIR)/scale_mesh_base2d.o $(OBJ_DIR)/scale_mesh_base3d.o $(OBJ_DIR)/scale_meshfield_base.o $(OBJ_DIR)/scale_meshfieldcomm_base.o $(OBJ_DIR)/scale_variableinfo.o +$(OBJ_DIR)/scale_polygon.o: common/scale_polygon.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_polynominal.o: common/scale_polynominal.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_quicksort.o: common/scale_quicksort.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_sparsemat.o: common/scale_sparsemat.F90 $(DEPENDLIB) @@ -141,6 +142,7 @@ MODS = \ $(OBJ_DIR)/scale_model_component_proc.mod \ $(OBJ_DIR)/scale_model_mesh_manager.mod \ $(OBJ_DIR)/scale_model_var_manager.mod \ + $(OBJ_DIR)/scale_polygon.mod \ $(OBJ_DIR)/scale_polynominal.mod \ $(OBJ_DIR)/scale_quicksort.mod \ $(OBJ_DIR)/scale_sparsemat.mod \ diff --git a/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 b/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 index 42e87e59..f44dbaa7 100644 --- a/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 +++ b/FElib/src/mesh/scale_meshutil_cubedsphere2d.F90 @@ -32,6 +32,7 @@ module scale_meshutil_cubedsphere2d public :: MeshUtilCubedSphere2D_genPatchBoundaryMap public :: MeshUtilCubedSphere2D_modifyConnectivity public :: MeshUtilCubedSphere2D_GetPanelConnectivity + public :: MeshUtilCubedSphere2D_getPanelID contains !OCL SERIAL @@ -279,4 +280,69 @@ subroutine MeshUtilCubedSphere2D_getPanelConnectivity( panel_connectivity, face_ end subroutine MeshUtilCubedSphere2D_getPanelConnectivity +!OCL SERIAL + subroutine MeshUtilCubedSphere2D_getPanelID( panelID, lon, lat, Np ) + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSPos + implicit none + + integer, intent(in) :: Np + integer, intent(out) :: panelID(Np) + real(RP), intent(in) :: lon(Np) + real(RP), intent(in) :: lat(Np) + + integer :: p + integer :: pnl + real(RP) :: alph(Np), beta(Np) + real(RP) :: lon_(Np), lat_(Np) + + real(RP), parameter :: EPS = 1.0E-64_RP + !------------------------------------------ + + !$omp parallel do + do p=1, Np + if ( abs(cos(lon(p))) < EPS ) then + lon_(p) = lon(p) + EPS + else + lon_(p) = lon(p) + end if + if ( abs( lat(p) - 0.5_RP * PI ) < EPS ) then + lat_(p) = lat(p) - sign(EPS, lat(p)) + else + lat_(p) = lat(p) + end if + end do + + panelID(:) = -1 + do pnl=1, 6 + call CubedSphereCnv_LonLat2CSPos( pnl, lon_, lat_, Np, & + alph, beta ) + + select case(pnl) + case (5) + where ( lat(:) > 0.0_RP .and. abs(alph(:)) <= 0.25_RP * PI .and. abs(beta(:)) <= 0.25_RP * PI ) + panelID(:) = pnl + end where + case (6) + where ( lat(:) < 0.0_RP .and. abs(alph(:)) <= 0.25_RP * PI .and. abs(beta(:)) <= 0.25_RP * PI ) + panelID(:) = pnl + end where + case default + where ( abs(alph(:)) <= 0.25_RP * PI .and. abs(beta(:)) <= 0.25_RP * PI ) + panelID(:) = pnl + end where + end select + end do + + do p=1, Np + if (panelID(p) < 0) then + LOG_ERROR("MeshUtilCubedSphere2D_getPanelID",*) 'Fail to search a panel ID of cubed sphere grid!' + write(*,*) "p=", p, ": (lon,lat)=", lon(p), lat(p), "(alpha,beta)=", alph(p), beta(p) + call PRC_abort + end if + end do + + return + end subroutine MeshUtilCubedSphere2D_getPanelID + end module scale_meshutil_cubedsphere2d diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile b/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile index 09c1d00e..bb84a0d9 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile @@ -18,6 +18,7 @@ LIBS = $(LIBDIR)/libScaleFECore.a VPATH = plugin: OBJS = \ + mod_cs2lonlat_interp_vcoord.o \ mod_cs2lonlat_interp_mesh.o \ mod_cs2lonlat_interp_field.o \ mod_cs2lonlat_interp_file.o @@ -46,6 +47,7 @@ $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$ $(BUILD_DIR)/mod_cs2lonlat_interp_mesh.o : mod_cs2lonlat_interp_mesh.F90 $(BUILD_DIR)/mod_cs2lonlat_interp_file.o : $(BUILD_DIR)/mod_cs2lonlat_interp_field.o mod_cs2lonlat_interp_file.F90 $(BUILD_DIR)/mod_cs2lonlat_interp_field.o : $(BUILD_DIR)/mod_cs2lonlat_interp_mesh.o mod_cs2lonlat_interp_field.F90 +$(BUILD_DIR)/mod_cs2lonlat_interp_vcoord.o : $(BUILD_DIR)/mod_cs2lonlat_interp_field.o $(BUILD_DIR)/mod_cs2lonlat_interp_mesh.o mod_cs2lonlat_interp_vcoord.F90 distclean: clean diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 index 0e8913e9..47631eed 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 @@ -87,13 +87,12 @@ module mod_cs2lonlat_interp_field contains !OCL SERIAL - subroutine interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D, nodeMap_list ) + subroutine interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D ) use scale_file_h implicit none class(MeshRectDom2D), intent(in) :: out_mesh2D class(MeshCubeDom3D), intent(in) :: out_mesh3D logical, intent(in) :: is_mesh3D - type(NodeMappingInfo), intent(in) :: nodeMap_list(:) integer :: nn character(len=H_SHORT) :: vars(ITEM_MAX_NUM) = '' ! name of variables diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 index 530fc3a6..29a98747 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 @@ -21,10 +21,12 @@ module mod_cs2lonlat_interp_mesh use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedom3d, only: MeshCubeDom3D use scale_mesh_cubedspheredom2d, only: & - MeshCubedSphereDom2D, & + MeshCubedSphereDom2D, & MeshCubedSphereDom2D_check_division_params use scale_mesh_cubedspheredom3d, only: & MeshCubedSphereDom3D + use scale_mesh_topography, only: MeshTopography + !----------------------------------------------------------------------------- implicit none private @@ -76,9 +78,11 @@ module mod_cs2lonlat_interp_mesh integer, public :: in_NeGY = 1 integer, public :: in_NeGZ = 1 integer, public :: in_NLocalMeshPerPrc = 6 + integer, public :: in_NprcX_lc + integer, public :: in_NprcY_lc type(QuadrilateralElement), public :: in_elem2D type(HexahedralElement), public :: in_elem3D - + logical, public :: is_mesh3D !----------------------------------------------------------------------------- @@ -211,7 +215,8 @@ subroutine interp_mesh_Init() call out_mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, 'lonlatt', 'degree', 'longitude,latitude' ) call out_mesh2D%Generate() - call construct_map() + call construct_map( in_NprcX_lc, in_NprcY_lc ) + else is_mesh3D = .true. call in_elem3D%Init( in_PolyOrder_h, in_PolyOrder_v, .false. ) @@ -235,11 +240,12 @@ subroutine interp_mesh_Init() call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude' ) call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatz', 'degree', 'longitude,latitude,altitude' ) call out_mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzt', 'degree', 'longitude,latitude,altitude' ) - + call out_mesh3D%Generate() - call construct_map( in_FZ(1:in_NeGZ+1), is_spec_in_FZ ) + call construct_map( in_NprcX_lc, in_NprcY_lc, & ! (out) + in_FZ(1:in_NeGZ+1), is_spec_in_FZ ) ! (in) end if - + return end subroutine interp_mesh_Init @@ -255,7 +261,7 @@ subroutine interp_mesh_Final() call in_elem3D%Final() call out_mesh3D%Final() - call out_elem3D%Final() + call out_elem3D%Final() else call out_mesh2D%Final() call out_elem2D%Final() @@ -271,9 +277,12 @@ end subroutine interp_mesh_Final !- private ------------------------------------- !OCL SERIAL - subroutine construct_map( in_Fz, is_spec_in_Fz ) + subroutine construct_map( NprcX_lc, NprcY_lc, & + in_Fz, is_spec_in_Fz ) implicit none + integer, intent(out) :: NprcX_lc + integer, intent(out) :: NprcY_lc real(RP), intent(in), optional :: in_Fz(1:in_NeGZ+1) logical, intent(in), optional :: is_spec_in_Fz @@ -286,7 +295,6 @@ subroutine construct_map( in_Fz, is_spec_in_Fz ) type(LocalMesh2D), pointer :: lcmesh2D type(LocalMesh3D), pointer :: lcmesh3D - integer :: NprcX_lc, NprcY_lc integer :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) integer :: panelID_table(in_NLocalMeshPerPrc*in_Nprc) integer :: pi_table(in_NLocalMeshPerPrc*in_Nprc) @@ -353,8 +361,12 @@ subroutine NodeMappingInfo_Init_2D( this, & lcmesh, elem2D, tile_x, tile_y, tileID_table, panelID_table, & NprcX_lc, NprcY_lc ) use scale_prc + use scale_polygon, only: & + polygon_inpoly use scale_cubedsphere_cnv, only: & CubedSphereCnv_LonLat2CSPos + use scale_meshutil_cubedsphere2d, only: & + MeshUtilCubedSphere2D_getPanelID implicit none class(NodeMappingInfo), intent(inout), target :: this @@ -409,10 +421,11 @@ subroutine NodeMappingInfo_Init_2D( this, & in_lcprc2prc_tmp(:) = -1 in_prc2lcprc_tmp(:) = -1 - call get_panelID( this%inCSPanelID(:,:), & - lcmesh%pos_en(:,:,1) * PI / 180.0_RP, & - lcmesh%pos_en(:,:,2) * PI / 180.0_RP, & - elem2D%Nfp**2 * lcmesh%NeX*lcmesh%NeY ) + call MeshUtilCubedSphere2D_getPanelID ( & + this%inCSPanelID(:,:), & ! (out) + lcmesh%pos_en(:,:,1) * PI / 180.0_RP, & ! (in) + lcmesh%pos_en(:,:,2) * PI / 180.0_RP, & ! (in) + elem2D%Nfp**2 * lcmesh%NeX*lcmesh%NeY ) ! (in) in_tile_num = 0 in_prc_num = 0 @@ -436,8 +449,8 @@ subroutine NodeMappingInfo_Init_2D( this, & if ( out_cspanel /= panelID_table(in_n,in_prc) ) cycle - is_inside_tile(p_h) = inpoly( out_x(1), out_y(1), & - 4, tile_x(:,in_n,in_prc), tile_y(:,in_n,in_prc) ) + is_inside_tile(p_h) = polygon_inpoly( out_x(1), out_y(1), & + 4, tile_x(:,in_n,in_prc), tile_y(:,in_n,in_prc) ) if ( is_inside_tile(p_h) ) then this%local_domID(p_h,ke_h) = in_n @@ -499,8 +512,8 @@ subroutine NodeMappingInfo_Init_2D( this, & do i=1, in_NeX in_elem_x(:) = tile_x(1,lc_domID,prcID) + delx * dble( (/ i-1, i, i, i-1 /) ) in_elem_y(:) = tile_y(1,lc_domID,prcID) + dely * dble( (/ j-1, j-1, j, j /) ) - is_inside_elem = inpoly( out_x(1), out_y(1), & - 4, in_elem_x(:), in_elem_y(:) ) + is_inside_elem = polygon_inpoly( out_x(1), out_y(1), & + 4, in_elem_x(:), in_elem_y(:) ) if (i==in_NeX) then in_elem_x(2:3) = in_elem_x(2:3) + 1.0E-12_RP * delx end if @@ -543,8 +556,12 @@ subroutine NodeMappingInfo_Init_3D( this, & tileID_table, panelID_table, & NprcX_lc, NprcY_lc, is_spec_in_FZ ) use scale_prc + use scale_polygon, only: & + polygon_inpoly use scale_cubedsphere_cnv, only: & CubedSphereCnv_LonLat2CSPos + use scale_meshutil_cubedsphere2d, only: & + MeshUtilCubedSphere2D_getPanelID implicit none class(NodeMappingInfo), intent(inout), target :: this @@ -563,7 +580,6 @@ subroutine NodeMappingInfo_Init_3D( this, & integer :: p, ke integer :: ke_h integer :: p_h, p_h_x, p_h_y - integer :: ke_z, ke_z2, p_z, p_z2 logical :: is_inside_tile(elem3D%Nnode_h1D**2) logical :: is_inside_elem real(RP) :: in_elem_x(4) @@ -576,16 +592,12 @@ subroutine NodeMappingInfo_Init_3D( this, & integer :: in_lcprc2prc_tmp(in_Nprc) integer :: in_tile_num integer :: in_prc_num - type(LocalMesh3D), pointer :: in_lcmesh - real(RP) :: in_Z0, in_Z1 - integer :: in_ke3D real(RP) :: out_lon(1), out_lat(1) real(RP) :: out_x(1), out_y(1) integer :: out_cspanel real(RP) :: out_x0, del_x real(RP) :: out_y0, del_y - integer :: in_NeX, in_NeY real(RP) :: out_lon2D(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) @@ -612,9 +624,9 @@ subroutine NodeMappingInfo_Init_3D( this, & out_lon2D(:,ke_h) = lcmesh%pos_en(elem3D%Hslice(:,1),ke_h,1) * PI / 180.0_RP out_lat2D(:,ke_h) = lcmesh%pos_en(elem3D%Hslice(:,1),ke_h,2) * PI / 180.0_RP end do - call get_panelID( this%inCSPanelID(:,:), & - out_lon2D, out_lat2D, & - elem3D%Nnode_h1D**2 * lcmesh%NeX*lcmesh%NeY ) + + call MeshUtilCubedSphere2D_getPanelID( this%inCSPanelID(:,:), & ! (out) + out_lon2D, out_lat2D, elem3D%Nnode_h1D**2 * lcmesh%NeX*lcmesh%NeY ) ! (in) in_tile_num = 0 in_prc_num = 0 @@ -638,8 +650,8 @@ subroutine NodeMappingInfo_Init_3D( this, & if ( out_cspanel /= panelID_table(in_n,in_prc) ) cycle - is_inside_tile(p_h) = inpoly( out_x(1), out_y(1), & - 4, tile_x(:,in_n,in_prc), tile_y(:,in_n,in_prc) ) + is_inside_tile(p_h) = polygon_inpoly( out_x(1), out_y(1), & + 4, tile_x(:,in_n,in_prc), tile_y(:,in_n,in_prc) ) if ( is_inside_tile(p_h) ) then this%local_domID(p_h,ke_h) = in_n @@ -706,8 +718,8 @@ subroutine NodeMappingInfo_Init_3D( this, & in_elem_y(3:4) = in_elem_y(3:4) + 1.0E-12_RP * dely end if - is_inside_elem = inpoly( out_x(1), out_y(1), & - 4, in_elem_x(:), in_elem_y(:) ) + is_inside_elem = polygon_inpoly( out_x(1), out_y(1), & + 4, in_elem_x(:), in_elem_y(:) ) if (is_inside_elem) then this%elem_i(p_h,ke_h) = i @@ -741,50 +753,6 @@ subroutine NodeMappingInfo_Init_3D( this, & call this%in_mesh3D_list(i)%Generate() end do - !-- - !$omp parallel private( & - !$omp ke_h, p_h, in_lcmesh, in_prc, in_n, & - !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) - - !$omp workshare - this%elem_k(:,:) = -1 - !$omp end workshare - - !$omp do collapse(2) - do ke_h=1, lcmesh%NeX * lcmesh%NeY - do p_h=1, elem3D%Nnode_h1D**2 - - in_n = this%local_domID(p_h,ke_h) - in_prc = this%lcprc(p_h,ke_h) - - if ( in_n > 0 .and. in_prc > 0 .and. & - this%elem_i(p_h,ke_h) > 0 .and. this%elem_j(p_h,ke_h) > 0 ) then - - in_lcmesh => this%in_mesh3D_list(in_prc)%lcmesh_list(in_n) - do ke_z=1, lcmesh%NeZ - do p_z=1, out_elem3D%Nnode_v - ke = ke_h + (ke_z-1)*lcmesh%NeX*lcmesh%NeY - p = p_h + (p_z-1)*elem3D%Nnode_h1D**2 - do ke_z2=1, in_NeGZ - in_ke3D = this%elem_i(p_h,ke_h) + (this%elem_j(p_h,ke_h)-1)*in_NeX & - + (ke_z2-1)*in_NeX*in_NeY - in_Z0 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,1),3) - in_Z1 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,5),3) - if ( in_Z0 <= lcmesh%pos_en(p,ke,3) .and. lcmesh%pos_en(p,ke,3) <= in_Z1 ) then - this%elem_k(p,ke) = ke_z2 - this%elem_z(p,ke) = lcmesh%pos_en(p,ke,3) - exit - end if - end do - end do - end do - end if - - end do - end do - !$omp end do - !$omp end parallel - return end subroutine NodeMappingInfo_Init_3D @@ -819,106 +787,4 @@ subroutine NodeMappingInfo_Final( this ) return end subroutine NodeMappingInfo_Final - !> Check whether the point is located inside a polyngon -!OCL SERIAL - function inpoly( pt_x, pt_y, num_node, v_x, v_y ) result(ret) - implicit none - real(RP), intent(in) :: pt_x - real(RP), intent(in) :: pt_y - integer, intent(in) :: num_node - real(RP), intent(in) :: v_x(num_node) - real(RP), intent(in) :: v_y(num_node) - logical :: ret - - integer :: wn - integer :: i, ii - !------------------------------------------ - - wn = 0 - do i=1, num_node - ii = mod(i, num_node) + 1 - if ( v_y(i) <= pt_y .and. pt_y < v_y(ii)) then - if( pt_x < v_x(i) + (pt_y - v_y(i)) * (v_x(ii) - v_x(i))/(v_y(ii) - v_y(i)) ) then - wn = wn + 1 - end if - else if ( v_y(i) > pt_y .and. v_y(ii) <= pt_y ) then - if( pt_x < v_x(i) + (pt_y - v_y(i)) * (v_x(ii) - v_x(i))/(v_y(ii) - v_y(i)) ) then - wn = wn - 1 - end if - end if - end do - - if (wn == 0) then - ret = .false. - else - ret = .true. - end if - - return - end function inpoly - -!OCL SERIAL - subroutine get_panelID( panelID, lon, lat, Np ) - use scale_cubedsphere_cnv, only: & - CubedSphereCnv_LonLat2CSPos - implicit none - - integer, intent(in) :: Np - integer, intent(out) :: panelID(Np) - real(RP), intent(in) :: lon(Np) - real(RP), intent(in) :: lat(Np) - - integer :: p - integer :: pnl - real(RP) :: alph(Np), beta(Np) - real(RP) :: lon_(Np), lat_(Np) - real(RP), parameter :: EPS = 1.0E-64_RP - !------------------------------------------ - - !$omp parallel do - do p=1, Np - if ( abs(cos(lon(p))) < EPS ) then - lon_(p) = lon(p) + EPS - else - lon_(p) = lon(p) - end if - if ( abs( lat(p) - 0.5_RP * PI ) < EPS ) then - lat_(p) = lat(p) - sign(EPS, lat(p)) - else - lat_(p) = lat(p) - end if - end do - - panelID(:) = -1 - do pnl=1, 6 - call CubedSphereCnv_LonLat2CSPos( pnl, lon_, lat_, Np, & - alph, beta ) - - select case(pnl) - case (5) - where ( lat(:) > 0.0_RP .and. abs(alph(:)) <= 0.25_RP * PI .and. abs(beta(:)) <= 0.25_RP * PI ) - panelID(:) = pnl - end where - case (6) - where ( lat(:) < 0.0_RP .and. abs(alph(:)) <= 0.25_RP * PI .and. abs(beta(:)) <= 0.25_RP * PI ) - panelID(:) = pnl - end where - case default - where ( abs(alph(:)) <= 0.25_RP * PI .and. abs(beta(:)) <= 0.25_RP * PI ) - panelID(:) = pnl - end where - end select - end do - - do p=1, Np - if (panelID(p) < 0) then - LOG_ERROR("get_panelID",*) 'Fail to search a panel ID of cubed sphere grid!' - write(*,*) "p=", p, ": (lon,lat)=", lon(p), lat(p), "(alpha,beta)=", alph(p), beta(p) - call PRC_abort - end if - end do - - return - end subroutine get_panelID - end module mod_cs2lonlat_interp_mesh \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 new file mode 100644 index 00000000..3ed72dc2 --- /dev/null +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 @@ -0,0 +1,586 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_cs2lonlat_interp_vcoord + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: & + PRC_myrank, PRC_abort + use scale_const, only: & + PI => CONST_PI, & + RPlanet => CONST_radius, & + UNDEF => CONST_UNDEF, & + EPS => CONST_EPS + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom2d, only: & + MeshCubedSphereDom2D + use scale_mesh_cubedspheredom3d, only: & + MeshCubedSphereDom3D + use scale_mesh_topography, only: & + MeshTopography + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_meshfield_base, only: MeshField3D + + use mod_cs2lonlat_interp_mesh, only: & + NodeMappingInfo + use mod_cs2lonlat_interp_field, only: & + interp_field_Interpolate + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + type :: vinterpcoef_info + real(RP), allocatable :: xi2v_coef(:,:) + integer , allocatable :: xi2v_idx_k (:,:,:) + integer , allocatable :: xi2v_idx_p (:,:,:) + end type + + type, public :: interp_vcoord + integer :: vintrp_typeid + type(MeshCubeDom3D) :: out_mesh + type(MeshTopography) :: topography + + type(vinterpcoef_info), allocatable :: vintrp_info(:) + type(MeshField3D) :: pres + type(HexahedralElement) :: elem + type(MeshCubeDom3D), pointer :: out_mesh3D_ptr + logical :: extrapolate + + type(MeshField3D), public :: vintrp_var3D + contains + procedure :: Init => interp_vcoord_Init + procedure :: Final => interp_vcoord_Final + procedure :: Update_weight => interp_vcoord_update_weight + procedure :: Interpolate => interp_vcoord_interpolate + end type + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + integer, public, parameter :: INTERP_VCOORD_MODEL_ID = 1 + integer, public, parameter :: INTERP_VCOORD_HEIGHT_ID = 2 + integer, public, parameter :: INTERP_VCOORD_PRESS_ID = 3 + + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + +!OCL SERIAL + subroutine interp_vcoord_Init( this, out_mesh3D, nodeMap_list ) + + use scale_mesh_base2d, only: & + MF2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_mesh_base3d, only: & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_XYZT + use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D + use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D + use scale_meshutil_vcoord, only: MESH_VCOORD_TERRAIN_FOLLOWING_ID + + use mod_cs2lonlat_interp_mesh, only: & + in_NeGX, in_NeGY, in_NeGZ, & + in_NprcX_lc, in_NprcY_lc + implicit none + + class(interp_vcoord), intent(inout), target :: this + class(MeshCubeDom3D), intent(inout), target :: out_mesh3D + type(NodeMappingInfo), intent(in), target :: nodeMap_list(:) + + character(len=H_SHORT) :: vintrp_name + character(len=H_LONG ) :: in_topofile_basename = '' ! Basename of the input file + character(len=H_SHORT) :: topo_varname = 'topo' + + integer, parameter :: FZ_nmax = 1000 + integer :: out_NeZ = -1 + integer :: out_PolyOrder_v = 1 + real(RP) :: out_dom_vmin + real(RP) :: out_dom_vmax + real(RP) :: out_FZ(FZ_nmax) + logical :: extrapolate + + namelist / PARAM_INTERP_VCOORD / & + vintrp_name, & + in_topofile_basename, & + topo_varname, & + out_NeZ, & + out_PolyOrder_v, & + out_dom_vmin, & + out_dom_vmax, & + out_Fz, & + extrapolate + + integer :: ierr + + type(FILE_base_meshfield) :: topo_file + integer :: vcoordid + type(MeshFieldCommRectDom2D) :: comm2d + type(MeshFieldCommCubeDom3D) :: comm3d + + integer :: n + type(NodeMappingInfo), pointer :: nmap + type(LocalMesh3D), pointer :: lcmesh + type(ElementBase3D), pointer :: elem + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("interp_vcoord_Init",*) 'Setup' + + vintrp_name = 'MODEL' + extrapolate = .false. + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_INTERP_VCOORD,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("interp_vcoord",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("interp_vcoord",*) 'Not appropriate names in namelist PARAM_INTERP_VCOORD. Check!' + call PRC_abort + endif + LOG_NML(PARAM_INTERP_VCOORD) + + select case( vintrp_name ) + case( 'MODEL' ) + this%vintrp_typeid= INTERP_VCOORD_MODEL_ID + this%out_mesh3D_ptr => out_mesh3D + case( 'HEIGHT' ) + this%vintrp_typeid = INTERP_VCOORD_HEIGHT_ID + case( 'PRESSURE' ) + this%vintrp_typeid = INTERP_VCOORD_PRESS_ID + case default + LOG_ERROR("interp_vcoord_Init",*) 'Not appropriate vintrp_type. Check!', vintrp_name + call PRC_abort + end select + + !- Vertical interpolation (MODEL) + + do n=1, out_mesh3D%LOCAL_MESH_NUM + lcmesh => out_mesh3D%lcmesh_list(n) + !--- + nmap => nodeMap_list(n) + call interp_vcoord_search_pos_model( this, & + nmap%elem_k(:,:), nmap%elem_z(:,:), & ! (out) + lcmesh, lcmesh%refElem3D, nmap%local_domID(:,:), nmap%lcprc(:,:), & ! (in) + nmap%elem_i(:,:), nmap%elem_j(:,:), & ! (in) + nmap%in_mesh3D_list, in_NeGZ, in_NeGX/in_NprcX_lc, in_NeGY/in_NprcY_lc ) ! (in) + end do + + this%extrapolate = extrapolate + + !- Prepair topography data + + call this%topography%Init( topo_varname, out_mesh3D%mesh2D ) + if ( in_topofile_basename /= '' ) then + call topo_file%Init( 1, mesh2D=out_mesh3D%mesh2D ) + call topo_file%Open( in_topofile_basename, PRC_myrank ) + call topo_file%Read_Var( MF2D_XY, topo_varname, this%topography%topo ) + call topo_file%Close() + call topo_file%Final() + end if + + !-- Setup vertical coordinate + + call comm2d%Init( 1, 0, out_mesh3D%mesh2D ) + call comm3d%Init( 1, 1, out_mesh3D ) + call this%topography%SetVCoordinate( out_mesh3D, & ! (inout) + MESH_VCOORD_TERRAIN_FOLLOWING_ID, out_mesh3D%zmax_gl, & ! (in) + comm3d, comm2d ) ! (in) + call comm2d%Final() + call comm3d%Final() + + !-- + + if ( this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + + call this%elem%Init( out_mesh3D%refElem3D%PolyOrder_h, out_PolyOrder_v, .true. ) + call this%out_mesh%Init( out_mesh3D%NeGX, out_mesh3D%NeGY, out_NeZ, & + out_mesh3D%xmin_gl, out_mesh3D%xmax_gl, out_mesh3D%ymin_gl, out_mesh3D%ymax_gl, & + out_dom_vmin, out_dom_vmax, & + out_mesh3D%isPeriodicX, out_mesh3D%isPeriodicY, out_mesh3D%isPeriodicZ, & + this%elem, 1, & + out_mesh3D%NprcX, out_mesh3D%NprcY, & + FZ=out_FZ(1:out_NeZ+1) ) + + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatv', 'degree', 'longitude,latitude,altitude' ) + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzv', 'degree', 'longitude,latitude,altitude' ) + + call this%out_mesh%Generate() + + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)' ) + call this%pres%Init( "PRES", "Pa", out_mesh3D ) + else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude (height coordinate)' ) + end if + + this%out_mesh3D_ptr => this%out_mesh + !------------------------ + + allocate( this%vintrp_info(this%out_mesh%LOCAL_MESH_NUM) ) + + do n=1, this%out_mesh%LOCAL_MESH_NUM + lcmesh => this%out_mesh%lcmesh_list(n) + elem => lcmesh%refElem3D + allocate( this%vintrp_info(n)%xi2v_coef(elem%Np,lcmesh%Ne) ) + allocate( this%vintrp_info(n)%xi2v_idx_k(elem%Np,lcmesh%Ne,2) ) + allocate( this%vintrp_info(n)%xi2v_idx_p(elem%Np,lcmesh%Ne,2) ) + end do + + end if + + call this%vintrp_var3D%Init( 'vintrp_var3D', '', this%out_mesh ) + + return + end subroutine interp_vcoord_Init + +!OCL SERIAL + subroutine interp_vcoord_Final( this ) + implicit none + class(interp_vcoord), intent(inout) :: this + + integer :: n + !------------------------------------------- + + call this%vintrp_var3D%Final() + call this%topography%Final() + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) & + call this%pres%Final() + + if ( allocated(this%vintrp_info) ) then + do n=1, size(this%vintrp_info) + deallocate( this%vintrp_info(n)%xi2v_coef ) + deallocate( this%vintrp_info(n)%xi2v_idx_k ) + deallocate( this%vintrp_info(n)%xi2v_idx_p ) + end do + deallocate( this%vintrp_info ) + end if + + if (this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + call this%out_mesh%Final() + call this%elem%Final() + end if + + nullify( this%out_mesh3D_ptr ) + + return + end subroutine interp_vcoord_Final + +!OCL SERIAL + subroutine interp_vcoord_update_weight( this, istep, out_mesh, nodeMap_list ) + implicit none + class(interp_vcoord), intent(inout) :: this + integer, intent(in) :: istep + class(MeshCubeDom3D), intent(in) :: out_mesh + type(NodeMappingInfo), intent(in) :: nodeMap_list(:) + + integer :: n + !--------------------------------------------------------------- + + select case( this%vintrp_typeid ) + case ( INTERP_VCOORD_MODEL_ID ) + return + case ( INTERP_VCOORD_PRESS_ID ) + call interp_field_Interpolate( istep, this%pres%varname, & + out_mesh, this%pres, nodeMap_list ) + end select + + do n=1, out_mesh%LOCAL_MESH_NUM + call interp_vcoord_update_weight_core( this, n, & + out_mesh%lcmesh_list(n), out_mesh%refElem3D, & + this%out_mesh%lcmesh_list(n), this%elem ) + end do + + return + end subroutine interp_vcoord_update_weight + +!OCL SERIAL + subroutine interp_vcoord_interpolate( this, istep, mesh_ref, field_ref ) + implicit none + class(interp_vcoord), intent(inout) :: this + integer, intent(in) :: istep + class(MeshCubeDom3D), intent(in) :: mesh_ref + class(MeshField3D), intent(in) :: field_ref + + integer :: n + !--------------------------------------------------------------- + + if ( this%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) return + + do n=1, this%out_mesh%LOCAL_MESH_NUM + call interp_vcoord_interpolate_core( this%vintrp_info(n), n, & + this%vintrp_var3D%local(n)%val, field_ref%local(n)%val, & + mesh_ref%lcmesh_list(n), mesh_ref%lcmesh_list(n)%refElem3D, & + this%out_mesh%lcmesh_list(n), this%elem ) + end do + + return + end subroutine interp_vcoord_interpolate + +!- private ------------------------------------- + +!OCL SERIAL + subroutine interp_vcoord_interpolate_core( & + vintrp_info, domID, var_intrp, var_ref, lcmesh_ref, elem_ref, lcmesh, elem ) + + implicit none + type(vinterpcoef_info), intent(inout) :: vintrp_info + integer, intent(in) :: domID + class(LocalMesh3D), intent(in) :: lcmesh_ref + class(ElementBase3D), intent(in) :: elem_ref + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: var_intrp(elem %Np,lcmesh %NeA) + real(RP), intent(in) :: var_ref (elem_ref%Np,lcmesh_ref%NeA) + + integer :: ke, p + integer :: ke_r, p_r, kke_r, pp_r + real(RP) :: coef + !-------------------------------------------------- + + !$omp parallel do collapse(2) private(ke, p, ke_r, p_r, kke_r, pp_r, coef) + do ke=lcmesh%NeS, lcmesh%NeE + do p=1, elem%Np + ke_r = vintrp_info%xi2v_idx_k(p,ke,1) + kke_r = vintrp_info%xi2v_idx_k(p,ke,2) + p_r = vintrp_info%xi2v_idx_p(p,ke,1) + pp_r = vintrp_info%xi2v_idx_p(p,ke,2) + coef = vintrp_info%xi2v_coef(p,ke) + var_intrp(p,ke) = UNDEF + if ( ke_r > 0 ) var_intrp(p,ke) = coef * var_ref(p_r,ke_r) + if ( kke_r > 0 ) var_intrp(p,ke) = var_intrp(p,ke) + (1.0_RP - coef) * var_ref(pp_r,kke_r) + end do + end do + + return + end subroutine interp_vcoord_interpolate_core + +!OCL SERIAL + subroutine interp_vcoord_update_weight_core( & + this, domID, lcmesh_ref, elem_ref, lcmesh, elem ) + + implicit none + + class(interp_vcoord), intent(inout) :: this + integer, intent(in) :: domID + class(LocalMesh3D), intent(in) :: lcmesh_ref + class(ElementBase3D), intent(in) :: elem_ref + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + + integer :: p, ke + integer :: p_ref, pp_ref, ke_ref, kke_ref + integer :: ke_xy, ke_z, ke_zz + integer :: p_xy, p_z, p_zz + integer :: ke_sfc_ref, ke_top_ref + integer :: p_sfc_ref, p_top_ref + real(RP) :: height_ref(elem_ref%Np,lcmesh_ref%Ne) + real(RP) :: height (elem%Np ,lcmesh%Ne ) + + integer :: indx_k(elem%Np,2) + integer :: indx_p(elem%Np,2) + real(RP) :: vfact(elem%Np) + !------------------------------------------------------------- + + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + !$omp parallel + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + height_ref(:,ke) = - log( this%pres%local(domID)%val(:,ke) ) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) + end do + !$omp end parallel + else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + !$omp parallel + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + height_ref(:,ke) = lcmesh_ref%zlev(:,ke) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + height(:,ke) = lcmesh%pos_en(:,ke,3) + end do + !$omp end parallel + end if + + !$omp parallel do collapse(2) private( & + !$omp ke_z, ke_xy, ke, ke_sfc_ref, ke_top_ref, & + !$omp indx_k, indx_p, vfact, & + !$omp p_z, p_xy, p, p_sfc_ref, p_top_ref, & + !$omp ke_zz, p_zz, ke_ref, p_ref, kke_ref, pp_ref ) + do ke_z=1, lcmesh%NeZ + do ke_xy=1, lcmesh%NeX * lcmesh%NeY + ke = ke_xy + (ke_z - 1) * lcmesh%NeX * lcmesh%NeY + ke_sfc_ref = ke_xy + ke_top_ref = ke_xy + (lcmesh_ref%NeZ - 1) * lcmesh%NeX * lcmesh%NeY + + indx_k(:,:) = -1 + indx_p(:,:) = -1 + vfact(:) = UNDEF + do p_z=1, elem%Nnode_v + do p_xy=1, elem%Nnode_h1D**2 + p = p_xy + (p_z -1) * elem%Nnode_h1D**2 + p_sfc_ref = p_xy + p_top_ref = p_xy + (elem_ref%Nnode_v -1) * elem%Nnode_h1D**2 + + if ( this%extrapolate .and. height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + else if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + else if ( this%extrapolate .and. height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + else if ( height(p,ke) >= height_ref(p_top_ref,ke_top_ref) ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + else + + search : do ke_zz = 1, lcmesh_ref%NeZ + do p_zz = 1, elem_ref%Nnode_v + ke_ref = ke_xy + (ke_zz-1) * lcmesh%NeX * lcmesh%NeY + p_ref = p_xy + (p_zz-1) * elem%Nnode_h1D**2 + if ( p_zz < elem_ref%Nnode_v ) then + pp_ref = p_xy + p_zz * elem%Nnode_h1D**2 + kke_ref = ke_ref + else + pp_ref = 2 + kke_ref = ke_xy + ke_zz * lcmesh%NeX * lcmesh%NeY + end if + if ( height(p,ke) >= height_ref(p_ref,ke_ref) & + .and. height(p,ke) < height_ref(pp_ref,kke_ref) ) then + indx_k(p,1) = ke_ref; indx_k(p,2) = kke_ref; + indx_p(p,1) = p_ref; indx_p(p,2) = pp_ref; + vfact(p) = ( height_ref(pp_ref,kke_ref) - height (p,ke) ) & + / ( height_ref(pp_ref,kke_ref) - height_ref(p_ref,ke_ref) ) + exit search + end if + end do + end do search + + end if + end do + end do + + this%vintrp_info(domID)%xi2v_idx_k(:,ke,1) = indx_k(:,1) + this%vintrp_info(domID)%xi2v_idx_k(:,ke,2) = indx_k(:,2) + this%vintrp_info(domID)%xi2v_idx_p(:,ke,1) = indx_p(:,1) + this%vintrp_info(domID)%xi2v_idx_p(:,ke,2) = indx_p(:,2) + this%vintrp_info(domID)%xi2v_coef(:,ke) = vfact(:) + end do + end do + + return + end subroutine interp_vcoord_update_weight_core + +!OCL SERIAL + subroutine interp_vcoord_search_pos_model( this, elem_k, elem_out, & + lcmesh, elem3D, local_domID, lcprc, elem_i, elem_j, & + in_mesh3D_list, in_NeGZ, in_NeX, in_NeY ) + + implicit none + type(interp_vcoord), intent(in) :: this + type(LocalMesh3D), intent(in) :: lcmesh + type(ElementBase3D), intent(in) :: elem3D + integer, intent(out) :: elem_k(elem3D%Np,lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) + real(RP), intent(out) :: elem_out(elem3D%Np,lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) + integer, intent(in) :: local_domID(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: lcprc(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: elem_i(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: elem_j(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + type(MeshCubedSphereDom3D), intent(in), target :: in_mesh3D_list(:) + integer, intent(in) :: in_NeGZ + integer, intent(in) :: in_NeX + integer, intent(in) :: in_NeY + + integer :: in_n + integer :: in_prc + integer :: ke, p + integer :: ke_h, p_h + integer :: ke_z, ke_z2 + integer :: p_z + + type(LocalMesh3D), pointer :: in_lcmesh + real(RP) :: in_Z0, in_Z1 + integer :: in_ke3D + !------------------------------------------- + + !$omp parallel private( & + !$omp ke_h, p_h, in_lcmesh, in_prc, in_n, & + !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) + + !$omp workshare + elem_k(:,:) = -1 + !$omp end workshare + + !$omp do collapse(2) + do ke_h=1, lcmesh%NeX * lcmesh%NeY + do p_h=1, elem3D%Nnode_h1D**2 + in_n = local_domID(p_h,ke_h) + in_prc = lcprc(p_h,ke_h) + + if ( in_n > 0 .and. in_prc > 0 .and. & + elem_i(p_h,ke_h) > 0 .and. elem_j(p_h,ke_h) > 0 ) then + + in_lcmesh => in_mesh3D_list(in_prc)%lcmesh_list(in_n) + do ke_z=1, lcmesh%NeZ + do p_z=1, elem3D%Nnode_v + ke = ke_h + (ke_z-1)*lcmesh%NeX*lcmesh%NeY + p = p_h + (p_z-1)*elem3D%Nnode_h1D**2 + do ke_z2=1, in_NeGZ + in_ke3D = elem_i(p_h,ke_h) + (elem_j(p_h,ke_h) - 1) * in_NeX & + + (ke_z2 - 1) * in_NeX * in_NeY + in_Z0 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,1),3) + in_Z1 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,5),3) + if ( in_Z0 <= lcmesh%pos_en(p,ke,3) .and. lcmesh%pos_en(p,ke,3) <= in_Z1 ) then + elem_k (p,ke) = ke_z2 + elem_out(p,ke) = lcmesh%pos_en(p,ke,3) + exit + end if + end do + end do + end do + end if + + end do + end do + !$omp end do + !$omp end parallel + + return + end subroutine interp_vcoord_search_pos_model + +end module mod_cs2lonlat_interp_vcoord \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 index 4dab2682..02b081d8 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 @@ -24,7 +24,10 @@ program convert_cs2lonlat use mod_cs2lonlat_interp_mesh, only: & out_mesh2D, out_mesh3D, & is_mesh3D, & - nodeMap_list + NodeMappingInfo, nodeMap_list + use mod_cs2lonlat_interp_vcoord, only: & + interp_vcoord, & + INTERP_VCOORD_MODEL_ID use mod_cs2lonlat_interp_field, only: & OutVarInfo, & out_var_num, & @@ -61,6 +64,7 @@ program convert_cs2lonlat real(DP) :: start_sec type(OutVarInfo), pointer :: vinfo + type(interp_vcoord) :: vintrp !----------------------------------------------------------------------------- call initialize() @@ -81,8 +85,18 @@ program convert_cs2lonlat if (is_mesh3D) then call interp_field_Interpolate( istep, vinfo%varname, & out_mesh3D, out_var3D, nodeMap_list ) - call interp_file_write_var( vid, out_var3D, & - start_sec, start_sec + vinfo%dt ) + + if ( vintrp%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) then + call interp_file_write_var( vid, out_var3D, & + start_sec, start_sec + vinfo%dt ) + else + call vintrp%Update_weight( istep, out_mesh3D, nodeMap_list ) + call vintrp%Interpolate( istep, out_mesh3D, out_var3D ) + + call interp_file_write_var( vid, vintrp%vintrp_var3D, & + start_sec, start_sec + vinfo%dt ) + end if + else call interp_field_Interpolate( istep, vinfo%varname, & out_mesh2D, out_var2D, nodeMap_list ) @@ -129,6 +143,8 @@ subroutine initialize() integer :: ierr integer :: comm ! communicator (execution) + + integer :: n !----------------------------------------------------------------------- ! start MPI @@ -177,9 +193,10 @@ subroutine initialize() LOG_NML(PARAM_INTERP) ! - call interp_mesh_Init() - call interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D, nodeMap_list ) - call interp_file_Init( in_basename, out_vinfo, out_mesh2D, out_mesh3D, is_mesh3D ) + call interp_mesh_Init() + call interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D ) + if ( is_mesh3D ) call vintrp%Init( out_mesh3D, nodeMap_list ) + call interp_file_Init( in_basename, out_vinfo, out_mesh2D, vintrp%out_mesh3D_ptr, is_mesh3D ) !- do_output = .true. @@ -209,7 +226,8 @@ subroutine finalize call PROF_rapstart ('Finalize', 0) call interp_file_Final - call interp_field_Final(is_mesh3D) + call interp_field_Final( is_mesh3D ) + if ( is_mesh3D ) call vintrp%Final() call interp_mesh_Final ! diff --git a/model/atm_nonhydro3d/util/interp/Makefile b/model/atm_nonhydro3d/util/interp/Makefile index 8c7e5281..73fde07f 100644 --- a/model/atm_nonhydro3d/util/interp/Makefile +++ b/model/atm_nonhydro3d/util/interp/Makefile @@ -18,8 +18,9 @@ LIBS = $(LIBDIR)/libScaleFECore.a VPATH = plugin: OBJS = \ - mod_interp_mesh.o \ - mod_interp_file.o \ + mod_interp_mesh.o \ + mod_interp_vcoord.o \ + mod_interp_file.o \ mod_interp_field.o @@ -47,7 +48,7 @@ $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$ $(BUILD_DIR)/mod_interp_mesh.o : mod_interp_mesh.F90 $(BUILD_DIR)/mod_interp_file.o : $(BUILD_DIR)/mod_interp_field.o mod_interp_file.F90 $(BUILD_DIR)/mod_interp_field.o : $(BUILD_DIR)/mod_interp_mesh.o mod_interp_field.F90 - +$(BUILD_DIR)/mod_interp_vcoord.o : $(BUILD_DIR)/mod_interp_mesh.o mod_interp_vcoord.F90 distclean: clean rm -f $(BINDIR)/$(BINNAME) diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 index 8a7b725d..506b0e1f 100644 --- a/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 @@ -41,6 +41,7 @@ module mod_interp_mesh integer, allocatable :: elem_i(:,:) integer, allocatable :: elem_j(:,:) integer, allocatable :: elem_k(:,:) + real(RP), allocatable :: elem_z(:,:) type(MeshCubeDom3D), allocatable :: in_mesh_list(:) integer, allocatable :: in_tileID_list(:) @@ -233,6 +234,7 @@ end subroutine construct_map !OCL SERIAL subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) use scale_prc + use scale_polygon, only: polygon_inpoly implicit none class(NodeMappingInfo), intent(inout), target :: this @@ -272,6 +274,7 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) allocate( this%elem_i(elem%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) allocate( this%elem_j(elem%Nnode_h1D**2, lcmesh%NeX*lcmesh%NeY) ) allocate( this%elem_k(elem%Np, lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) ) + allocate( this%elem_z(elem%Np, lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) ) target_tile_flag(:,:) = .false. this%prcXY2inListID(:,:) = -1 @@ -290,8 +293,8 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) loop_prc: do prc_j=1, in_NprcY do prc_i=1, in_NprcX - is_inside_tile(p_h) = inpoly( out_x, out_y, & - 4, tile_x(:,prc_i,prc_j), tile_y(:,prc_i,prc_j)) + is_inside_tile(p_h) = polygon_inpoly( out_x, out_y, & + 4, tile_x(:,prc_i,prc_j), tile_y(:,prc_i,prc_j) ) if ( is_inside_tile(p_h) ) then this%prc_x(p_h,ke_h) = prc_i this%prc_y(p_h,ke_h) = prc_j @@ -335,8 +338,8 @@ subroutine NodeMappingInfo_Init( this, lcmesh, elem, tile_x, tile_y, in_Fz ) do i=1, in_NeX in_elem_x(:) = tile_x(1,prc_i,prc_j) + delx * dble( (/ i-1, i, i, i-1 /) ) in_elem_y(:) = tile_y(1,prc_i,prc_j) + dely * dble( (/ j-1, j-1, j, j /) ) - is_inside_elem = inpoly( out_x, out_y, & - 4, in_elem_x(:), in_elem_y(:) ) + is_inside_elem = polygon_inpoly( out_x, out_y, & + 4, in_elem_x(:), in_elem_y(:) ) if (is_inside_elem) then this%elem_i(p_h,ke_h) = i this%elem_j(p_h,ke_h) = j @@ -421,6 +424,7 @@ subroutine NodeMappingInfo_Final( this ) if ( allocated(this%prc_x) ) then deallocate( this%prc_x, this%prc_y ) deallocate( this%elem_i, this%elem_j ) + if ( allocated(this%elem_k) ) deallocate( this%elem_k ) deallocate( this%in_tileID_list ) do i=1, size(this%in_mesh_list) @@ -431,44 +435,4 @@ subroutine NodeMappingInfo_Final( this ) return end subroutine NodeMappingInfo_Final - - !> Check whether the point is located inside a polyngon -!OCL SERIAL - function inpoly( pt_x, pt_y, num_node, v_x, v_y ) result(ret) - implicit none - real(RP), intent(in) :: pt_x - real(RP), intent(in) :: pt_y - integer, intent(in) :: num_node - real(RP), intent(in) :: v_x(num_node) - real(RP), intent(in) :: v_y(num_node) - logical :: ret - - integer :: wn - integer :: i, ii - !------------------------------------------ - - wn = 0 - do i=1, num_node - ii = mod(i, num_node) + 1 - if ( v_y(i) <= pt_y .and. pt_y < v_y(ii)) then - if( pt_x < v_x(i) + (pt_y - v_y(i)) * (v_x(ii) - v_x(i))/(v_y(ii) - v_y(i)) ) then - wn = wn + 1 - end if - else if ( v_y(i) > pt_y .and. v_y(ii) <= pt_y ) then - if( pt_x < v_x(i) + (pt_y - v_y(i)) * (v_x(ii) - v_x(i))/(v_y(ii) - v_y(i)) ) then - wn = wn - 1 - end if - end if - end do - - if (wn == 0) then - ret = .false. - else - ret = .true. - end if - - return - end function inpoly - - end module mod_interp_mesh \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 new file mode 100644 index 00000000..c86c8cb3 --- /dev/null +++ b/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 @@ -0,0 +1,578 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_interp_vcoord + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: & + PRC_myrank, PRC_abort + use scale_const, only: & + PI => CONST_PI, & + RPlanet => CONST_radius, & + UNDEF => CONST_UNDEF, & + EPS => CONST_EPS + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_topography, only: & + MeshTopography + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_meshfield_base, only: MeshField3D + + use mod_interp_mesh, only: & + NodeMappingInfo + use mod_interp_field, only: & + interp_field_Interpolate + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + type :: vinterpcoef_info + real(RP), allocatable :: xi2v_coef(:,:) + integer , allocatable :: xi2v_idx_k (:,:,:) + integer , allocatable :: xi2v_idx_p (:,:,:) + end type + + type, public :: interp_vcoord + integer :: vintrp_typeid + type(MeshCubeDom3D) :: out_mesh + type(MeshTopography) :: topography + + type(vinterpcoef_info), allocatable :: vintrp_info(:) + type(MeshField3D) :: pres + type(HexahedralElement) :: elem + type(MeshCubeDom3D), pointer :: out_mesh3D_ptr + logical :: extrapolate + + type(MeshField3D), public :: vintrp_var3D + contains + procedure :: Init => interp_vcoord_Init + procedure :: Final => interp_vcoord_Final + procedure :: Update_weight => interp_vcoord_update_weight + procedure :: Interpolate => interp_vcoord_interpolate + end type + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + integer, public, parameter :: INTERP_VCOORD_MODEL_ID = 1 + integer, public, parameter :: INTERP_VCOORD_HEIGHT_ID = 2 + integer, public, parameter :: INTERP_VCOORD_PRESS_ID = 3 + + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + +!OCL SERIAL + subroutine interp_vcoord_Init( this, out_mesh3D, nodeMap_list ) + + use scale_mesh_base2d, only: & + MF2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_mesh_base3d, only: & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_XYZT + use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D + use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D + use scale_meshutil_vcoord, only: MESH_VCOORD_TERRAIN_FOLLOWING_ID + + use mod_interp_mesh, only: & + in_NeX, in_NeY, in_NeZ, & + in_NprcX, in_NprcY + implicit none + + class(interp_vcoord), intent(inout), target :: this + class(MeshCubeDom3D), intent(inout), target :: out_mesh3D + type(NodeMappingInfo), intent(in), target :: nodeMap_list(:) + + character(len=H_SHORT) :: vintrp_name + character(len=H_LONG ) :: in_topofile_basename = '' ! Basename of the input file + character(len=H_SHORT) :: topo_varname = 'topo' + + integer, parameter :: FZ_nmax = 1000 + integer :: out_NeZ = -1 + integer :: out_PolyOrder_v = 1 + real(RP) :: out_dom_vmin + real(RP) :: out_dom_vmax + real(RP) :: out_FZ(FZ_nmax) + logical :: extrapolate + + namelist / PARAM_INTERP_VCOORD / & + vintrp_name, & + in_topofile_basename, & + topo_varname, & + out_NeZ, & + out_PolyOrder_v, & + out_dom_vmin, & + out_dom_vmax, & + out_Fz, & + extrapolate + + integer :: ierr + + type(FILE_base_meshfield) :: topo_file + integer :: vcoordid + type(MeshFieldCommRectDom2D) :: comm2d + type(MeshFieldCommCubeDom3D) :: comm3d + + integer :: n + type(NodeMappingInfo), pointer :: nmap + type(LocalMesh3D), pointer :: lcmesh + type(ElementBase3D), pointer :: elem + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("interp_vcoord_Init",*) 'Setup' + + vintrp_name = 'MODEL' + extrapolate = .false. + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_INTERP_VCOORD,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("interp_vcoord",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("interp_vcoord",*) 'Not appropriate names in namelist PARAM_INTERP_VCOORD. Check!' + call PRC_abort + endif + LOG_NML(PARAM_INTERP_VCOORD) + + select case( vintrp_name ) + case( 'MODEL' ) + this%vintrp_typeid= INTERP_VCOORD_MODEL_ID + this%out_mesh3D_ptr => out_mesh3D + case( 'HEIGHT' ) + this%vintrp_typeid = INTERP_VCOORD_HEIGHT_ID + case( 'PRESSURE' ) + this%vintrp_typeid = INTERP_VCOORD_PRESS_ID + case default + LOG_ERROR("interp_vcoord_Init",*) 'Not appropriate vintrp_type. Check!', vintrp_name + call PRC_abort + end select + + !- Vertical interpolation (MODEL) + + do n=1, out_mesh3D%LOCAL_MESH_NUM + lcmesh => out_mesh3D%lcmesh_list(n) + !--- + nmap => nodeMap_list(n) + call interp_vcoord_search_pos_model( this, & + nmap%elem_k(:,:), nmap%elem_z(:,:), & ! (out) + lcmesh, lcmesh%refElem3D, nmap%prc_x(:,:), nmap%prc_y(:,:), & ! (in) + nmap%elem_i(:,:), nmap%elem_j(:,:), & ! (in) + nmap%prcXY2inListID(:,:), nmap%in_mesh_list(:), & ! (in) + in_NeZ, in_NeX, in_NeY ) ! (in) + end do + + this%extrapolate = extrapolate + + !- Prepair topography data + + call this%topography%Init( topo_varname, out_mesh3D%mesh2D ) + if ( in_topofile_basename /= '' ) then + call topo_file%Init( 1, mesh2D=out_mesh3D%mesh2D ) + call topo_file%Open( in_topofile_basename, PRC_myrank ) + call topo_file%Read_Var( MF2D_XY, topo_varname, this%topography%topo ) + call topo_file%Close() + call topo_file%Final() + end if + + !-- Setup vertical coordinate + + call comm2d%Init( 1, 0, out_mesh3D%mesh2D ) + call comm3d%Init( 1, 1, out_mesh3D ) + call this%topography%SetVCoordinate( out_mesh3D, & ! (inout) + MESH_VCOORD_TERRAIN_FOLLOWING_ID, out_mesh3D%zmax_gl, & ! (in) + comm3d, comm2d ) ! (in) + call comm2d%Final() + call comm3d%Final() + + !-- + + if ( this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + + call this%elem%Init( out_mesh3D%refElem3D%PolyOrder_h, out_PolyOrder_v, .true. ) + call this%out_mesh%Init( out_mesh3D%NeGX, out_mesh3D%NeGY, out_NeZ, & + out_mesh3D%xmin_gl, out_mesh3D%xmax_gl, out_mesh3D%ymin_gl, out_mesh3D%ymax_gl, & + out_dom_vmin, out_dom_vmax, & + out_mesh3D%isPeriodicX, out_mesh3D%isPeriodicY, out_mesh3D%isPeriodicZ, & + this%elem, 1, & + out_mesh3D%NprcX, out_mesh3D%NprcY, & + FZ=out_FZ(1:out_NeZ+1) ) + + call this%out_mesh%Generate() + + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)' ) + call this%pres%Init( "PRES", "Pa", out_mesh3D ) + else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude (height coordinate)' ) + end if + + this%out_mesh3D_ptr => this%out_mesh + !------------------------ + + allocate( this%vintrp_info(this%out_mesh%LOCAL_MESH_NUM) ) + + do n=1, this%out_mesh%LOCAL_MESH_NUM + lcmesh => this%out_mesh%lcmesh_list(n) + elem => lcmesh%refElem3D + allocate( this%vintrp_info(n)%xi2v_coef(elem%Np,lcmesh%Ne) ) + allocate( this%vintrp_info(n)%xi2v_idx_k(elem%Np,lcmesh%Ne,2) ) + allocate( this%vintrp_info(n)%xi2v_idx_p(elem%Np,lcmesh%Ne,2) ) + end do + + end if + + call this%vintrp_var3D%Init( 'vintrp_var3D', '', this%out_mesh ) + + return + end subroutine interp_vcoord_Init + +!OCL SERIAL + subroutine interp_vcoord_Final( this ) + implicit none + class(interp_vcoord), intent(inout) :: this + + integer :: n + !------------------------------------------- + + call this%vintrp_var3D%Final() + call this%topography%Final() + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) & + call this%pres%Final() + + if ( allocated(this%vintrp_info) ) then + do n=1, size(this%vintrp_info) + deallocate( this%vintrp_info(n)%xi2v_coef ) + deallocate( this%vintrp_info(n)%xi2v_idx_k ) + deallocate( this%vintrp_info(n)%xi2v_idx_p ) + end do + deallocate( this%vintrp_info ) + end if + + if (this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + call this%out_mesh%Final() + call this%elem%Final() + end if + + nullify( this%out_mesh3D_ptr ) + + return + end subroutine interp_vcoord_Final + +!OCL SERIAL + subroutine interp_vcoord_update_weight( this, istep, out_mesh, nodeMap_list ) + implicit none + class(interp_vcoord), intent(inout) :: this + integer, intent(in) :: istep + class(MeshCubeDom3D), intent(in) :: out_mesh + type(NodeMappingInfo), intent(in) :: nodeMap_list(:) + + integer :: n + !--------------------------------------------------------------- + + select case( this%vintrp_typeid ) + case ( INTERP_VCOORD_MODEL_ID ) + return + case ( INTERP_VCOORD_PRESS_ID ) + call interp_field_Interpolate( istep, this%pres%varname, & + out_mesh, this%pres, nodeMap_list ) + end select + + do n=1, out_mesh%LOCAL_MESH_NUM + call interp_vcoord_update_weight_core( this, n, & + out_mesh%lcmesh_list(n), out_mesh%refElem3D, & + this%out_mesh%lcmesh_list(n), this%elem ) + end do + + return + end subroutine interp_vcoord_update_weight + +!OCL SERIAL + subroutine interp_vcoord_interpolate( this, istep, mesh_ref, field_ref ) + implicit none + class(interp_vcoord), intent(inout) :: this + integer, intent(in) :: istep + class(MeshCubeDom3D), intent(in) :: mesh_ref + class(MeshField3D), intent(in) :: field_ref + + integer :: n + !--------------------------------------------------------------- + + if ( this%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) return + + do n=1, this%out_mesh%LOCAL_MESH_NUM + call interp_vcoord_interpolate_core( this%vintrp_info(n), n, & + this%vintrp_var3D%local(n)%val, field_ref%local(n)%val, & + mesh_ref%lcmesh_list(n), mesh_ref%lcmesh_list(n)%refElem3D, & + this%out_mesh%lcmesh_list(n), this%elem ) + end do + + return + end subroutine interp_vcoord_interpolate + +!- private ------------------------------------- + +!OCL SERIAL + subroutine interp_vcoord_interpolate_core( & + vintrp_info, domID, var_intrp, var_ref, lcmesh_ref, elem_ref, lcmesh, elem ) + + implicit none + type(vinterpcoef_info), intent(inout) :: vintrp_info + integer, intent(in) :: domID + class(LocalMesh3D), intent(in) :: lcmesh_ref + class(ElementBase3D), intent(in) :: elem_ref + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: var_intrp(elem %Np,lcmesh %NeA) + real(RP), intent(in) :: var_ref (elem_ref%Np,lcmesh_ref%NeA) + + integer :: ke, p + integer :: ke_r, p_r, kke_r, pp_r + real(RP) :: coef + !-------------------------------------------------- + + !$omp parallel do collapse(2) private(ke, p, ke_r, p_r, kke_r, pp_r, coef) + do ke=lcmesh%NeS, lcmesh%NeE + do p=1, elem%Np + ke_r = vintrp_info%xi2v_idx_k(p,ke,1) + kke_r = vintrp_info%xi2v_idx_k(p,ke,2) + p_r = vintrp_info%xi2v_idx_p(p,ke,1) + pp_r = vintrp_info%xi2v_idx_p(p,ke,2) + coef = vintrp_info%xi2v_coef(p,ke) + var_intrp(p,ke) = UNDEF + if ( ke_r > 0 ) var_intrp(p,ke) = coef * var_ref(p_r,ke_r) + if ( kke_r > 0 ) var_intrp(p,ke) = var_intrp(p,ke) + (1.0_RP - coef) * var_ref(pp_r,kke_r) + end do + end do + + return + end subroutine interp_vcoord_interpolate_core + +!OCL SERIAL + subroutine interp_vcoord_update_weight_core( & + this, domID, lcmesh_ref, elem_ref, lcmesh, elem ) + + implicit none + + class(interp_vcoord), intent(inout) :: this + integer, intent(in) :: domID + class(LocalMesh3D), intent(in) :: lcmesh_ref + class(ElementBase3D), intent(in) :: elem_ref + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + + integer :: p, ke + integer :: p_ref, pp_ref, ke_ref, kke_ref + integer :: ke_xy, ke_z, ke_zz + integer :: p_xy, p_z, p_zz + integer :: ke_sfc_ref, ke_top_ref + integer :: p_sfc_ref, p_top_ref + real(RP) :: height_ref(elem_ref%Np,lcmesh_ref%Ne) + real(RP) :: height (elem%Np ,lcmesh%Ne ) + + integer :: indx_k(elem%Np,2) + integer :: indx_p(elem%Np,2) + real(RP) :: vfact(elem%Np) + !------------------------------------------------------------- + + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + !$omp parallel + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + height_ref(:,ke) = - log( this%pres%local(domID)%val(:,ke) ) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) + end do + !$omp end parallel + else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + !$omp parallel + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + height_ref(:,ke) = lcmesh_ref%zlev(:,ke) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + height(:,ke) = lcmesh%pos_en(:,ke,3) + end do + !$omp end parallel + end if + + !$omp parallel do collapse(2) private( & + !$omp ke_z, ke_xy, ke, ke_sfc_ref, ke_top_ref, & + !$omp indx_k, indx_p, vfact, & + !$omp p_z, p_xy, p, p_sfc_ref, p_top_ref, & + !$omp ke_zz, p_zz, ke_ref, p_ref, kke_ref, pp_ref ) + do ke_z=1, lcmesh%NeZ + do ke_xy=1, lcmesh%NeX * lcmesh%NeY + ke = ke_xy + (ke_z - 1) * lcmesh%NeX * lcmesh%NeY + ke_sfc_ref = ke_xy + ke_top_ref = ke_xy + (lcmesh_ref%NeZ - 1) * lcmesh%NeX * lcmesh%NeY + + indx_k(:,:) = -1 + indx_p(:,:) = -1 + vfact(:) = UNDEF + do p_z=1, elem%Nnode_v + do p_xy=1, elem%Nnode_h1D**2 + p = p_xy + (p_z -1) * elem%Nnode_h1D**2 + p_sfc_ref = p_xy + p_top_ref = p_xy + (elem_ref%Nnode_v -1) * elem%Nnode_h1D**2 + + if ( this%extrapolate .and. height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + else if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + else if ( this%extrapolate .and. height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + else if ( height(p,ke) >= height_ref(p_top_ref,ke_top_ref) ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + else + + search : do ke_zz = 1, lcmesh_ref%NeZ + do p_zz = 1, elem_ref%Nnode_v + ke_ref = ke_xy + (ke_zz-1) * lcmesh%NeX * lcmesh%NeY + p_ref = p_xy + (p_zz-1) * elem%Nnode_h1D**2 + if ( p_zz < elem_ref%Nnode_v ) then + pp_ref = p_xy + p_zz * elem%Nnode_h1D**2 + kke_ref = ke_ref + else + pp_ref = 2 + kke_ref = ke_xy + ke_zz * lcmesh%NeX * lcmesh%NeY + end if + if ( height(p,ke) >= height_ref(p_ref,ke_ref) & + .and. height(p,ke) < height_ref(pp_ref,kke_ref) ) then + indx_k(p,1) = ke_ref; indx_k(p,2) = kke_ref; + indx_p(p,1) = p_ref; indx_p(p,2) = pp_ref; + vfact(p) = ( height_ref(pp_ref,kke_ref) - height (p,ke) ) & + / ( height_ref(pp_ref,kke_ref) - height_ref(p_ref,ke_ref) ) + exit search + end if + end do + end do search + + end if + end do + end do + + this%vintrp_info(domID)%xi2v_idx_k(:,ke,1) = indx_k(:,1) + this%vintrp_info(domID)%xi2v_idx_k(:,ke,2) = indx_k(:,2) + this%vintrp_info(domID)%xi2v_idx_p(:,ke,1) = indx_p(:,1) + this%vintrp_info(domID)%xi2v_idx_p(:,ke,2) = indx_p(:,2) + this%vintrp_info(domID)%xi2v_coef(:,ke) = vfact(:) + end do + end do + + return + end subroutine interp_vcoord_update_weight_core + +!OCL SERIAL + subroutine interp_vcoord_search_pos_model( this, elem_k, elem_out, & + lcmesh, elem3D, prc_x, prc_y, elem_i, elem_j, & + prcXY2inListID, in_mesh3D_list, in_NeGZ, in_NeX, in_NeY ) + + implicit none + type(interp_vcoord), intent(in) :: this + type(LocalMesh3D), intent(in) :: lcmesh + type(ElementBase3D), intent(in) :: elem3D + integer, intent(out) :: elem_k(elem3D%Np,lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) + real(RP), intent(out) :: elem_out(elem3D%Np,lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) + integer, intent(in) :: prc_x(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: prc_y(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: elem_i(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: elem_j(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: prcXY2inListID(:,:) + type(MeshCubeDom3D), intent(in), target :: in_mesh3D_list(:) + integer, intent(in) :: in_NeGZ + integer, intent(in) :: in_NeX + integer, intent(in) :: in_NeY + + integer :: prc_i, prc_j + integer :: ke, p + integer :: ke_h, p_h + integer :: ke_z, ke_z2 + integer :: p_z + + type(LocalMesh3D), pointer :: in_lcmesh + real(RP) :: in_Z0, in_Z1 + integer :: in_ke3D + !------------------------------------------- + + !$omp parallel private( & + !$omp ke_h, p_h, prc_i, prc_j, in_lcmesh, & + !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) + + !$omp workshare + elem_k(:,:) = -1 + !$omp end workshare + + !$omp do collapse(2) + do ke_h=1, lcmesh%NeX * lcmesh%NeY + do p_h=1, elem3D%Nnode_h1D**2 + prc_i = prc_x(p_h,ke_h) + prc_j = prc_y(p_h,ke_h) + + if ( prc_i > 0 .and. prc_j > 0 .and. & + elem_i(p_h,ke_h) > 0 .and. elem_j(p_h,ke_h) > 0 ) then + + in_lcmesh => in_mesh3D_list( prcXY2inListID(prc_i,prc_j) )%lcmesh_list(1) + do ke_z=1, lcmesh%NeZ + do p_z=1, elem3D%Nnode_v + ke = ke_h + (ke_z-1)*lcmesh%NeX*lcmesh%NeY + p = p_h + (p_z-1)*elem3D%Nnode_h1D**2 + do ke_z2=1, in_NeGZ + in_ke3D = elem_i(p_h,ke_h) + (elem_j(p_h,ke_h) - 1) * in_NeX & + + (ke_z2 - 1) * in_NeX * in_NeY + in_Z0 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,1),3) + in_Z1 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,5),3) + if ( in_Z0 <= lcmesh%pos_en(p,ke,3) .and. lcmesh%pos_en(p,ke,3) <= in_Z1 ) then + elem_k (p,ke) = ke_z2 + elem_out(p,ke) = lcmesh%pos_en(p,ke,3) + exit + end if + end do + end do + end do + end if + + end do + end do + !$omp end do + !$omp end parallel + + return + end subroutine interp_vcoord_search_pos_model + +end module mod_interp_vcoord \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/interp/prg_interp.F90 b/model/atm_nonhydro3d/util/interp/prg_interp.F90 index 3e37f43e..c222fdfd 100644 --- a/model/atm_nonhydro3d/util/interp/prg_interp.F90 +++ b/model/atm_nonhydro3d/util/interp/prg_interp.F90 @@ -23,7 +23,10 @@ program interp use mod_interp_mesh, only: & out_mesh, & - nodeMap_list + nodeMap_list + use mod_interp_vcoord, only: & + interp_vcoord, & + INTERP_VCOORD_MODEL_ID use mod_interp_field, only: & OutVarInfo, & out_var3D_num, & @@ -53,12 +56,12 @@ program interp integer :: myrank ! my rank (execution) logical :: ismaster ! master process? (execution) - logical :: do_output integer :: vid integer :: istep real(DP) :: start_sec type(OutVarInfo), pointer :: vinfo + type(interp_vcoord) :: vintrp !----------------------------------------------------------------------------- call initialize() @@ -78,8 +81,17 @@ program interp LOG_INFO("INTERP",'(a,i4)') 'Interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep call interp_field_Interpolate( istep, vinfo%varname, & out_mesh, out_var3D, nodeMap_list ) - call interp_file_write_var( vid, out_var3D, & - start_sec, start_sec + vinfo%dt ) + + if ( vintrp%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) then + call interp_file_write_var( vid, out_var3D, & + start_sec, start_sec + vinfo%dt ) + else + call vintrp%Update_weight( istep, out_mesh, nodeMap_list ) + call vintrp%Interpolate( istep, out_mesh, out_var3D ) + + call interp_file_write_var( vid, vintrp%vintrp_var3D, & + start_sec, start_sec + vinfo%dt ) + end if if( IO_L ) call flush(IO_FID_LOG) end do @@ -169,13 +181,12 @@ subroutine initialize() LOG_NML(PARAM_INTERP) ! - call interp_mesh_Init + call interp_mesh_Init() call interp_field_Init( out_mesh, nodeMap_list ) - call interp_file_Init( in_basename, out_vinfo, out_mesh ) + call vintrp%Init( out_mesh, nodeMap_list ) + call interp_file_Init( in_basename, out_vinfo, vintrp%out_mesh ) !- - do_output = .true. - LOG_INFO("INTERP",*) 'Setup has been finished.' if( IO_L ) call flush(IO_FID_LOG) From a080e2fb52260a3d7f0484467b371b280b4be860 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 2 Aug 2021 14:57:04 +0900 Subject: [PATCH 72/98] Refactor source codes to put global attributes asociated with time. --- FElib/src/file/scale_file_base_meshfield.F90 | 42 ++++++++++++++ .../src/file/scale_file_restart_meshfield.F90 | 55 +------------------ 2 files changed, 43 insertions(+), 54 deletions(-) diff --git a/FElib/src/file/scale_file_base_meshfield.F90 b/FElib/src/file/scale_file_base_meshfield.F90 index f104a23b..806230fd 100644 --- a/FElib/src/file/scale_file_base_meshfield.F90 +++ b/FElib/src/file/scale_file_base_meshfield.F90 @@ -85,6 +85,8 @@ module scale_file_base_meshfield procedure :: FILE_base_meshfield_write_var3d generic :: Write_var3D => FILE_base_meshfield_write_var3d !- + procedure :: Put_GlobalAttribute_time => FILE_base_meshfield_put_global_attribute_time + !- procedure :: FILE_base_meshfield_read_var1d procedure :: FILE_base_meshfield_read_var1d_local procedure :: FILE_base_meshfield_read_var2d @@ -839,6 +841,46 @@ subroutine FILE_base_meshfield_Final( this ) ! (inout) return end subroutine FILE_base_meshfield_Final + subroutine FILE_base_meshfield_put_global_attribute_time( & + this, date, subsec ) + + use scale_file, only: & + FILE_Set_Attribute, & + FILE_get_CFtunits + use scale_calendar, only: & + CALENDAR_get_name + + implicit none + + class(FILE_base_meshfield), intent(inout) :: this + integer, intent(in) :: date(6) + real(DP), intent(in) :: subsec + + character(34) :: tunits + character(len=H_SHORT) :: calendar_name + !------------------------------------ + + call FILE_Set_Attribute( this%fid, "global", "Conventions", "CF-1.6" ) ! [IN] + call FILE_Set_Attribute( this%fid, "global", "grid_name", "hoge" ) ! [IN] + + !- time + + if ( date(1) > 0 ) then + call FILE_get_CFtunits( date(:), tunits ) + call CALENDAR_get_name( calendar_name ) + else + tunits = 'seconds' + calendar_name = '' + endif + + if ( calendar_name /= "" ) & + call FILE_Set_Attribute( this%fid, "global", "calendar", calendar_name ) + call FILE_Set_Attribute( this%fid, "global", "time_units", tunits ) + call FILE_Set_Attribute( this%fid, "global", "time_start", (/ subsec /) ) + + return + end subroutine FILE_base_meshfield_put_global_attribute_time + !- private ----------------------------------------- subroutine def_axes( this, & ! (in) diff --git a/FElib/src/file/scale_file_restart_meshfield.F90 b/FElib/src/file/scale_file_restart_meshfield.F90 index c9eabdc9..1d3b0d7e 100644 --- a/FElib/src/file/scale_file_restart_meshfield.F90 +++ b/FElib/src/file/scale_file_restart_meshfield.F90 @@ -304,15 +304,13 @@ subroutine FILE_restart_meshfield_component_create( & LOG_INFO(trim(this%comp_name)//"_vars_restart_create",*) 'basename: ', trim(basename) - call get_tunits_and_calendarname( NOWDATE, & - tunits, calendar ) call this%base%Create( basename, this%out_title, this%out_dtype, & ! (in) fileexisted, & ! (out) myrank=PRC_myrank, tunits=tunits, calendar=calendar ) ! (in) if ( .not. fileexisted ) then - call put_global_attribute( this%base%fid, NOWSUBSEC, tunits, calendar ) + call this%base%Put_GlobalAttribute_time( NOWDATE, NOWSUBSEC ) end if return @@ -444,57 +442,6 @@ subroutine FILE_restart_meshfield_component_Final( this ) return end subroutine FILE_restart_meshfield_component_Final - - subroutine put_global_attribute( & - fid, time, tunits, calendar ) - - use scale_file, only: & - FILE_Set_Attribute - implicit none - - integer, intent(in) :: fid - real(DP), intent(in) :: time - character(*), intent(in) :: tunits - character(*), intent(in) :: calendar - - !------------------------------------ - - call FILE_Set_Attribute( fid, "global", "Conventions", "CF-1.6" ) ! [IN] - call FILE_Set_Attribute( fid, "global", "grid_name", "hoge" ) ! [IN] - - if ( calendar /= "" ) call FILE_Set_Attribute( fid, "global", "calendar", calendar ) - call FILE_Set_Attribute( fid, "global", "time_units", tunits ) - call FILE_Set_Attribute( fid, "global", "time_start", (/time/) ) - - return - end subroutine put_global_attribute - !------------ - - subroutine get_tunits_and_calendarname( date, & - tunits, calendar_name ) - - use scale_file, only: & - FILE_get_CFtunits - use scale_calendar, only: & - CALENDAR_get_name - implicit none - - integer, intent(in) :: date(6) - character(len=34), intent(out) :: tunits - character(len=H_SHORT), intent(out) :: calendar_name - !-------------------------------------------------- - - if ( date(1) > 0 ) then - call FILE_get_CFtunits( date(:), tunits ) - call CALENDAR_get_name( calendar_name ) - else - tunits = 'seconds' - calendar_name = '' - endif - - return - end subroutine get_tunits_and_calendarname - end module scale_file_restart_meshfield From ba35089ef2c2369a44c3f9b2e2df4985e0172ee9 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Mon, 2 Aug 2021 14:59:29 +0900 Subject: [PATCH 73/98] Fix some bugs. --- .../src/preprocess/mod_mktopo.F90 | 22 ++++++++++++++----- .../mod_cs2lonlat_interp_field.F90 | 16 +++++++++++++- .../mod_cs2lonlat_interp_mesh.F90 | 8 ++++--- .../mod_cs2lonlat_interp_vcoord.F90 | 16 +++++++++----- .../util/interp/mod_interp_vcoord.F90 | 16 +++++++++----- 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 b/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 index cc58e9ca..82d35f54 100644 --- a/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 +++ b/model/atm_nonhydro3d/src/preprocess/mod_mktopo.F90 @@ -177,13 +177,18 @@ subroutine MKTOPO( output, model_mesh, topography ) end subroutine MKTOPO subroutine MKTOPO_write( model_mesh, topography ) - use scale_time, only: TIME_NOWDAYSEC + + use scale_time, only: & + NOWDATE => TIME_NOWDATE, & + NOWSUBSEC => TIME_NOWSUBSEC, & + NOWDAYSEC => TIME_NOWDAYSEC + use scale_prc, only: PRC_myrank + use scale_file_base_meshfield, only: FILE_base_meshfield use scale_mesh_rectdom2d, only: MeshRectDom2D use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D use scale_mesh_base2d, only: & MFTYPE2D_XY => MeshBase2D_DIMTYPEID_XY - use scale_prc, only: PRC_myrank implicit none class(AtmosMesh), target, intent(in) :: model_mesh @@ -192,8 +197,8 @@ subroutine MKTOPO_write( model_mesh, topography ) type(FILE_base_meshfield) :: file class(MeshBase2D), pointer :: mesh - integer :: vid logical :: file_existed + integer, parameter :: vid_topo = 1 !-------------------------------------------------- nullify( mesh ) @@ -204,13 +209,18 @@ subroutine MKTOPO_write( model_mesh, topography ) class is (MeshRectDom2D) call file%Init( 1, mesh2D=mesh ) end select - + call file%Create( OUT_BASENAME, OUT_TITLE, OUT_DTYPE, & file_existed, & myrank=PRC_myrank ) - call file%Def_Var( topography%topo, "TOPOGRAPHY", vid, MFTYPE2D_XY, 'XY' ) + + if ( .not. file_existed ) then + call file%Put_GlobalAttribute_time( NOWDATE, NOWSUBSEC ) + end if + + call file%Def_Var( topography%topo, "TOPOGRAPHY", vid_topo, MFTYPE2D_XY, 'XY' ) call file%End_def() - call file%Write_var2D(vid, topography%topo, TIME_NOWDAYSEC, TIME_NOWDAYSEC) + call file%Write_var2D( vid_topo, topography%topo, NOWDAYSEC, NOWDAYSEC ) call file%Close() call file%Final() diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 index 47631eed..03fe59ec 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 @@ -88,6 +88,8 @@ module mod_cs2lonlat_interp_field contains !OCL SERIAL subroutine interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D ) + use scale_const, only: & + EPS => CONST_EPS use scale_file_h implicit none class(MeshRectDom2D), intent(in) :: out_mesh2D @@ -154,7 +156,18 @@ subroutine interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D ) out_vinfo(nn)%dt = time_endsec - out_vinfo(nn)%start_sec out_vinfo(nn)%out_tintrv = out_tinterval(nn) + + if ( abs(out_vinfo(nn)%dt) < EPS & + .and. out_vinfo(nn)%num_step == 0 ) then + out_vinfo(nn)%num_step = 1 + out_vinfo(nn)%out_tintrv = 1 + end if + + LOG_INFO("interp_field_Init", '(3a,i4,a,i4)') & + " Regist: name=", trim(vars(nn)), ", out_nstep=", out_vinfo(nn)%num_step, & + ", out_tinterval=", out_vinfo(nn)%out_tintrv end do + call in_file%Close() call in_file%Final() @@ -358,7 +371,8 @@ subroutine interpolate_local_2D( out_val, & !--------------------------------------------- - nprc_local = size(mappingInfo%in_mesh3D_list) + nprc_local = size(mappingInfo%in_mesh2D_list) + allocate( in_val_list(nprc_local) ) do in_prc=1, nprc_local diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 index 29a98747..9e985ea4 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 @@ -512,15 +512,17 @@ subroutine NodeMappingInfo_Init_2D( this, & do i=1, in_NeX in_elem_x(:) = tile_x(1,lc_domID,prcID) + delx * dble( (/ i-1, i, i, i-1 /) ) in_elem_y(:) = tile_y(1,lc_domID,prcID) + dely * dble( (/ j-1, j-1, j, j /) ) - is_inside_elem = polygon_inpoly( out_x(1), out_y(1), & - 4, in_elem_x(:), in_elem_y(:) ) + if (i==in_NeX) then in_elem_x(2:3) = in_elem_x(2:3) + 1.0E-12_RP * delx end if if (j==in_NeY) then in_elem_y(3:4) = in_elem_y(3:4) + 1.0E-12_RP * dely end if - + + is_inside_elem = polygon_inpoly( out_x(1), out_y(1), & + 4, in_elem_x(:), in_elem_y(:) ) + if (is_inside_elem) then this%elem_i(p_h,ke_h) = i this%elem_j(p_h,ke_h) = j diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 index 3ed72dc2..5592778c 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 @@ -455,15 +455,19 @@ subroutine interp_vcoord_update_weight_core( & p_sfc_ref = p_xy p_top_ref = p_xy + (elem_ref%Nnode_v -1) * elem%Nnode_h1D**2 - if ( this%extrapolate .and. height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then - indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref - vfact(p) = 1.0_RP + if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then + if ( this%extrapolate ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + end if else if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) ) then indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref vfact(p) = 1.0_RP - else if ( this%extrapolate .and. height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then - indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref - vfact(p) = 1.0_RP + else if ( height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then + if ( this%extrapolate ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + end if else if ( height(p,ke) >= height_ref(p_top_ref,ke_top_ref) ) then indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref vfact(p) = 1.0_RP diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 b/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 index c86c8cb3..f1eaacfc 100644 --- a/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 +++ b/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 @@ -447,15 +447,19 @@ subroutine interp_vcoord_update_weight_core( & p_sfc_ref = p_xy p_top_ref = p_xy + (elem_ref%Nnode_v -1) * elem%Nnode_h1D**2 - if ( this%extrapolate .and. height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then - indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref - vfact(p) = 1.0_RP + if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then + if ( this%extrapolate ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + end if else if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) ) then indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref vfact(p) = 1.0_RP - else if ( this%extrapolate .and. height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then - indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref - vfact(p) = 1.0_RP + else if ( height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then + if ( this%extrapolate ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + end if else if ( height(p,ke) >= height_ref(p_top_ref,ke_top_ref) ) then indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref vfact(p) = 1.0_RP From 7d7384c454cb9703512a74cfa68dbfc3b6902dca Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 12 Aug 2021 22:30:39 +0900 Subject: [PATCH 74/98] Add an attribute of vertical axis to indicate the direction. --- FElib/src/file/scale_file_base_meshfield.F90 | 7 ++- .../src/file/scale_file_common_meshfield.F90 | 19 +++++--- .../src/file/scale_file_history_meshfield.F90 | 14 +++--- FElib/src/mesh/scale_mesh_base.F90 | 15 +++++-- .../test/case/Held_Suarez/cs2lonlat.cnf | 44 +++++++++++++++++++ .../case/mountain_wave_global/cs2lonlat.cnf | 14 +++++- .../mod_cs2lonlat_interp_vcoord.F90 | 39 ++++++++++++++-- 7 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 model/atm_nonhydro3d/test/case/Held_Suarez/cs2lonlat.cnf diff --git a/FElib/src/file/scale_file_base_meshfield.F90 b/FElib/src/file/scale_file_base_meshfield.F90 index 806230fd..83f7db5c 100644 --- a/FElib/src/file/scale_file_base_meshfield.F90 +++ b/FElib/src/file/scale_file_base_meshfield.F90 @@ -937,7 +937,8 @@ subroutine write_axes( this, & ! (in) use scale_const, only: & UNDEF => CONST_UNDEF use scale_file, only: & - FILE_Write_Axis + FILE_Write_Axis, & + FILE_Set_Attribute use scale_file_common_meshfield, only: & File_common_meshfield_get_axis implicit none @@ -980,6 +981,8 @@ subroutine write_axes( this, & ! (in) call FILE_Write_Axis( this%fid, this%dimsinfo(1)%name, x(:), start(1:1) ) call FILE_Write_Axis( this%fid, this%dimsinfo(2)%name, y(:), start(2:2) ) call FILE_Write_Axis( this%fid, this%dimsinfo(3)%name, z(:), start(3:3) ) + if ( this%dimsinfo(3)%positive_down(1) ) & + call FILE_Set_Attribute( this%fid, this%dimsinfo(3)%name, "positive", "down" ) end if if ( associated(this%meshCS3D) ) then @@ -989,6 +992,8 @@ subroutine write_axes( this, & ! (in) call FILE_Write_Axis( this%fid, this%dimsinfo(1)%name, x(:), start(1:1) ) call FILE_Write_Axis( this%fid, this%dimsinfo(2)%name, y(:), start(2:2) ) call FILE_Write_Axis( this%fid, this%dimsinfo(3)%name, z(:), start(3:3) ) + if ( this%dimsinfo(3)%positive_down(1) ) & + call FILE_Set_Attribute( this%fid, this%dimsinfo(3)%name, "positive", "down" ) end if return diff --git a/FElib/src/file/scale_file_common_meshfield.F90 b/FElib/src/file/scale_file_common_meshfield.F90 index 7fd8dea4..12892322 100644 --- a/FElib/src/file/scale_file_common_meshfield.F90 +++ b/FElib/src/file/scale_file_common_meshfield.F90 @@ -90,6 +90,7 @@ module scale_file_common_meshfield character(len=H_SHORT) :: unit integer :: count(3) integer :: size + logical :: positive_down(3) end type FILE_common_meshfield_diminfo public :: File_common_meshfield_get_dtype @@ -879,8 +880,9 @@ subroutine File_common_meshfield_get_dims3D( mesh3D, dimsinfo ) diminfo_y, "Y", 1, (/ diminfo_y%name /), (/ j_size /) ) diminfo_z => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_Z) - call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Z), & - diminfo_z, "Z", 1, (/ diminfo_z%name /), (/ k_size /) ) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Z), & + diminfo_z, "Z", 1, (/ diminfo_z%name /), (/ k_size /), & + positive_down=(/ dimInfo_z%positive_down /) ) diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_ZT) call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_ZT), & @@ -949,8 +951,9 @@ subroutine File_common_meshfield_get_dims3D_cubedsphere( mesh3D, dimsinfo ) diminfo_y, "Y", 1, (/ diminfo_y%name /), (/ j_size /) ) diminfo_z => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_Z) - call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Z), & - diminfo_z, "Z", 1, (/ diminfo_z%name /), (/ k_size /) ) + call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_Z), & + diminfo_z, "Z", 1, (/ diminfo_z%name /), (/ k_size /), & + positive_down=(/ dimInfo_z%positive_down /) ) diminfo => mesh3D%dimInfo(MeshBase3D_DIMTYPEID_ZT) call set_dimension( dimsinfo(MeshBase3D_DIMTYPEID_ZT), & @@ -1503,7 +1506,7 @@ subroutine get_uniform_grid1D( pos1D, Np ) return end subroutine get_uniform_grid1D - subroutine set_dimension( dim, diminfo, dim_type, ndims, dims, count ) + subroutine set_dimension( dim, diminfo, dim_type, ndims, dims, count, positive_down ) implicit none type(FILE_common_meshfield_diminfo), intent(out) :: dim @@ -1512,6 +1515,7 @@ subroutine set_dimension( dim, diminfo, dim_type, ndims, dims, count ) integer, intent(in) :: ndims character(len=*), intent(in) :: dims(ndims) integer, intent(in) :: count(ndims) + logical, intent(in), optional :: positive_down(ndims) integer :: d !---------------------------------------------------- @@ -1526,6 +1530,11 @@ subroutine set_dimension( dim, diminfo, dim_type, ndims, dims, count ) dim%dims(d) = dims(d) dim%count(d) = count(d) dim%size = dim%size * count(d) + if ( present(positive_down) ) then + dim%positive_down(d) = positive_down(d) + else + dim%positive_down(d) = .false. + end if end do return diff --git a/FElib/src/file/scale_file_history_meshfield.F90 b/FElib/src/file/scale_file_history_meshfield.F90 index a75a8c4b..70f0508f 100644 --- a/FElib/src/file/scale_file_history_meshfield.F90 +++ b/FElib/src/file/scale_file_history_meshfield.F90 @@ -506,9 +506,10 @@ subroutine set_dim_axis3D() call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) end do - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%desc, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:) ) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:) ) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%desc, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:), & + down=dimsinfo(DIMTYPE_Z)%positive_down(1) ) return end subroutine set_dim_axis3D @@ -596,9 +597,10 @@ subroutine set_dim_axis3D_cubedsphere() call FILE_HISTORY_Set_Dim ( dimsinfo(n)%type, ndim, 1, dims(1:ndim,:), zs(:), start(1:ndim,:), count(1:ndim,:)) end do - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:)) - call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%desc, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:)) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_X)%name, dimsinfo(DIMTYPE_X)%desc, dimsinfo(DIMTYPE_X)%unit, dimsinfo(DIMTYPE_X)%name, x(:) ) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Y)%name, dimsinfo(DIMTYPE_Y)%desc, dimsinfo(DIMTYPE_Y)%unit, dimsinfo(DIMTYPE_Y)%name, y(:) ) + call FILE_HISTORY_Set_Axis( dimsinfo(DIMTYPE_Z)%name, dimsinfo(DIMTYPE_Z)%desc, dimsinfo(DIMTYPE_Z)%unit, dimsinfo(DIMTYPE_Z)%name, z(:), & + down=dimsinfo(DIMTYPE_Z)%positive_down(1) ) return end subroutine set_dim_axis3D_cubedsphere diff --git a/FElib/src/mesh/scale_mesh_base.F90 b/FElib/src/mesh/scale_mesh_base.F90 index ada835b0..5c988d0d 100644 --- a/FElib/src/mesh/scale_mesh_base.F90 +++ b/FElib/src/mesh/scale_mesh_base.F90 @@ -24,6 +24,7 @@ module scale_mesh_base character(len=H_SHORT) :: name character(len=H_MID) :: desc character(len=H_SHORT) :: unit + logical :: positive_down end type MeshDimInfo type, abstract, public :: Meshbase @@ -161,19 +162,25 @@ end subroutine MeshBase_setGeometricInfo subroutine MeshBase_SetDimInfo( this, & - dimID, name, unit, desc ) + dimID, name, unit, desc, positive_down ) implicit none class(MeshBase), intent(inout) :: this - integer, intent(in) :: dimId + integer, intent(in) :: dimID character(len=*), intent(in) :: name character(len=*), intent(in) :: unit character(len=*), intent(in) :: desc + logical, intent(in), optional :: positive_down !----------------------------------------------- - this%dimInfo(dimId)%name = name - this%dimInfo(dimId)%unit = unit + this%dimInfo(dimID)%name = name + this%dimInfo(dimID)%unit = unit this%dimInfo(dimID)%desc = desc + if ( present(positive_down) ) then + this%dimInfo(dimID)%positive_down = positive_down + else + this%dimInfo(dimID)%positive_down = .false. + end if return end subroutine MeshBase_SetDimInfo diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/Held_Suarez/cs2lonlat.cnf new file mode 100644 index 00000000..e46110e7 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/cs2lonlat.cnf @@ -0,0 +1,44 @@ +&PARAM_IO + IO_LOG_BASENAME = "cs2lonlat_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "W", "Umet", "Vmet", "T", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_INTERP_MESH + !-- input ---------------- + in_Nprc = 24, + in_NeGX = 6, + in_NeGY = 6, + in_NeGZ = 4, + in_PolyOrder_h = 7, + in_PolyOrder_v = 7, + in_NLocalMeshPerPrc = 1, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + in_Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, + !-- output ---------------- + out_NprcX = 2, + out_NeX = 32, + out_NprcY = 2, + out_NeY = 16, + out_NeZ = 15, + out_PolyOrder_h =3, + out_PolyOrder_v =2, +/ +&PARAM_INTERP_VCOORD + vintrp_name = 'PRESSURE', + out_NeZ = 6, + out_PolyOrder_v = 3, + out_dom_vmin = 1000D2, + out_dom_vmax = 50D2, + out_Fz = 1000D2, 800D2, 550D2, 250D2, 100D2, 50D2, 25D2, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf index e7e39f65..9e15dee1 100644 --- a/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf @@ -30,7 +30,17 @@ out_NeX = 64, out_NprcY = 2, out_NeY = 32, - out_NeZ = 15, + out_NeZ = 6, out_PolyOrder_h =3, - out_PolyOrder_v =2, + out_PolyOrder_v =7, +/ +&PARAM_INTERP_VCOORD + vintrp_name = 'HEIGHT', + in_topofile_basename = 'oudata/topo', + topo_varname = 'topo', + out_NeZ = 6, + out_PolyOrder_v = 7, + out_dom_vmin = 0.0D0, + out_dom_vmax = 40.0D3, + out_Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, / \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 index 5592778c..d9fefd18 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 @@ -77,7 +77,7 @@ module mod_cs2lonlat_interp_vcoord integer, public, parameter :: INTERP_VCOORD_MODEL_ID = 1 integer, public, parameter :: INTERP_VCOORD_HEIGHT_ID = 2 integer, public, parameter :: INTERP_VCOORD_PRESS_ID = 3 - + integer, public, parameter :: INTERP_VCOORD_SIGMA_ID = 4 !----------------------------------------------------------------------------- ! @@ -175,6 +175,8 @@ subroutine interp_vcoord_Init( this, out_mesh3D, nodeMap_list ) this%vintrp_typeid = INTERP_VCOORD_HEIGHT_ID case( 'PRESSURE' ) this%vintrp_typeid = INTERP_VCOORD_PRESS_ID + case( 'SIGMA' ) + this%vintrp_typeid = INTERP_VCOORD_SIGMA_ID case default LOG_ERROR("interp_vcoord_Init",*) 'Not appropriate vintrp_type. Check!', vintrp_name call PRC_abort @@ -237,7 +239,12 @@ subroutine interp_vcoord_Init( this, out_mesh3D, nodeMap_list ) call this%out_mesh%Generate() if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then - call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)' ) + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)', & + positive_down = .true. ) + call this%pres%Init( "PRES", "Pa", out_mesh3D ) + else if ( this%vintrp_typeid == INTERP_VCOORD_SIGMA_ID ) then + call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'sig', '1', 'altitude (sigma coordinate)', & + positive_down = .true. ) call this%pres%Init( "PRES", "Pa", out_mesh3D ) else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then call this%out_mesh%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude (height coordinate)' ) @@ -309,7 +316,7 @@ subroutine interp_vcoord_update_weight( this, istep, out_mesh, nodeMap_list ) select case( this%vintrp_typeid ) case ( INTERP_VCOORD_MODEL_ID ) return - case ( INTERP_VCOORD_PRESS_ID ) + case ( INTERP_VCOORD_PRESS_ID, INTERP_VCOORD_SIGMA_ID ) call interp_field_Interpolate( istep, this%pres%varname, & out_mesh, this%pres, nodeMap_list ) end select @@ -392,7 +399,7 @@ subroutine interp_vcoord_update_weight_core( & class(interp_vcoord), intent(inout) :: this integer, intent(in) :: domID - class(LocalMesh3D), intent(in) :: lcmesh_ref + class(LocalMesh3D), intent(in), target :: lcmesh_ref class(ElementBase3D), intent(in) :: elem_ref class(LocalMesh3D), intent(in) :: lcmesh class(ElementBase3D), intent(in) :: elem @@ -409,6 +416,10 @@ subroutine interp_vcoord_update_weight_core( & integer :: indx_k(elem%Np,2) integer :: indx_p(elem%Np,2) real(RP) :: vfact(elem%Np) + + class(LocalMesh2D), pointer :: lcmesh2D + real(RP), allocatable :: SfcPres(:,:) + !------------------------------------------------------------- if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then @@ -422,6 +433,26 @@ subroutine interp_vcoord_update_weight_core( & height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) end do !$omp end parallel + else if ( this%vintrp_typeid == INTERP_VCOORD_SIGMA_ID ) then + lcmesh2D => lcmesh_ref%lcmesh2D + allocate( SfcPres(lcmesh2D%refElem2D%Np,lcmesh2D%NeA) ) + !$omp parallel private(ke, ke_xy) + !$omp do + do ke_xy=lcmesh2D%NeS, lcmesh2D%NeE + SfcPres(:,ke_xy) = this%pres%local(domID)%val(elem_ref%Hslice(:,1),ke_xy) + end do + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + ke_xy = lcmesh_ref%EMap3Dto2D(ke) + height_ref(:,ke) = - log( this%pres%local(domID)%val(:,ke) ) & + + log( SfcPres(elem_ref%IndexH2Dto3D(:),ke_xy) ) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + ke_xy = lcmesh%EMap3Dto2D(ke) + height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) + end do + !$omp end parallel else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then !$omp parallel !$omp do From d71155aa5da0f6c242843b52a582b2813bc884dd Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Fri, 13 Aug 2021 00:46:32 +0900 Subject: [PATCH 75/98] Modify the dependency described in Makefile for INTERP tool. --- model/atm_nonhydro3d/util/interp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/atm_nonhydro3d/util/interp/Makefile b/model/atm_nonhydro3d/util/interp/Makefile index 73fde07f..d746bf01 100644 --- a/model/atm_nonhydro3d/util/interp/Makefile +++ b/model/atm_nonhydro3d/util/interp/Makefile @@ -48,7 +48,7 @@ $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$ $(BUILD_DIR)/mod_interp_mesh.o : mod_interp_mesh.F90 $(BUILD_DIR)/mod_interp_file.o : $(BUILD_DIR)/mod_interp_field.o mod_interp_file.F90 $(BUILD_DIR)/mod_interp_field.o : $(BUILD_DIR)/mod_interp_mesh.o mod_interp_field.F90 -$(BUILD_DIR)/mod_interp_vcoord.o : $(BUILD_DIR)/mod_interp_mesh.o mod_interp_vcoord.F90 +$(BUILD_DIR)/mod_interp_vcoord.o : $(BUILD_DIR)/mod_interp_field.o $(BUILD_DIR)/mod_interp_mesh.o mod_interp_vcoord.F90 distclean: clean rm -f $(BINDIR)/$(BINNAME) From 45d9209fa8eb4b5bf3955d2b0d496e97ca671913 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Fri, 13 Aug 2021 01:08:21 +0900 Subject: [PATCH 76/98] Modify the order of libs linked to INTERP and cs2lonlat tools. --- model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile | 2 +- model/atm_nonhydro3d/util/interp/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile b/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile index bb84a0d9..0f239036 100644 --- a/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile +++ b/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile @@ -40,7 +40,7 @@ $(OBJECT): $(MODS) @mv *.mod inc/; mv *.o inc/; $(BUILD_DIR)/$(BINNAME) : $(BUILD_DIR)/prg_$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) - $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(CONTRIB_LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) diff --git a/model/atm_nonhydro3d/util/interp/Makefile b/model/atm_nonhydro3d/util/interp/Makefile index d746bf01..8877dbf8 100644 --- a/model/atm_nonhydro3d/util/interp/Makefile +++ b/model/atm_nonhydro3d/util/interp/Makefile @@ -41,7 +41,7 @@ $(OBJECT): $(MODS) @mv *.mod inc/; mv *.o inc/; $(BUILD_DIR)/$(BINNAME) : $(BUILD_DIR)/prg_$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) - $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(CONTRIB_LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) From 5a24dc95d384abc84cc7076a0d434c9b9160ee87 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 17 Aug 2021 14:17:20 +0900 Subject: [PATCH 77/98] Modify the finalization of modules to manage meshes and elements. --- FElib/src/element/scale_element_base.F90 | 53 +++++++++++-------- FElib/src/mesh/scale_mesh_base.F90 | 16 +++--- FElib/src/mesh/scale_mesh_base1d.F90 | 11 ++-- FElib/src/mesh/scale_mesh_base2d.F90 | 11 ++-- FElib/src/mesh/scale_mesh_base3d.F90 | 13 +++-- FElib/src/mesh/scale_mesh_cubedom3d.F90 | 2 +- .../src/mesh/scale_mesh_cubedspheredom3d.F90 | 4 +- 7 files changed, 63 insertions(+), 47 deletions(-) diff --git a/FElib/src/element/scale_element_base.F90 b/FElib/src/element/scale_element_base.F90 index 6ad7bb79..914e5632 100644 --- a/FElib/src/element/scale_element_base.F90 +++ b/FElib/src/element/scale_element_base.F90 @@ -137,14 +137,13 @@ subroutine ElementBase_Init( elem, lumpedmat_flag ) logical, intent(in) :: lumpedmat_flag !----------------------------------------------------------------------------- - allocate( elem%IntWeight_lgl(elem%Np) ) - allocate( elem%M(elem%Np, elem%Np) ) allocate( elem%invM(elem%Np, elem%Np) ) allocate( elem%V(elem%Np, elem%Np) ) allocate( elem%invV(elem%Np, elem%Np) ) allocate( elem%Lift(elem%Np, elem%NfpTot) ) + allocate( elem%IntWeight_lgl(elem%Np) ) allocate( elem%Filter(elem%Np, elem%Np)) elem%LumpedMatFlag = lumpedmat_flag @@ -158,13 +157,15 @@ subroutine ElementBase_Final( elem ) class(ElementBase), intent(inout) :: elem !----------------------------------------------------------------------------- - deallocate( elem%M ) - deallocate( elem%invM ) - deallocate( elem%V ) - deallocate( elem%invV ) - deallocate( elem%Lift ) - deallocate( elem%IntWeight_lgl ) - deallocate( elem%Filter ) + if ( allocated(elem%M) ) then + deallocate( elem%M ) + deallocate( elem%invM ) + deallocate( elem%V ) + deallocate( elem%invV ) + deallocate( elem%Lift ) + deallocate( elem%IntWeight_lgl ) + deallocate( elem%Filter ) + end if return end subroutine ElementBase_Final @@ -204,10 +205,12 @@ subroutine ElementBase1D_Final( elem ) class(ElementBase1D), intent(inout) :: elem !----------------------------------------------------------------------------- - deallocate( elem%x1 ) - deallocate( elem%Dx1 ) - deallocate( elem%Sx1 ) - deallocate( elem%Fmask ) + if ( allocated( elem%x1 ) ) then + deallocate( elem%x1 ) + deallocate( elem%Dx1 ) + deallocate( elem%Sx1 ) + deallocate( elem%Fmask ) + end if call ElementBase_Final( elem ) @@ -238,11 +241,13 @@ subroutine ElementBase2D_Final( elem ) class(ElementBase2D), intent(inout) :: elem !----------------------------------------------------------------------------- - deallocate( elem%x1, elem%x2 ) - deallocate( elem%Fmask ) + if ( allocated( elem%x1 ) ) then + deallocate( elem%x1, elem%x2 ) + deallocate( elem%Fmask ) - deallocate( elem%Dx1, elem%Dx2 ) - deallocate( elem%Sx1, elem%Sx2 ) + deallocate( elem%Dx1, elem%Dx2 ) + deallocate( elem%Sx1, elem%Sx2 ) + end if call ElementBase_Final( elem ) @@ -276,12 +281,14 @@ subroutine ElementBase3D_Final( elem ) class(ElementBase3D), intent(inout) :: elem !----------------------------------------------------------------------------- - deallocate( elem%x1, elem%x2, elem%x3 ) - deallocate( elem%Dx1, elem%Dx2, elem%Dx3 ) - deallocate( elem%Sx1, elem%Sx2, elem%Sx3 ) - deallocate( elem%Fmask_h, elem%Fmask_v ) - deallocate( elem%Colmask, elem%Hslice ) - deallocate( elem%IndexH2Dto3D, elem%IndexZ1Dto3D ) + if ( allocated( elem%x1 ) ) then + deallocate( elem%x1, elem%x2, elem%x3 ) + deallocate( elem%Dx1, elem%Dx2, elem%Dx3 ) + deallocate( elem%Sx1, elem%Sx2, elem%Sx3 ) + deallocate( elem%Fmask_h, elem%Fmask_v ) + deallocate( elem%Colmask, elem%Hslice ) + deallocate( elem%IndexH2Dto3D, elem%IndexZ1Dto3D ) + end if call ElementBase_Final( elem ) diff --git a/FElib/src/mesh/scale_mesh_base.F90 b/FElib/src/mesh/scale_mesh_base.F90 index 5c988d0d..ee4fc83b 100644 --- a/FElib/src/mesh/scale_mesh_base.F90 +++ b/FElib/src/mesh/scale_mesh_base.F90 @@ -120,16 +120,16 @@ end subroutine MeshBase_Init subroutine MeshBase_Final( this ) implicit none class(MeshBase), intent(inout) :: this - - integer :: n !----------------------------------------------------------------------------- - deallocate( this%tileID_globalMap ) - deallocate( this%tileFaceID_globalMap ) - deallocate( this%tilePanelID_globalMap ) - deallocate( this%tileID_global2localMap ) - deallocate( this%PRCRank_globalMap ) - deallocate( this%dimInfo ) + if ( allocated(this%tileID_globalMap) ) then + deallocate( this%tileID_globalMap ) + deallocate( this%tileFaceID_globalMap ) + deallocate( this%tilePanelID_globalMap ) + deallocate( this%tileID_global2localMap ) + deallocate( this%PRCRank_globalMap ) + deallocate( this%dimInfo ) + end if return end subroutine MeshBase_Final diff --git a/FElib/src/mesh/scale_mesh_base1d.F90 b/FElib/src/mesh/scale_mesh_base1d.F90 index 13da3c89..f8ce9ed2 100644 --- a/FElib/src/mesh/scale_mesh_base1d.F90 +++ b/FElib/src/mesh/scale_mesh_base1d.F90 @@ -134,10 +134,13 @@ subroutine Meshbase1d_Final( this ) integer :: n !----------------------------------------------------------------------------- - do n=1, this%LOCAL_MESH_NUM - call LocalMesh1D_Final( this%lcmesh_list(n), this%isGenerated ) - end do - deallocate( this%lcmesh_list ) + if ( allocated ( this%lcmesh_list ) ) then + do n=1, this%LOCAL_MESH_NUM + call LocalMesh1D_Final( this%lcmesh_list(n), this%isGenerated ) + end do + + deallocate( this%lcmesh_list ) + end if call MeshBase_Final(this) diff --git a/FElib/src/mesh/scale_mesh_base2d.F90 b/FElib/src/mesh/scale_mesh_base2d.F90 index 2213cfa5..b7a4e912 100644 --- a/FElib/src/mesh/scale_mesh_base2d.F90 +++ b/FElib/src/mesh/scale_mesh_base2d.F90 @@ -103,10 +103,13 @@ subroutine MeshBase2D_Final( this ) integer :: n !----------------------------------------------------------------------------- - do n=1, this%LOCAL_MESH_NUM - call LocalMesh2D_Final( this%lcmesh_list(n), this%isGenerated ) - end do - deallocate( this%lcmesh_list ) + if ( allocated ( this%lcmesh_list ) ) then + do n=1, this%LOCAL_MESH_NUM + call LocalMesh2D_Final( this%lcmesh_list(n), this%isGenerated ) + end do + + deallocate( this%lcmesh_list ) + end if call MeshBase_Final(this) diff --git a/FElib/src/mesh/scale_mesh_base3d.F90 b/FElib/src/mesh/scale_mesh_base3d.F90 index 1d4db1c5..96928808 100644 --- a/FElib/src/mesh/scale_mesh_base3d.F90 +++ b/FElib/src/mesh/scale_mesh_base3d.F90 @@ -118,11 +118,14 @@ subroutine MeshBase3D_Final( this ) integer :: n !----------------------------------------------------------------------------- - - do n=1, this%LOCAL_MESH_NUM - call LocalMesh3D_Final( this%lcmesh_list(n), this%isGenerated ) - end do - deallocate( this%lcmesh_list ) + + if ( allocated ( this%lcmesh_list ) ) then + do n=1, this%LOCAL_MESH_NUM + call LocalMesh3D_Final( this%lcmesh_list(n), this%isGenerated ) + end do + + deallocate( this%lcmesh_list ) + end if call MeshBase_Final(this) diff --git a/FElib/src/mesh/scale_mesh_cubedom3d.F90 b/FElib/src/mesh/scale_mesh_cubedom3d.F90 index 7541f836..7f3cf92f 100644 --- a/FElib/src/mesh/scale_mesh_cubedom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedom3d.F90 @@ -181,7 +181,7 @@ subroutine MeshCubeDom3D_Final( this ) if (this%isGenerated) then deallocate( this%rcdomIJK2LCMeshID ) else - deallocate( this%FZ ) + if ( allocated( this%FZ ) ) deallocate( this%FZ ) end if call this%mesh2D%Final() diff --git a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 index 1b194860..45097d5c 100644 --- a/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 +++ b/FElib/src/mesh/scale_mesh_cubedspheredom3d.F90 @@ -158,13 +158,13 @@ subroutine MeshCubedSphereDom3D_Final( this ) implicit none class(MeshCubedSphereDom3D), intent(inout) :: this !----------------------------------------------------------------------------- - + if (this%isGenerated) then if ( allocated(this%rcdomIJKP2LCMeshID) ) then deallocate( this%rcdomIJKP2LCMeshID ) end if else - deallocate( this%FZ ) + if ( allocated( this%FZ ) ) deallocate( this%FZ ) end if call this%mesh2D%Final() From aeb59d84f6717a4a41091d9899332c7b412609a2 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 17 Aug 2021 14:17:49 +0900 Subject: [PATCH 78/98] Add a statement to output log. --- sample/advect3dGlobal/test_advect3dGlobal.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sample/advect3dGlobal/test_advect3dGlobal.f90 b/sample/advect3dGlobal/test_advect3dGlobal.f90 index 4208a04c..488eb672 100644 --- a/sample/advect3dGlobal/test_advect3dGlobal.f90 +++ b/sample/advect3dGlobal/test_advect3dGlobal.f90 @@ -105,7 +105,7 @@ program test_advect3dGlobal call init() call set_initcond() - + prgvars_comm_vars(1)%field3d => q auxvars_comm_vars(1)%field3d => W auxvars_comm_vars(2)%field3d => U @@ -175,6 +175,7 @@ program test_advect3dGlobal call FILE_HISTORY_meshfield_put(HST_ID(7), Vellat) call FILE_HISTORY_meshfield_write() + if( IO_L ) call flush(IO_FID_LOG) end do call final() From 1c877a34aceebc0d2a1510e5e6048e163fa08b4c Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 17 Aug 2021 14:19:02 +0900 Subject: [PATCH 79/98] Add some modules for a regrid_tool. --- .../atm_nonhydro3d/util/regrid_tool/Makefile | 73 ++ .../util/regrid_tool/mod_regrid_mesh.F90 | 113 +++ .../util/regrid_tool/mod_regrid_mesh_base.F90 | 667 ++++++++++++++++++ .../util/regrid_tool/mod_regrid_nodemap.F90 | 392 ++++++++++ .../util/regrid_tool/prg_regrid_tool.F90 | 228 ++++++ .../util/regrid_tool/regrid.conf | 35 + 6 files changed, 1508 insertions(+) create mode 100644 model/atm_nonhydro3d/util/regrid_tool/Makefile create mode 100644 model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 create mode 100644 model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 create mode 100644 model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 create mode 100644 model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 create mode 100644 model/atm_nonhydro3d/util/regrid_tool/regrid.conf diff --git a/model/atm_nonhydro3d/util/regrid_tool/Makefile b/model/atm_nonhydro3d/util/regrid_tool/Makefile new file mode 100644 index 00000000..9358364f --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/Makefile @@ -0,0 +1,73 @@ +################################################################################ +# +# Makefile +# +################################################################################ + +TOPDIR = $(abspath ../../../..) +BUILD_DIR = ./.libs +SYSDEP_DIR = ../../../../sysdep + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + +BINNAME = regrid_tool + +LIBS = $(LIBDIR)/libScaleFECore.a + +VPATH = plugin: + +OBJS = \ + mod_regrid_mesh.o \ + mod_regrid_mesh_base.o \ + mod_regrid_nodemap.o + + +all: + $(MAKE) build + $(MAKE) install + +build: + mkdir -p $(BUILD_DIR) + $(MAKE) $(BUILD_DIR)/$(BINNAME) + +install: + mkdir -p $(BINDIR) + $(INSTALL) $(BUILD_DIR)/$(BINNAME) $(BINDIR)/$(BINNAME) + +$(OBJECT): $(MODS) + $(FC) $(FFLAGS) -o $@ $^ $(LIBS) + @mv *.mod inc/; mv *.o inc/; + +$(BUILD_DIR)/$(BINNAME) : $(BUILD_DIR)/prg_$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(CONTRIB_LIBS) + +$(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) + +$(BUILD_DIR)/mod_regrid_mesh.o : $(BUILD_DIR)/mod_regrid_nodemap.o $(BUILD_DIR)/mod_regrid_mesh_base.o mod_regrid_mesh.F90 +$(BUILD_DIR)/mod_regrid_nodemap.o : $(BUILD_DIR)/mod_regrid_mesh_base.o mod_regrid_nodemap.F90 +$(BUILD_DIR)/mod_regrid_mesh_base.o : mod_regrid_mesh_base.F90 +$(BUILD_DIR)/mod_regrid_file.o : $(BUILD_DIR)/mod_regrid_field.o mod_regrid_file.F90 +$(BUILD_DIR)/mod_regrid_field.o : $(BUILD_DIR)/mod_regrid_mesh.o mod_regrid_field.F90 +$(BUILD_DIR)/mod_regrid_vcoord.o : $(BUILD_DIR)/mod_regrid_mesh.o mod_regrid_vcoord.F90 + +distclean: clean + rm -f $(BINDIR)/$(BINNAME) + +clean: + rm -rf $(BUILD_DIR) + + + +.SUFFIXES: +.SUFFIXES: .o .F90 .mod + +%.mod: %.F90 + make $(patsubst %.F90,%.o,$<) + +$(BUILD_DIR)/%.o : %.F90 + $(FC) $(FFLAGS) $(ADDITIONAL_FFLAGS) -DVERSION_MACRO=\"$(VERSION)\" -I$(BUILD_DIR) -I$(MODDIR) -I../include $(CONTRIB_INCLUDE) -I$(SCALEFELIBDIR)/include -I$(SAMPLE_AUX_INCLUDE) $(SCALE_NETCDF_INCLUDE) $(MODDIROPT) $(BUILD_DIR) -o $@ -c $< + +.PHONY : clean distclean allclean + +include $(TOPDIR)/utils/make/Make_environments diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 new file mode 100644 index 00000000..c0ce1d35 --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 @@ -0,0 +1,113 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_regrid_mesh + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use scale_const, only: & + PI => CONST_PI, & + RPlanet => CONST_radius + + use scale_localmesh_base, only: LocalMeshBase + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + + use mod_regrid_mesh_base, only: & + regrid_mesh_base, & + MESHIN_ID => REGRID_MESH_BASE_IN_ID, & + MESHOUT_ID => REGRID_MESH_BASE_IN_ID + + use mod_regrid_nodemap, only: & + regrid_nodemap + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + public :: regrid_mesh_Init + public :: regrid_mesh_Final + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + type(regrid_mesh_base), public :: out_mesh + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type(regrid_nodemap), allocatable :: nodemap(:) + + +contains + subroutine regrid_mesh_Init() + implicit none + + character(len=H_MID) :: in_meshType + character(len=H_MID) :: out_meshType + + namelist / PARAM_REGRID_MESH / & + in_MeshType, & + out_MeshType + + integer :: ierr + integer :: n + !------------------------------- + + LOG_NEWLINE + LOG_INFO("regrid_mesh",*) 'Setup' + + !--- read namelist (PARAM_REGRID_MESH) + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_REGRID_MESH,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh",*) 'Not appropriate names in namelist PARAM_REGRID_MESH. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_MESH) + + !-- + call out_mesh%Init( MESHOUT_ID, out_meshType ) + call out_mesh%Generate() + + !-- + + allocate( nodemap( out_mesh%NLocalMeshPerPRC ) ) + do n=1, size(nodemap) + call nodemap(n)%Init(in_meshType) + end do + + return + end subroutine regrid_mesh_Init + + subroutine regrid_mesh_Final() + implicit none + + integer :: n + !------------------------------- + + call out_mesh%Final() + + do n=1, size(nodemap) + call nodemap(n)%Final() + end do + deallocate( nodemap ) + + return + end subroutine regrid_mesh_Final + +end module mod_regrid_mesh diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 new file mode 100644 index 00000000..e6bcaeae --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 @@ -0,0 +1,667 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_regrid_mesh_base + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use scale_const, only: & + UNDEF => CONST_UNDEF, & + PI => CONST_PI, & + RPlanet => CONST_radius + + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom2d, only: & + MeshCubedSphereDom2D, & + MeshCubedSphereDom2D_check_division_params + use scale_mesh_cubedspheredom3d, only: & + MeshCubedSphereDom3D + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + type, public :: regrid_mesh_base + integer :: NprcX + integer :: NprcY + integer :: NprcZ + integer :: Nprc + real(RP) :: dom_xmin + real(RP) :: dom_xmax + real(RP) :: dom_ymin + real(RP) :: dom_ymax + real(RP) :: dom_zmin + real(RP) :: dom_zmax + logical :: isPeriodicX = .false. + logical :: isPeriodicY = .false. + logical :: isPeriodicZ = .false. + integer :: NLocalMeshPerPRC + + integer :: NeX + integer :: NeY + integer :: NeZ + integer :: NeGX + integer :: NeGY + integer :: NeGZ + + integer :: polyorder_h + integer :: polyorder_v + + type(QuadrilateralElement) :: elem2D + type(HexahedralElement) :: elem3D + + type(MeshRectDom2D) :: mesh2D + type(MeshCubeDom3D) :: mesh3D + type(MeshCubedSphereDom2D) :: csmesh2D + type(MeshCubedSphereDom3D) :: csmesh3D + + class(MeshBase2D), pointer :: ptr_mesh2D + class(MeshBase3D), pointer :: ptr_mesh3D + + integer :: inout_id + integer :: mesh_type_id + + real(RP), allocatable :: FZ(:) + contains + procedure :: Init => regrid_mesh_base_init + procedure :: Final => regrid_mesh_base_final + procedure :: Generate => regrid_mesh_base_generate + end type regrid_mesh_base + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + integer, public, parameter :: REGRID_MESH_BASE_IN_ID = 1 + integer, public, parameter :: REGRID_MESH_BASE_OUT_ID = 2 + + integer, public, parameter :: REGRID_MESHTYPE_STRUCTURED2D_ID = 1 + integer, public, parameter :: REGRID_MESHTYPE_CUBEDSPHERE2D_ID = 2 + integer, public, parameter :: REGRID_MESHTYPE_LONLAT2D_ID = 3 + integer, public, parameter :: REGRID_MESHTYPE_STRUCTURED3D_ID = 4 + integer, public, parameter :: REGRID_MESHTYPE_CUBEDSPHERE3D_ID = 5 + integer, public, parameter :: REGRID_MESHTYPE_LONLAT3D_ID = 6 + +contains + +!OCL SERIAL + subroutine regrid_mesh_base_init( this, & ! (inout) + mesh_inout_id, mesh_type_name ) ! (in) + + implicit none + class(regrid_mesh_base), intent(inout) :: this + integer, intent(in) :: mesh_inout_id + character(len=*), intent(in) :: mesh_type_name + !---------------------------------------- + + select case( mesh_inout_id ) + case ( REGRID_MESH_BASE_IN_ID, REGRID_MESH_BASE_OUT_ID ) + this%inout_id = mesh_inout_id + case default + LOG_ERROR("regrid_mesh_base",*) 'Not appropriate inout id of mesh. Check!' + call PRC_abort + end select + + select case(trim(mesh_type_name)) + case( "STRUCTURED2D" ) + this%mesh_type_id = REGRID_MESHTYPE_STRUCTURED2D_ID + call regrid_mesh_base_init_mesh2D( this ) + case( "STRUCTURED3D" ) + this%mesh_type_id = REGRID_MESHTYPE_STRUCTURED3D_ID + call regrid_mesh_base_init_mesh3D( this ) + case( "LONLAT2D" ) + this%mesh_type_id = REGRID_MESHTYPE_LONLAT2D_ID + call regrid_mesh_base_init_mesh2D( this ) + case( "LONLAT3D" ) + this%mesh_type_id = REGRID_MESHTYPE_LONLAT3D_ID + call regrid_mesh_base_init_mesh3D( this ) + case( "CUBEDSPHERE2D" ) + this%mesh_type_id = REGRID_MESHTYPE_CUBEDSPHERE2D_ID + call regrid_mesh_base_init_csmesh2D( this ) + case( "CUBEDSPHERE3D" ) + this%mesh_type_id = REGRID_MESHTYPE_CUBEDSPHERE3D_ID + call regrid_mesh_base_init_csmesh3D( this ) + case default + LOG_ERROR("regrid_mesh_base",*) 'Not supported type of mesh. Check! ', trim(mesh_type_name) + call PRC_abort + end select + + nullify( this%ptr_mesh2D, this%ptr_mesh3D ) + + return + end subroutine regrid_mesh_base_init + +!OCL SERIAL + subroutine regrid_mesh_base_final( this ) + implicit none + class(regrid_mesh_base), intent(inout) :: this + !---------------------------------------- + + select case( this%mesh_type_id ) + case( REGRID_MESHTYPE_STRUCTURED2D_ID, REGRID_MESHTYPE_LONLAT2D_ID ) + call this%mesh2D%Final() + case( REGRID_MESHTYPE_STRUCTURED3D_ID, REGRID_MESHTYPE_LONLAT3D_ID ) + call this%mesh3D%Final() + case( REGRID_MESHTYPE_CUBEDSPHERE2D_ID ) + call this%csmesh2D%Final() + case( REGRID_MESHTYPE_CUBEDSPHERE3D_ID ) + call this%csmesh3D%Final() + end select + + if ( allocated(this%FZ) ) then + deallocate( this%FZ ) + end if + + return + end subroutine regrid_mesh_base_final + +!OCL SERIAL + subroutine regrid_mesh_base_generate( this ) + + use scale_mesh_base2d, only: & + MeshBase2D_DIMTYPEID_X, MeshBase2D_DIMTYPEID_Y, & + MeshBase2D_DIMTYPEID_XY, MeshBase2D_DIMTYPEID_XYT + use scale_mesh_base3d, only: & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_XYZT + + implicit none + class(regrid_mesh_base), intent(inout), target :: this + !----------------------------------------------- + + select case( this%mesh_type_id ) + case( REGRID_MESHTYPE_STRUCTURED2D_ID ) + + call this%mesh2D%Init( this%NeGX, this%NeGY, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, & + this%isPeriodicX, this%isPeriodicY, this%elem2D, this%NLocalMeshPerPrc, & + this%NprcX, this%NprcY ) + + this%ptr_mesh2D => this%mesh2D + + case( REGRID_MESHTYPE_LONLAT2D_ID ) + + call this%mesh2D%Init( this%NeGX, this%NeGY, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, & + this%isPeriodicX, .false., this%elem2D, this%NLocalMeshPerPrc, & + this%NprcX, this%NprcY ) + + call this%mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call this%mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call this%mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XY, 'lonlat', 'degree', 'longitude,latitude' ) + call this%mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_XYT, 'lonlatt', 'degree', 'longitude,latitude' ) + + this%ptr_mesh2D => this%mesh2D + + case( REGRID_MESHTYPE_STRUCTURED3D_ID ) + + if ( allocated( this%FZ ) ) then + call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & + this%isPeriodicX, this%isPeriodicY, this%isPeriodicY, this%elem3D, this%NLocalMeshPerPrc, & + this%NprcX, this%NprcY, nproc=this%Nprc, FZ=this%FZ ) + else + call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & + this%isPeriodicX, .false., .false., this%elem3D, this%NLocalMeshPerPrc, & + this%NprcX, this%NprcY, nproc=this%Nprc ) + end if + + this%ptr_mesh3D => this%mesh3D + + case( REGRID_MESHTYPE_LONLAT3D_ID ) + + if ( allocated( this%FZ ) ) then + call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & + this%isPeriodicX, .false., .false., this%elem3D, this%NLocalMeshPerPrc, & + this%NprcX, this%NprcY, nproc=this%Nprc, FZ=this%FZ ) + else + call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & + this%isPeriodicX, .false., .false., this%elem3D, this%NLocalMeshPerPrc, & + this%NprcX, this%NprcY, nproc=this%Nprc ) + end if + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatz', '', 'longitude,latitude,altitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzt', '', 'longitude,latitude,altitude' ) + + this%ptr_mesh3D => this%mesh3D + + case( REGRID_MESHTYPE_CUBEDSPHERE2D_ID ) + + call this%csmesh2D%Init( this%NeGX, this%NeGY, RPlanet, & + this%elem2D, this%NLocalMeshPerPrc, nproc=this%Nprc ) + + this%ptr_mesh2D => this%csmesh2D + + case( REGRID_MESHTYPE_CUBEDSPHERE3D_ID ) + + if ( allocated( this%FZ ) ) then + call this%csmesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, RPlanet, & + this%dom_zmin, this%dom_zmax, this%elem3D, this%NLocalMeshPerPrc, & + nproc=this%Nprc, FZ=this%FZ ) + else + call this%csmesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, RPlanet, & + this%dom_zmin, this%dom_zmax, this%elem3D, this%NLocalMeshPerPrc, & + nproc=this%Nprc ) + end if + + this%ptr_mesh3D => this%csmesh3D + + end select + + return + end subroutine regrid_mesh_base_generate + + !-- private -------------------------------- + +!OCL SERIAL + subroutine regrid_mesh_base_init_mesh2D( this ) + + implicit none + class(regrid_mesh_base), intent(inout) :: this + + ! Structured mesh + integer :: NprcX = 1 + integer :: NprcY = 1 + integer :: NeX = 1 + integer :: NeY = 1 + real(RP) :: dom_xmin = 0.0_RP + real(RP) :: dom_xmax = 0.0_RP + real(RP) :: dom_ymin = 0.0_RP + real(RP) :: dom_ymax = 0.0_RP + logical :: isPeriodicX = .false. + logical :: isPeriodicY = .false. + integer :: NLocalMeshPerPrc = 1 + + integer :: PolyOrder_h = 1 + + namelist / PARAM_REGRID_INMESH2D_STRUCTURED / & + NprcX, NprcY, NeX, NeY, NLocalMeshPerPrc, & + dom_xmin, dom_xmax, dom_ymin, dom_ymax, & + PolyOrder_h, isPeriodicX, isPeriodicY + + namelist / PARAM_REGRID_OUTMESH2D_STRUCTURED / & + NprcX, NprcY, NeX, NeY, NLocalMeshPerPrc, & + dom_xmin, dom_xmax, dom_ymin, dom_ymax, & + PolyOrder_h, isPeriodicX, isPeriodicY + + integer :: ierr + !---------------------------------------- + + rewind(IO_FID_CONF) + + if (this%inout_id == REGRID_MESH_BASE_IN_ID) then + + read(IO_FID_CONF,nml=PARAM_REGRID_INMESH2D_STRUCTURED,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init2D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init2D",*) 'Not appropriate names in namelist PARAM_REGRID_INMESH2D_STRUCTURED. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_INMESH2D_STRUCTURED) + + else if (this%inout_id == REGRID_MESH_BASE_OUT_ID ) then + + read(IO_FID_CONF,nml=PARAM_REGRID_OUTMESH2D_STRUCTURED,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init2D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init2D",*) 'Not appropriate names in namelist PARAM_REGRID_OUTMESH2D_STRUCTURED. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_OUTMESH2D_STRUCTURED) + + end if + + this%NprcX = NprcX + this%NprcY = NprcY + this%Nprc = NprcX * NprcY + + this%NeX = NeX + this%NeY = NeY + this%NeGX = NeX * NprcX + this%NeGY = NeY * NprcY + this%NLocalMeshPerPRC = NLocalMeshPerPrc + + this%dom_xmin = dom_xmin + this%dom_xmax = dom_xmax + this%dom_ymin = dom_ymin + this%dom_ymax = dom_ymax + + this%polyorder_h = PolyOrder_h + + this%isPeriodicX = isPeriodicX + this%isPeriodicY = isPeriodicY + + call this%elem2D%Init( PolyOrder_h, .true. ) + + return + end subroutine regrid_mesh_base_init_mesh2D + +!OCL SERIAL + subroutine regrid_mesh_base_init_csmesh2D( this ) + implicit none + + class(regrid_mesh_base), intent(inout) :: this + + ! Structured mesh + integer :: Nprc = 1 + integer :: NeGX = 1 + integer :: NeGY = 1 + integer :: NLocalMeshPerPrc = 1 + + integer :: PolyOrder_h = 1 + + namelist / PARAM_REGRID_INMESH2D_CUBEDSPHERE / & + Nprc, NeGX, NeGY, NLocalMeshPerPrc, & + PolyOrder_h + + namelist / PARAM_REGRID_OUTMESH2D_CUBEDSPHERE / & + Nprc, NeGX, NeGY, NLocalMeshPerPrc, & + PolyOrder_h + + integer :: ierr + + type(MeshCubedSphereDom2D) :: csmesh2D_dummy + !---------------------------------------- + + rewind(IO_FID_CONF) + + if (this%inout_id == REGRID_MESH_BASE_IN_ID) then + + read(IO_FID_CONF,nml=PARAM_REGRID_INMESH2D_CUBEDSPHERE,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init2D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init2D",*) 'Not appropriate names in namelist PARAM_REGRID_INMESH2D_CUBEDSPHERE. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_INMESH2D_CUBEDSPHERE) + + else if (this%inout_id == REGRID_MESH_BASE_OUT_ID ) then + + read(IO_FID_CONF,nml=PARAM_REGRID_OUTMESH2D_CUBEDSPHERE,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init2D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init2D",*) 'Not appropriate names in namelist PARAM_REGRID_OUTMESH2D_CUBEDSPHERE. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_OUTMESH2D_CUBEDSPHERE) + + end if + + this%Nprc = Nprc + + this%NeGX = NeGX + this%NeGY = NeGY + this%NLocalMeshPerPRC = NLocalMeshPerPrc + + this%polyorder_h = PolyOrder_h + + call this%elem2D%Init( PolyOrder_h, .true. ) + + call csmesh2D_dummy%Init( NeGX, NeGY, RPlanet, & + this%elem2D, NLocalMeshPerPrc, nproc=Nprc, myrank=0 ) + + call MeshCubedSphereDom2D_check_division_params( & + this%NprcX, this%NprcY, & ! (out) + Nprc, NLocalMeshPerPrc * Nprc ) ! (in) + + this%NeX = NeGX / this%NprcX + this%NeY = NeGY / this%NprcY + + call csmesh2D_dummy%Final() + + return + end subroutine regrid_mesh_base_init_csmesh2D + +!OCL SERIAL + subroutine regrid_mesh_base_init_mesh3D( this ) + + implicit none + + class(regrid_mesh_base), intent(inout) :: this + + ! Structured mesh + integer :: NprcX = 1 + integer :: NprcY = 1 + integer :: NprcZ = 1 + integer :: NeX = 1 + integer :: NeY = 1 + integer :: NeGZ = 1 + real(RP) :: dom_xmin = 0.0_RP + real(RP) :: dom_xmax = 0.0_RP + real(RP) :: dom_ymin = 0.0_RP + real(RP) :: dom_ymax = 0.0_RP + real(RP) :: dom_zmin = 0.0_RP + real(RP) :: dom_zmax = 0.0_RP + logical :: isPeriodicX = .false. + logical :: isPeriodicY = .false. + logical :: isPeriodicZ = .false. + integer :: NLocalMeshPerPrc = 1 + + integer :: PolyOrder_h = 1 + integer :: PolyOrder_v = 1 + + logical :: is_spec_FZ + integer, parameter :: FZ_nmax = 1000 + real(RP) :: FZ(FZ_nmax) + + namelist / PARAM_REGRID_INMESH3D_STRUCTURED / & + NprcX, NprcY, NprcZ, NeX, NeY, NeGZ, NLocalMeshPerPrc, & + dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + PolyOrder_h, PolyOrder_v, isPeriodicX, isPeriodicY, isPeriodicZ, & + is_spec_FZ, FZ + + namelist / PARAM_REGRID_OUTMESH3D_STRUCTURED / & + NprcX, NprcY, NprcZ, NeX, NeY, NeGZ, NLocalMeshPerPrc, & + dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & + PolyOrder_h, PolyOrder_v, isPeriodicX, isPeriodicY, isPeriodicZ, & + is_spec_FZ, FZ + + integer :: ierr + integer :: k + !---------------------------------------- + + is_spec_FZ = .false. + NeGZ = -1 + FZ(:) = UNDEF + + rewind(IO_FID_CONF) + + if (this%inout_id == REGRID_MESH_BASE_IN_ID) then + + read(IO_FID_CONF,nml=PARAM_REGRID_INMESH3D_STRUCTURED,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init3D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init3D",*) 'Not appropriate names in namelist PARAM_REGRID_INMESH3D_STRUCTURED. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_INMESH3D_STRUCTURED) + + else if (this%inout_id == REGRID_MESH_BASE_OUT_ID ) then + + read(IO_FID_CONF,nml=PARAM_REGRID_OUTMESH3D_STRUCTURED,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init3D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init3D",*) 'Not appropriate names in namelist PARAM_REGRID_OUTMESH3D_STRUCTURED. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_OUTMESH3D_STRUCTURED) + + end if + + this%NprcX = NprcX + this%NprcY = NprcY + this%NprcZ = NprcZ + this%Nprc = NprcX * NprcY * NprcZ + + this%NeX = NeX + this%NeY = NeY + this%NeZ = NeGZ / NprcZ + this%NeGX = NeX * NprcX + this%NeGY = NeY * NprcY + this%NeGZ = NeGZ + this%NLocalMeshPerPRC = NLocalMeshPerPrc + + this%dom_xmin = dom_xmin + this%dom_xmax = dom_xmax + this%dom_ymin = dom_ymin + this%dom_ymax = dom_ymax + this%dom_zmin = dom_zmin + this%dom_zmax = dom_zmax + + this%polyorder_h = PolyOrder_h + this%polyorder_v = PolyOrder_v + + this%isPeriodicX = isPeriodicX + this%isPeriodicY = isPeriodicY + this%isPeriodicZ = isPeriodicZ + + call this%elem2D%Init( PolyOrder_h, .true. ) + call this%elem3D%Init( PolyOrder_h, PolyOrder_v, .true. ) + + is_spec_FZ = .true. + do k=1, NeGZ+1 + if ( FZ(k) == UNDEF ) then + is_spec_FZ = .false.; exit + end if + end do + if ( is_spec_FZ ) then + allocate( this%FZ(1:NeGZ+1) ) + this%FZ(:) = FZ(1:NeGZ+1) + end if + + return + end subroutine regrid_mesh_base_init_mesh3D + +!OCL SERIAL + subroutine regrid_mesh_base_init_csmesh3D( this ) + implicit none + + class(regrid_mesh_base), intent(inout) :: this + + ! Structured mesh + integer :: Nprc = 1 + integer :: NeGX = 1 + integer :: NeGY = 1 + integer :: NeGZ = 1 + integer :: NLocalMeshPerPrc = 1 + + integer :: PolyOrder_h = 1 + integer :: PolyOrder_v = 1 + + logical :: is_spec_FZ + integer, parameter :: FZ_nmax = 1000 + real(RP) :: FZ(FZ_nmax) + + namelist / PARAM_REGRID_INMESH3D_CUBEDSPHERE / & + Nprc, NeGX, NeGY, NeGZ, NLocalMeshPerPrc, & + PolyOrder_h, PolyOrder_v, & + is_spec_FZ, FZ + + namelist / PARAM_REGRID_OUTMESH3D_CUBEDSPHERE / & + Nprc, NeGX, NeGY, NeGZ, NLocalMeshPerPrc, & + PolyOrder_h, PolyOrder_v, & + is_spec_FZ, FZ + + integer :: ierr + integer :: k + + type(MeshCubedSphereDom2D) :: csmesh2D_dummy + !---------------------------------------- + + is_spec_FZ = .false. + NeGZ = -1 + FZ(:) = UNDEF + + rewind(IO_FID_CONF) + + if (this%inout_id == REGRID_MESH_BASE_IN_ID) then + + read(IO_FID_CONF,nml=PARAM_REGRID_INMESH3D_CUBEDSPHERE,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init3D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init3D",*) 'Not appropriate names in namelist PARAM_REGRID_INMESH3D_CUBEDSPHERE. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_INMESH3D_CUBEDSPHERE) + + else if (this%inout_id == REGRID_MESH_BASE_OUT_ID ) then + + read(IO_FID_CONF,nml=PARAM_REGRID_OUTMESH3D_CUBEDSPHERE,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_mesh_base_init3D",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_mesh_base_init3D",*) 'Not appropriate names in namelist PARAM_REGRID_OUTMESH3D_CUBEDSPHERE. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_OUTMESH3D_CUBEDSPHERE) + + end if + + this%Nprc = Nprc + this%NprcZ = 1 + + this%NeGX = NeGX + this%NeGY = NeGY + this%NeZ = NeGZ / this%NprcZ + this%NLocalMeshPerPRC = NLocalMeshPerPrc + + this%polyorder_h = PolyOrder_h + this%polyorder_v = PolyOrder_v + + call this%elem2D%Init( PolyOrder_h, .true. ) + call this%elem3D%Init( PolyOrder_h, PolyOrder_v, .true. ) + + call csmesh2D_dummy%Init( NeGX, NeGY, RPlanet, & + this%elem2D, NLocalMeshPerPrc, nproc=Nprc, myrank=0 ) + + call MeshCubedSphereDom2D_check_division_params( & + this%NprcX, this%NprcY, & ! (out) + Nprc, NLocalMeshPerPrc * Nprc ) ! (in) + + this%NeX = NeGX / this%NprcX + this%NeY = NeGY / this%NprcY + call csmesh2D_dummy%Final() + + is_spec_FZ = .true. + do k=1, NeGZ+1 + if ( FZ(k) == UNDEF ) then + is_spec_FZ = .false.; exit + end if + end do + if ( is_spec_FZ ) then + allocate( this%FZ(1:NeGZ+1) ) + this%FZ(:) = FZ(1:NeGZ+1) + end if + + return + end subroutine regrid_mesh_base_init_csmesh3D + +end module mod_regrid_mesh_base diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 new file mode 100644 index 00000000..1d919715 --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 @@ -0,0 +1,392 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_regrid_nodemap + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + use scale_const, only: & + PI => CONST_PI + + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + + use mod_regrid_mesh_base, only: & + regrid_mesh_base, & + MESH_INID => REGRID_MESH_BASE_IN_ID, & + REGRID_MESHTYPE_CUBEDSPHERE2D_ID, & + REGRID_MESHTYPE_CUBEDSPHERE3D_ID, & + REGRID_MESHTYPE_LONLAT2D_ID, & + REGRID_MESHTYPE_LONLAT3D_ID + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + type, public :: regrid_nodemap + integer, allocatable :: local_domID(:,:) + integer, allocatable :: lcprc(:,:) + integer, allocatable :: inPanelID(:,:) + integer, allocatable :: elem_i(:,:) + integer, allocatable :: elem_j(:,:) + integer, allocatable :: elem_k(:,:) + real(RP), allocatable :: elem_x(:,:) + real(RP), allocatable :: elem_y(:,:) + real(RP), allocatable :: elem_z(:,:) + + type(regrid_mesh_base), allocatable :: in_mesh_list(:) + integer, allocatable :: in_tileID_list(:) + contains + procedure :: Init => Nodemap_Init + procedure :: Final => Nodemap_Final + end type + +contains +!OCL SERIAL + subroutine NodeMap_Init( this, & + inmesh_type, out_mesh ) + implicit none + class(regrid_nodemap), intent(inout) :: this + character(len=*), intent(in) :: inmesh_type + class(regrid_mesh_base), intent(in), target :: out_mesh + + type(regrid_mesh_base) :: inmesh_dummy + + integer :: n + class(LocalMesh2D), pointer :: lcmesh2D + !------------------------------------ + + call inmesh_dummy%Init( MESH_INID, inmesh_type ) + + if ( associated(out_mesh%ptr_mesh2D ) ) then + do n=1, out_mesh%ptr_mesh2D%LOCAL_MESH_NUM + lcmesh2D => out_mesh%ptr_mesh2D%lcmesh_list(n) + call NodeMap_construct_nodemap_2D( this, & + inmesh_dummy%mesh_type_id, out_mesh%mesh_type_id, & + lcmesh2D%refElem2D%Nfp, lcmesh2D%NeX * lcmesh2D%NeY, lcmesh2D, & + inmesh_dummy%Nprc, inmesh_dummy%NprcX, inmesh_dummy%NprcY, & + inmesh_dummy%NeX, inmesh_dummy%NeY, inmesh_dummy%NLocalMeshPerPRC ) + end do + + end if + if ( associated(out_mesh%ptr_mesh3D ) ) then + end if + + call inmesh_dummy%Final() + + return + end subroutine NodeMap_Init + +!OCL SERIAL + subroutine NodeMap_Final( this ) + implicit none + class(regrid_nodemap), intent(inout) :: this + !------------------------------------ + + return + end subroutine NodeMap_Final + +!-- private ----------------- + +!OCL SERIAL + subroutine NodeMap_construct_nodemap_2D( this, & + in_meshtype_id, out_meshtype_id, & + Np1D, Ne2D, lcmesh, & + in_Nprc, in_NprcX, in_NprcY, in_NeX, in_NeY, & + in_NLocalMeshPerPrc ) + + use scale_polygon, only: & + polygon_inpoly + + implicit none + + class(regrid_nodemap), intent(inout) :: this + integer, intent(in) :: Np1D + integer, intent(in) :: Ne2D + class(LocalMesh2D), intent(in) :: lcmesh + integer, intent(in) :: in_meshtype_id + integer, intent(in) :: out_meshtype_id + integer, intent(in) :: in_Nprc + integer, intent(in) :: in_NprcX + integer, intent(in) :: in_NprcY + integer, intent(in) :: in_NeX + integer, intent(in) :: in_NeY + integer, intent(in) :: in_NLocalMeshPerPrc + + real(RP) :: tile_x(4,in_NLocalMeshPerPrc,in_Nprc) + real(RP) :: tile_y(4,in_NLocalMeshPerPrc,in_Nprc) + integer :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) + integer :: panelID_table(in_NLocalMeshPerPrc,in_Nprc) + + integer :: lc_domID, prcID, in_prc, in_n + integer :: i, j + integer :: p, ke + integer :: ke_h + integer :: p_h, p_h_x, p_h_y + integer :: ke_z, ke_z2, p_z, p_z2 + logical :: is_inside_tile(Np1D**2) + logical :: is_inside_elem + real(RP) :: in_elem_x(4) + real(RP) :: in_elem_y(4) + real(RP) :: delx, dely + logical :: target_tile_flag(in_NLocalMeshPerPrc,in_Nprc) + logical :: target_prc_flag(in_Nprc) + integer :: in_tileID_tmp(in_NLocalMeshPerPrc*in_Nprc) + integer :: in_prc2lcprc_tmp(in_Nprc) + integer :: in_lcprc2prc_tmp(in_Nprc) + integer :: in_tile_num + integer :: in_prc_num + type(LocalMesh2D), pointer :: in_lcmesh + + real(RP), allocatable :: out_x(:,:) + real(RP), allocatable :: out_y(:,:) + + integer :: out_panel + real(RP) :: out_x0, del_x + real(RP) :: out_y0, del_y + + integer :: Np2D + !----------------------------------------------------------------- + + Np2D = Np1D**2 + allocate( this%local_domID(Np2D, Ne2D) ) + allocate( this%lcprc(Np2D, Ne2D) ) + allocate( this%inPanelID(Np2D, Ne2D) ) + allocate( this%elem_i(Np2D, Ne2D) ) + allocate( this%elem_j(Np2D, Ne2D) ) + allocate( this%elem_x(Np2D, Ne2D) ) + allocate( this%elem_y(Np2D, Ne2D) ) + + allocate( out_x(Np2D,Ne2D), out_y(Np2D,Ne2D) ) + + target_tile_flag(:,:) = .false. + target_prc_flag(:) = .false. + in_lcprc2prc_tmp(:) = -1 + in_prc2lcprc_tmp(:) = -1 + + call get_panelID( this%inPanelID, & ! (out) + in_meshtype_id, out_meshtype_id, & ! (in) + Np1D, Ne2D, lcmesh ) ! (in) + + call get_out_xy( out_x, out_y, & ! (out) + in_meshtype_id, out_meshtype_id, & ! (in) + this%inPanelID, & ! (in) + Np1D, Ne2D, lcmesh ) ! (in) + + in_tile_num = 0 + in_prc_num = 0 + do ke_h=1, Ne2D + + do p_h_y=1, Np1D + do p_h_x=1, Np1D + p_h = p_h_x + (p_h_y-1)*Np1D + + this%local_domID(p_h,ke_h) = -1 + this%lcprc(p_h,ke_h) = -1 + + out_panel = this%inPanelID(p_h,ke_h) + + loop_prc: do in_prc=1, in_Nprc + do in_n=1, in_NLocalMeshPerPrc + + if ( out_panel /= panelID_table(in_n,in_prc) ) cycle + + is_inside_tile(p_h) = polygon_inpoly( out_x(p_h,ke_h), out_y(p_h,ke_h), & + 4, tile_x(:,in_n,in_prc), tile_y(:,in_n,in_prc) ) + + if ( is_inside_tile(p_h) ) then + this%local_domID(p_h,ke_h) = in_n + + if ( .not. target_tile_flag(in_n,in_prc) ) then + target_tile_flag(in_n,in_prc) = .true. + in_tile_num = in_tile_num + 1 + in_tileID_tmp(in_tile_num) = tileID_table(in_n,in_prc) + end if + if ( .not. target_prc_flag(in_prc) ) then + target_prc_flag(in_prc) = .true. + in_prc_num = in_prc_num + 1 + in_prc2lcprc_tmp(in_prc) = in_prc_num + in_lcprc2prc_tmp(in_prc_num) = in_prc + end if + this%lcprc(p_h,ke_h) = in_prc2lcprc_tmp(in_prc) + + exit loop_prc + end if + + end do + end do loop_prc + + end do + end do + + end do + + + allocate( this%in_tileID_list(in_tile_num) ) + this%in_tileID_list(:) = in_tileID_tmp(1:in_tile_num) + + do ke_h=1, Ne2D + do p_h_y=1, Np1D + do p_h_x=1, Np1D + + p_h = p_h_x + (p_h_y-1)*Np1D + + lc_domID = this%local_domID(p_h,ke_h) + prcID = in_lcprc2prc_tmp( this%lcprc(p_h,ke_h) ) + out_panel = this%inPanelID(p_h,ke_h) + + this%elem_i(p_h,ke_h) = -1 + this%elem_j(p_h,ke_h) = -1 + if ( lc_domID > 0 .and. prcID > 0) then + delx = ( tile_x(2,lc_domID,prcID) - tile_x(1,lc_domID,prcID) ) / dble(in_NeX) + dely = ( tile_y(4,lc_domID,prcID) - tile_y(1,lc_domID,prcID) ) / dble(in_NeY) + + loop_ne: do j=1, in_NeY + do i=1, in_NeX + in_elem_x(:) = tile_x(1,lc_domID,prcID) + delx * dble( (/ i-1, i, i, i-1 /) ) + in_elem_y(:) = tile_y(1,lc_domID,prcID) + dely * dble( (/ j-1, j-1, j, j /) ) + + if (i==in_NeX) then + in_elem_x(2:3) = in_elem_x(2:3) + 1.0E-12_RP * delx + end if + if (j==in_NeY) then + in_elem_y(3:4) = in_elem_y(3:4) + 1.0E-12_RP * dely + end if + + is_inside_elem = polygon_inpoly( out_x(p_h,ke_h), out_y(p_h,ke_h), & + 4, in_elem_x(:), in_elem_y(:) ) + + if (is_inside_elem) then + this%elem_i(p_h,ke_h) = i + this%elem_j(p_h,ke_h) = j + this%elem_x(p_h,ke_h) = out_x(p_h,ke_h) + this%elem_y(p_h,ke_h) = out_y(p_h,ke_h) + + exit loop_ne + end if + end do + end do loop_ne + end if + end do + end do + end do + + !-- prepair mesh for input data -------------------------------- + + + return + end subroutine NodeMap_construct_nodemap_2D + +!OCL SERIAL + subroutine get_inmesh_mapinfo( & + in_meshtype_id, in_Nprc, in_NLocalMeshPerPrc ) + implicit none + + integer, intent(in) :: in_meshtype_id + integer, intent(in) :: in_Nprc + integer, intent(in) :: in_NLocalMeshPerPrc + !----------------------------------------------------- + + return + end subroutine get_inmesh_mapinfo + +!OCL SERIAL + subroutine get_panelID( inPanelID, & + in_meshtype_id, out_meshtype_id, & + Np1D, Ne2D, lcmesh ) + + use scale_meshutil_cubedsphere2d, only: & + MeshUtilCubedSphere2D_getPanelID + implicit none + + integer, intent(in) :: Np1D + integer, intent(in) :: Ne2D + class(LocalMesh2D), intent(in) :: lcmesh + integer, intent(out) :: inPanelID(Np1D**2,Ne2D) + integer, intent(in) :: in_meshtype_id + integer, intent(in) :: out_meshtype_id + !---------------------------------------------- + + if ( ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE2D_ID & + .and. out_meshtype_id == REGRID_MESHTYPE_LONLAT2D_ID ) & + .or. ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE3D_ID & + .and. out_meshtype_id == REGRID_MESHTYPE_LONLAT3D_ID ) ) then + + + call MeshUtilCubedSphere2D_getPanelID ( & + inPanelID(:,:), & ! (out) + lcmesh%pos_en(:,:,1) * PI / 180.0_RP, & ! (in) + lcmesh%pos_en(:,:,2) * PI / 180.0_RP, & ! (in) + Np1D**2 * Ne2D ) ! (in) + else + inPanelID(:,:) = 1 + end if + + return + end subroutine get_panelID + +!OCL SERIAL + subroutine get_out_xy( out_x, out_y, & + in_meshtype_id, out_meshtype_id, & + inPanelID, & + Np1D, Ne2D, lcmesh ) + + use scale_cubedsphere_cnv, only: & + CubedSphereCnv_LonLat2CSPos + implicit none + + integer, intent(in) :: Np1D + integer, intent(in) :: Ne2D + class(LocalMesh2D), intent(in) :: lcmesh + real(RP), intent(out) :: out_x(Np1D**2,Ne2D) + real(RP), intent(out) :: out_y(Np1D**2,Ne2D) + integer, intent(in) :: in_meshtype_id + integer, intent(in) :: out_meshtype_id + integer, intent(in) :: inPanelID(Np1D**2,Ne2D) + + integer :: p_h, ke_h + + real(RP) :: out_lon(1) + real(RP) :: out_lat(1) + + !---------------------------------------------- + + if ( ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE2D_ID & + .and. out_meshtype_id == REGRID_MESHTYPE_LONLAT2D_ID ) & + .or. ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE3D_ID & + .and. out_meshtype_id == REGRID_MESHTYPE_LONLAT3D_ID ) ) then + + do ke_h=1, Ne2D + do p_h=1, Np1D**2 + out_lon(1) = lcmesh%pos_en(p_h,ke_h,1) * PI / 180.0_RP + out_lat(1) = lcmesh%pos_en(p_h,ke_h,2) * PI / 180.0_RP + + call CubedSphereCnv_LonLat2CSPos( & + inPanelID(p_h,ke_h), & ! (in) + out_lon(1), out_lat(1), 1, & ! (in) + out_x(p_h,ke_h), out_y(p_h,ke_h) ) ! (out) + end do + end do + else + !$omp parallel do private(p_h) + do ke_h=1, Ne2D + do p_h=1, Np1D**2 + out_x(p_h,ke_h) = lcmesh%pos_en(p_h,ke_h,1) + out_y(p_h,ke_h) = lcmesh%pos_en(p_h,ke_h,2) + end do + end do + end if + + return + end subroutine get_out_xy + +end module mod_regrid_nodemap \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 new file mode 100644 index 00000000..9d59befc --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 @@ -0,0 +1,228 @@ +!------------------------------------------------------------------------------- +!> Program regrid tool (SCALE-DG) +!! +!! @par Description +!! SCALE: Scalable Computing by Advanced Library and Environment +!! regrid tool for models based DG methods +!! +!! @author Team SCALE +!! +!< +!------------------------------------------------------------------------------- +#include "scalelib.h" +program regrid_tool + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use mpi + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: PRC_abort + + !----------------------------------------------------------------------------- + implicit none + !----------------------------------------------------------------------------- + ! + !++ included parameters + ! + !----------------------------------------------------------------------------- + ! + !++ parameters & variables + ! + !============================================================================= + + ! namelist parameters + logical :: debug = .false. + + ! MPI parameters + integer :: nprocs ! number of processes (execution) + integer :: myrank ! my rank (execution) + logical :: ismaster ! master process? (execution) + + logical :: do_output + integer :: vid + integer :: istep + real(DP) :: start_sec + + !----------------------------------------------------------------------------- + + call initialize() + + !- + !########## main ########## + call PROF_rapstart('Main', 0) + + LOG_NEWLINE + LOG_PROGRESS(*) 'START LOOP' + + ! do vid =1, out_var_num + ! vinfo => out_vinfo(vid) + ! do istep=1, vinfo%num_step, vinfo%out_tintrv + ! start_sec = vinfo%start_sec + (istep - 1) * vinfo%dt + + ! LOG_INFO("INTERP",'(a,i4)') 'Interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep + ! if (is_mesh3D) then + ! call interp_field_Interpolate( istep, vinfo%varname, & + ! out_mesh3D, out_var3D, nodeMap_list ) + + ! if ( vintrp%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) then + ! call interp_file_write_var( vid, out_var3D, & + ! start_sec, start_sec + vinfo%dt ) + ! else + ! call vintrp%Update_weight( istep, out_mesh3D, nodeMap_list ) + ! call vintrp%Interpolate( istep, out_mesh3D, out_var3D ) + + ! call interp_file_write_var( vid, vintrp%vintrp_var3D, & + ! start_sec, start_sec + vinfo%dt ) + ! end if + + ! else + ! call interp_field_Interpolate( istep, vinfo%varname, & + ! out_mesh2D, out_var2D, nodeMap_list ) + ! call interp_file_write_var( vid, out_var2D, & + ! start_sec, start_sec + vinfo%dt ) + ! end if + ! if( IO_L ) call flush(IO_FID_LOG) + ! end do + ! end do + + LOG_PROGRESS(*) 'END LOOP' + LOG_NEWLINE + call PROF_rapend ('Main', 0) + + !- + call finalize() + +contains + +!OCL SERIAL + subroutine initialize() + use scale_prc, only: & + PRC_MPIstart, & + PRC_SINGLECOM_setup, & + PRC_ERRHANDLER_setup + use scale_const, only: & + CONST_setup + use scale_calendar, only: & + CALENDAR_setup + use scale_file, only: & + FILE_setup + + use mod_regrid_mesh, only: & + regrid_mesh_Init + ! use mod_cs2lonlat_interp_field, only: & + ! interp_field_Init, & + ! in_basename + ! use mod_cs2lonlat_interp_file, only: & + ! interp_file_Init + + implicit none + + namelist / PARAM_REGRID_TOOL / & + debug + + integer :: ierr + integer :: comm ! communicator (execution) + + integer :: n + !----------------------------------------------------------------------- + + ! start MPI + call PRC_MPIstart( comm ) ! [OUT] + + ! setup MPI communicator + call PRC_SINGLECOM_setup( comm, & ! [IN] + nprocs, & ! [OUT] + myrank, & ! [OUT] + ismaster ) ! [OUT] + + call PRC_ERRHANDLER_setup( use_fpm = .false., & ! [IN] + master = .false. ) ! [IN] + + ! setup standard I/O + call IO_setup( "regrid_tool" ) + + ! setup Log + call IO_LOG_setup( myrank, ismaster ) + + ! setup profiler + call PROF_setup + call PROF_rapstart ('Initialize', 0) + + ! setup constants + call CONST_setup + + ! setup calendar + call CALENDAR_setup + + ! setup fie I/O + call FILE_setup( myrank ) + + LOG_NEWLINE + LOG_INFO("regrid_tool",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_REGRID_TOOL,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_tool",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_tool",*) 'Not appropriate names in namelist PARAM_REGRID_TOOL. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_TOOL) + + ! + call regrid_mesh_Init() + ! call interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D ) + ! if ( is_mesh3D ) call vintrp%Init( out_mesh3D, nodeMap_list ) + ! call interp_file_Init( in_basename, out_vinfo, out_mesh2D, vintrp%out_mesh3D_ptr, is_mesh3D ) + + !- + do_output = .true. + + LOG_INFO("regrid_tool",*) 'Setup has been finished.' + + call PROF_rapend ('Initialize', 0) + + return + end subroutine initialize + +!OCL SERIAL + subroutine finalize + use scale_prc, only: & + PRC_mpibarrier, & + PRC_MPIfinish + use scale_file, only: & + FILE_close_all + + ! use mod_cs2lonlat_interp_field, only: interp_field_Final + use mod_regrid_mesh, only: regrid_mesh_Final + ! use mod_cs2lonlat_interp_file, only: interp_file_Final + + implicit none + !-------------------------------------- + + call PROF_rapstart ('Finalize', 0) + + ! call interp_file_Final + ! call interp_field_Final( is_mesh3D ) + ! if ( is_mesh3D ) call vintrp%Final() + call regrid_mesh_Final() + + ! + call FILE_close_all + call PROF_rapend ('Finalize', 0) + + call PROF_rapreport + + ! stop MPI + call PRC_mpibarrier + call PRC_MPIfinish + + return + end subroutine finalize + +end program regrid_tool \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/regrid_tool/regrid.conf b/model/atm_nonhydro3d/util/regrid_tool/regrid.conf new file mode 100644 index 00000000..2496a2fb --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/regrid.conf @@ -0,0 +1,35 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE3D", + out_MeshType = "LONLAT3D", +/ +&PARAM_INTERP_FIELD + !- input -------------------- + in_basename="../../../../sample/advect3dGlobal/history", + vars = "q", "lat", "lon", + !out_tinterval = 5, +/ +&PARAM_INTERP_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH3D_CUBEDSPHERE + Nprc = 2, + NeGX = 5, + NeGY = 5, + PolyOrder_h = 4, + NLocalMeshPerPrc = 3, +/ +&PARAM_REGRID_OUTMESH3D_LONLAT + NprcX = 1, + NeX = 32, + NprcY = 1, + NeY = 16, + NeZ = 16, + PolyOrder_h = 2, + PolyOrder_v = 2, +/ \ No newline at end of file From f26d9ec36d8d1ba2866223d7e38b403eb3a50386 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 17 Aug 2021 23:52:41 +0900 Subject: [PATCH 80/98] Add an optional argument to specify a MPI rank. --- FElib/src/mesh/scale_mesh_rectdom2d.F90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/FElib/src/mesh/scale_mesh_rectdom2d.F90 b/FElib/src/mesh/scale_mesh_rectdom2d.F90 index 40871cc6..b69c635d 100644 --- a/FElib/src/mesh/scale_mesh_rectdom2d.F90 +++ b/FElib/src/mesh/scale_mesh_rectdom2d.F90 @@ -67,7 +67,8 @@ subroutine MeshRectDom2D_Init(this, & NeGX, NeGY, & dom_xmin, dom_xmax, dom_ymin, dom_ymax, & isPeriodicX, isPeriodicY, & - refElem, NLocalMeshPerPrc, NprcX, NprcY ) + refElem, NLocalMeshPerPrc, & + NprcX, NprcY, myrank ) implicit none @@ -84,6 +85,7 @@ subroutine MeshRectDom2D_Init(this, & integer, intent(in) :: NLocalMeshPerPrc integer, intent(in) :: NprcX integer, intent(in) :: NprcY + integer, intent(in), optional :: myrank !----------------------------------------------------------------------------- @@ -101,7 +103,8 @@ subroutine MeshRectDom2D_Init(this, & this%NprcX = NprcX this%NprcY = NprcY - call MeshBase2D_Init(this, refElem, NLocalMeshPerPrc) + call MeshBase2D_Init( this, refElem, NLocalMeshPerPrc, & + NeGX * NeGY, myrank ) return end subroutine MeshRectDom2D_Init From 49b36cc4c84838534f113164b0280fab7e44efe5 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 17 Aug 2021 23:53:06 +0900 Subject: [PATCH 81/98] Implement a regrid tool. --- .../atm_nonhydro3d/util/regrid_tool/Makefile | 15 +- .../util/regrid_tool/mod_regrid_file.F90 | 245 +++++++ .../regrid_tool/mod_regrid_interp_field.F90 | 660 +++++++++++++++++ .../regrid_tool/mod_regrid_interp_vcoord.F90 | 680 ++++++++++++++++++ .../util/regrid_tool/mod_regrid_mesh.F90 | 4 +- .../util/regrid_tool/mod_regrid_mesh_base.F90 | 95 ++- .../util/regrid_tool/mod_regrid_nodemap.F90 | 161 ++++- .../util/regrid_tool/prg_regrid_tool.F90 | 105 +-- .../util/regrid_tool/regrid.conf | 14 +- 9 files changed, 1894 insertions(+), 85 deletions(-) create mode 100644 model/atm_nonhydro3d/util/regrid_tool/mod_regrid_file.F90 create mode 100644 model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 create mode 100644 model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 diff --git a/model/atm_nonhydro3d/util/regrid_tool/Makefile b/model/atm_nonhydro3d/util/regrid_tool/Makefile index 9358364f..95511cc1 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/Makefile +++ b/model/atm_nonhydro3d/util/regrid_tool/Makefile @@ -18,9 +18,12 @@ LIBS = $(LIBDIR)/libScaleFECore.a VPATH = plugin: OBJS = \ - mod_regrid_mesh.o \ - mod_regrid_mesh_base.o \ - mod_regrid_nodemap.o + mod_regrid_mesh.o \ + mod_regrid_mesh_base.o \ + mod_regrid_nodemap.o \ + mod_regrid_interp_vcoord.o \ + mod_regrid_interp_field.o \ + mod_regrid_file.o all: @@ -47,9 +50,9 @@ $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$ $(BUILD_DIR)/mod_regrid_mesh.o : $(BUILD_DIR)/mod_regrid_nodemap.o $(BUILD_DIR)/mod_regrid_mesh_base.o mod_regrid_mesh.F90 $(BUILD_DIR)/mod_regrid_nodemap.o : $(BUILD_DIR)/mod_regrid_mesh_base.o mod_regrid_nodemap.F90 $(BUILD_DIR)/mod_regrid_mesh_base.o : mod_regrid_mesh_base.F90 -$(BUILD_DIR)/mod_regrid_file.o : $(BUILD_DIR)/mod_regrid_field.o mod_regrid_file.F90 -$(BUILD_DIR)/mod_regrid_field.o : $(BUILD_DIR)/mod_regrid_mesh.o mod_regrid_field.F90 -$(BUILD_DIR)/mod_regrid_vcoord.o : $(BUILD_DIR)/mod_regrid_mesh.o mod_regrid_vcoord.F90 +$(BUILD_DIR)/mod_regrid_file.o : $(BUILD_DIR)/mod_regrid_interp_field.o $(BUILD_DIR)/mod_regrid_mesh_base.o mod_regrid_file.F90 +$(BUILD_DIR)/mod_regrid_interp_field.o : $(BUILD_DIR)/mod_regrid_mesh_base.o $(BUILD_DIR)/mod_regrid_nodemap.o mod_regrid_interp_field.F90 +$(BUILD_DIR)/mod_regrid_interp_vcoord.o : $(BUILD_DIR)/mod_regrid_interp_field.o $(BUILD_DIR)/mod_regrid_mesh_base.o $(BUILD_DIR)/mod_regrid_nodemap.o mod_regrid_interp_vcoord.F90 distclean: clean rm -f $(BINDIR)/$(BINNAME) diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_file.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_file.F90 new file mode 100644 index 00000000..9e65acf2 --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_file.F90 @@ -0,0 +1,245 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_regrid_file + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: & + PRC_myrank, PRC_abort + + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_meshfield_base, only: & + MeshField2D, MeshField3D + + use mod_regrid_mesh_base, only: & + regrid_mesh_base + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + public :: regrid_file_Init + interface regrid_file_write_var + module procedure regrid_file_write_var2D + module procedure regrid_file_write_var3D + end interface + public :: regrid_file_write_var + public :: regrid_file_Final + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + + type(FILE_base_meshfield) :: out_file + logical, private :: out_UniformGrid = .false. + +contains + subroutine regrid_file_Init( in_basename, out_vinfo, out_mesh ) + use scale_file_h + use mod_regrid_interp_field, only: OutVarInfo + implicit none + + character(*), intent(in) :: in_basename + type(OutVarInfo), intent(in) :: out_vinfo(:) + class(regrid_mesh_base), intent(in) :: out_mesh + + character(len=H_LONG ) :: out_basename = '' ! Basename of the output file + character(len=H_MID) :: out_title = '' !< Title of the output file + character(len=H_SHORT) :: out_dtype = 'DEFAULT' !< REAL4 or REAL8 + + namelist / PARAM_REGRID_FILE / & + out_basename, & + out_title, & + out_dtype, & + out_UniformGrid + + integer :: ierr + logical :: fileexisted + + type(FILE_base_meshfield) :: in_file + integer :: nn + integer :: var_num + + character(len=FILE_HMID) :: tunits + character(len=FILE_HSHORT) :: calendar + character(len=FILE_HMID) :: desc + character(len=FILE_HMID) :: standard_name + + integer :: dimtype_id + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("regrid_file",*) 'Setup' + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_REGRID_FILE,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_file",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_file",*) 'Not appropriate names in namelist PARAM_REGRID_FILE. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_FILE) + + + !-- + var_num = size(out_vinfo) + + + call file_init( in_file, dimtype_id, var_num, out_mesh ) + call in_file%Open( in_basename, myrank=0 ) + if (out_title=='') then + call in_file%Get_commonInfo( title=out_title ) ! (out) + end if + + call in_file%Get_dataInfo( out_vinfo(1)%varname, 1, & ! (in) + time_units=tunits, calendar=calendar ) ! (out) + + call file_init( out_file, dimtype_id, var_num, out_mesh, out_UniformGrid ) + + call out_file%Create( out_basename, out_title, out_dtype, & ! (in) + fileexisted, & ! (out) + myrank=PRC_myrank, calendar=calendar, tunits=tunits ) ! (in) + + do nn=1, var_num + call out_file%Def_Var( out_vinfo(nn)%varname, out_vinfo(nn)%units, & + desc, nn, dimtype_id, out_dtype, & + standard_name=standard_name, & + timeinv=out_vinfo(nn)%dt * dble(out_vinfo(nn)%out_tintrv) ) + end do + call out_file%End_def() + + call in_file%Close() + call in_file%Final() + + return + end subroutine regrid_file_Init + + subroutine regrid_file_write_var2D( vid, field, start_sec, end_sec ) + implicit none + integer, intent(in) :: vid + class(MeshField2D), intent(in) :: field + real(DP), intent(in) :: start_sec + real(DP), intent(in) :: end_sec + !------------------------------------------- + + call PROF_rapstart('regrid_file_write_var2D', 0) + + call out_file%Write_var2D( vid, field, start_sec, end_sec ) + + call PROF_rapend('regrid_file_write_var2D', 0) + + return + end subroutine regrid_file_write_var2D + + subroutine regrid_file_write_var3D( vid, field, start_sec, end_sec ) + implicit none + integer, intent(in) :: vid + class(MeshField3D), intent(in) :: field + real(DP), intent(in) :: start_sec + real(DP), intent(in) :: end_sec + !------------------------------------------- + + call PROF_rapstart('regrid_file_write_var3D', 0) + + call out_file%Write_var3D( vid, field, start_sec, end_sec ) + + call PROF_rapend('regrid_file_write_var3D', 0) + + return + end subroutine regrid_file_write_var3D + + subroutine regrid_file_Final() + implicit none + !------------------------------------------- + + call out_file%Close() + call out_file%Final() + return + end subroutine regrid_file_Final + +!-- private ----------------------------------- + + subroutine file_init( file, dimtype_id, & + var_num, mesh, force_uniform_grid ) + + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + + use scale_mesh_base2d, only: & + DIMTYPE2D_XYT => MeshBase2D_DIMTYPEID_XYT + use scale_mesh_base3d, only: & + DIMTYPE3D_XYZT => MeshBase3D_DIMTYPEID_XYZT + + implicit none + + type(FILE_base_meshfield), intent(inout) :: file + integer, intent(out) :: dimtype_id + integer, intent(in) :: var_num + class(regrid_mesh_base), intent(in) :: mesh + logical, intent(in), optional :: force_uniform_grid + + class(MeshBase2D), pointer :: ptr_mesh2D + class(MeshBase3D), pointer :: ptr_mesh3D + + logical :: force_uniform_grid_ + !------------------------------------------- + + if ( present(force_uniform_grid) ) then + force_uniform_grid_ = force_uniform_grid + else + force_uniform_grid_ = .false. + end if + + if ( associated( mesh%ptr_mesh2D ) ) then + + select type( ptr_mesh2D => mesh%ptr_mesh2D ) + class is ( MeshRectDom2D ) + call file%Init( var_num, mesh2D=ptr_mesh2D, force_uniform_grid=force_uniform_grid_ ) + class is ( MeshCubedSphereDom2D ) + call file%Init( var_num, meshCubedSphere2D=ptr_mesh2D, force_uniform_grid=force_uniform_grid_ ) + end select + dimtype_id = DIMTYPE2D_XYT + + else if ( associated( mesh%ptr_mesh3D ) ) then + + select type( ptr_mesh3D => mesh%ptr_mesh3D ) + class is ( MeshCubeDom3D ) + call file%Init( var_num, mesh3D=ptr_mesh3D, force_uniform_grid=force_uniform_grid_ ) + class is ( MeshCubedSphereDom3D ) + call file%Init( var_num, meshCubedSphere3D=ptr_mesh3D, force_uniform_grid=force_uniform_grid_ ) + end select + dimtype_id = DIMTYPE3D_XYZT + + end if + + return + end subroutine file_init + +end module mod_regrid_file \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 new file mode 100644 index 00000000..4dbb9ea0 --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 @@ -0,0 +1,660 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_regrid_interp_field + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_file_h + use scale_prof + use scale_prc, only: & + PRC_myrank, PRC_abort + + use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_meshfield_base, only: MeshField2D, MeshField3D + use scale_file_base_meshfield, only: & + FILE_base_meshfield + + use mod_regrid_mesh_base, only: & + regrid_mesh_base + use mod_regrid_nodemap, only: & + regrid_nodemap + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + public :: regrid_interp_field_Init + public :: regrid_interp_field_Final + interface regrid_interp_field_Interpolate + module procedure :: interp_field_Interpolate_2D + module procedure :: interp_field_Interpolate_3D + end interface + public :: regrid_interp_field_Interpolate + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + type(MeshField2D), public :: out_var2D + type(MeshField3D), public :: out_var3D + type, public :: OutVarInfo + character(FILE_HSHORT) :: varname + character(FILE_HSHORT) :: units + integer :: num_step + real(DP) :: dt + real(DP) :: start_sec + integer :: out_tintrv + end type OutVarInfo + integer, public :: out_var_num + type(OutVarInfo), public, allocatable, target :: out_vinfo(:) + + character(len=H_LONG), public :: in_basename = '' ! Basename of the input file + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + integer, private, parameter :: ITEM_MAX_NUM = 128 + + type :: in_local_val + real(RP), allocatable :: spectral_coef2D(:,:,:,:) + real(RP), allocatable :: spectral_coef3D(:,:,:,:,:) + end type in_local_val + + type :: in_local_file_list + type(FILE_base_meshfield), allocatable :: in_files(:) + end type in_local_file_list + type(in_local_file_list), private, allocatable, target :: in_file_list(:) + logical, private :: is_cached_in_files + +contains +!OCL SERIAL + subroutine regrid_interp_field_Init( out_mesh ) + use scale_const, only: & + EPS => CONST_EPS + use scale_file_h + implicit none + class(regrid_mesh_base), intent(in), target :: out_mesh + + integer :: nn + character(len=H_SHORT) :: vars(ITEM_MAX_NUM) = '' ! name of variables + integer :: out_tinterval(ITEM_MAX_NUM) + + namelist /PARAM_REGRID_INTERP_FIELD/ & + in_basename, & + vars, & + out_tinterval + integer :: ierr + + type(FILE_base_meshfield) :: in_file + real(DP) :: time_endsec + + class(MeshBase2D), pointer :: ptr_mesh2D + class(MeshBase3D), pointer :: ptr_mesh3D + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("regrid_field",*) 'Setup' + + out_tinterval(:) = 1 + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_REGRID_INTERP_FIELD,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("regrid_field",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("regrid_field",*) 'Not appropriate names in namelist PARAM_REGRID_INTERP_FIELD. Check!' + call PRC_abort + endif + LOG_NML(PARAM_REGRID_INTERP_FIELD) + + out_var_num = 0 + do nn= 1, ITEM_MAX_NUM + if ( vars(nn) == '' ) then + exit + else + out_var_num = out_var_num + 1 + end if + end do + allocate( out_vinfo(out_var_num) ) + + !-- + + if ( associated( out_mesh%ptr_mesh2D ) ) then + + select type( ptr_mesh2D => out_mesh%ptr_mesh2D ) + class is ( MeshRectDom2D ) + call in_file%Init( out_var_num, mesh2D=ptr_mesh2D ) + class is ( MeshCubedSphereDom2D ) + call in_file%Init( out_var_num, meshCubedSphere2D=ptr_mesh2D ) + end select + + call out_var2D%Init( "tmp", "1", out_mesh%ptr_mesh2D ) + + else if ( associated( out_mesh%ptr_mesh3D ) ) then + + select type( ptr_mesh3D => out_mesh%ptr_mesh3D ) + class is ( MeshCubeDom3D ) + call in_file%Init( out_var_num, mesh3D=ptr_mesh3D ) + class is ( MeshCubedSphereDom3D ) + call in_file%Init( out_var_num, meshCubedSphere3D=ptr_mesh3D ) + end select + + call out_var3D%Init( "tmp", "1", out_mesh%ptr_mesh3D ) + end if + + call in_file%Open( in_basename, myrank=0 ) + do nn = 1, out_var_num + out_vinfo(nn)%varname = vars(nn) + call in_file%Get_dataInfo( vars(nn), istep=1, & ! (in) + units=out_vinfo(nn)%units, & ! (out) + time_start=out_vinfo(nn)%start_sec, & ! (out) + time_end=time_endsec ) ! (out) + + call in_file%Get_VarStepSize( vars(nn), & ! (in) + out_vinfo(nn)%num_step ) ! (out) + + out_vinfo(nn)%dt = time_endsec - out_vinfo(nn)%start_sec + out_vinfo(nn)%out_tintrv = out_tinterval(nn) + + if ( abs(out_vinfo(nn)%dt) < EPS & + .and. out_vinfo(nn)%num_step == 0 ) then + out_vinfo(nn)%num_step = 1 + out_vinfo(nn)%out_tintrv = 1 + end if + + LOG_INFO("regrid_field_Init", '(3a,i4,a,i4)') & + " Regist: name=", trim(vars(nn)), ", out_nstep=", out_vinfo(nn)%num_step, & + ", out_tinterval=", out_vinfo(nn)%out_tintrv + end do + + call in_file%Close() + call in_file%Final() + + !-- + is_cached_in_files = .false. + + return + end subroutine regrid_interp_field_Init + +!OCL SERIAL + subroutine regrid_interp_field_Final( out_mesh ) + implicit none + + class(regrid_mesh_base), intent(in), target :: out_mesh + + integer :: domID + integer :: in_ii + type(FILE_base_meshfield), pointer :: in_file_ptr + !------------------------------------------- + + if ( associated( out_mesh%ptr_mesh2D ) ) then + call out_var2D%Final() + end if + if ( associated( out_mesh%ptr_mesh3D ) ) then + call out_var3D%Final() + end if + + if (is_cached_in_files) then + do domID=1, size(in_file_list) + do in_ii=1, size(in_file_list(domID)%in_files) + in_file_ptr => in_file_list(domID)%in_files(in_ii) + call in_file_ptr%Close() + call in_file_ptr%Final() + end do + deallocate( in_file_list(domID)%in_files ) + end do + deallocate( in_file_list ) + end if + + return + end subroutine regrid_interp_field_Final + +!OCL SERIAL + subroutine interp_field_Interpolate_2D( istep, varname, out_mesh, out_field, nodeMap_list ) + use scale_mesh_rectdom2d, only: MeshRectDom2D + implicit none + + integer, intent(in) :: istep + character(*), intent(in) :: varname + class(regrid_mesh_base), intent(in), target :: out_mesh + class(MeshField2D), intent(inout) :: out_field + type(regrid_nodemap), intent(in) :: nodeMap_list(:) + + class(LocalMesh2D), pointer :: lcmesh + integer :: n + + integer :: domID + integer :: in_mesh_num + integer :: in_ii + integer :: in_rank + type(FILE_base_meshfield), pointer :: in_file_ptr + + class(MeshBase2D), pointer :: ptr_outmesh2D + class(MeshBase2D), pointer :: ptr_inmesh2D + !------------------------------------------- + + call PROF_rapstart('INTERP_field_interpolate_2D', 0) + + ptr_outmesh2D => out_mesh%ptr_mesh2D + + if (.not. is_cached_in_files) then + allocate( in_file_list(ptr_outmesh2D%LOCAL_MESH_NUM) ) + do domID=1, ptr_outmesh2D%LOCAL_MESH_NUM + in_mesh_num = size(nodeMap_list(domID)%in_mesh_list) + allocate( in_file_list(domID)%in_files(in_mesh_num) ) + do in_ii=1, in_mesh_num + in_file_ptr => in_file_list(domID)%in_files(in_ii) + ptr_inmesh2D => nodeMap_list(domID)%in_mesh_list(in_ii)%ptr_mesh2D + in_rank = ptr_inmesh2D%lcmesh_list(1)%PRC_myrank + LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank + + select type( ptr_inmesh2D ) + class is (MeshRectDom2D) + call in_file_ptr%Init( out_var_num, mesh2D=ptr_inmesh2D ) + class is (MeshCubedSphereDom2D) + call in_file_ptr%Init( out_var_num, meshCubedSphere2D=ptr_inmesh2D ) + end select + call in_file_ptr%Open( in_basename, in_rank ) + end do + end do + is_cached_in_files = .true. + end if + + do n=1, ptr_outmesh2D%LOCAL_MESH_NUM + lcmesh => ptr_outmesh2D%lcmesh_list(n) + call interpolate_local_2D( out_field%local(n)%val(:,:), & + n, istep, varname, lcmesh, lcmesh%refElem2D, nodeMap_list(n)%in_mesh_list(1)%elem2D, & + nodeMap_list(n) ) + end do + + call PROF_rapend('INTERP_field_interpolate_2D', 0) + + return + end subroutine interp_field_interpolate_2D + +!OCL SERIAL + subroutine interp_field_Interpolate_3D( istep, varname, out_mesh, out_field, nodeMap_list ) + use scale_mesh_cubedom3d, only: MeshCubeDom3D + implicit none + + integer, intent(in) :: istep + character(*), intent(in) :: varname + class(regrid_mesh_base), intent(in), target :: out_mesh + class(MeshField3D), intent(inout) :: out_field + type(regrid_nodemap), intent(in), target :: nodeMap_list(:) + + class(LocalMesh3D), pointer :: lcmesh + integer :: n + + integer :: domID + integer :: in_mesh_num + integer :: in_ii + integer :: in_rank + type(FILE_base_meshfield), pointer :: in_file_ptr + + class(MeshBase3D), pointer :: ptr_outmesh3D + class(MeshBase3D), pointer :: ptr_inmesh3D + !------------------------------------------- + + call PROF_rapstart('INTERP_field_interpolate_3D', 0) + + ptr_outmesh3D => out_mesh%ptr_mesh3D + + if (.not. is_cached_in_files) then + allocate( in_file_list(ptr_outmesh3D%LOCAL_MESH_NUM) ) + do domID=1, ptr_outmesh3D%LOCAL_MESH_NUM + in_mesh_num = size(nodeMap_list(domID)%in_mesh_list) + allocate( in_file_list(domID)%in_files(in_mesh_num) ) + do in_ii=1, in_mesh_num + in_file_ptr => in_file_list(domID)%in_files(in_ii) + ptr_inmesh3D => nodeMap_list(domID)%in_mesh_list(in_ii)%ptr_mesh3D + in_rank = ptr_inmesh3D%lcmesh_list(1)%PRC_myrank + + LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank + + select type( ptr_inmesh3D ) + class is (MeshCubeDom3D) + call in_file_ptr%Init( out_var_num, mesh3D=ptr_inmesh3D ) + class is (MeshCubedSphereDom3D) + call in_file_ptr%Init( out_var_num, meshCubedSphere3D=ptr_inmesh3D ) + end select + call in_file_ptr%Open( in_basename, in_rank ) + end do + end do + is_cached_in_files = .true. + end if + + do n=1, ptr_outmesh3D%LOCAL_MESH_NUM + lcmesh => ptr_outmesh3D%lcmesh_list(n) + call interpolate_local_3D( out_field%local(n)%val(:,:), & + n, istep, varname, lcmesh, lcmesh%refElem3D, nodeMap_list(n)%in_mesh_list(1)%elem3D, & + nodeMap_list(n) ) + end do + + call PROF_rapend('INTERP_field_interpolate_3D', 0) + + return + end subroutine interp_field_interpolate_3D + +!------------------------ + +!OCL SERIAL + subroutine interpolate_local_2D( out_val, & + out_domID, istep, varname, & + out_lcmesh, out_elem2D, in_elem2D, & + mappingInfo ) + + use scale_const, only: & + UNDEF8 => CONST_UNDEF8, & + PI => CONST_PI + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_mesh_base2d, only: & + MF2D_XYT => MeshBase2D_DIMTYPEID_XYT + use scale_polynominal, only: & + Polynominal_GenLegendrePoly_sub + + implicit none + class(LocalMesh2D), intent(in) :: out_lcmesh + class(ElementBase2D), intent(in) :: out_elem2D + class(ElementBase2D), intent(in) :: in_elem2D + real(DP), intent(out) :: out_val(out_elem2D%Np,out_lcmesh%NeA) + integer, intent(in) :: out_domID + integer, intent(in) :: istep + character(*), intent(in) :: varname + type(regrid_nodemap), intent(in), target :: mappingInfo + + integer :: nprc_local + integer :: ke2D, ke_h + integer :: p, p_h, pX, pY + integer :: p1, p2, l + integer :: in_ke2D, in_ex, in_ey, in_domID, in_prc + integer :: in_rank + type(LocalMesh2D), pointer :: in_lcmesh + integer :: n + integer :: ii, jj + + type(in_local_val), allocatable :: in_val_list(:) + class(MeshBase2D), pointer :: in_mesh + real(RP) :: P1D_ori_x(1,in_elem2D%Nfp) + real(RP) :: P1D_ori_y(1,in_elem2D%Nfp) + real(RP) :: ox(1), oy(1) + real(RP) :: vx(in_elem2D%Nv), vy(in_elem2D%Nv) + integer :: node_ids(in_elem2D%Nv) + type(MeshField2D) :: tmp_field2D + + !--------------------------------------------- + + nprc_local = size(mappingInfo%in_mesh_list) + + allocate( in_val_list(nprc_local) ) + + do in_prc=1, nprc_local + in_rank = in_prc - 1 + in_mesh => mappingInfo%in_mesh_list(in_prc)%ptr_mesh2D + + n = 1 + in_lcmesh => in_mesh%lcmesh_list(n) + allocate( in_val_list(in_prc)%spectral_coef2D(in_lcmesh%refElem2D%Np,in_lcmesh%NeX,in_lcmesh%NeY,in_mesh%LOCAL_MESH_NUM) ) + + call tmp_field2D%Init( varname, "", in_mesh ) + call in_file_list(out_domID)%in_files(in_prc)%Read_Var( & + MF2D_XYT, varname, tmp_field2D, step=istep ) + + !$omp parallel do collapse(2) private(in_ke2D,ii,jj) + do in_domID=1, in_mesh%LOCAL_MESH_NUM + do jj=1, in_lcmesh%NeY + do ii=1, in_lcmesh%NeX + in_ke2D = ii + (jj-1)*in_lcmesh%NeX + in_val_list(in_prc)%spectral_coef2D(:,ii,jj,in_domID) = & + matmul( in_elem2D%invV, tmp_field2D%local(in_domID)%val(:,in_ke2D) ) + end do + end do + end do + + call tmp_field2D%Final() + end do + + + !$omp parallel do collapse(2) private( ke_h, ke2D, & + !$omp pX, pY, p_h, p, in_domID, in_prc, & + !$omp in_ex, in_ey, in_ke2D, & + !$omp in_lcmesh, node_ids, vx, vy, ox, oy, & + !$omp P1D_ori_x, P1D_ori_y, & + !$omp p1, p2, l ) + do jj=1, out_lcmesh%NeY + do ii=1, out_lcmesh%NeX + ke_h = ii + (jj-1)*out_lcmesh%NeX + ke2D = ke_h + + do pY=1, out_elem2D%Nfp + do pX=1, out_elem2D%Nfp + p_h = pX + (pY-1)*out_elem2D%Nfp + p = p_h + out_val(p,ke2D) = UNDEF8 + + in_domID = mappingInfo%local_domID(p_h,ke_h) + in_prc = mappingInfo%lcprc(p_h,ke_h) + + if (in_domID > 0 .and. in_prc > 0) then + in_ex = mappingInfo%elem_i(p_h,ke_h) + in_ey = mappingInfo%elem_j(p_h,ke_h) + + if ( in_ex > 0 .and. in_ey > 0 ) then + in_lcmesh => mappingInfo%in_mesh_list(in_prc)%ptr_mesh2D%lcmesh_list(in_domID) + in_ke2D = in_ex + (in_ey - 1)*in_lcmesh%NeX + + node_ids(:) = in_lcmesh%EToV(in_ke2D,:) + vx(:) = in_lcmesh%pos_ev(node_ids(:),1) + vy(:) = in_lcmesh%pos_ev(node_ids(:),2) + + ox(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_x(p,ke2D) - vx(1)) / (vx(2) - vx(1)) + oy(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_y(p,ke2D) - vy(1)) / (vy(3) - vy(1)) + + call Polynominal_GenLegendrePoly_sub( in_elem2D%PolyOrder, ox, P1D_ori_x(:,:) ) + call Polynominal_GenLegendrePoly_sub( in_elem2D%PolyOrder, oy, P1D_ori_y(:,:) ) + + out_val(p,ke2D) = 0.0_RP + do p2=1, in_elem2D%Nfp + do p1=1, in_elem2D%Nfp + l = p1 + (p2-1)*in_elem2D%Nfp + out_val(p,ke2D) = out_val(p,ke2D) + & + ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) ) & + * sqrt((dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)) & + * in_val_list(in_prc)%spectral_coef2D(l,in_ex,in_ey,in_domID) + end do + end do + end if + end if + + end do + end do + end do + end do + + do in_prc=1, nprc_local + deallocate( in_val_list(in_prc)%spectral_coef2D ) + end do + + return + end subroutine interpolate_local_2D + + +!OCL SERIAL + subroutine interpolate_local_3D( out_val, & + out_domID, istep, varname, & + out_lcmesh, out_elem3D, in_elem3D, & + mappingInfo ) + + use scale_const, only: & + UNDEF8 => CONST_UNDEF8, & + PI => CONST_PI + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_mesh_base3d, only: & + MF3D_XYZT => MeshBase3D_DIMTYPEID_XYZT + use scale_polynominal, only: & + Polynominal_GenLegendrePoly_sub + implicit none + + class(LocalMesh3D), intent(in) :: out_lcmesh + class(ElementBase3D), intent(in) :: out_elem3D + class(ElementBase3D), intent(in) :: in_elem3D + real(DP), intent(out) :: out_val(out_elem3D%Np,out_lcmesh%NeA) + integer, intent(in) :: out_domID + integer, intent(in) :: istep + character(*), intent(in) :: varname + type(regrid_nodemap), intent(in), target :: mappingInfo + + integer :: nprc_local + integer :: ke3D, ke_h + integer :: p, p_h, pX, pY, pZ + integer :: p1, p2, p3, l + integer :: elem_i, elem_j + integer :: in_ke3D, in_ex, in_ey, in_ez, in_domID, in_prc + integer :: in_rank + type(LocalMesh3D), pointer :: in_lcmesh + integer :: n + integer :: ii, jj, kk, pp, i0_s, j0_s, k0_s, p0_s + + type(in_local_val), allocatable :: in_val_list(:) + class(MeshBase3D), pointer :: in_mesh + real(RP) :: P1D_ori_x(1,in_elem3D%Nnode_h1D) + real(RP) :: P1D_ori_y(1,in_elem3D%Nnode_h1D) + real(RP) :: P1D_ori_z(1,in_elem3D%Nnode_v) + real(RP) :: ox(1), oy(1), oz(1) + real(RP) :: vx(in_elem3D%Nv), vy(in_elem3D%Nv), vz(in_elem3D%Nv) + integer :: node_ids(in_elem3D%Nv) + type(MeshField3D) :: tmp_field3D + !--------------------------------------------- + + nprc_local = size(mappingInfo%in_mesh_list) + + allocate( in_val_list(nprc_local) ) + + do in_prc=1, nprc_local + in_rank = in_prc - 1 + in_mesh => mappingInfo%in_mesh_list(in_prc)%ptr_mesh3D + + n = 1 + in_lcmesh => in_mesh%lcmesh_list(n) + allocate( in_val_list(in_prc)%spectral_coef3D(in_lcmesh%refElem3D%Np,in_lcmesh%NeX,in_lcmesh%NeY,in_lcmesh%NeZ,in_mesh%LOCAL_MESH_NUM) ) + + call tmp_field3D%Init( varname, "", in_mesh ) + call in_file_list(out_domID)%in_files(in_prc)%Read_Var( & + MF3D_XYZT, varname, tmp_field3D, step=istep ) + + !$omp parallel do collapse(2) private(in_ke3D,ii,jj,kk) + do in_domID=1, in_mesh%LOCAL_MESH_NUM + do kk=1, in_lcmesh%NeZ + do jj=1, in_lcmesh%NeY + do ii=1, in_lcmesh%NeX + in_ke3D = ii + (jj-1)*in_lcmesh%NeX + (kk-1)*in_lcmesh%NeX*in_lcmesh%NeY + in_val_list(in_prc)%spectral_coef3D(:,ii,jj,kk,in_domID) = & + matmul( in_elem3D%invV, tmp_field3D%local(in_domID)%val(:,in_ke3D) ) + end do + end do + end do + end do + + call tmp_field3D%Final() + end do + + !$omp parallel do collapse(3) private( ke_h, ke3D, & + !$omp pX, pY, pZ, p_h, p, in_domID, in_prc, & + !$omp in_ex, in_ey, in_ez, in_ke3D, & + !$omp in_lcmesh, node_ids, vx, vy, vz, ox, oy, oz, & + !$omp P1D_ori_x, P1D_ori_y, P1D_ori_z, & + !$omp p1, p2, p3, l ) + do kk=1, out_lcmesh%NeZ + do jj=1, out_lcmesh%NeY + do ii=1, out_lcmesh%NeX + ke_h = ii + (jj-1)*out_lcmesh%NeX + ke3D = ke_h + (kk-1)*out_lcmesh%NeX*out_lcmesh%NeY + + do pZ=1, out_elem3D%Nnode_v + do pY=1, out_elem3D%Nnode_h1D + do pX=1, out_elem3D%Nnode_h1D + p_h = pX + (pY-1)*out_elem3D%Nnode_h1D + p = p_h + (pZ-1)*out_elem3D%Nnode_h1D**2 + out_val(p,ke3D) = UNDEF8 + + in_domID = mappingInfo%local_domID(p_h,ke_h) + in_prc = mappingInfo%lcprc(p_h,ke_h) + + if (in_domID > 0 .and. in_prc > 0) then + in_ex = mappingInfo%elem_i(p_h,ke_h) + in_ey = mappingInfo%elem_j(p_h,ke_h) + in_ez = mappingInfo%elem_k(p ,ke3D) + + if ( in_ex > 0 .and. in_ey > 0 .and. in_ez > 0 ) then + in_lcmesh => mappingInfo%in_mesh_list(in_prc)%ptr_mesh3D%lcmesh_list(in_domID) + in_ke3D = in_ex + (in_ey - 1)*in_lcmesh%NeX & + + (in_ez - 1)*in_lcmesh%NeX*in_lcmesh%NeY + + node_ids(:) = in_lcmesh%EToV(in_ke3D,:) + vx(:) = in_lcmesh%pos_ev(node_ids(:),1) + vy(:) = in_lcmesh%pos_ev(node_ids(:),2) + vz(:) = in_lcmesh%pos_ev(node_ids(:),3) + + ox(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_x(p_h,ke_h) - vx(1)) / (vx(2) - vx(1)) + oy(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_y(p_h,ke_h) - vy(1)) / (vy(3) - vy(1)) + oz(1) = - 1.0_RP + 2.0_RP * (mappingInfo%elem_z(p ,ke3D) - vz(1)) / (vz(5) - vz(1)) + + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_h, ox, P1D_ori_x(:,:) ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_h, oy, P1D_ori_y(:,:) ) + call Polynominal_GenLegendrePoly_sub( in_elem3D%PolyOrder_v, oz, P1D_ori_z(:,:) ) + + out_val(p,ke3D) = 0.0_RP + do p3=1, in_elem3D%Nnode_v + do p2=1, in_elem3D%Nnode_h1D + do p1=1, in_elem3D%Nnode_h1D + l = p1 + (p2-1)*in_elem3D%Nnode_h1D + (p3-1)*in_elem3D%Nnode_h1D**2 + out_val(p,ke3D) = out_val(p,ke3D) + & + ( P1D_ori_x(1,p1) * P1D_ori_y(1,p2) * P1D_ori_z(1,p3) ) & + * sqrt( (dble(p1-1) + 0.5_RP)*(dble(p2-1) + 0.5_RP)*(dble(p3-1) + 0.5_RP) ) & + * in_val_list(in_prc)%spectral_coef3D(l,in_ex,in_ey,in_ez,in_domID) + end do + end do + end do + end if + end if + + end do + end do + end do + end do + end do + end do + + do in_prc=1, nprc_local + deallocate( in_val_list(in_prc)%spectral_coef3D ) + end do + + return + end subroutine interpolate_local_3D + +end module mod_regrid_interp_field \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 new file mode 100644 index 00000000..5f78aaf3 --- /dev/null +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 @@ -0,0 +1,680 @@ +!------------------------------------------------------------------------------- +#include "scaleFElib.h" +module mod_regrid_interp_vcoord + !----------------------------------------------------------------------------- + ! + !++ used modules + ! + use scale_precision + use scale_io + use scale_prof + use scale_prc, only: & + PRC_myrank, PRC_abort + use scale_const, only: & + PI => CONST_PI, & + RPlanet => CONST_radius, & + UNDEF => CONST_UNDEF, & + EPS => CONST_EPS + use scale_element_base, only: ElementBase2D, ElementBase3D + use scale_element_quadrilateral, only: QuadrilateralElement + use scale_element_hexahedral, only: HexahedralElement + use scale_localmesh_2d, only: LocalMesh2D + use scale_localmesh_3d, only: LocalMesh3D + use scale_mesh_base2d, only: MeshBase2D + use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_rectdom2d, only: MeshRectDom2D + use scale_mesh_cubedom3d, only: MeshCubeDom3D + use scale_mesh_cubedspheredom2d, only: MeshCubedSphereDom2D + use scale_mesh_cubedspheredom3d, only: MeshCubedSphereDom3D + use scale_mesh_topography, only: & + MeshTopography + use scale_file_base_meshfield, only: & + FILE_base_meshfield + use scale_meshfield_base, only: MeshField3D + + use mod_regrid_mesh_base, only: & + regrid_mesh_base, & + REGRID_MESHTYPE_CUBEDSPHERE3D_ID, & + REGRID_MESHTYPE_LONLAT3D_ID, & + REGRID_MESHTYPE_STRUCTURED3D_ID, & + INMESH_ID => REGRID_MESH_BASE_IN_ID, & + OUTMESH_ID => REGRID_MESH_BASE_OUT_ID + + use mod_regrid_nodemap, only: regrid_nodemap + + !----------------------------------------------------------------------------- + implicit none + private + !----------------------------------------------------------------------------- + ! + !++ Public type & procedures + ! + + type :: vinterpcoef_info + real(RP), allocatable :: xi2v_coef(:,:) + integer , allocatable :: xi2v_idx_k (:,:,:) + integer , allocatable :: xi2v_idx_p (:,:,:) + end type + + type, public :: regrid_interp_vcoord + integer :: vintrp_typeid + type(MeshTopography) :: topography + + type(vinterpcoef_info), allocatable :: vintrp_info(:) + type(MeshField3D) :: pres + type(HexahedralElement) :: elem + + class(MeshBase3D), pointer :: out_mesh3D_ptr + type(MeshCubeDom3D) :: mesh3D + type(MeshCubedSphereDom3D) :: csmesh3D + + logical :: extrapolate + + type(MeshField3D), public :: vintrp_var3D + contains + procedure :: Init => regrid_interp_vcoord_Init + procedure :: Final => regrid_interp_vcoord_Final + procedure :: Update_weight => regrid_interp_vcoord_update_weight + procedure :: Interpolate => regrid_interp_vcoord_interpolate + end type + + !----------------------------------------------------------------------------- + ! + !++ Public parameters & variables + ! + integer, public, parameter :: INTERP_VCOORD_MODEL_ID = 1 + integer, public, parameter :: INTERP_VCOORD_HEIGHT_ID = 2 + integer, public, parameter :: INTERP_VCOORD_PRESS_ID = 3 + integer, public, parameter :: INTERP_VCOORD_SIGMA_ID = 4 + + !----------------------------------------------------------------------------- + ! + !++ Private procedures + ! + !------------------- + + + !----------------------------------------------------------------------------- + ! + !++ Private parameters & variables + ! + +contains + +!OCL SERIAL + subroutine regrid_interp_vcoord_Init( this, & + out_mesh, nodeMap_list ) + + use scale_mesh_base2d, only: & + MF2D_XY => MeshBase2D_DIMTYPEID_XY + use scale_mesh_base3d, only: & + MeshBase3D_DIMTYPEID_X, MeshBase3D_DIMTYPEID_Y, MeshBase3D_DIMTYPEID_Z, & + MeshBase3D_DIMTYPEID_XYZ, MeshBase3D_DIMTYPEID_XYZT + use scale_meshfieldcomm_rectdom2d, only: MeshFieldCommRectDom2D + use scale_meshfieldcomm_cubedspheredom2d, only: MeshFieldCommCubedSphereDom2D + use scale_meshfieldcomm_cubedom3d, only: MeshFieldCommCubeDom3D + use scale_meshfieldcomm_cubedspheredom3d, only: MeshFieldCommCubedSphereDom3D + use scale_meshutil_vcoord, only: MESH_VCOORD_TERRAIN_FOLLOWING_ID + + implicit none + + class(regrid_interp_vcoord), intent(inout), target :: this + class(regrid_mesh_base), intent(inout), target :: out_mesh + type(regrid_nodemap), intent(in), target :: nodeMap_list(:) + + character(len=H_SHORT) :: vintrp_name + character(len=H_LONG ) :: in_topofile_basename = '' ! Basename of the input file + character(len=H_SHORT) :: topo_varname = 'topo' + + integer, parameter :: FZ_nmax = 1000 + integer :: out_NeZ = -1 + integer :: out_PolyOrder_v = 1 + real(RP) :: out_dom_vmin + real(RP) :: out_dom_vmax + real(RP) :: out_FZ(FZ_nmax) + logical :: extrapolate + + namelist / PARAM_INTERP_VCOORD / & + vintrp_name, & + in_topofile_basename, & + topo_varname, & + out_NeZ, & + out_PolyOrder_v, & + out_dom_vmin, & + out_dom_vmax, & + out_Fz, & + extrapolate + + integer :: ierr + + type(FILE_base_meshfield) :: topo_file + type(MeshFieldCommRectDom2D) :: comm2d + type(MeshFieldCommCubeDom3D) :: comm3d + type(MeshFieldCommCubedSphereDom2D) :: comm2d_cs + type(MeshFieldCommCubedSphereDom3D) :: comm3d_cs + + integer :: n + type(regrid_nodemap), pointer :: nmap + type(LocalMesh3D), pointer :: lcmesh + type(ElementBase3D), pointer :: elem + + class(MeshBase2D), pointer :: ptr_mesh2D + class(regrid_mesh_base), pointer :: in_mesh + !------------------------------------------- + + LOG_NEWLINE + LOG_INFO("interp_vcoord_Init",*) 'Setup' + + vintrp_name = 'MODEL' + extrapolate = .false. + + !--- read namelist + rewind(IO_FID_CONF) + read(IO_FID_CONF,nml=PARAM_INTERP_VCOORD,iostat=ierr) + if ( ierr < 0 ) then !--- missing + LOG_INFO("interp_vcoord",*) 'Not found namelist. Default used.' + elseif( ierr > 0 ) then !--- fatal error + LOG_ERROR("interp_vcoord",*) 'Not appropriate names in namelist PARAM_INTERP_VCOORD. Check!' + call PRC_abort + endif + LOG_NML(PARAM_INTERP_VCOORD) + + select case( vintrp_name ) + case( 'MODEL' ) + this%vintrp_typeid= INTERP_VCOORD_MODEL_ID + this%out_mesh3D_ptr => out_mesh%ptr_mesh3D + case( 'HEIGHT' ) + this%vintrp_typeid = INTERP_VCOORD_HEIGHT_ID + case( 'PRESSURE' ) + this%vintrp_typeid = INTERP_VCOORD_PRESS_ID + case( 'SIGMA' ) + this%vintrp_typeid = INTERP_VCOORD_SIGMA_ID + case default + LOG_ERROR("interp_vcoord_Init",*) 'Not appropriate vintrp_type. Check!', vintrp_name + call PRC_abort + end select + + !- Vertical interpolation (MODEL) + + do n=1, out_mesh%ptr_mesh3D%LOCAL_MESH_NUM + lcmesh => out_mesh%ptr_mesh3D%lcmesh_list(n) + !--- + nmap => nodeMap_list(n) + in_mesh => nmap%in_mesh_list(1) + call regrid_vcoord_search_pos_model( this, & + nmap%elem_k(:,:), nmap%elem_z(:,:), & ! (out) + lcmesh, lcmesh%refElem3D, nmap%local_domID(:,:), nmap%lcprc(:,:), & ! (in) + nmap%elem_i(:,:), nmap%elem_j(:,:), & ! (in) + nmap%in_mesh_list, in_mesh%NeZ, in_mesh%NeX, in_mesh%NeY ) ! (in) + end do + + this%extrapolate = extrapolate + + !- Prepair topography data + + call out_mesh%ptr_mesh3D%GetMesh2D( ptr_mesh2D ) + + call this%topography%Init( topo_varname, ptr_mesh2D ) + if ( in_topofile_basename /= '' ) then + select type( ptr_mesh2D ) + class is (MeshRectDom2D) + call topo_file%Init( 1, mesh2D=ptr_mesh2D ) + class is (MeshCubedSphereDom2D) + call topo_file%Init( 1, meshCubedSphere2D=ptr_mesh2D ) + end select + call topo_file%Open( in_topofile_basename, PRC_myrank ) + call topo_file%Read_Var( MF2D_XY, topo_varname, this%topography%topo ) + call topo_file%Close() + call topo_file%Final() + end if + + !-- Setup vertical coordinate + + select type( ptr_mesh2D ) + class is (MeshRectDom2D) + call comm2d%Init( 1, 0, ptr_mesh2D ) + call comm3d%Init( 1, 1, out_mesh%mesh3D ) + call this%topography%SetVCoordinate( out_mesh%ptr_mesh3D, & ! (inout) + MESH_VCOORD_TERRAIN_FOLLOWING_ID, out_mesh%dom_zmax, & ! (in) + comm3d, comm2d ) ! (in) + call comm2d%Final() + call comm3d%Final() + class is (MeshCubedSphereDom2D) + call comm2d_cs%Init( 1, 0, ptr_mesh2D ) + call comm3d_cs%Init( 1, 1, out_mesh%csmesh3D ) + call this%topography%SetVCoordinate( out_mesh%ptr_mesh3D, & ! (inout) + MESH_VCOORD_TERRAIN_FOLLOWING_ID, out_mesh%dom_zmax, & ! (in) + comm3d_cs, comm2d_cs ) ! (in) + call comm2d_cs%Final() + call comm3d_cs%Final() + end select + + !-- + + if ( this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + + call this%elem%Init( out_mesh%elem3D%PolyOrder_h, out_PolyOrder_v, .true. ) + + select type( ptr_mesh2D ) + class is (MeshRectDom2D) + + call this%mesh3D%Init( out_mesh%NeGX, out_mesh%NeGY, out_NeZ, & + out_mesh%dom_xmin, out_mesh%dom_xmax, out_mesh%dom_ymin, out_mesh%dom_ymax, & + out_dom_vmin, out_dom_vmax, & + out_mesh%isPeriodicX, out_mesh%isPeriodicY, out_mesh%isPeriodicZ, & + this%elem, out_mesh%NLocalMeshPerPRC, & + out_mesh%NprcX, out_mesh%NprcY, & + FZ=out_FZ(1:out_NeZ+1) ) + + this%out_mesh3D_ptr => this%mesh3D + + if ( out_mesh%mesh_type_id == REGRID_MESHTYPE_LONLAT3D_ID ) then + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatv', 'degree', 'longitude,latitude,altitude' ) + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzv', 'degree', 'longitude,latitude,altitude' ) + end if + + class is (MeshCubedSphereDom2D) + + call this%csmesh3D%Init( out_mesh%NeGX, out_mesh%NeGY, out_NeZ, RPlanet, & + out_dom_vmin, out_dom_vmax, & + this%elem, out_mesh%NLocalMeshPerPRC, & + nproc=out_mesh%Nprc, FZ=out_FZ(1:out_NeZ+1) ) + + this%out_mesh3D_ptr => this%csmesh3D + + end select + + call this%out_mesh3D_ptr%Generate() + + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)', & + positive_down = .true. ) + call this%pres%Init( "PRES", "Pa", out_mesh%ptr_mesh3D ) + else if ( this%vintrp_typeid == INTERP_VCOORD_SIGMA_ID ) then + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'sig', '1', 'altitude (sigma coordinate)', & + positive_down = .true. ) + call this%pres%Init( "PRES", "Pa", out_mesh%ptr_mesh3D ) + else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude (height coordinate)' ) + end if + + !------------------------ + + allocate( this%vintrp_info(this%out_mesh3D_ptr%LOCAL_MESH_NUM) ) + + do n=1, this%out_mesh3D_ptr%LOCAL_MESH_NUM + lcmesh => this%out_mesh3D_ptr%lcmesh_list(n) + elem => lcmesh%refElem3D + allocate( this%vintrp_info(n)%xi2v_coef(elem%Np,lcmesh%Ne) ) + allocate( this%vintrp_info(n)%xi2v_idx_k(elem%Np,lcmesh%Ne,2) ) + allocate( this%vintrp_info(n)%xi2v_idx_p(elem%Np,lcmesh%Ne,2) ) + end do + + end if + + call this%vintrp_var3D%Init( 'regrid_vintrp_var3D', '', this%out_mesh3D_ptr ) + + return + end subroutine regrid_interp_vcoord_Init + +!OCL SERIAL + subroutine regrid_interp_vcoord_Final( this ) + implicit none + class(regrid_interp_vcoord), intent(inout) :: this + + integer :: n + class(MeshBase3D), pointer :: mesh3D + !------------------------------------------- + + call this%vintrp_var3D%Final() + call this%topography%Final() + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) & + call this%pres%Final() + + if ( allocated(this%vintrp_info) ) then + do n=1, size(this%vintrp_info) + deallocate( this%vintrp_info(n)%xi2v_coef ) + deallocate( this%vintrp_info(n)%xi2v_idx_k ) + deallocate( this%vintrp_info(n)%xi2v_idx_p ) + end do + deallocate( this%vintrp_info ) + end if + + if (this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + select type( mesh3D => this%out_mesh3D_ptr ) + class is (MeshCubeDom3D) + call mesh3D%Final() + class is (MeshCubedSphereDom3D) + call mesh3D%Final() + end select + call this%elem%Final() + end if + + nullify( this%out_mesh3D_ptr ) + + return + end subroutine regrid_interp_vcoord_Final + +!OCL SERIAL + subroutine regrid_interp_vcoord_update_weight( this, istep, out_mesh, nodeMap_list ) + use mod_regrid_interp_field, only: & + regrid_interp_field_Interpolate + implicit none + class(regrid_interp_vcoord), intent(inout) :: this + integer, intent(in) :: istep + class(regrid_mesh_base), intent(in), target :: out_mesh + type(regrid_nodemap), intent(in) :: nodeMap_list(:) + + integer :: n + class(MeshBase3D), pointer :: mesh3D + !--------------------------------------------------------------- + + select case( this%vintrp_typeid ) + case ( INTERP_VCOORD_MODEL_ID ) + return + case ( INTERP_VCOORD_PRESS_ID, INTERP_VCOORD_SIGMA_ID ) + call regrid_interp_field_Interpolate( istep, this%pres%varname, & + out_mesh, this%pres, nodeMap_list ) + end select + + mesh3D => out_mesh%ptr_mesh3D + do n=1, mesh3D%LOCAL_MESH_NUM + call interp_vcoord_update_weight_core( this, n, & + mesh3D%lcmesh_list(n), mesh3D%refElem3D, & + this%out_mesh3D_ptr%lcmesh_list(n), this%elem ) + end do + + return + end subroutine regrid_interp_vcoord_update_weight + +!OCL SERIAL + subroutine regrid_interp_vcoord_interpolate( this, istep, mesh_ref, field_ref ) + implicit none + class(regrid_interp_vcoord), intent(inout) :: this + integer, intent(in) :: istep + class(MeshBase3D), intent(in) :: mesh_ref + class(MeshField3D), intent(in) :: field_ref + + integer :: n + !--------------------------------------------------------------- + + if ( this%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) return + + do n=1, this%out_mesh3D_ptr%LOCAL_MESH_NUM + call interp_vcoord_interpolate_core( this%vintrp_info(n), n, & + this%vintrp_var3D%local(n)%val, field_ref%local(n)%val, & + mesh_ref%lcmesh_list(n), mesh_ref%lcmesh_list(n)%refElem3D, & + this%out_mesh3D_ptr%lcmesh_list(n), this%elem ) + end do + + return + end subroutine regrid_interp_vcoord_interpolate + +!- private ------------------------------------- + +!OCL SERIAL + subroutine interp_vcoord_interpolate_core( & + vintrp_info, domID, var_intrp, var_ref, lcmesh_ref, elem_ref, lcmesh, elem ) + + implicit none + type(vinterpcoef_info), intent(inout) :: vintrp_info + integer, intent(in) :: domID + class(LocalMesh3D), intent(in) :: lcmesh_ref + class(ElementBase3D), intent(in) :: elem_ref + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + real(RP), intent(out) :: var_intrp(elem %Np,lcmesh %NeA) + real(RP), intent(in) :: var_ref (elem_ref%Np,lcmesh_ref%NeA) + + integer :: ke, p + integer :: ke_r, p_r, kke_r, pp_r + real(RP) :: coef + !-------------------------------------------------- + + !$omp parallel do collapse(2) private(ke, p, ke_r, p_r, kke_r, pp_r, coef) + do ke=lcmesh%NeS, lcmesh%NeE + do p=1, elem%Np + ke_r = vintrp_info%xi2v_idx_k(p,ke,1) + kke_r = vintrp_info%xi2v_idx_k(p,ke,2) + p_r = vintrp_info%xi2v_idx_p(p,ke,1) + pp_r = vintrp_info%xi2v_idx_p(p,ke,2) + coef = vintrp_info%xi2v_coef(p,ke) + var_intrp(p,ke) = UNDEF + if ( ke_r > 0 ) var_intrp(p,ke) = coef * var_ref(p_r,ke_r) + if ( kke_r > 0 ) var_intrp(p,ke) = var_intrp(p,ke) + (1.0_RP - coef) * var_ref(pp_r,kke_r) + end do + end do + + return + end subroutine interp_vcoord_interpolate_core + +!OCL SERIAL + subroutine interp_vcoord_update_weight_core( & + this, domID, lcmesh_ref, elem_ref, lcmesh, elem ) + + implicit none + + class(regrid_interp_vcoord), intent(inout) :: this + integer, intent(in) :: domID + class(LocalMesh3D), intent(in), target :: lcmesh_ref + class(ElementBase3D), intent(in) :: elem_ref + class(LocalMesh3D), intent(in) :: lcmesh + class(ElementBase3D), intent(in) :: elem + + integer :: p, ke + integer :: p_ref, pp_ref, ke_ref, kke_ref + integer :: ke_xy, ke_z, ke_zz + integer :: p_xy, p_z, p_zz + integer :: ke_sfc_ref, ke_top_ref + integer :: p_sfc_ref, p_top_ref + real(RP) :: height_ref(elem_ref%Np,lcmesh_ref%Ne) + real(RP) :: height (elem%Np ,lcmesh%Ne ) + + integer :: indx_k(elem%Np,2) + integer :: indx_p(elem%Np,2) + real(RP) :: vfact(elem%Np) + + class(LocalMesh2D), pointer :: lcmesh2D + real(RP), allocatable :: SfcPres(:,:) + + !------------------------------------------------------------- + + if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + !$omp parallel + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + height_ref(:,ke) = - log( this%pres%local(domID)%val(:,ke) ) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) + end do + !$omp end parallel + else if ( this%vintrp_typeid == INTERP_VCOORD_SIGMA_ID ) then + lcmesh2D => lcmesh_ref%lcmesh2D + allocate( SfcPres(lcmesh2D%refElem2D%Np,lcmesh2D%NeA) ) + !$omp parallel private(ke, ke_xy) + !$omp do + do ke_xy=lcmesh2D%NeS, lcmesh2D%NeE + SfcPres(:,ke_xy) = this%pres%local(domID)%val(elem_ref%Hslice(:,1),ke_xy) + end do + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + ke_xy = lcmesh_ref%EMap3Dto2D(ke) + height_ref(:,ke) = - log( this%pres%local(domID)%val(:,ke) ) & + + log( SfcPres(elem_ref%IndexH2Dto3D(:),ke_xy) ) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + ke_xy = lcmesh%EMap3Dto2D(ke) + height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) + end do + !$omp end parallel + else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + !$omp parallel + !$omp do + do ke=lcmesh_ref%NeS, lcmesh_ref%NeE + height_ref(:,ke) = lcmesh_ref%zlev(:,ke) + end do + !$omp do + do ke=lcmesh%NeS, lcmesh%NeE + height(:,ke) = lcmesh%pos_en(:,ke,3) + end do + !$omp end parallel + end if + + !$omp parallel do collapse(2) private( & + !$omp ke_z, ke_xy, ke, ke_sfc_ref, ke_top_ref, & + !$omp indx_k, indx_p, vfact, & + !$omp p_z, p_xy, p, p_sfc_ref, p_top_ref, & + !$omp ke_zz, p_zz, ke_ref, p_ref, kke_ref, pp_ref ) + do ke_z=1, lcmesh%NeZ + do ke_xy=1, lcmesh%NeX * lcmesh%NeY + ke = ke_xy + (ke_z - 1) * lcmesh%NeX * lcmesh%NeY + ke_sfc_ref = ke_xy + ke_top_ref = ke_xy + (lcmesh_ref%NeZ - 1) * lcmesh%NeX * lcmesh%NeY + + indx_k(:,:) = -1 + indx_p(:,:) = -1 + vfact(:) = UNDEF + do p_z=1, elem%Nnode_v + do p_xy=1, elem%Nnode_h1D**2 + p = p_xy + (p_z -1) * elem%Nnode_h1D**2 + p_sfc_ref = p_xy + p_top_ref = p_xy + (elem_ref%Nnode_v -1) * elem%Nnode_h1D**2 + + if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) - EPS ) then + if ( this%extrapolate ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + end if + else if ( height(p,ke) < height_ref(p_sfc_ref,ke_sfc_ref) ) then + indx_k(p,1) = ke_sfc_ref; indx_p(p,1) = p_sfc_ref + vfact(p) = 1.0_RP + else if ( height(p,ke) > height_ref(p_top_ref,ke_top_ref) + EPS ) then + if ( this%extrapolate ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + end if + else if ( height(p,ke) >= height_ref(p_top_ref,ke_top_ref) ) then + indx_k(p,1) = ke_top_ref; indx_p(p,1) = p_top_ref + vfact(p) = 1.0_RP + else + + search : do ke_zz = 1, lcmesh_ref%NeZ + do p_zz = 1, elem_ref%Nnode_v + ke_ref = ke_xy + (ke_zz-1) * lcmesh%NeX * lcmesh%NeY + p_ref = p_xy + (p_zz-1) * elem%Nnode_h1D**2 + if ( p_zz < elem_ref%Nnode_v ) then + pp_ref = p_xy + p_zz * elem%Nnode_h1D**2 + kke_ref = ke_ref + else + pp_ref = 2 + kke_ref = ke_xy + ke_zz * lcmesh%NeX * lcmesh%NeY + end if + if ( height(p,ke) >= height_ref(p_ref,ke_ref) & + .and. height(p,ke) < height_ref(pp_ref,kke_ref) ) then + indx_k(p,1) = ke_ref; indx_k(p,2) = kke_ref; + indx_p(p,1) = p_ref; indx_p(p,2) = pp_ref; + vfact(p) = ( height_ref(pp_ref,kke_ref) - height (p,ke) ) & + / ( height_ref(pp_ref,kke_ref) - height_ref(p_ref,ke_ref) ) + exit search + end if + end do + end do search + + end if + end do + end do + + this%vintrp_info(domID)%xi2v_idx_k(:,ke,1) = indx_k(:,1) + this%vintrp_info(domID)%xi2v_idx_k(:,ke,2) = indx_k(:,2) + this%vintrp_info(domID)%xi2v_idx_p(:,ke,1) = indx_p(:,1) + this%vintrp_info(domID)%xi2v_idx_p(:,ke,2) = indx_p(:,2) + this%vintrp_info(domID)%xi2v_coef(:,ke) = vfact(:) + end do + end do + + return + end subroutine interp_vcoord_update_weight_core + +!OCL SERIAL + subroutine regrid_vcoord_search_pos_model( this, elem_k, elem_out, & + lcmesh, elem3D, local_domID, lcprc, elem_i, elem_j, & + in_mesh_list, in_NeGZ, in_NeX, in_NeY ) + + implicit none + type(regrid_interp_vcoord), intent(in) :: this + type(LocalMesh3D), intent(in) :: lcmesh + type(ElementBase3D), intent(in) :: elem3D + integer, intent(out) :: elem_k(elem3D%Np,lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) + real(RP), intent(out) :: elem_out(elem3D%Np,lcmesh%NeX*lcmesh%NeY*lcmesh%NeZ) + integer, intent(in) :: local_domID(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: lcprc(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: elem_i(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + integer, intent(in) :: elem_j(elem3D%Nnode_h1D**2,lcmesh%NeX*lcmesh%NeY) + type(regrid_mesh_base), intent(in), target :: in_mesh_list(:) + integer, intent(in) :: in_NeGZ + integer, intent(in) :: in_NeX + integer, intent(in) :: in_NeY + + integer :: in_n + integer :: in_prc + integer :: ke, p + integer :: ke_h, p_h + integer :: ke_z, ke_z2 + integer :: p_z + + type(LocalMesh3D), pointer :: in_lcmesh + real(RP) :: in_Z0, in_Z1 + integer :: in_ke3D + !------------------------------------------- + + !$omp parallel private( & + !$omp ke_h, p_h, in_lcmesh, in_prc, in_n, & + !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) + + !$omp workshare + elem_k(:,:) = -1 + !$omp end workshare + + !$omp do collapse(2) + do ke_h=1, lcmesh%NeX * lcmesh%NeY + do p_h=1, elem3D%Nnode_h1D**2 + in_n = local_domID(p_h,ke_h) + in_prc = lcprc(p_h,ke_h) + + if ( in_n > 0 .and. in_prc > 0 .and. & + elem_i(p_h,ke_h) > 0 .and. elem_j(p_h,ke_h) > 0 ) then + + in_lcmesh => in_mesh_list(in_prc)%ptr_mesh3D%lcmesh_list(in_n) + do ke_z=1, lcmesh%NeZ + do p_z=1, elem3D%Nnode_v + ke = ke_h + (ke_z-1)*lcmesh%NeX*lcmesh%NeY + p = p_h + (p_z-1)*elem3D%Nnode_h1D**2 + do ke_z2=1, in_NeGZ + in_ke3D = elem_i(p_h,ke_h) + (elem_j(p_h,ke_h) - 1) * in_NeX & + + (ke_z2 - 1) * in_NeX * in_NeY + in_Z0 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,1),3) + in_Z1 = in_lcmesh%pos_ev(in_lcmesh%EToV(in_ke3D,5),3) + if ( in_Z0 <= lcmesh%pos_en(p,ke,3) .and. lcmesh%pos_en(p,ke,3) <= in_Z1 ) then + elem_k (p,ke) = ke_z2 + elem_out(p,ke) = lcmesh%pos_en(p,ke,3) + exit + end if + end do + end do + end do + end if + + end do + end do + !$omp end do + !$omp end parallel + + return + end subroutine regrid_vcoord_search_pos_model + +end module mod_regrid_interp_vcoord \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 index c0ce1d35..a81a5a50 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 @@ -42,13 +42,13 @@ module mod_regrid_mesh ! type(regrid_mesh_base), public :: out_mesh + type(regrid_nodemap), public, allocatable :: nodemap(:) !----------------------------------------------------------------------------- ! !++ Private parameters & variables ! - type(regrid_nodemap), allocatable :: nodemap(:) contains @@ -88,7 +88,7 @@ subroutine regrid_mesh_Init() allocate( nodemap( out_mesh%NLocalMeshPerPRC ) ) do n=1, size(nodemap) - call nodemap(n)%Init(in_meshType) + call nodemap(n)%Init( in_meshType, out_mesh ) end do return diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 index e6bcaeae..7a15f1ca 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 @@ -82,6 +82,7 @@ module mod_regrid_mesh_base procedure :: Init => regrid_mesh_base_init procedure :: Final => regrid_mesh_base_final procedure :: Generate => regrid_mesh_base_generate + procedure :: Get_inmesh_hmapinfo => regrid_mesh_base_get_inmesh_hmapinfo end type regrid_mesh_base !----------------------------------------------------------------------------- @@ -173,8 +174,10 @@ subroutine regrid_mesh_base_final( this ) end subroutine regrid_mesh_base_final !OCL SERIAL - subroutine regrid_mesh_base_generate( this ) - + subroutine regrid_mesh_base_generate( this, myrank ) + use scale_prc, only: & + PRC_myrank + use scale_mesh_base2d, only: & MeshBase2D_DIMTYPEID_X, MeshBase2D_DIMTYPEID_Y, & MeshBase2D_DIMTYPEID_XY, MeshBase2D_DIMTYPEID_XYT @@ -184,15 +187,24 @@ subroutine regrid_mesh_base_generate( this ) implicit none class(regrid_mesh_base), intent(inout), target :: this + integer, intent(in), optional :: myrank + + integer :: myrank_ !----------------------------------------------- + if ( present(myrank) ) then + myrank_ = myrank + else + myrank_ = PRC_myrank + end if + select case( this%mesh_type_id ) case( REGRID_MESHTYPE_STRUCTURED2D_ID ) call this%mesh2D%Init( this%NeGX, this%NeGY, & this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, & this%isPeriodicX, this%isPeriodicY, this%elem2D, this%NLocalMeshPerPrc, & - this%NprcX, this%NprcY ) + this%NprcX, this%NprcY, myrank=myrank_ ) this%ptr_mesh2D => this%mesh2D @@ -201,7 +213,7 @@ subroutine regrid_mesh_base_generate( this ) call this%mesh2D%Init( this%NeGX, this%NeGY, & this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, & this%isPeriodicX, .false., this%elem2D, this%NLocalMeshPerPrc, & - this%NprcX, this%NprcY ) + this%NprcX, this%NprcY, myrank=myrank_ ) call this%mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) call this%mesh2D%SetDimInfo( MeshBase2D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) @@ -216,12 +228,12 @@ subroutine regrid_mesh_base_generate( this ) call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & this%isPeriodicX, this%isPeriodicY, this%isPeriodicY, this%elem3D, this%NLocalMeshPerPrc, & - this%NprcX, this%NprcY, nproc=this%Nprc, FZ=this%FZ ) + this%NprcX, this%NprcY, nproc=this%Nprc, myrank=myrank_, FZ=this%FZ ) else call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & this%isPeriodicX, .false., .false., this%elem3D, this%NLocalMeshPerPrc, & - this%NprcX, this%NprcY, nproc=this%Nprc ) + this%NprcX, this%NprcY, nproc=this%Nprc, myrank=myrank_ ) end if this%ptr_mesh3D => this%mesh3D @@ -232,12 +244,12 @@ subroutine regrid_mesh_base_generate( this ) call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & this%isPeriodicX, .false., .false., this%elem3D, this%NLocalMeshPerPrc, & - this%NprcX, this%NprcY, nproc=this%Nprc, FZ=this%FZ ) + this%NprcX, this%NprcY, nproc=this%Nprc, myrank=myrank_, FZ=this%FZ ) else call this%mesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, & this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, this%dom_zmin, this%dom_zmax, & this%isPeriodicX, .false., .false., this%elem3D, this%NLocalMeshPerPrc, & - this%NprcX, this%NprcY, nproc=this%Nprc ) + this%NprcX, this%NprcY, nproc=this%Nprc, myrank=myrank_ ) end if call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) @@ -248,8 +260,8 @@ subroutine regrid_mesh_base_generate( this ) case( REGRID_MESHTYPE_CUBEDSPHERE2D_ID ) - call this%csmesh2D%Init( this%NeGX, this%NeGY, RPlanet, & - this%elem2D, this%NLocalMeshPerPrc, nproc=this%Nprc ) + call this%csmesh2D%Init( this%NeGX, this%NeGY, RPlanet, & + this%elem2D, this%NLocalMeshPerPrc, nproc=this%Nprc, myrank=myrank_ ) this%ptr_mesh2D => this%csmesh2D @@ -258,21 +270,67 @@ subroutine regrid_mesh_base_generate( this ) if ( allocated( this%FZ ) ) then call this%csmesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, RPlanet, & this%dom_zmin, this%dom_zmax, this%elem3D, this%NLocalMeshPerPrc, & - nproc=this%Nprc, FZ=this%FZ ) + nproc=this%Nprc, myrank=myrank_, FZ=this%FZ ) else call this%csmesh3D%Init( this%NeGX, this%NeGY, this%NeGZ, RPlanet, & this%dom_zmin, this%dom_zmax, this%elem3D, this%NLocalMeshPerPrc, & - nproc=this%Nprc ) + nproc=this%Nprc, myrank=myrank_ ) end if this%ptr_mesh3D => this%csmesh3D end select + if ( associated( this%ptr_mesh2D ) ) call this%ptr_mesh2D%Generate() + if ( associated( this%ptr_mesh3D ) ) call this%ptr_mesh3D%Generate() + return end subroutine regrid_mesh_base_generate - !-- private -------------------------------- + subroutine regrid_mesh_base_get_inmesh_hmapinfo( this, & + tileID_table, panelID_table, pi_table, pj_table ) + + implicit none + class(regrid_mesh_base), intent(inout) :: this + integer, intent(out) :: tileID_table(this%NLocalMeshPerPrc,this%Nprc) + integer, intent(out) :: panelID_table(this%NLocalMeshPerPrc,this%Nprc) + integer, intent(out) :: pi_table(this%NLocalMeshPerPrc*this%Nprc) + integer, intent(out) :: pj_table(this%NLocalMeshPerPrc*this%Nprc) + + type(MeshCubedSphereDom2D) :: csmesh_dummy + type(MeshRectDom2D) :: mesh_dummy + !---------------------------------------- + + select case( this%mesh_type_id ) + case ( REGRID_MESHTYPE_CUBEDSPHERE2D_ID, REGRID_MESHTYPE_CUBEDSPHERE3D_ID ) + + call csmesh_dummy%Init( this%NeGX, this%NeGY, RPlanet, & + this%elem2D, this%NLocalMeshPerPRC, nproc=this%Nprc, myrank=0 ) + + call csmesh_dummy%AssignDomID( this%NprcX, this%NprcY, & ! (in) + tileID_table, panelID_table, pi_table, pj_table ) ! (out) + + call csmesh_dummy%Final() + + case ( REGRID_MESHTYPE_STRUCTURED2D_ID, REGRID_MESHTYPE_STRUCTURED3D_ID, & + REGRID_MESHTYPE_LONLAT2D_ID, REGRID_MESHTYPE_LONLAT3D_ID ) + + call mesh_dummy%Init( this%NeGX, this%NeGY, & + this%dom_xmin, this%dom_xmax, this%dom_ymin, this%dom_ymax, & + this%isPeriodicX, this%isPeriodicY, this%elem2D, & + this%NLocalMeshPerPRC, this%NprcX, this%NprcY ) + + call mesh_dummy%AssignDomID( & + tileID_table, panelID_table, pi_table, pj_table ) + + call mesh_dummy%Final() + + end select + + return + end subroutine regrid_mesh_base_get_inmesh_hmapinfo + +!-- private -------------------------------- !OCL SERIAL subroutine regrid_mesh_base_init_mesh2D( this ) @@ -431,6 +489,10 @@ subroutine regrid_mesh_base_init_csmesh2D( this ) this%NeX = NeGX / this%NprcX this%NeY = NeGY / this%NprcY + this%dom_xmin = csmesh2D_dummy%xmin_gl + this%dom_xmax = csmesh2D_dummy%xmax_gl + this%dom_ymin = csmesh2D_dummy%ymin_gl + this%dom_ymax = csmesh2D_dummy%ymax_gl call csmesh2D_dummy%Final() @@ -647,7 +709,12 @@ subroutine regrid_mesh_base_init_csmesh3D( this ) Nprc, NLocalMeshPerPrc * Nprc ) ! (in) this%NeX = NeGX / this%NprcX - this%NeY = NeGY / this%NprcY + this%NeY = NeGY / this%NprcY + this%dom_xmin = csmesh2D_dummy%xmin_gl + this%dom_xmax = csmesh2D_dummy%xmax_gl + this%dom_ymin = csmesh2D_dummy%ymin_gl + this%dom_ymax = csmesh2D_dummy%ymax_gl + call csmesh2D_dummy%Final() is_spec_FZ = .true. diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 index 1d919715..510afa6f 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 @@ -63,22 +63,87 @@ subroutine NodeMap_Init( this, & integer :: n class(LocalMesh2D), pointer :: lcmesh2D + class(LocalMesh3D), pointer :: lcmesh3D + + real(RP), allocatable :: in_tiles_x(:,:,:) + real(RP), allocatable :: in_tiles_y(:,:,:) + integer, allocatable :: tileID_table(:,:) + integer, allocatable :: panelID_table(:,:) + integer, allocatable :: pi_table(:) + integer, allocatable :: pj_table(:) + + integer :: in_p, in_n + integer :: i, j + integer :: tileID + + real(RP) :: delx, dely !------------------------------------ call inmesh_dummy%Init( MESH_INID, inmesh_type ) + allocate( in_tiles_x(4,inmesh_dummy%NLocalMeshPerPrc,inmesh_dummy%Nprc) ) + allocate( in_tiles_y(4,inmesh_dummy%NLocalMeshPerPrc,inmesh_dummy%Nprc) ) + allocate( tileID_table(inmesh_dummy%NLocalMeshPerPrc,inmesh_dummy%Nprc) ) + allocate( panelID_table(inmesh_dummy%NLocalMeshPerPrc,inmesh_dummy%Nprc) ) + allocate( pi_table(inmesh_dummy%NLocalMeshPerPrc*inmesh_dummy%Nprc) ) + allocate( pj_table(inmesh_dummy%NLocalMeshPerPrc*inmesh_dummy%Nprc) ) + + return + !--- + + call inmesh_dummy%Get_inmesh_hmapinfo( & + tileID_table, panelID_table, pi_table, pj_table ) ! (out) + + delx = ( inmesh_dummy%dom_xmax - inmesh_dummy%dom_xmin ) / dble(inmesh_dummy%NprcX) + dely = ( inmesh_dummy%dom_ymax - inmesh_dummy%dom_ymin ) / dble(inmesh_dummy%NprcY) + + do in_p=1, inmesh_dummy%Nprc + do in_n=1, inmesh_dummy%NLocalMeshPerPRC + tileID = tileID_table(in_n,in_p) + i = pi_table(tileID); j = pj_table(tileID) + + in_tiles_x(:,in_n,in_p) = inmesh_dummy%dom_xmin + delx * dble( (/ i-1, i, i, i-1 /) ) + in_tiles_y(:,in_n,in_p) = inmesh_dummy%dom_ymin * dble( (/ j-1, j-1, j, j /) ) + + if (i==inmesh_dummy%NprcX) then + in_tiles_x(2:3,in_n,in_p) = in_tiles_x(2:3,in_n,in_p) + 1.0E-12_RP * delx + end if + if (j==inmesh_dummy%NprcY) then + in_tiles_y(3:4,in_n,in_p) = in_tiles_y(3:4,in_n,in_p) + 1.0E-12_RP * dely + end if + end do + end do + if ( associated(out_mesh%ptr_mesh2D ) ) then + do n=1, out_mesh%ptr_mesh2D%LOCAL_MESH_NUM lcmesh2D => out_mesh%ptr_mesh2D%lcmesh_list(n) call NodeMap_construct_nodemap_2D( this, & inmesh_dummy%mesh_type_id, out_mesh%mesh_type_id, & + inmesh_type, & lcmesh2D%refElem2D%Nfp, lcmesh2D%NeX * lcmesh2D%NeY, lcmesh2D, & + in_tiles_x, in_tiles_y, tileID_table, panelID_table, & inmesh_dummy%Nprc, inmesh_dummy%NprcX, inmesh_dummy%NprcY, & - inmesh_dummy%NeX, inmesh_dummy%NeY, inmesh_dummy%NLocalMeshPerPRC ) + inmesh_dummy%NeX, inmesh_dummy%NeY, inmesh_dummy%NLocalMeshPerPRC, & + .true. ) end do end if + if ( associated(out_mesh%ptr_mesh3D ) ) then + + do n=1, out_mesh%ptr_mesh3D%LOCAL_MESH_NUM + lcmesh3D => out_mesh%ptr_mesh3D%lcmesh_list(n) + call NodeMap_construct_nodemap_3D( this, & + inmesh_dummy%mesh_type_id, out_mesh%mesh_type_id, & + inmesh_type, & + lcmesh3D%refElem3D%Nnode_h1D, lcmesh3D%NeX * lcmesh3D%NeY, lcmesh2D, & + lcmesh3D%refElem3D%Np, lcmesh3D%Ne, lcmesh3D, & + in_tiles_x, in_tiles_y, tileID_table, panelID_table, & + inmesh_dummy%Nprc, inmesh_dummy%NprcX, inmesh_dummy%NprcY, & + inmesh_dummy%NeX, inmesh_dummy%NeY, inmesh_dummy%NLocalMeshPerPRC ) + end do + end if call inmesh_dummy%Final() @@ -100,9 +165,13 @@ end subroutine NodeMap_Final !OCL SERIAL subroutine NodeMap_construct_nodemap_2D( this, & in_meshtype_id, out_meshtype_id, & + in_meshtype_name, & Np1D, Ne2D, lcmesh, & + tile_x, tile_y, tileID_table, panelID_table, & in_Nprc, in_NprcX, in_NprcY, in_NeX, in_NeY, & - in_NLocalMeshPerPrc ) + in_NLocalMeshPerPrc, & + do_mesh_generation, & + in_lcprc2prc, in_prcnum_out ) use scale_polygon, only: & polygon_inpoly @@ -115,18 +184,21 @@ subroutine NodeMap_construct_nodemap_2D( this, & class(LocalMesh2D), intent(in) :: lcmesh integer, intent(in) :: in_meshtype_id integer, intent(in) :: out_meshtype_id + character(len=*), intent(in) :: in_meshtype_name integer, intent(in) :: in_Nprc integer, intent(in) :: in_NprcX integer, intent(in) :: in_NprcY integer, intent(in) :: in_NeX integer, intent(in) :: in_NeY integer, intent(in) :: in_NLocalMeshPerPrc + real(RP), intent(in) :: tile_x(4,in_NLocalMeshPerPrc,in_Nprc) + real(RP), intent(in) :: tile_y(4,in_NLocalMeshPerPrc,in_Nprc) + integer, intent(in) :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) + integer, intent(in) :: panelID_table(in_NLocalMeshPerPrc,in_Nprc) + logical, intent(in) :: do_mesh_generation + integer, intent(out), optional :: in_lcprc2prc(in_Nprc) + integer, intent(out), optional :: in_prcnum_out - real(RP) :: tile_x(4,in_NLocalMeshPerPrc,in_Nprc) - real(RP) :: tile_y(4,in_NLocalMeshPerPrc,in_Nprc) - integer :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) - integer :: panelID_table(in_NLocalMeshPerPrc,in_Nprc) - integer :: lc_domID, prcID, in_prc, in_n integer :: i, j integer :: p, ke @@ -282,22 +354,85 @@ subroutine NodeMap_construct_nodemap_2D( this, & !-- prepair mesh for input data -------------------------------- + if ( .not. do_mesh_generation ) return + + allocate( this%in_mesh_list(in_prc_num) ) + do i=1, in_prc_num + call this%in_mesh_list(i)%Init( MESH_INID, in_meshtype_name ) + call this%in_mesh_list(i)%Generate( myrank=in_lcprc2prc_tmp(i)-1 ) + end do + + if ( present(in_lcprc2prc) ) in_lcprc2prc(:) = in_lcprc2prc_tmp(i) + if ( present(in_prcnum_out) ) in_prcnum_out = in_prc_num return end subroutine NodeMap_construct_nodemap_2D -!OCL SERIAL - subroutine get_inmesh_mapinfo( & - in_meshtype_id, in_Nprc, in_NLocalMeshPerPrc ) + +!OCL SERIAL + subroutine NodeMap_construct_nodemap_3D( this, & + in_meshtype_id, out_meshtype_id, & + in_meshtype_name, & + Np1D, Ne2D, lcmesh2D, & + Np3D, Ne3D, lcmesh3D, & + tile_x, tile_y, tileID_table, panelID_table, & + in_Nprc, in_NprcX, in_NprcY, in_NeX, in_NeY, & + in_NLocalMeshPerPrc ) + + use scale_polygon, only: & + polygon_inpoly + implicit none + class(regrid_nodemap), intent(inout) :: this + integer, intent(in) :: Np1D + integer, intent(in) :: Ne2D + class(LocalMesh2D), intent(in) :: lcmesh2D + integer, intent(in) :: Np3D + integer, intent(in) :: Ne3D + class(LocalMesh3D), intent(in) :: lcmesh3D integer, intent(in) :: in_meshtype_id + character(len=*), intent(in) :: in_meshtype_name + integer, intent(in) :: out_meshtype_id integer, intent(in) :: in_Nprc + integer, intent(in) :: in_NprcX + integer, intent(in) :: in_NprcY + integer, intent(in) :: in_NeX + integer, intent(in) :: in_NeY integer, intent(in) :: in_NLocalMeshPerPrc - !----------------------------------------------------- - + real(RP), intent(in) :: tile_x(4,in_NLocalMeshPerPrc,in_Nprc) + real(RP), intent(in) :: tile_y(4,in_NLocalMeshPerPrc,in_Nprc) + integer, intent(in) :: tileID_table(in_NLocalMeshPerPrc,in_Nprc) + integer, intent(in) :: panelID_table(in_NLocalMeshPerPrc,in_Nprc) + + integer :: in_lcprc2prc(in_Nprc) + integer :: in_prc_num + integer :: i + !----------------------------------------------------------------- + + allocate( this%elem_k(Np3D, Ne3D) ) + allocate( this%elem_z(Np3D, Ne3D) ) + + call NodeMap_construct_nodemap_2D( this, & + in_meshtype_id, out_meshtype_id, & + in_meshtype_name, & + Np1D, Ne2D, lcmesh2D, & + tile_x, tile_y, tileID_table, panelID_table, & + in_Nprc, in_NprcX, in_NprcY, in_NeX, in_NeY, & + in_NLocalMeshPerPrc, .false., & + in_lcprc2prc=in_lcprc2prc, & + in_prcnum_out=in_prc_num ) + + !-- prepair mesh for input data -------------------------------- + + allocate( this%in_mesh_list(in_prc_num) ) + do i=1, in_prc_num + call this%in_mesh_list(i)%Init( MESH_INID, in_meshtype_name ) + call this%in_mesh_list(i)%Generate( myrank=in_lcprc2prc(i)-1 ) + end do + return - end subroutine get_inmesh_mapinfo + end subroutine NodeMap_construct_nodemap_3D !OCL SERIAL subroutine get_panelID( inPanelID, & diff --git a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 index 9d59befc..1198216b 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 @@ -21,6 +21,20 @@ program regrid_tool use scale_prof use scale_prc, only: PRC_abort + use mod_regrid_mesh, only: & + out_mesh, nodemap + use mod_regrid_interp_field, only: & + OutVarInfo, & + out_vinfo, out_var_num, & + out_var3D, out_var2D, & + regrid_interp_field_Interpolate + use mod_regrid_interp_vcoord, only: & + regrid_interp_vcoord, & + INTERP_VCOORD_MODEL_ID + use mod_regrid_file, only: & + regrid_file_write_var + + !----------------------------------------------------------------------------- implicit none !----------------------------------------------------------------------------- @@ -46,7 +60,10 @@ program regrid_tool integer :: istep real(DP) :: start_sec - !----------------------------------------------------------------------------- + type(regrid_interp_vcoord) :: vintrp + type(OutVarInfo), pointer :: vinfo + + !----------------------------------------------------------------------------- call initialize() @@ -57,36 +74,36 @@ program regrid_tool LOG_NEWLINE LOG_PROGRESS(*) 'START LOOP' - ! do vid =1, out_var_num - ! vinfo => out_vinfo(vid) - ! do istep=1, vinfo%num_step, vinfo%out_tintrv - ! start_sec = vinfo%start_sec + (istep - 1) * vinfo%dt - - ! LOG_INFO("INTERP",'(a,i4)') 'Interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep - ! if (is_mesh3D) then - ! call interp_field_Interpolate( istep, vinfo%varname, & - ! out_mesh3D, out_var3D, nodeMap_list ) - - ! if ( vintrp%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) then - ! call interp_file_write_var( vid, out_var3D, & - ! start_sec, start_sec + vinfo%dt ) - ! else - ! call vintrp%Update_weight( istep, out_mesh3D, nodeMap_list ) - ! call vintrp%Interpolate( istep, out_mesh3D, out_var3D ) - - ! call interp_file_write_var( vid, vintrp%vintrp_var3D, & - ! start_sec, start_sec + vinfo%dt ) - ! end if - - ! else - ! call interp_field_Interpolate( istep, vinfo%varname, & - ! out_mesh2D, out_var2D, nodeMap_list ) - ! call interp_file_write_var( vid, out_var2D, & - ! start_sec, start_sec + vinfo%dt ) - ! end if - ! if( IO_L ) call flush(IO_FID_LOG) - ! end do - ! end do + do vid =1, out_var_num + vinfo => out_vinfo(vid) + do istep=1, vinfo%num_step, vinfo%out_tintrv + start_sec = vinfo%start_sec + (istep - 1) * vinfo%dt + + LOG_INFO("INTERP",'(a,i4)') 'Interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep + if ( associated( out_mesh%ptr_mesh3D ) ) then + call regrid_interp_field_Interpolate( istep, vinfo%varname, & + out_mesh, out_var3D, nodemap ) + + if ( vintrp%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) then + call regrid_file_write_var( vid, out_var3D, & + start_sec, start_sec + vinfo%dt ) + else + call vintrp%Update_weight( istep, out_mesh, nodemap ) + call vintrp%Interpolate( istep, out_mesh%ptr_mesh3D, out_var3D ) + + call regrid_file_write_var( vid, vintrp%vintrp_var3D, & + start_sec, start_sec + vinfo%dt ) + end if + + else + call regrid_interp_field_Interpolate( istep, vinfo%varname, & + out_mesh, out_var2D, nodemap ) + call regrid_file_write_var( vid, out_var2D, & + start_sec, start_sec + vinfo%dt ) + end if + if( IO_L ) call flush(IO_FID_LOG) + end do + end do LOG_PROGRESS(*) 'END LOOP' LOG_NEWLINE @@ -112,11 +129,11 @@ subroutine initialize() use mod_regrid_mesh, only: & regrid_mesh_Init - ! use mod_cs2lonlat_interp_field, only: & - ! interp_field_Init, & - ! in_basename - ! use mod_cs2lonlat_interp_file, only: & - ! interp_file_Init + use mod_regrid_interp_field, only: & + regrid_interp_field_Init, & + in_basename + use mod_regrid_file, only: & + regrid_file_Init implicit none @@ -176,9 +193,9 @@ subroutine initialize() ! call regrid_mesh_Init() - ! call interp_field_Init( out_mesh2D, out_mesh3D, is_mesh3D ) - ! if ( is_mesh3D ) call vintrp%Init( out_mesh3D, nodeMap_list ) - ! call interp_file_Init( in_basename, out_vinfo, out_mesh2D, vintrp%out_mesh3D_ptr, is_mesh3D ) + call regrid_interp_field_Init( out_mesh ) + if ( associated(out_mesh%ptr_mesh3D) ) call vintrp%Init( out_mesh, nodemap ) + call regrid_file_Init( in_basename, out_vinfo, out_mesh ) !- do_output = .true. @@ -198,18 +215,18 @@ subroutine finalize use scale_file, only: & FILE_close_all - ! use mod_cs2lonlat_interp_field, only: interp_field_Final + use mod_regrid_interp_field, only: regrid_interp_field_Final use mod_regrid_mesh, only: regrid_mesh_Final - ! use mod_cs2lonlat_interp_file, only: interp_file_Final + use mod_regrid_file, only: regrid_file_Final implicit none !-------------------------------------- call PROF_rapstart ('Finalize', 0) - ! call interp_file_Final - ! call interp_field_Final( is_mesh3D ) - ! if ( is_mesh3D ) call vintrp%Final() + call regrid_file_Final + call regrid_interp_field_Final( out_mesh ) + if ( associated(out_mesh%ptr_mesh3D) ) call vintrp%Final() call regrid_mesh_Final() ! diff --git a/model/atm_nonhydro3d/util/regrid_tool/regrid.conf b/model/atm_nonhydro3d/util/regrid_tool/regrid.conf index 2496a2fb..052629e4 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/regrid.conf +++ b/model/atm_nonhydro3d/util/regrid_tool/regrid.conf @@ -19,16 +19,18 @@ / &PARAM_REGRID_INMESH3D_CUBEDSPHERE Nprc = 2, - NeGX = 5, - NeGY = 5, + NeGX = 7, + NeGY = 7, + NeGZ = 8, PolyOrder_h = 4, + PolyOrder_v = 4, NLocalMeshPerPrc = 3, / &PARAM_REGRID_OUTMESH3D_LONLAT - NprcX = 1, - NeX = 32, - NprcY = 1, - NeY = 16, + NprcX = 2, + NeX = 16, + NprcY = 2, + NeY = 8, NeZ = 16, PolyOrder_h = 2, PolyOrder_v = 2, From bf2cb1ea5821938e29ed20c8719343a741c87f6d Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 21 Aug 2021 21:10:14 +0900 Subject: [PATCH 82/98] Modify a flag to output mesh data when restart files are created. --- FElib/src/file/scale_file_base_meshfield.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/FElib/src/file/scale_file_base_meshfield.F90 b/FElib/src/file/scale_file_base_meshfield.F90 index 83f7db5c..55906e5f 100644 --- a/FElib/src/file/scale_file_base_meshfield.F90 +++ b/FElib/src/file/scale_file_base_meshfield.F90 @@ -247,6 +247,7 @@ subroutine FILE_base_meshfield_create( & if ( .not. fileexisted ) then call def_axes( this, dtype ) + this%File_axes_written = .false. end if return From e31d7e19db2856838c2dc92552a7281144249251 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 21 Aug 2021 21:11:33 +0900 Subject: [PATCH 83/98] Fix bugs of codes in the regrid_tool. --- .../regrid_tool/mod_regrid_interp_field.F90 | 39 +++-- .../regrid_tool/mod_regrid_interp_vcoord.F90 | 138 ++++++++++-------- .../util/regrid_tool/mod_regrid_mesh.F90 | 2 +- .../util/regrid_tool/mod_regrid_mesh_base.F90 | 109 ++++++++++---- .../util/regrid_tool/mod_regrid_nodemap.F90 | 83 ++++++++--- .../util/regrid_tool/prg_regrid_tool.F90 | 15 +- .../util/regrid_tool/regrid.conf | 18 ++- 7 files changed, 258 insertions(+), 146 deletions(-) diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 index 4dbb9ea0..b6eb3a43 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_field.F90 @@ -41,8 +41,8 @@ module mod_regrid_interp_field public :: regrid_interp_field_Init public :: regrid_interp_field_Final interface regrid_interp_field_Interpolate - module procedure :: interp_field_Interpolate_2D - module procedure :: interp_field_Interpolate_3D + module procedure :: regrid_field_Interpolate_2D + module procedure :: regrid_field_Interpolate_3D end interface public :: regrid_interp_field_Interpolate @@ -115,7 +115,7 @@ subroutine regrid_interp_field_Init( out_mesh ) !------------------------------------------- LOG_NEWLINE - LOG_INFO("regrid_field",*) 'Setup' + LOG_INFO("regrid_interp_field",*) 'Setup' out_tinterval(:) = 1 @@ -123,9 +123,9 @@ subroutine regrid_interp_field_Init( out_mesh ) rewind(IO_FID_CONF) read(IO_FID_CONF,nml=PARAM_REGRID_INTERP_FIELD,iostat=ierr) if ( ierr < 0 ) then !--- missing - LOG_INFO("regrid_field",*) 'Not found namelist. Default used.' + LOG_INFO("regrid_interp_field",*) 'Not found namelist. Default used.' elseif( ierr > 0 ) then !--- fatal error - LOG_ERROR("regrid_field",*) 'Not appropriate names in namelist PARAM_REGRID_INTERP_FIELD. Check!' + LOG_ERROR("regrid_interp_field",*) 'Not appropriate names in namelist PARAM_REGRID_INTERP_FIELD. Check!' call PRC_abort endif LOG_NML(PARAM_REGRID_INTERP_FIELD) @@ -185,7 +185,7 @@ subroutine regrid_interp_field_Init( out_mesh ) out_vinfo(nn)%out_tintrv = 1 end if - LOG_INFO("regrid_field_Init", '(3a,i4,a,i4)') & + LOG_INFO("regrid_interp_field_Init", '(3a,i4,a,i4)') & " Regist: name=", trim(vars(nn)), ", out_nstep=", out_vinfo(nn)%num_step, & ", out_tinterval=", out_vinfo(nn)%out_tintrv end do @@ -233,7 +233,7 @@ subroutine regrid_interp_field_Final( out_mesh ) end subroutine regrid_interp_field_Final !OCL SERIAL - subroutine interp_field_Interpolate_2D( istep, varname, out_mesh, out_field, nodeMap_list ) + subroutine regrid_field_Interpolate_2D( istep, varname, out_mesh, out_field, nodeMap_list ) use scale_mesh_rectdom2d, only: MeshRectDom2D implicit none @@ -256,7 +256,7 @@ subroutine interp_field_Interpolate_2D( istep, varname, out_mesh, out_field, nod class(MeshBase2D), pointer :: ptr_inmesh2D !------------------------------------------- - call PROF_rapstart('INTERP_field_interpolate_2D', 0) + call PROF_rapstart('regrid_field_interpolate_2D', 0) ptr_outmesh2D => out_mesh%ptr_mesh2D @@ -269,12 +269,12 @@ subroutine interp_field_Interpolate_2D( istep, varname, out_mesh, out_field, nod in_file_ptr => in_file_list(domID)%in_files(in_ii) ptr_inmesh2D => nodeMap_list(domID)%in_mesh_list(in_ii)%ptr_mesh2D in_rank = ptr_inmesh2D%lcmesh_list(1)%PRC_myrank - LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank + LOG_INFO("regrid_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank select type( ptr_inmesh2D ) class is (MeshRectDom2D) call in_file_ptr%Init( out_var_num, mesh2D=ptr_inmesh2D ) - class is (MeshCubedSphereDom2D) + class is ( MeshCubedSphereDom2D ) call in_file_ptr%Init( out_var_num, meshCubedSphere2D=ptr_inmesh2D ) end select call in_file_ptr%Open( in_basename, in_rank ) @@ -290,13 +290,13 @@ subroutine interp_field_Interpolate_2D( istep, varname, out_mesh, out_field, nod nodeMap_list(n) ) end do - call PROF_rapend('INTERP_field_interpolate_2D', 0) + call PROF_rapend('regrid_field_interpolate_2D', 0) return - end subroutine interp_field_interpolate_2D + end subroutine regrid_field_Interpolate_2D !OCL SERIAL - subroutine interp_field_Interpolate_3D( istep, varname, out_mesh, out_field, nodeMap_list ) + subroutine regrid_field_Interpolate_3D( istep, varname, out_mesh, out_field, nodeMap_list ) use scale_mesh_cubedom3d, only: MeshCubeDom3D implicit none @@ -319,7 +319,7 @@ subroutine interp_field_Interpolate_3D( istep, varname, out_mesh, out_field, nod class(MeshBase3D), pointer :: ptr_inmesh3D !------------------------------------------- - call PROF_rapstart('INTERP_field_interpolate_3D', 0) + call PROF_rapstart('regrid_field_interpolate_3D', 0) ptr_outmesh3D => out_mesh%ptr_mesh3D @@ -333,12 +333,12 @@ subroutine interp_field_Interpolate_3D( istep, varname, out_mesh, out_field, nod ptr_inmesh3D => nodeMap_list(domID)%in_mesh_list(in_ii)%ptr_mesh3D in_rank = ptr_inmesh3D%lcmesh_list(1)%PRC_myrank - LOG_INFO("interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank + LOG_INFO("regrid_interp_field",'(a,i4,a,a,i6)') 'domID=', domID, ', Open in_file:', trim(in_basename), in_rank select type( ptr_inmesh3D ) class is (MeshCubeDom3D) call in_file_ptr%Init( out_var_num, mesh3D=ptr_inmesh3D ) - class is (MeshCubedSphereDom3D) + class is ( MeshCubedSphereDom3D ) call in_file_ptr%Init( out_var_num, meshCubedSphere3D=ptr_inmesh3D ) end select call in_file_ptr%Open( in_basename, in_rank ) @@ -354,10 +354,10 @@ subroutine interp_field_Interpolate_3D( istep, varname, out_mesh, out_field, nod nodeMap_list(n) ) end do - call PROF_rapend('INTERP_field_interpolate_3D', 0) + call PROF_rapend('regrid_field_interpolate_3D', 0) return - end subroutine interp_field_interpolate_3D + end subroutine regrid_field_Interpolate_3D !------------------------ @@ -533,12 +533,11 @@ subroutine interpolate_local_3D( out_val, & integer :: ke3D, ke_h integer :: p, p_h, pX, pY, pZ integer :: p1, p2, p3, l - integer :: elem_i, elem_j integer :: in_ke3D, in_ex, in_ey, in_ez, in_domID, in_prc integer :: in_rank type(LocalMesh3D), pointer :: in_lcmesh integer :: n - integer :: ii, jj, kk, pp, i0_s, j0_s, k0_s, p0_s + integer :: ii, jj, kk type(in_local_val), allocatable :: in_val_list(:) class(MeshBase3D), pointer :: in_mesh diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 index 5f78aaf3..17bea4e5 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_interp_vcoord.F90 @@ -64,7 +64,9 @@ module mod_regrid_interp_vcoord type(MeshField3D) :: pres type(HexahedralElement) :: elem - class(MeshBase3D), pointer :: out_mesh3D_ptr + class(regrid_mesh_base), pointer :: out_mesh_ptr + type(regrid_mesh_base) :: out_mesh + type(MeshCubeDom3D) :: mesh3D type(MeshCubedSphereDom3D) :: csmesh3D @@ -82,10 +84,10 @@ module mod_regrid_interp_vcoord ! !++ Public parameters & variables ! - integer, public, parameter :: INTERP_VCOORD_MODEL_ID = 1 - integer, public, parameter :: INTERP_VCOORD_HEIGHT_ID = 2 - integer, public, parameter :: INTERP_VCOORD_PRESS_ID = 3 - integer, public, parameter :: INTERP_VCOORD_SIGMA_ID = 4 + integer, public, parameter :: REGRID_VCOORD_MODEL_ID = 1 + integer, public, parameter :: REGRID_VCOORD_HEIGHT_ID = 2 + integer, public, parameter :: REGRID_VCOORD_PRESS_ID = 3 + integer, public, parameter :: REGRID_VCOORD_SIGMA_ID = 4 !----------------------------------------------------------------------------- ! @@ -134,7 +136,7 @@ subroutine regrid_interp_vcoord_Init( this, & real(RP) :: out_FZ(FZ_nmax) logical :: extrapolate - namelist / PARAM_INTERP_VCOORD / & + namelist / PARAM_REGRID_VCOORD / & vintrp_name, & in_topofile_basename, & topo_varname, & @@ -160,37 +162,40 @@ subroutine regrid_interp_vcoord_Init( this, & class(MeshBase2D), pointer :: ptr_mesh2D class(regrid_mesh_base), pointer :: in_mesh + + class(MeshBase3D), pointer :: vintrp_ptr_outmesh3D !------------------------------------------- LOG_NEWLINE - LOG_INFO("interp_vcoord_Init",*) 'Setup' + LOG_INFO("regrid_vcoord_Init",*) 'Setup' vintrp_name = 'MODEL' + out_FZ(:) = UNDEF extrapolate = .false. !--- read namelist rewind(IO_FID_CONF) - read(IO_FID_CONF,nml=PARAM_INTERP_VCOORD,iostat=ierr) + read(IO_FID_CONF,nml=PARAM_REGRID_VCOORD,iostat=ierr) if ( ierr < 0 ) then !--- missing - LOG_INFO("interp_vcoord",*) 'Not found namelist. Default used.' + LOG_INFO("regrid_vcoord",*) 'Not found namelist. Default used.' elseif( ierr > 0 ) then !--- fatal error - LOG_ERROR("interp_vcoord",*) 'Not appropriate names in namelist PARAM_INTERP_VCOORD. Check!' + LOG_ERROR("regrid_vcoord",*) 'Not appropriate names in namelist PARAM_REGRID_VCOORD. Check!' call PRC_abort endif - LOG_NML(PARAM_INTERP_VCOORD) + LOG_NML(PARAM_REGRID_VCOORD) select case( vintrp_name ) case( 'MODEL' ) - this%vintrp_typeid= INTERP_VCOORD_MODEL_ID - this%out_mesh3D_ptr => out_mesh%ptr_mesh3D + this%vintrp_typeid= REGRID_VCOORD_MODEL_ID + this%out_mesh_ptr => out_mesh case( 'HEIGHT' ) - this%vintrp_typeid = INTERP_VCOORD_HEIGHT_ID + this%vintrp_typeid = REGRID_VCOORD_HEIGHT_ID case( 'PRESSURE' ) - this%vintrp_typeid = INTERP_VCOORD_PRESS_ID + this%vintrp_typeid = REGRID_VCOORD_PRESS_ID case( 'SIGMA' ) - this%vintrp_typeid = INTERP_VCOORD_SIGMA_ID + this%vintrp_typeid = REGRID_VCOORD_SIGMA_ID case default - LOG_ERROR("interp_vcoord_Init",*) 'Not appropriate vintrp_type. Check!', vintrp_name + LOG_ERROR("regrid_vcoord_Init",*) 'Not appropriate vintrp_type. Check!', vintrp_name call PRC_abort end select @@ -251,10 +256,13 @@ subroutine regrid_interp_vcoord_Init( this, & !-- - if ( this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then + if ( this%vintrp_typeid /= REGRID_VCOORD_MODEL_ID ) then call this%elem%Init( out_mesh%elem3D%PolyOrder_h, out_PolyOrder_v, .true. ) + call this%out_mesh%Init( OUTMESH_ID, out_mesh%mesh_type_id ) + this%out_mesh_ptr => this%out_mesh + select type( ptr_mesh2D ) class is (MeshRectDom2D) @@ -266,15 +274,15 @@ subroutine regrid_interp_vcoord_Init( this, & out_mesh%NprcX, out_mesh%NprcY, & FZ=out_FZ(1:out_NeZ+1) ) - this%out_mesh3D_ptr => this%mesh3D - if ( out_mesh%mesh_type_id == REGRID_MESHTYPE_LONLAT3D_ID ) then - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatv', 'degree', 'longitude,latitude,altitude' ) - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzv', 'degree', 'longitude,latitude,altitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_X, 'lon', 'degree_east', 'longitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Y, 'lat', 'degree_north', 'latitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZ, 'lonlatv', 'degree', 'longitude,latitude,altitude' ) + call this%mesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_XYZT, 'lonlatzv', 'degree', 'longitude,latitude,altitude' ) end if + this%out_mesh_ptr%ptr_mesh3D => this%mesh3D + class is (MeshCubedSphereDom2D) call this%csmesh3D%Init( out_mesh%NeGX, out_mesh%NeGY, out_NeZ, RPlanet, & @@ -282,30 +290,31 @@ subroutine regrid_interp_vcoord_Init( this, & this%elem, out_mesh%NLocalMeshPerPRC, & nproc=out_mesh%Nprc, FZ=out_FZ(1:out_NeZ+1) ) - this%out_mesh3D_ptr => this%csmesh3D + this%out_mesh_ptr%ptr_mesh3D => this%csmesh3D end select - call this%out_mesh3D_ptr%Generate() + vintrp_ptr_outmesh3D => this%out_mesh_ptr%ptr_mesh3D + call vintrp_ptr_outmesh3D%Generate() - if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)', & + if ( this%vintrp_typeid == REGRID_VCOORD_PRESS_ID ) then + call vintrp_ptr_outmesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'p', 'Pa', 'altitude (preesure coordinate)', & positive_down = .true. ) call this%pres%Init( "PRES", "Pa", out_mesh%ptr_mesh3D ) - else if ( this%vintrp_typeid == INTERP_VCOORD_SIGMA_ID ) then - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'sig', '1', 'altitude (sigma coordinate)', & + else if ( this%vintrp_typeid == REGRID_VCOORD_SIGMA_ID ) then + call vintrp_ptr_outmesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'sig', '1', 'altitude (sigma coordinate)', & positive_down = .true. ) call this%pres%Init( "PRES", "Pa", out_mesh%ptr_mesh3D ) - else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then - call this%out_mesh3D_ptr%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude (height coordinate)' ) + else if ( this%vintrp_typeid == REGRID_VCOORD_HEIGHT_ID ) then + call vintrp_ptr_outmesh3D%SetDimInfo( MeshBase3D_DIMTYPEID_Z, 'z', 'm', 'altitude (height coordinate)' ) end if !------------------------ - allocate( this%vintrp_info(this%out_mesh3D_ptr%LOCAL_MESH_NUM) ) + allocate( this%vintrp_info(vintrp_ptr_outmesh3D%LOCAL_MESH_NUM) ) - do n=1, this%out_mesh3D_ptr%LOCAL_MESH_NUM - lcmesh => this%out_mesh3D_ptr%lcmesh_list(n) + do n=1, vintrp_ptr_outmesh3D%LOCAL_MESH_NUM + lcmesh => vintrp_ptr_outmesh3D%lcmesh_list(n) elem => lcmesh%refElem3D allocate( this%vintrp_info(n)%xi2v_coef(elem%Np,lcmesh%Ne) ) allocate( this%vintrp_info(n)%xi2v_idx_k(elem%Np,lcmesh%Ne,2) ) @@ -314,7 +323,7 @@ subroutine regrid_interp_vcoord_Init( this, & end if - call this%vintrp_var3D%Init( 'regrid_vintrp_var3D', '', this%out_mesh3D_ptr ) + call this%vintrp_var3D%Init( 'vintrp_var3D', '', this%out_mesh_ptr%ptr_mesh3D ) return end subroutine regrid_interp_vcoord_Init @@ -330,7 +339,8 @@ subroutine regrid_interp_vcoord_Final( this ) call this%vintrp_var3D%Final() call this%topography%Final() - if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) & + + if ( this%vintrp_typeid == REGRID_VCOORD_PRESS_ID ) & call this%pres%Final() if ( allocated(this%vintrp_info) ) then @@ -342,17 +352,12 @@ subroutine regrid_interp_vcoord_Final( this ) deallocate( this%vintrp_info ) end if - if (this%vintrp_typeid /= INTERP_VCOORD_MODEL_ID ) then - select type( mesh3D => this%out_mesh3D_ptr ) - class is (MeshCubeDom3D) - call mesh3D%Final() - class is (MeshCubedSphereDom3D) - call mesh3D%Final() - end select + if (this%vintrp_typeid /= REGRID_VCOORD_MODEL_ID ) then + call this%out_mesh%Final() call this%elem%Final() end if - nullify( this%out_mesh3D_ptr ) + nullify( this%out_mesh_ptr ) return end subroutine regrid_interp_vcoord_Final @@ -372,18 +377,18 @@ subroutine regrid_interp_vcoord_update_weight( this, istep, out_mesh, nodeMap_li !--------------------------------------------------------------- select case( this%vintrp_typeid ) - case ( INTERP_VCOORD_MODEL_ID ) + case ( REGRID_VCOORD_MODEL_ID ) return - case ( INTERP_VCOORD_PRESS_ID, INTERP_VCOORD_SIGMA_ID ) + case ( REGRID_VCOORD_PRESS_ID, REGRID_VCOORD_SIGMA_ID ) call regrid_interp_field_Interpolate( istep, this%pres%varname, & out_mesh, this%pres, nodeMap_list ) end select mesh3D => out_mesh%ptr_mesh3D do n=1, mesh3D%LOCAL_MESH_NUM - call interp_vcoord_update_weight_core( this, n, & - mesh3D%lcmesh_list(n), mesh3D%refElem3D, & - this%out_mesh3D_ptr%lcmesh_list(n), this%elem ) + call interp_vcoord_update_weight_core( this, n, & + mesh3D%lcmesh_list(n), mesh3D%refElem3D, & + this%out_mesh_ptr%ptr_mesh3D%lcmesh_list(n), this%elem ) end do return @@ -400,13 +405,13 @@ subroutine regrid_interp_vcoord_interpolate( this, istep, mesh_ref, field_ref ) integer :: n !--------------------------------------------------------------- - if ( this%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) return + if ( this%vintrp_typeid == REGRID_VCOORD_MODEL_ID ) return - do n=1, this%out_mesh3D_ptr%LOCAL_MESH_NUM + do n=1, this%out_mesh_ptr%ptr_mesh3D%LOCAL_MESH_NUM call interp_vcoord_interpolate_core( this%vintrp_info(n), n, & this%vintrp_var3D%local(n)%val, field_ref%local(n)%val, & mesh_ref%lcmesh_list(n), mesh_ref%lcmesh_list(n)%refElem3D, & - this%out_mesh3D_ptr%lcmesh_list(n), this%elem ) + this%out_mesh_ptr%ptr_mesh3D%lcmesh_list(n), this%elem ) end do return @@ -481,7 +486,7 @@ subroutine interp_vcoord_update_weight_core( & !------------------------------------------------------------- - if ( this%vintrp_typeid == INTERP_VCOORD_PRESS_ID ) then + if ( this%vintrp_typeid == REGRID_VCOORD_PRESS_ID ) then !$omp parallel !$omp do do ke=lcmesh_ref%NeS, lcmesh_ref%NeE @@ -492,7 +497,7 @@ subroutine interp_vcoord_update_weight_core( & height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) end do !$omp end parallel - else if ( this%vintrp_typeid == INTERP_VCOORD_SIGMA_ID ) then + else if ( this%vintrp_typeid == REGRID_VCOORD_SIGMA_ID ) then lcmesh2D => lcmesh_ref%lcmesh2D allocate( SfcPres(lcmesh2D%refElem2D%Np,lcmesh2D%NeA) ) !$omp parallel private(ke, ke_xy) @@ -512,7 +517,7 @@ subroutine interp_vcoord_update_weight_core( & height(:,ke) = - log( lcmesh%pos_en(:,ke,3) ) end do !$omp end parallel - else if ( this%vintrp_typeid == INTERP_VCOORD_HEIGHT_ID ) then + else if ( this%vintrp_typeid == REGRID_VCOORD_HEIGHT_ID ) then !$omp parallel !$omp do do ke=lcmesh_ref%NeS, lcmesh_ref%NeE @@ -541,7 +546,7 @@ subroutine interp_vcoord_update_weight_core( & vfact(:) = UNDEF do p_z=1, elem%Nnode_v do p_xy=1, elem%Nnode_h1D**2 - p = p_xy + (p_z -1) * elem%Nnode_h1D**2 + p = p_xy + (p_z - 1) * elem%Nnode_h1D**2 p_sfc_ref = p_xy p_top_ref = p_xy + (elem_ref%Nnode_v -1) * elem%Nnode_h1D**2 @@ -571,15 +576,17 @@ subroutine interp_vcoord_update_weight_core( & pp_ref = p_xy + p_zz * elem%Nnode_h1D**2 kke_ref = ke_ref else - pp_ref = 2 + pp_ref = p_xy + elem%Nnode_h1D**2 kke_ref = ke_xy + ke_zz * lcmesh%NeX * lcmesh%NeY end if - if ( height(p,ke) >= height_ref(p_ref,ke_ref) & + if ( height(p,ke) >= height_ref(p_ref,ke_ref) & .and. height(p,ke) < height_ref(pp_ref,kke_ref) ) then + indx_k(p,1) = ke_ref; indx_k(p,2) = kke_ref; - indx_p(p,1) = p_ref; indx_p(p,2) = pp_ref; - vfact(p) = ( height_ref(pp_ref,kke_ref) - height (p,ke) ) & + indx_p(p,1) = p_ref; indx_p(p,2) = pp_ref; + vfact(p) = ( height_ref(pp_ref,kke_ref) - height (p,ke) ) & / ( height_ref(pp_ref,kke_ref) - height_ref(p_ref,ke_ref) ) + exit search end if end do @@ -606,6 +613,7 @@ subroutine regrid_vcoord_search_pos_model( this, elem_k, elem_out, & in_mesh_list, in_NeGZ, in_NeX, in_NeY ) implicit none + type(regrid_interp_vcoord), intent(in) :: this type(LocalMesh3D), intent(in) :: lcmesh type(ElementBase3D), intent(in) :: elem3D @@ -631,7 +639,7 @@ subroutine regrid_vcoord_search_pos_model( this, elem_k, elem_out, & real(RP) :: in_Z0, in_Z1 integer :: in_ke3D !------------------------------------------- - + !$omp parallel private( & !$omp ke_h, p_h, in_lcmesh, in_prc, in_n, & !$omp ke_z, ke_z2, p_z, ke, p, in_ke3D, in_Z0, in_Z1 ) @@ -643,6 +651,7 @@ subroutine regrid_vcoord_search_pos_model( this, elem_k, elem_out, & !$omp do collapse(2) do ke_h=1, lcmesh%NeX * lcmesh%NeY do p_h=1, elem3D%Nnode_h1D**2 + in_n = local_domID(p_h,ke_h) in_prc = lcprc(p_h,ke_h) @@ -650,6 +659,7 @@ subroutine regrid_vcoord_search_pos_model( this, elem_k, elem_out, & elem_i(p_h,ke_h) > 0 .and. elem_j(p_h,ke_h) > 0 ) then in_lcmesh => in_mesh_list(in_prc)%ptr_mesh3D%lcmesh_list(in_n) + do ke_z=1, lcmesh%NeZ do p_z=1, elem3D%Nnode_v ke = ke_h + (ke_z-1)*lcmesh%NeX*lcmesh%NeY @@ -671,8 +681,8 @@ subroutine regrid_vcoord_search_pos_model( this, elem_k, elem_out, & end do end do - !$omp end do - !$omp end parallel + !$omp end do + !$omp end parallel return end subroutine regrid_vcoord_search_pos_model diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 index a81a5a50..208b94ba 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh.F90 @@ -20,7 +20,7 @@ module mod_regrid_mesh use mod_regrid_mesh_base, only: & regrid_mesh_base, & MESHIN_ID => REGRID_MESH_BASE_IN_ID, & - MESHOUT_ID => REGRID_MESH_BASE_IN_ID + MESHOUT_ID => REGRID_MESH_BASE_OUT_ID use mod_regrid_nodemap, only: & regrid_nodemap diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 index 7a15f1ca..b528dcfa 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 @@ -79,12 +79,16 @@ module mod_regrid_mesh_base real(RP), allocatable :: FZ(:) contains - procedure :: Init => regrid_mesh_base_init + procedure :: Init1 => regrid_mesh_base_init_1 + procedure :: Init2 => regrid_mesh_base_init_2 + generic :: Init => Init1, Init2 procedure :: Final => regrid_mesh_base_final procedure :: Generate => regrid_mesh_base_generate procedure :: Get_inmesh_hmapinfo => regrid_mesh_base_get_inmesh_hmapinfo end type regrid_mesh_base + public :: regrid_mesh_base_meshtype_name2id + !----------------------------------------------------------------------------- ! !++ Public parameters & variables @@ -103,13 +107,14 @@ module mod_regrid_mesh_base contains !OCL SERIAL - subroutine regrid_mesh_base_init( this, & ! (inout) - mesh_inout_id, mesh_type_name ) ! (in) + subroutine regrid_mesh_base_init_1( this, & ! (inout) + mesh_inout_id, mesh_type_id ) ! (in) implicit none class(regrid_mesh_base), intent(inout) :: this integer, intent(in) :: mesh_inout_id - character(len=*), intent(in) :: mesh_type_name + integer, intent(in) :: mesh_type_id + !---------------------------------------- select case( mesh_inout_id ) @@ -120,34 +125,76 @@ subroutine regrid_mesh_base_init( this, & ! (inout) call PRC_abort end select - select case(trim(mesh_type_name)) - case( "STRUCTURED2D" ) - this%mesh_type_id = REGRID_MESHTYPE_STRUCTURED2D_ID + this%mesh_type_id = mesh_type_id + + select case (this%mesh_type_id) + case( REGRID_MESHTYPE_STRUCTURED2D_ID ) call regrid_mesh_base_init_mesh2D( this ) - case( "STRUCTURED3D" ) - this%mesh_type_id = REGRID_MESHTYPE_STRUCTURED3D_ID + case( REGRID_MESHTYPE_STRUCTURED3D_ID ) call regrid_mesh_base_init_mesh3D( this ) - case( "LONLAT2D" ) - this%mesh_type_id = REGRID_MESHTYPE_LONLAT2D_ID + case( REGRID_MESHTYPE_LONLAT2D_ID ) call regrid_mesh_base_init_mesh2D( this ) - case( "LONLAT3D" ) - this%mesh_type_id = REGRID_MESHTYPE_LONLAT3D_ID + case( REGRID_MESHTYPE_LONLAT3D_ID ) call regrid_mesh_base_init_mesh3D( this ) - case( "CUBEDSPHERE2D" ) - this%mesh_type_id = REGRID_MESHTYPE_CUBEDSPHERE2D_ID + case( REGRID_MESHTYPE_CUBEDSPHERE2D_ID ) call regrid_mesh_base_init_csmesh2D( this ) - case( "CUBEDSPHERE3D" ) - this%mesh_type_id = REGRID_MESHTYPE_CUBEDSPHERE3D_ID + case( REGRID_MESHTYPE_CUBEDSPHERE3D_ID ) call regrid_mesh_base_init_csmesh3D( this ) case default - LOG_ERROR("regrid_mesh_base",*) 'Not supported type of mesh. Check! ', trim(mesh_type_name) + LOG_ERROR("regrid_mesh_base_init",*) 'Not supported type id of mesh. Check! ', mesh_type_id call PRC_abort end select nullify( this%ptr_mesh2D, this%ptr_mesh3D ) return - end subroutine regrid_mesh_base_init + end subroutine regrid_mesh_base_init_1 + +!OCL SERIAL + subroutine regrid_mesh_base_init_2( this, & ! (inout) + mesh_inout_id, mesh_type_name ) ! (in) + + implicit none + class(regrid_mesh_base), intent(inout) :: this + integer, intent(in) :: mesh_inout_id + character(len=*), intent(in) :: mesh_type_name + + integer :: mesh_type_id + !---------------------------------------- + + mesh_type_id = regrid_mesh_base_meshtype_name2id( mesh_type_name ) + call this%Init1( mesh_inout_id, mesh_type_id ) + + return + end subroutine regrid_mesh_base_init_2 + +!OCL SERIAL + function regrid_mesh_base_meshtype_name2id( mesh_type_name ) result(mesh_type_id) + implicit none + character(len=*), intent(in) :: mesh_type_name + integer :: mesh_type_id + !---------------------------------------- + + select case(trim(mesh_type_name)) + case( "STRUCTURED2D" ) + mesh_type_id = REGRID_MESHTYPE_STRUCTURED2D_ID + case( "STRUCTURED3D" ) + mesh_type_id = REGRID_MESHTYPE_STRUCTURED3D_ID + case( "LONLAT2D" ) + mesh_type_id = REGRID_MESHTYPE_LONLAT2D_ID + case( "LONLAT3D" ) + mesh_type_id = REGRID_MESHTYPE_LONLAT3D_ID + case( "CUBEDSPHERE2D" ) + mesh_type_id = REGRID_MESHTYPE_CUBEDSPHERE2D_ID + case( "CUBEDSPHERE3D" ) + mesh_type_id = REGRID_MESHTYPE_CUBEDSPHERE3D_ID + case default + LOG_ERROR("regrid_mesh_meshtype_name2id",*) 'Not supported type of mesh. Check! ', trim(mesh_type_name) + call PRC_abort + end select + + return + end function regrid_mesh_base_meshtype_name2id !OCL SERIAL subroutine regrid_mesh_base_final( this ) @@ -526,7 +573,7 @@ subroutine regrid_mesh_base_init_mesh3D( this ) integer :: PolyOrder_h = 1 integer :: PolyOrder_v = 1 - + logical :: is_spec_FZ integer, parameter :: FZ_nmax = 1000 real(RP) :: FZ(FZ_nmax) @@ -535,19 +582,18 @@ subroutine regrid_mesh_base_init_mesh3D( this ) NprcX, NprcY, NprcZ, NeX, NeY, NeGZ, NLocalMeshPerPrc, & dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & PolyOrder_h, PolyOrder_v, isPeriodicX, isPeriodicY, isPeriodicZ, & - is_spec_FZ, FZ + FZ namelist / PARAM_REGRID_OUTMESH3D_STRUCTURED / & NprcX, NprcY, NprcZ, NeX, NeY, NeGZ, NLocalMeshPerPrc, & dom_xmin, dom_xmax, dom_ymin, dom_ymax, dom_zmin, dom_zmax, & PolyOrder_h, PolyOrder_v, isPeriodicX, isPeriodicY, isPeriodicZ, & - is_spec_FZ, FZ + FZ integer :: ierr integer :: k !---------------------------------------- - is_spec_FZ = .false. NeGZ = -1 FZ(:) = UNDEF @@ -633,6 +679,8 @@ subroutine regrid_mesh_base_init_csmesh3D( this ) integer :: NeGY = 1 integer :: NeGZ = 1 integer :: NLocalMeshPerPrc = 1 + real(RP) :: dom_zmin = 0.0_RP + real(RP) :: dom_zmax = 0.0_RP integer :: PolyOrder_h = 1 integer :: PolyOrder_v = 1 @@ -644,12 +692,14 @@ subroutine regrid_mesh_base_init_csmesh3D( this ) namelist / PARAM_REGRID_INMESH3D_CUBEDSPHERE / & Nprc, NeGX, NeGY, NeGZ, NLocalMeshPerPrc, & PolyOrder_h, PolyOrder_v, & - is_spec_FZ, FZ + dom_zmin, dom_zmax, & + FZ namelist / PARAM_REGRID_OUTMESH3D_CUBEDSPHERE / & Nprc, NeGX, NeGY, NeGZ, NLocalMeshPerPrc, & PolyOrder_h, PolyOrder_v, & - is_spec_FZ, FZ + dom_zmin, dom_zmax, & + FZ integer :: ierr integer :: k @@ -657,7 +707,6 @@ subroutine regrid_mesh_base_init_csmesh3D( this ) type(MeshCubedSphereDom2D) :: csmesh2D_dummy !---------------------------------------- - is_spec_FZ = .false. NeGZ = -1 FZ(:) = UNDEF @@ -692,7 +741,7 @@ subroutine regrid_mesh_base_init_csmesh3D( this ) this%NeGX = NeGX this%NeGY = NeGY - this%NeZ = NeGZ / this%NprcZ + this%NeGZ = NeGZ this%NLocalMeshPerPRC = NLocalMeshPerPrc this%polyorder_h = PolyOrder_h @@ -709,11 +758,15 @@ subroutine regrid_mesh_base_init_csmesh3D( this ) Nprc, NLocalMeshPerPrc * Nprc ) ! (in) this%NeX = NeGX / this%NprcX - this%NeY = NeGY / this%NprcY + this%NeY = NeGY / this%NprcY + this%NeZ = NeGZ / this%NprcZ + this%dom_xmin = csmesh2D_dummy%xmin_gl this%dom_xmax = csmesh2D_dummy%xmax_gl this%dom_ymin = csmesh2D_dummy%ymin_gl this%dom_ymax = csmesh2D_dummy%ymax_gl + this%dom_zmin = dom_zmin + this%dom_zmax = dom_zmax call csmesh2D_dummy%Final() diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 index 510afa6f..70d45a64 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_nodemap.F90 @@ -51,6 +51,7 @@ module mod_regrid_nodemap end type contains + !OCL SERIAL subroutine NodeMap_Init( this, & inmesh_type, out_mesh ) @@ -88,7 +89,6 @@ subroutine NodeMap_Init( this, & allocate( pi_table(inmesh_dummy%NLocalMeshPerPrc*inmesh_dummy%Nprc) ) allocate( pj_table(inmesh_dummy%NLocalMeshPerPrc*inmesh_dummy%Nprc) ) - return !--- call inmesh_dummy%Get_inmesh_hmapinfo( & @@ -103,7 +103,7 @@ subroutine NodeMap_Init( this, & i = pi_table(tileID); j = pj_table(tileID) in_tiles_x(:,in_n,in_p) = inmesh_dummy%dom_xmin + delx * dble( (/ i-1, i, i, i-1 /) ) - in_tiles_y(:,in_n,in_p) = inmesh_dummy%dom_ymin * dble( (/ j-1, j-1, j, j /) ) + in_tiles_y(:,in_n,in_p) = inmesh_dummy%dom_ymin + dely * dble( (/ j-1, j-1, j, j /) ) if (i==inmesh_dummy%NprcX) then in_tiles_x(2:3,in_n,in_p) = in_tiles_x(2:3,in_n,in_p) + 1.0E-12_RP * delx @@ -117,7 +117,9 @@ subroutine NodeMap_Init( this, & if ( associated(out_mesh%ptr_mesh2D ) ) then do n=1, out_mesh%ptr_mesh2D%LOCAL_MESH_NUM + lcmesh2D => out_mesh%ptr_mesh2D%lcmesh_list(n) + call NodeMap_construct_nodemap_2D( this, & inmesh_dummy%mesh_type_id, out_mesh%mesh_type_id, & inmesh_type, & @@ -126,6 +128,7 @@ subroutine NodeMap_Init( this, & inmesh_dummy%Nprc, inmesh_dummy%NprcX, inmesh_dummy%NprcY, & inmesh_dummy%NeX, inmesh_dummy%NeY, inmesh_dummy%NLocalMeshPerPRC, & .true. ) + end do end if @@ -133,7 +136,10 @@ subroutine NodeMap_Init( this, & if ( associated(out_mesh%ptr_mesh3D ) ) then do n=1, out_mesh%ptr_mesh3D%LOCAL_MESH_NUM + lcmesh3D => out_mesh%ptr_mesh3D%lcmesh_list(n) + lcmesh2D => lcmesh3D%lcmesh2D + call NodeMap_construct_nodemap_3D( this, & inmesh_dummy%mesh_type_id, out_mesh%mesh_type_id, & inmesh_type, & @@ -142,6 +148,7 @@ subroutine NodeMap_Init( this, & in_tiles_x, in_tiles_y, tileID_table, panelID_table, & inmesh_dummy%Nprc, inmesh_dummy%NprcX, inmesh_dummy%NprcY, & inmesh_dummy%NeX, inmesh_dummy%NeY, inmesh_dummy%NLocalMeshPerPRC ) + end do end if @@ -155,7 +162,23 @@ end subroutine NodeMap_Init subroutine NodeMap_Final( this ) implicit none class(regrid_nodemap), intent(inout) :: this + + integer :: n !------------------------------------ + + deallocate( this%local_domID ) + deallocate( this%lcprc ) + deallocate( this%inPanelID ) + deallocate( this%elem_i, this%elem_j ) + deallocate( this%elem_x, this%elem_y ) + if ( allocated(this%elem_k) ) deallocate( this%elem_k, this%elem_z ) + + do n=1, size(this%in_mesh_list) + call this%in_mesh_list(n)%Final() + end do + deallocate( this%in_mesh_list ) + + deallocate( this%in_tileID_list ) return end subroutine NodeMap_Final @@ -201,10 +224,8 @@ subroutine NodeMap_construct_nodemap_2D( this, & integer :: lc_domID, prcID, in_prc, in_n integer :: i, j - integer :: p, ke integer :: ke_h integer :: p_h, p_h_x, p_h_y - integer :: ke_z, ke_z2, p_z, p_z2 logical :: is_inside_tile(Np1D**2) logical :: is_inside_elem real(RP) :: in_elem_x(4) @@ -217,15 +238,11 @@ subroutine NodeMap_construct_nodemap_2D( this, & integer :: in_lcprc2prc_tmp(in_Nprc) integer :: in_tile_num integer :: in_prc_num - type(LocalMesh2D), pointer :: in_lcmesh real(RP), allocatable :: out_x(:,:) real(RP), allocatable :: out_y(:,:) integer :: out_panel - real(RP) :: out_x0, del_x - real(RP) :: out_y0, del_y - integer :: Np2D !----------------------------------------------------------------- @@ -253,7 +270,7 @@ subroutine NodeMap_construct_nodemap_2D( this, & in_meshtype_id, out_meshtype_id, & ! (in) this%inPanelID, & ! (in) Np1D, Ne2D, lcmesh ) ! (in) - + in_tile_num = 0 in_prc_num = 0 do ke_h=1, Ne2D @@ -301,8 +318,7 @@ subroutine NodeMap_construct_nodemap_2D( this, & end do end do - - + allocate( this%in_tileID_list(in_tile_num) ) this%in_tileID_list(:) = in_tileID_tmp(1:in_tile_num) @@ -352,18 +368,20 @@ subroutine NodeMap_construct_nodemap_2D( this, & end do end do + if ( present(in_lcprc2prc) ) in_lcprc2prc(:) = in_lcprc2prc_tmp(:) + if ( present(in_prcnum_out) ) in_prcnum_out = in_prc_num + !-- prepair mesh for input data -------------------------------- - if ( .not. do_mesh_generation ) return + if ( do_mesh_generation ) then - allocate( this%in_mesh_list(in_prc_num) ) - do i=1, in_prc_num - call this%in_mesh_list(i)%Init( MESH_INID, in_meshtype_name ) - call this%in_mesh_list(i)%Generate( myrank=in_lcprc2prc_tmp(i)-1 ) - end do + allocate( this%in_mesh_list(in_prc_num) ) + do i=1, in_prc_num + call this%in_mesh_list(i)%Init( MESH_INID, in_meshtype_name ) + call this%in_mesh_list(i)%Generate( myrank=in_lcprc2prc_tmp(i)-1 ) + end do - if ( present(in_lcprc2prc) ) in_lcprc2prc(:) = in_lcprc2prc_tmp(i) - if ( present(in_prcnum_out) ) in_prcnum_out = in_prc_num + end if return end subroutine NodeMap_construct_nodemap_2D @@ -440,7 +458,8 @@ subroutine get_panelID( inPanelID, & Np1D, Ne2D, lcmesh ) use scale_meshutil_cubedsphere2d, only: & - MeshUtilCubedSphere2D_getPanelID + MeshUtilCubedSphere2D_getPanelID + implicit none integer, intent(in) :: Np1D @@ -456,12 +475,31 @@ subroutine get_panelID( inPanelID, & .or. ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE3D_ID & .and. out_meshtype_id == REGRID_MESHTYPE_LONLAT3D_ID ) ) then - call MeshUtilCubedSphere2D_getPanelID ( & inPanelID(:,:), & ! (out) lcmesh%pos_en(:,:,1) * PI / 180.0_RP, & ! (in) lcmesh%pos_en(:,:,2) * PI / 180.0_RP, & ! (in) - Np1D**2 * Ne2D ) ! (in) + Np1D**2 * Ne2D ) ! (in) + + else if ( ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE2D_ID & + .and. out_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE2D_ID ) & + .or. ( in_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE3D_ID & + .and. out_meshtype_id == REGRID_MESHTYPE_CUBEDSPHERE3D_ID ) ) then + + ! We assume that panelID of input local mesh is equal to that of the corresponding local mesh. + inPanelID(:,:) = lcmesh%panelID + + ! Memo: + ! If we allow the panelID of input local mesh to be different from that of the corresponding local mesh, + ! the procedure should be the following. In addition, vector quantities in cubed sphere mesh need to be + ! temporally converted to that in a coordinate system that is commonly used between input and output local meshes. + !----- + ! call MeshUtilCubedSphere2D_getPanelID ( & + ! inPanelID(:,:), & ! (out) + ! lcmesh%lon(:,:), lcmesh%lat(:,:), & ! (in) + ! Np1D**2 * Ne2D ) ! (in) + !------ + else inPanelID(:,:) = 1 end if @@ -511,6 +549,7 @@ subroutine get_out_xy( out_x, out_y, & out_x(p_h,ke_h), out_y(p_h,ke_h) ) ! (out) end do end do + else !$omp parallel do private(p_h) do ke_h=1, Ne2D diff --git a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 index 1198216b..ecde3d59 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 @@ -30,7 +30,7 @@ program regrid_tool regrid_interp_field_Interpolate use mod_regrid_interp_vcoord, only: & regrid_interp_vcoord, & - INTERP_VCOORD_MODEL_ID + REGRID_VCOORD_MODEL_ID use mod_regrid_file, only: & regrid_file_write_var @@ -79,12 +79,12 @@ program regrid_tool do istep=1, vinfo%num_step, vinfo%out_tintrv start_sec = vinfo%start_sec + (istep - 1) * vinfo%dt - LOG_INFO("INTERP",'(a,i4)') 'Interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep + LOG_INFO("regrid_tool",'(a,i4)') ' interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep if ( associated( out_mesh%ptr_mesh3D ) ) then call regrid_interp_field_Interpolate( istep, vinfo%varname, & out_mesh, out_var3D, nodemap ) - if ( vintrp%vintrp_typeid == INTERP_VCOORD_MODEL_ID ) then + if ( vintrp%vintrp_typeid == REGRID_VCOORD_MODEL_ID ) then call regrid_file_write_var( vid, out_var3D, & start_sec, start_sec + vinfo%dt ) else @@ -143,7 +143,6 @@ subroutine initialize() integer :: ierr integer :: comm ! communicator (execution) - integer :: n !----------------------------------------------------------------------- ! start MPI @@ -195,12 +194,13 @@ subroutine initialize() call regrid_mesh_Init() call regrid_interp_field_Init( out_mesh ) if ( associated(out_mesh%ptr_mesh3D) ) call vintrp%Init( out_mesh, nodemap ) - call regrid_file_Init( in_basename, out_vinfo, out_mesh ) + call regrid_file_Init( in_basename, out_vinfo, vintrp%out_mesh_ptr ) !- do_output = .true. LOG_INFO("regrid_tool",*) 'Setup has been finished.' + if( IO_L ) call flush(IO_FID_LOG) call PROF_rapend ('Initialize', 0) @@ -224,9 +224,12 @@ subroutine finalize call PROF_rapstart ('Finalize', 0) + LOG_NEWLINE + LOG_INFO("regrid_tool",*) 'Shutdown' + call regrid_file_Final - call regrid_interp_field_Final( out_mesh ) if ( associated(out_mesh%ptr_mesh3D) ) call vintrp%Final() + call regrid_interp_field_Final( out_mesh ) call regrid_mesh_Final() ! diff --git a/model/atm_nonhydro3d/util/regrid_tool/regrid.conf b/model/atm_nonhydro3d/util/regrid_tool/regrid.conf index 052629e4..aaa794ee 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/regrid.conf +++ b/model/atm_nonhydro3d/util/regrid_tool/regrid.conf @@ -6,13 +6,13 @@ in_MeshType = "CUBEDSPHERE3D", out_MeshType = "LONLAT3D", / -&PARAM_INTERP_FIELD +&PARAM_REGRID_INTERP_FIELD !- input -------------------- in_basename="../../../../sample/advect3dGlobal/history", - vars = "q", "lat", "lon", + vars = "q", !out_tinterval = 5, / -&PARAM_INTERP_FILE +&PARAM_REGRID_FILE !-- output ---------------- out_basename="./outdata/history", out_UniformGrid=.false., @@ -25,13 +25,21 @@ PolyOrder_h = 4, PolyOrder_v = 4, NLocalMeshPerPrc = 3, + dom_zmin = 0.0D0, + dom_zmax = 12.0D3, / -&PARAM_REGRID_OUTMESH3D_LONLAT +&PARAM_REGRID_OUTMESH3D_STRUCTURED NprcX = 2, NeX = 16, NprcY = 2, NeY = 8, - NeZ = 16, + NeGZ = 16, PolyOrder_h = 2, PolyOrder_v = 2, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, + dom_zmin = 0.0D0, + dom_zmax = 12.0D3, / \ No newline at end of file From 4112d543203e15d9cc86e2c5b94f22435bbd3312 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 21 Aug 2021 21:19:40 +0900 Subject: [PATCH 84/98] Modify a yml file to check whether building the regrid_tool is successfull. --- .github/workflows/FEProject_build.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index 89d8c1de..5a1f7692 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -139,12 +139,6 @@ jobs: echo "Build 3D nonhydrostatic atmospheric model / utils" make -C atm_nonhydro3d/util/interp - make -C atm_nonhydro3d/util/convert_cs2lonlat + make -C atm_nonhydro3d/util/convert_cs2lonlat + make -C atm_nonhydro3d/util/regrid_tool - - - - - - - From dfdd328236c8de07dd30b8d33465df851b5e44a4 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 21 Aug 2021 21:27:39 +0900 Subject: [PATCH 85/98] Modify a dependency in bulding the regrid_tool. --- model/atm_nonhydro3d/util/regrid_tool/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/atm_nonhydro3d/util/regrid_tool/Makefile b/model/atm_nonhydro3d/util/regrid_tool/Makefile index 95511cc1..74fb3fe2 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/Makefile +++ b/model/atm_nonhydro3d/util/regrid_tool/Makefile @@ -43,7 +43,7 @@ $(OBJECT): $(MODS) @mv *.mod inc/; mv *.o inc/; $(BUILD_DIR)/$(BINNAME) : $(BUILD_DIR)/prg_$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) - $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(CONTRIB_LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) $(BUILD_DIR)/prg_$(BINNAME).o : prg_$(BINNAME).F90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) From bed289becfebed0c9589b7d1f3f1b6ca0ed04711 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 25 Aug 2021 10:16:47 +0900 Subject: [PATCH 86/98] Move cs2lonlat and interp tools into obsolete directory. --- .../atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/Makefile | 0 .../util/{ => obsolete}/convert_cs2lonlat/cs2lonlat.conf | 0 .../convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 | 0 .../convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 | 0 .../convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 | 0 .../convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 | 0 .../{ => obsolete}/convert_cs2lonlat/prg_convert_cs2lonlat.F90 | 0 model/atm_nonhydro3d/util/{ => obsolete}/interp/Makefile | 0 model/atm_nonhydro3d/util/{ => obsolete}/interp/interp.conf | 0 .../util/{ => obsolete}/interp/mod_interp_field.F90 | 0 .../atm_nonhydro3d/util/{ => obsolete}/interp/mod_interp_file.F90 | 0 .../atm_nonhydro3d/util/{ => obsolete}/interp/mod_interp_mesh.F90 | 0 .../util/{ => obsolete}/interp/mod_interp_vcoord.F90 | 0 model/atm_nonhydro3d/util/{ => obsolete}/interp/prg_interp.F90 | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/Makefile (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/cs2lonlat.conf (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/convert_cs2lonlat/prg_convert_cs2lonlat.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/Makefile (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/interp.conf (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/mod_interp_field.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/mod_interp_file.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/mod_interp_mesh.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/mod_interp_vcoord.F90 (100%) rename model/atm_nonhydro3d/util/{ => obsolete}/interp/prg_interp.F90 (100%) diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/Makefile similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/Makefile rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/Makefile diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/cs2lonlat.conf b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/cs2lonlat.conf similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/cs2lonlat.conf rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/cs2lonlat.conf diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_field.F90 diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_file.F90 diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_mesh.F90 diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/mod_cs2lonlat_interp_vcoord.F90 diff --git a/model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 b/model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/prg_convert_cs2lonlat.F90 similarity index 100% rename from model/atm_nonhydro3d/util/convert_cs2lonlat/prg_convert_cs2lonlat.F90 rename to model/atm_nonhydro3d/util/obsolete/convert_cs2lonlat/prg_convert_cs2lonlat.F90 diff --git a/model/atm_nonhydro3d/util/interp/Makefile b/model/atm_nonhydro3d/util/obsolete/interp/Makefile similarity index 100% rename from model/atm_nonhydro3d/util/interp/Makefile rename to model/atm_nonhydro3d/util/obsolete/interp/Makefile diff --git a/model/atm_nonhydro3d/util/interp/interp.conf b/model/atm_nonhydro3d/util/obsolete/interp/interp.conf similarity index 100% rename from model/atm_nonhydro3d/util/interp/interp.conf rename to model/atm_nonhydro3d/util/obsolete/interp/interp.conf diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_field.F90 b/model/atm_nonhydro3d/util/obsolete/interp/mod_interp_field.F90 similarity index 100% rename from model/atm_nonhydro3d/util/interp/mod_interp_field.F90 rename to model/atm_nonhydro3d/util/obsolete/interp/mod_interp_field.F90 diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_file.F90 b/model/atm_nonhydro3d/util/obsolete/interp/mod_interp_file.F90 similarity index 100% rename from model/atm_nonhydro3d/util/interp/mod_interp_file.F90 rename to model/atm_nonhydro3d/util/obsolete/interp/mod_interp_file.F90 diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 b/model/atm_nonhydro3d/util/obsolete/interp/mod_interp_mesh.F90 similarity index 100% rename from model/atm_nonhydro3d/util/interp/mod_interp_mesh.F90 rename to model/atm_nonhydro3d/util/obsolete/interp/mod_interp_mesh.F90 diff --git a/model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 b/model/atm_nonhydro3d/util/obsolete/interp/mod_interp_vcoord.F90 similarity index 100% rename from model/atm_nonhydro3d/util/interp/mod_interp_vcoord.F90 rename to model/atm_nonhydro3d/util/obsolete/interp/mod_interp_vcoord.F90 diff --git a/model/atm_nonhydro3d/util/interp/prg_interp.F90 b/model/atm_nonhydro3d/util/obsolete/interp/prg_interp.F90 similarity index 100% rename from model/atm_nonhydro3d/util/interp/prg_interp.F90 rename to model/atm_nonhydro3d/util/obsolete/interp/prg_interp.F90 From 2c51e49e51ffdda46851fd06b1a7eb4dd473ad38 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 25 Aug 2021 21:50:19 +0900 Subject: [PATCH 87/98] Fix a bug of regrid_tool and add the config files for test cases. --- .../test/case/Held_Suarez/run.conf | 3 +- .../case/baroclinic_wave_global/cs2lonlat.cnf | 36 ------------ .../case/baroclinic_wave_global/regrid.conf | 47 ++++++++++++++++ .../case/equatorial_wave_global/regrid.conf | 44 +++++++++++++++ .../inertia_gravity_wave_global/regrid.conf | 44 +++++++++++++++ .../case/mountain_wave_global/cs2lonlat.cnf | 46 --------------- .../case/mountain_wave_global/regrid.conf | 56 +++++++++++++++++++ .../mountain_wave_global/regrid_topo.conf | 36 ++++++++++++ .../util/regrid_tool/mod_regrid_mesh_base.F90 | 5 ++ .../util/regrid_tool/prg_regrid_tool.F90 | 13 ++++- 10 files changed, 245 insertions(+), 85 deletions(-) delete mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf create mode 100644 model/atm_nonhydro3d/test/case/baroclinic_wave_global/regrid.conf create mode 100644 model/atm_nonhydro3d/test/case/equatorial_wave_global/regrid.conf create mode 100644 model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/regrid.conf delete mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/regrid.conf create mode 100644 model/atm_nonhydro3d/test/case/mountain_wave_global/regrid_topo.conf diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf b/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf index 6c48542a..fa77245e 100644 --- a/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/run.conf @@ -34,7 +34,7 @@ dom_zmax = 30.0D3, PolyOrder_h = 7, PolyOrder_v = 7, - Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, LumpedMassMatFlag = .true., / &PARAM_ATMOS_VARS @@ -86,6 +86,7 @@ &HISTORY_ITEM name='Vmet' / &HISTORY_ITEM name='W' / &HISTORY_ITEM name='T' / +&HISTORY_ITEM name='PRES' / !&HISTORY_ITEM name='DENS_hyd' / !&HISTORY_ITEM name='PRES_hyd' / diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf deleted file mode 100644 index 7b18895a..00000000 --- a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/cs2lonlat.cnf +++ /dev/null @@ -1,36 +0,0 @@ -&PARAM_IO - IO_LOG_BASENAME = "cs2lonlat_LOG" - IO_LOG_ALLNODE = .true., -/ -&PARAM_INTERP_FIELD - !- input -------------------- - in_basename="history", - vars = "W", "Umet", "Vmet", "T", "PRES_hyd", - !out_tinterval = 5, -/ -&PARAM_INTERP_FILE - !-- output ---------------- - out_basename="./outdata/history", - out_UniformGrid=.false., -/ -&PARAM_INTERP_MESH - !-- input ---------------- - in_Nprc = 6, - in_NeGX = 9, - in_NeGY = 9, - in_NeGZ = 4, - in_PolyOrder_h = 7, - in_PolyOrder_v = 7, - in_NLocalMeshPerPrc = 1, - dom_zmin = 0.0D0, - dom_zmax = 30.0D3, - in_Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, - !-- output ---------------- - out_NprcX = 2, - out_NeX = 32, - out_NprcY = 2, - out_NeY = 16, - out_NeZ = 15, - out_PolyOrder_h =3, - out_PolyOrder_v =2, -/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/baroclinic_wave_global/regrid.conf b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/regrid.conf new file mode 100644 index 00000000..a91ac0d3 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/baroclinic_wave_global/regrid.conf @@ -0,0 +1,47 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE3D", + out_MeshType = "LONLAT3D", +/ +&PARAM_REGRID_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "W", "Umet", "Vmet", "T", "DDENS", !"PRES_hyd", + !out_tinterval = 5, +/ +&PARAM_REGRID_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH3D_CUBEDSPHERE + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeGZ = 4, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, +/ +&PARAM_REGRID_OUTMESH3D_STRUCTURED + NprcX = 2, + NeX = 16, + NprcY = 2, + NeY = 8, + NeGZ = 4, + PolyOrder_h = 3, + PolyOrder_v = 7, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/equatorial_wave_global/regrid.conf b/model/atm_nonhydro3d/test/case/equatorial_wave_global/regrid.conf new file mode 100644 index 00000000..f1453721 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/equatorial_wave_global/regrid.conf @@ -0,0 +1,44 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE3D", + out_MeshType = "LONLAT3D", +/ +&PARAM_REGRID_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "W", "Umet", "Vmet", +/ +&PARAM_REGRID_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH3D_CUBEDSPHERE + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeGZ = 2, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, +/ +&PARAM_REGRID_OUTMESH3D_STRUCTURED + NprcX = 2, + NeX = 16, + NprcY = 2, + NeY = 8, + NeGZ = 2, + PolyOrder_h = 3, + PolyOrder_v = 7, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/regrid.conf b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/regrid.conf new file mode 100644 index 00000000..e5e4d708 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/inertia_gravity_wave_global/regrid.conf @@ -0,0 +1,44 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE3D", + out_MeshType = "LONLAT3D", +/ +&PARAM_REGRID_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "W", "Umet", "Vmet", "PT_diff", +/ +&PARAM_REGRID_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH3D_CUBEDSPHERE + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 9, + NeGY = 9, + NeGZ = 2, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, +/ +&PARAM_REGRID_OUTMESH3D_STRUCTURED + NprcX = 2, + NeX = 16, + NprcY = 2, + NeY = 8, + NeGZ = 2, + PolyOrder_h = 3, + PolyOrder_v = 7, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, + dom_zmin = 0.0D0, + dom_zmax = 10.0D3, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf b/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf deleted file mode 100644 index 9e15dee1..00000000 --- a/model/atm_nonhydro3d/test/case/mountain_wave_global/cs2lonlat.cnf +++ /dev/null @@ -1,46 +0,0 @@ -&PARAM_IO - IO_LOG_BASENAME = "cs2lonlat_LOG" - IO_LOG_ALLNODE = .true., -/ -&PARAM_INTERP_FIELD - !- input -------------------- - in_basename="./history", - vars = "W", "Umet", "Vmet", "PT_diff", - !out_tinterval = 5, -/ -&PARAM_INTERP_FILE - !-- output ---------------- - out_basename="./outdata/history", - out_UniformGrid=.false., -/ -&PARAM_INTERP_MESH - !-- input ---------------- - in_Nprc = 6, - in_NeGX = 5, - in_NeGY = 5, - in_NeGZ = 6, - in_PolyOrder_h = 7, - in_PolyOrder_v = 7, - in_NLocalMeshPerPrc = 1, - dom_zmin = 0.0D0, - dom_zmax = 40.0D3, - in_Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, - !-- output ---------------- - out_NprcX = 2, - out_NeX = 64, - out_NprcY = 2, - out_NeY = 32, - out_NeZ = 6, - out_PolyOrder_h =3, - out_PolyOrder_v =7, -/ -&PARAM_INTERP_VCOORD - vintrp_name = 'HEIGHT', - in_topofile_basename = 'oudata/topo', - topo_varname = 'topo', - out_NeZ = 6, - out_PolyOrder_v = 7, - out_dom_vmin = 0.0D0, - out_dom_vmax = 40.0D3, - out_Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, -/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/regrid.conf b/model/atm_nonhydro3d/test/case/mountain_wave_global/regrid.conf new file mode 100644 index 00000000..5ddaae0e --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/regrid.conf @@ -0,0 +1,56 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE3D", + out_MeshType = "LONLAT3D", +/ +&PARAM_REGRID_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "Umet", "Vmet", "W", "PT_diff", +/ +&PARAM_REGRID_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH3D_CUBEDSPHERE + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + NeGZ = 6, + dom_zmin = 0.0D0, + dom_zmax = 40.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, +/ +&PARAM_REGRID_OUTMESH3D_STRUCTURED + NprcX = 2, + NeX = 16, + NprcY = 2, + NeY = 8, + NeGZ = 6, + PolyOrder_h = 3, + PolyOrder_v = 7, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, + dom_zmin = 0.0D0, + dom_zmax = 40.0D3, + Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, +/ +&PARAM_REGRID_VCOORD + vintrp_name = 'HEIGHT', + out_NeZ = 6, + out_PolyOrder_v = 7, + out_dom_vmin = 0D0, + out_dom_vmax = 40D3, + out_Fz = 0D0, 4.0D3, 9.D3, 15D3, 22.D3, 30.D3, 40.D3, + in_topofile_basename = "outdata/topo", + topo_varname = "topo", +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/test/case/mountain_wave_global/regrid_topo.conf b/model/atm_nonhydro3d/test/case/mountain_wave_global/regrid_topo.conf new file mode 100644 index 00000000..fa296b41 --- /dev/null +++ b/model/atm_nonhydro3d/test/case/mountain_wave_global/regrid_topo.conf @@ -0,0 +1,36 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG_topo" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE2D", + out_MeshType = "LONLAT2D", +/ +&PARAM_REGRID_INTERP_FIELD + !- input -------------------- + in_basename="./TOPO", + vars = "topo", +/ +&PARAM_REGRID_FILE + !-- output ---------------- + out_basename="./outdata/topo", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH2D_CUBEDSPHERE + NLocalMeshPerPrc = 1, + Nprc = 6, + NeGX = 5, + NeGY = 5, + PolyOrder_h = 7, +/ +&PARAM_REGRID_OUTMESH2D_STRUCTURED + NprcX = 2, + NeX = 16, + NprcY = 2, + NeY = 8, + PolyOrder_h = 3, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, +/ \ No newline at end of file diff --git a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 index b528dcfa..a5d681a7 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/mod_regrid_mesh_base.F90 @@ -441,12 +441,15 @@ subroutine regrid_mesh_base_init_mesh2D( this ) this%NprcX = NprcX this%NprcY = NprcY + this%NprcZ = 1 this%Nprc = NprcX * NprcY this%NeX = NeX this%NeY = NeY + this%NeZ = 1 this%NeGX = NeX * NprcX this%NeGY = NeY * NprcY + this%NeGZ = 1 this%NLocalMeshPerPRC = NLocalMeshPerPrc this%dom_xmin = dom_xmin @@ -521,6 +524,7 @@ subroutine regrid_mesh_base_init_csmesh2D( this ) this%NeGX = NeGX this%NeGY = NeGY + this%NeGZ = 1 this%NLocalMeshPerPRC = NLocalMeshPerPrc this%polyorder_h = PolyOrder_h @@ -536,6 +540,7 @@ subroutine regrid_mesh_base_init_csmesh2D( this ) this%NeX = NeGX / this%NprcX this%NeY = NeGY / this%NprcY + this%NeZ = 1 this%dom_xmin = csmesh2D_dummy%xmin_gl this%dom_xmax = csmesh2D_dummy%xmax_gl this%dom_ymin = csmesh2D_dummy%ymin_gl diff --git a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 index ecde3d59..642888f0 100644 --- a/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 +++ b/model/atm_nonhydro3d/util/regrid_tool/prg_regrid_tool.F90 @@ -81,6 +81,7 @@ program regrid_tool LOG_INFO("regrid_tool",'(a,i4)') ' interpolate :' // trim(out_vinfo(vid)%varname) // " step=", istep if ( associated( out_mesh%ptr_mesh3D ) ) then + call regrid_interp_field_Interpolate( istep, vinfo%varname, & out_mesh, out_var3D, nodemap ) @@ -96,11 +97,14 @@ program regrid_tool end if else + call regrid_interp_field_Interpolate( istep, vinfo%varname, & out_mesh, out_var2D, nodemap ) call regrid_file_write_var( vid, out_var2D, & start_sec, start_sec + vinfo%dt ) + end if + if( IO_L ) call flush(IO_FID_LOG) end do end do @@ -193,8 +197,13 @@ subroutine initialize() ! call regrid_mesh_Init() call regrid_interp_field_Init( out_mesh ) - if ( associated(out_mesh%ptr_mesh3D) ) call vintrp%Init( out_mesh, nodemap ) - call regrid_file_Init( in_basename, out_vinfo, vintrp%out_mesh_ptr ) + + if ( associated(out_mesh%ptr_mesh3D) ) then + call vintrp%Init( out_mesh, nodemap ) + call regrid_file_Init( in_basename, out_vinfo, vintrp%out_mesh_ptr ) + else + call regrid_file_Init( in_basename, out_vinfo, out_mesh ) + end if !- do_output = .true. From c3d84d6c2fd4b9eedd21bcc3cf56c6ba3888fc32 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Wed, 25 Aug 2021 22:02:42 +0900 Subject: [PATCH 88/98] Remove the building of cs2lonlat and interp tools in FEProject_build.yml. --- .github/workflows/FEProject_build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index 5a1f7692..bde21129 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -138,7 +138,5 @@ jobs: make -C atm_nonhydro3d/src echo "Build 3D nonhydrostatic atmospheric model / utils" - make -C atm_nonhydro3d/util/interp - make -C atm_nonhydro3d/util/convert_cs2lonlat make -C atm_nonhydro3d/util/regrid_tool From c52a90f79ab5ebcbedc6988ac910961e91f6a6e9 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Thu, 26 Aug 2021 09:47:09 +0900 Subject: [PATCH 89/98] Use v5.4.4 of SCALE library. --- .github/workflows/scalelib_build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scalelib_build.yml b/.github/workflows/scalelib_build.yml index 73717eaa..685fc85e 100644 --- a/.github/workflows/scalelib_build.yml +++ b/.github/workflows/scalelib_build.yml @@ -38,8 +38,8 @@ jobs: mkdir -p ${SCALE_INST_DIR} && cd ${SCALE_INST_DIR} echo "Download SCALE library .." - wget -q https://scale.riken.jp/archives/scale-5.4.3.tar.gz - tar xzf scale-5.4.3.tar.gz --strip-components 1 + wget -q https://scale.riken.jp/archives/scale-5.4.4.tar.gz + tar xzf scale-5.4.4.tar.gz --strip-components 1 echo "Build SCALE library .." export SCALE_SYS=Linux64-gnu-ompi From 41136ead99b1b8fed5363b2c22006d6b89ac2772 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 11 Sep 2021 11:11:34 +0900 Subject: [PATCH 90/98] Change the vertical dependency of the forcing in Held Suarez test. --- .../test/case/Held_Suarez/mod_user.F90 | 3 +- .../test/case/Held_Suarez/regrid.conf | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 model/atm_nonhydro3d/test/case/Held_Suarez/regrid.conf diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 index de629c0b..7bf9b262 100644 --- a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 @@ -176,7 +176,8 @@ subroutine USER_calc_tendency( atm ) ke2D = lcmesh%EMap3Dto2D(ke) PRES_sfc(:) = PRES%val(elem3D%Hslice(:,1),ke2D) - sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) + !sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) + sig(:) = PRES%val(:,ke) / PRES00 lat(:) = lcmesh%lat2D(elem3D%IndexH2Dto3D,ke2D) rtauT(:) = ka + (ks - ka) * max( 0.0_RP, (sig(:) - sigb)/(1.0_RP - sigb) ) * cos(lat(:))**4 diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/regrid.conf b/model/atm_nonhydro3d/test/case/Held_Suarez/regrid.conf new file mode 100644 index 00000000..5bb47bcd --- /dev/null +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/regrid.conf @@ -0,0 +1,55 @@ +&PARAM_IO + IO_LOG_BASENAME = "regrid_LOG" + IO_LOG_ALLNODE = .true., +/ +&PARAM_REGRID_MESH + in_MeshType = "CUBEDSPHERE3D", + out_MeshType = "LONLAT3D", +/ +&PARAM_REGRID_INTERP_FIELD + !- input -------------------- + in_basename="history", + vars = "Umet", "Vmet", "W", "T", "PRES", + !out_tinterval = 5, +/ +&PARAM_REGRID_FILE + !-- output ---------------- + out_basename="./outdata/history", + out_UniformGrid=.false., +/ +&PARAM_REGRID_INMESH3D_CUBEDSPHERE + NLocalMeshPerPrc = 1, + Nprc = 24, + NeGX = 6, + NeGY = 6, + NeGZ = 4, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + PolyOrder_h = 7, + PolyOrder_v = 7, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, +/ +&PARAM_REGRID_OUTMESH3D_STRUCTURED + NprcX = 4, + NeX = 32, !16, + NprcY = 4, + NeY = 16, !8, + NeGZ = 4, + PolyOrder_h = 3, + PolyOrder_v = 7, + dom_xmin = 0.0D0, + dom_xmax = 360.0D0, + dom_ymin = -90.0D0, + dom_ymax = 90.0D0, + dom_zmin = 0.0D0, + dom_zmax = 30.0D3, + Fz = 0.0D0, 3000D0, 8000.0D0, 15000.0D0, 30000.0D0, +/ +&PARAM_REGRID_VCOORD + vintrp_name = 'SIGMA', + out_NeZ = 10, + out_PolyOrder_v = 3, + out_dom_vmin = 1D0, + out_dom_vmax = 2D-2, + out_Fz = 1D0, 9.5D-1, 8.8D-1, 7.9D-1, 6.8D-1, 5.5D-1, 4.0D-1, 2.5D-1, 1.0D-1, 5D-2, 2D-2, +/ \ No newline at end of file From 2e5af21e34eeeb603746e391b3b30b97ad38a9be Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 11 Sep 2021 11:14:38 +0900 Subject: [PATCH 91/98] Move iM2Dto3D (an array for mapping) into DG element modules. --- FElib/src/depend | 2 +- FElib/src/element/scale_element_base.F90 | 6 ++- .../src/element/scale_element_hexahedral.F90 | 39 +++++++++++++++++++ ...cale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 | 5 ++- .../scale_atm_dyn_dgm_nonhydro3d_common.F90 | 27 ------------- 5 files changed, 47 insertions(+), 32 deletions(-) diff --git a/FElib/src/depend b/FElib/src/depend index f052aca3..d7df1aea 100644 --- a/FElib/src/depend +++ b/FElib/src/depend @@ -19,7 +19,7 @@ $(OBJ_DIR)/scale_atm_phy_tb_dgm_smg.o: turbulence/scale_atm_phy_tb_dgm_smg.F90 $ $(OBJ_DIR)/scale_coriolis_param.o: common/scale_coriolis_param.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_cubedsphere_cnv.o: common/scale_cubedsphere_cnv.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o: element/scale_element_base.F90 $(DEPENDLIB) -$(OBJ_DIR)/scale_element_hexahedral.o: element/scale_element_hexahedral.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o +$(OBJ_DIR)/scale_element_hexahedral.o: element/scale_element_hexahedral.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o $(OBJ_DIR)/scale_element_line.o: element/scale_element_line.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o $(OBJ_DIR)/scale_element_modalfilter.o: element/scale_element_modalfilter.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_element_hexahedral.o $(OBJ_DIR)/scale_element_line.o $(OBJ_DIR)/scale_element_quadrilateral.o $(OBJ_DIR)/scale_element_quadrilateral.o: element/scale_element_quadrilateral.F90 $(DEPENDLIB) $(OBJ_DIR)/scale_element_base.o $(OBJ_DIR)/scale_linalgebra.o $(OBJ_DIR)/scale_polynominal.o diff --git a/FElib/src/element/scale_element_base.F90 b/FElib/src/element/scale_element_base.F90 index 914e5632..636e01c4 100644 --- a/FElib/src/element/scale_element_base.F90 +++ b/FElib/src/element/scale_element_base.F90 @@ -101,9 +101,9 @@ end function ElementBase2D_GenIntGaussLegendreIntrpMat integer, allocatable :: Colmask(:,:) integer, allocatable :: Hslice(:,:) integer, allocatable :: IndexH2Dto3D(:) + integer, allocatable :: IndexH2Dto3D_bnd(:) integer, allocatable :: IndexZ1Dto3D(:) - real(RP), allocatable :: x1(:) real(RP), allocatable :: x2(:) real(RP), allocatable :: x3(:) @@ -270,6 +270,7 @@ subroutine ElementBase3D_Init( elem, lumpedmat_flag ) allocate( elem%Colmask(elem%Nnode_v,elem%Nfp_v)) allocate( elem%Hslice(elem%Nfp_v,elem%Nnode_v) ) allocate( elem%IndexH2Dto3D(elem%Np) ) + allocate( elem%IndexH2Dto3D_bnd(elem%NfpTot) ) allocate( elem%IndexZ1Dto3D(elem%Np) ) return @@ -287,7 +288,8 @@ subroutine ElementBase3D_Final( elem ) deallocate( elem%Sx1, elem%Sx2, elem%Sx3 ) deallocate( elem%Fmask_h, elem%Fmask_v ) deallocate( elem%Colmask, elem%Hslice ) - deallocate( elem%IndexH2Dto3D, elem%IndexZ1Dto3D ) + deallocate( elem%IndexH2Dto3D, elem%IndexH2Dto3D_bnd ) + deallocate( elem%IndexZ1Dto3D ) end if call ElementBase_Final( elem ) diff --git a/FElib/src/element/scale_element_hexahedral.F90 b/FElib/src/element/scale_element_hexahedral.F90 index cafd78c6..d80f31ef 100644 --- a/FElib/src/element/scale_element_hexahedral.F90 +++ b/FElib/src/element/scale_element_hexahedral.F90 @@ -80,6 +80,7 @@ subroutine construct_Element(elem) polynominal_genGaussLobattoPt, Polynominal_GenGaussLobattoPtIntWeight, & polynominal_genLegendrePoly, Polynominal_genDLegendrePoly, & polynominal_genLagrangePoly, polynominal_genDLagrangePoly_lglpt + use scale_element_quadrilateral, only: QuadrilateralElement implicit none @@ -110,6 +111,11 @@ subroutine construct_Element(elem) integer :: n, l, f integer :: Nord integer :: is, ie + + integer :: f_h, f_v + integer :: fp, fp_h1, fp_h2, fp_v + + type(QuadrilateralElement) :: elem2D !----------------------------------------------------------------------------- lglPts1D_h(:) = polynominal_genGaussLobattoPt( elem%PolyOrder_h ) @@ -142,6 +148,8 @@ subroutine construct_Element(elem) elem%Fmask_v(:,1) = reshape(nodes_ijk(:,:,1), (/ elem%Nfp_v /)) elem%Fmask_v(:,2) = reshape(nodes_ijk(:,:,elem%Nnode_v), (/ elem%Nfp_v /)) + !- ColMask + do j=1, elem%Nnode_h1D do i=1, elem%Nnode_h1D n = i + (j-1)*elem%Nnode_h1D @@ -149,10 +157,14 @@ subroutine construct_Element(elem) end do end do + != Hslice + do k=1, elem%Nnode_v elem%Hslice(:,k) = reshape(nodes_ijk(:,:,k), (/ elem%Nfp_v /)) end do + !- IndexH2Dto3D + do k=1, elem%Nnode_v do j=1, elem%Nnode_h1D do i=1, elem%Nnode_h1D @@ -162,6 +174,33 @@ subroutine construct_Element(elem) end do end do + !- IndexH2Dto3D_bnd + + call elem2D%Init( elem%PolyOrder_h, .false. ) + + do f_h=1, 4 + do fp_v=1, elem%Nnode_v + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h + elem%IndexH2Dto3D_bnd(fp) = elem2D%Fmask(fp_h1,f_h) + end do + end do + end do + do f_v=1, 2 + do fp_h2=1, elem%Nnode_h1D + do fp_h1=1, elem%Nnode_h1D + fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & + + (f_v-1) * elem%Nfp_v & + + 4 * elem%Nnode_h1D * elem%Nnode_v + elem%IndexH2Dto3D_bnd(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D + end do + end do + end do + + call elem2D%Final() + + !- IndexZ1Dto3D + do k=1, elem%Nnode_v do j=1, elem%Nnode_h1D do i=1, elem%Nnode_h1D diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 index d747a5fd..23fd6800 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_globalnonhydro3d_hevi.F90 @@ -41,7 +41,7 @@ module scale_atm_dyn_dgm_globalnonhydro3d_hevi atm_dyn_dgm_nonhydro3d_common_Final, & DENS_VID, MOMX_VID, MOMY_VID, MOMZ_VID, RHOT_VID, & PROG_VARS_NUM, & - IntrpMat_VPOrdM1, iM2Dto3D + IntrpMat_VPOrdM1 !----------------------------------------------------------------------------- implicit none @@ -155,7 +155,8 @@ subroutine atm_dyn_dgm_globalnonhydro3d_hevi_cal_tend( & lmesh%Gsqrt, lmesh%GIJ(:,:,1,1), lmesh%GIJ(:,:,1,2), lmesh%GIJ(:,:,2,2), & ! (in) lmesh%GsqrtH, lmesh%GI3(:,:,1), lmesh%GI3(:,:,2), & ! (in) lmesh%normal_fn(:,:,1), lmesh%normal_fn(:,:,2), lmesh%normal_fn(:,:,3), & ! (in) - lmesh%vmapM, lmesh%vmapP, iM2Dto3D, lmesh, elem, lmesh2D, elem2D ) ! (in) + lmesh%vmapM, lmesh%vmapP, elem%IndexH2Dto3D_bnd, & ! (in) + lmesh, elem, lmesh2D, elem2D ) ! (in) call PROF_rapend('cal_dyn_tend_bndflux', 3) !----- diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 index 0aeade3f..6f95c99e 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_common.F90 @@ -77,8 +77,6 @@ subroutine atm_dyn_dgm_nonhydro3d_common_Init( mesh ) type(ElementBase3D), pointer :: elem real(RP) :: invV_VPOrdM1(mesh%refElem3D%Np,mesh%refElem3D%Np) - integer :: f_h, f_v - integer :: fp, fp_h1, fp_h2, fp_v type(ElementBase2D), pointer :: elem2D class(MeshBase2D), pointer :: mesh2D !-------------------------------------------- @@ -95,30 +93,6 @@ subroutine atm_dyn_dgm_nonhydro3d_common_Init( mesh ) end do IntrpMat_VPOrdM1(:,:) = matmul(elem%V, invV_VPOrdM1) - !-- - - allocate( iM2Dto3D(elem%NfpTot) ) - call mesh%GetMesh2D( mesh2D ) - elem2D => mesh2D%refElem2D - - do f_h=1, 4 - do fp_v=1, elem%Nnode_v - do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_v-1)*elem%Nnode_h1D + (f_h-1)*elem%Nfp_h - iM2Dto3D(fp) = elem2D%Fmask(fp_h1,f_h) - end do - end do - end do - do f_v=1, 2 - do fp_h2=1, elem%Nnode_h1D - do fp_h1=1, elem%Nnode_h1D - fp = fp_h1 + (fp_h2-1)*elem%Nnode_h1D & - + (f_v-1) * elem%Nfp_v & - + 4 * elem%Nnode_h1D * elem%Nnode_v - iM2Dto3D(fp) = fp_h1 + (fp_h2-1)*elem%Nnode_h1D - end do - end do - end do return end subroutine atm_dyn_dgm_nonhydro3d_common_Init @@ -129,7 +103,6 @@ subroutine atm_dyn_dgm_nonhydro3d_common_Final() !-------------------------------------------- deallocate( IntrpMat_VPOrdM1 ) - deallocate( iM2Dto3D ) return end subroutine atm_dyn_dgm_nonhydro3d_common_Final From 8e8bf10ce8011ee6979a1a2d4aac48cbd8fcc46d Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 11 Sep 2021 11:18:17 +0900 Subject: [PATCH 92/98] Modify tentative treatment of surface boundary condition when topography exists. --- ...le_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 | 8 +-- ...le_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 | 10 ---- .../src/atmos/mod_atmos_dyn.F90 | 12 +++-- .../src/atmos/mod_atmos_dyn_bnd.F90 | 51 ++++++++++++++----- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 index 37a5eae9..230ce452 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 @@ -309,7 +309,7 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc( & !$omp GsqrtDDENS_M, GsqrtDDENS_P, GsqrtDRHOT_M, GsqrtDRHOT_P, & !$omp Phyd_M, Phyd_P, & !$omp Gsqrt_P, Gsqrt_M, GsqrtV_P, GsqrtV_M, G13_P, G13_M, G23_P, G23_M, & - !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M ) + !$omp Gxz_P, Gxz_M, Gyz_P, Gyz_M, G1n_M, G2n_M, Gnn_P, Gnn_M ) do ke=lmesh%NeS, lmesh%NeE iM(:) = vmapM(:,ke); iP(:) = vmapP(:,ke) ke2D = lmesh%EMap3Dto2D(ke) @@ -366,12 +366,6 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalhvc( & + G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & ) / GsqrtDensP(:) - ! Tentative treatment - where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) - VelP(:) = - VelM(:) - GsqrtMOMZ_P(:) = - GsqrtMOMZ_M(:) - 2.0_RP * ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) - end where - dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & - Phyd_M(:) dpresP(:) = PRES00 * ( RovP0 * GsqrtRhotP(:) / Gsqrt_P(:) )**gamm & diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 index 3690633c..13b14765 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_hevi_numflux.F90 @@ -178,11 +178,6 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalvc( & VelM(:) = VelhM(:) + GsqrtMOMZ_M(:) / ( GsqrtV_M(:) * GsqrtDensM(:) ) * nz(:,ke) VelP(:) = VelhP(:) + GsqrtMOMZ_P(:) / ( GsqrtV_P(:) * GsqrtDensP(:) ) * nz(:,ke) - - ! Tentative treatment - where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) - VelP(:) = - VelM(:) - end where dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & - Phyd_M(:) @@ -364,11 +359,6 @@ subroutine atm_dyn_dgm_nonhydro3d_hevi_numflux_get_generalhvc( & VelM(:) = VelhM(:) + GsqrtMOMZ_M(:) / ( GsqrtV_M(:) * GsqrtDensM(:) ) * nz(:,ke) VelP(:) = VelhP(:) + GsqrtMOMZ_P(:) / ( GsqrtV_P(:) * GsqrtDensP(:) ) * nz(:,ke) - - ! Tentative treatment - where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) - VelP(:) = - VelM(:) - end where dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & - Phyd_M(:) diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 index 3423fa24..703bb30b 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn.F90 @@ -509,11 +509,13 @@ subroutine AtmosDyn_update( this, model_mesh, prgvars_list, auxvars_list, forcin !* Apply boundary conditions call PROF_rapstart( 'ATM_DYN_applyBC_prgv', 2) - call this%boundary_cond%ApplyBC_PROGVARS_lc( n, & ! (in) - DDENS%val, MOMX%val, MOMY%val, MOMZ%val, DRHOT%val, & ! (inout) - DENS_hyd%val, PRES_hyd%val, & ! (in) - lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%normal_fn(:,:,3), & ! (in) - lcmesh%vmapM, lcmesh%vmapP, lcmesh%vmapB, lcmesh, lcmesh%refElem3D ) ! (in) + call this%boundary_cond%ApplyBC_PROGVARS_lc( n, & ! (in) + DDENS%val, MOMX%val, MOMY%val, MOMZ%val, DRHOT%val, & ! (inout) + DENS_hyd%val, PRES_hyd%val, & ! (in) + lcmesh%Gsqrt(:,:), lcmesh%GsqrtH(:,:), lcmesh%GI3(:,:,1), lcmesh%GI3(:,:,2), & ! (in) + lcmesh%normal_fn(:,:,1), lcmesh%normal_fn(:,:,2), lcmesh%normal_fn(:,:,3), & ! (in) + lcmesh%vmapM, lcmesh%vmapP, lcmesh%vmapB, & ! (in) + lcmesh, lcmesh%refElem3D, lcmesh%lcmesh2D, lcmesh%lcmesh2D%refElem2D ) ! (in) call PROF_rapend( 'ATM_DYN_applyBC_prgv', 2) end do diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 index 1d8ae559..aa192900 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 @@ -25,12 +25,14 @@ module mod_atmos_dyn_bnd PRES00 => CONST_PRE00 use scale_element_base, only: & - ElementBase, ElementBase3D + ElementBase, ElementBase2D, ElementBase3D use scale_mesh_base, only: MeshBase use scale_localmesh_base, only: LocalMeshBase use scale_mesh_base3d, only: MeshBase3D + use scale_mesh_base2d, only: MeshBase2D use scale_localmesh_3d, only: LocalMesh3D + use scale_localmesh_2d, only: LocalMesh2D use scale_localmeshfield_base, only: LocalMeshField3D use scale_meshfield_base, only: MeshField3D @@ -203,11 +205,13 @@ subroutine ATMOS_dyn_bnd_setBCInfo( this, mesh ) return end subroutine ATMOS_dyn_bnd_setBCInfo - subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & - domID, & ! (in) - DDENS, MOMX, MOMY, MOMZ, DRHOT, & ! (inout) - DENS_hyd, PRES_hyd, & ! (in) - nx, ny, nz, vmapM, vmapP, vmapB, lmesh, elem ) ! (in) +!OCL SERIAL + subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & + domID, & ! (in) + DDENS, MOMX, MOMY, MOMZ, DRHOT, & ! (inout) + DENS_hyd, PRES_hyd, & ! (in) + Gsqrt, GsqrtH, G13, G23, nx, ny, nz, & ! (in) + vmapM, vmapP, vmapB, lmesh, elem, lmesh2D, elem2D ) ! (in) use scale_mesh_bndinfo, only: & BND_TYPE_SLIP_ID, BND_TYPE_NOSLIP_ID, & @@ -218,7 +222,9 @@ subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & class(AtmosDynBnd), intent(in) :: this integer, intent(in) :: domID class(LocalMesh3D), intent(in) :: lmesh - class(elementbase3D), intent(in) :: elem + class(ElementBase3D), intent(in) :: elem + class(LocalMesh2D), intent(in) :: lmesh2D + class(ElementBase2D), intent(in) :: elem2D real(RP), intent(inout) :: DDENS(elem%Np*lmesh%NeA) real(RP), intent(inout) :: MOMX(elem%Np*lmesh%NeA) real(RP), intent(inout) :: MOMY(elem%Np*lmesh%NeA) @@ -226,6 +232,10 @@ subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & real(RP), intent(inout) :: DRHOT(elem%Np*lmesh%NeA) real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) + real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) + real(RP), intent(in) :: G13(elem%Np*lmesh%Ne) + real(RP), intent(in) :: G23(elem%Np*lmesh%Ne) real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) @@ -233,19 +243,34 @@ subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & integer, intent(in) :: vmapP(elem%NfpTot*lmesh%Ne) integer, intent(in) :: vmapB(:) + integer :: p, ke, ke2D integer :: i, i_, iM, iP real(RP) :: mom_normal + + real(RP) :: MOMW !----------------------------------------------- - do i=1, elem%NfpTot*lmesh%Ne + !$omp parallel do collapse(2) private( & + !$omp ke, p, ke2D, i, i_, iM, iP, & + !$omp mom_normal, MOMW ) + do ke=lmesh%NeS, lmesh%NeE + do p=1, elem%NfpTot + i = p + (ke-1)*elem%NfpTot iP = vmapP(i) i_ = iP - elem%Np*lmesh%NeE - + if (i_ > 0) then iM = vmapM(i) + select case( this%VelBC_list(domID)%list(i_) ) case ( BND_TYPE_SLIP_ID) - mom_normal = MOMX(iM) * nx(i) + MOMY(iM) * ny(i) + MOMZ(iM) * nz(i) + ke2D = lmesh%EMap3Dto2D(ke) + + MOMW = MOMZ(iM) & + + Gsqrt(iM) / GsqrtH(elem%IndexH2Dto3D_bnd(p),ke2D) & + * ( G13(iM) * MOMX(iM) + G23(iM) * MOMY(iM) ) + mom_normal = MOMX(iM) * nx(i) + MOMY(iM) * ny(i) + MOMW * nz(i) + MOMX(iP) = MOMX(iM) - 2.0_RP * mom_normal * nx(i) MOMY(iP) = MOMY(iM) - 2.0_RP * mom_normal * ny(i) MOMZ(iP) = MOMZ(iM) - 2.0_RP * mom_normal * nz(i) @@ -255,8 +280,10 @@ subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & MOMZ(iP) = - MOMZ(iM) end select end if - end do - + + end do + end do + return end subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc From 3e0a743aa6d3ffb01b1914eec8078d1adbfdbc43 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 11 Sep 2021 11:19:31 +0900 Subject: [PATCH 93/98] Change the implimentation of forcing function in the Held Suarez test. --- .../test/case/Held_Suarez/mod_user.F90 | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 index 7bf9b262..c2c4cb36 100644 --- a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 @@ -114,9 +114,20 @@ subroutine USER_setup( atm ) end subroutine USER_setup subroutine USER_calc_tendency( atm ) + implicit none + + class(AtmosComponent), intent(inout) :: atm + !------------------------------------------ + + return + end subroutine USER_calc_tendency + + subroutine USER_update( atm ) + use scale_const, only: & Rdry => CONST_Rdry, & CPdry => CONST_CPdry, & + CVdry => CONST_CVdry, & PRES00 => CONST_PRE00 use scale_file_history_meshfield, only: & FILE_HISTORY_meshfield_in @@ -142,7 +153,7 @@ subroutine USER_calc_tendency( atm ) integer :: n integer :: ke, ke2D - real(RP), allocatable :: DENS(:), Teq(:), sig(:), PRES_sfc(:) + real(RP), allocatable :: DENS(:), T(:), Teq(:), sig(:), PRES_sfc(:) real(RP), allocatable :: rtauT(:), rtauV(:) real(RP), allocatable :: lat(:) real(RP), parameter :: kf = 1.0_RP / ( 86400.0_RP * 1.0_RP ) @@ -152,8 +163,12 @@ subroutine USER_calc_tendency( atm ) real(RP), parameter :: DelPT_z = 10.0_RP real(RP), parameter :: sigb = 0.7_RP - real(RP) :: dt - !------------------------------------------ + real(DP) :: dt + real(RP) :: Gamm + !---------------------------------------------------------- + + dt = atm%time_manager%dtsec + gamm = CpDry / CvDry do n=1, atm%mesh%ptr_mesh%LOCAL_MESH_NUM call AtmosVars_GetLocalMeshPrgVars( n, atm%mesh%ptr_mesh, & @@ -166,18 +181,18 @@ subroutine USER_calc_tendency( atm ) elem3D => lcmesh%refElem3D - allocate( DENS(elem3D%Np), Teq(elem3D%Np), sig(elem3D%Np) ) + allocate( DENS(elem3D%Np), T(elem3D%Np), Teq(elem3D%Np), sig(elem3D%Np) ) allocate( PRES_sfc(elem3D%Nnode_h1D**2) ) allocate( rtauT(elem3D%Np), rtauV(elem3D%Np) ) allocate( lat(elem3D%Np) ) - !$omp parallel do private(DENS, Teq, PRES_sfc, sig, lat, rtauT, rtauV, ke2D) + !$omp parallel do private(DENS, T, Teq, PRES_sfc, sig, lat, rtauT, rtauV, ke2D) do ke=lcmesh%NeS, lcmesh%NeE ke2D = lcmesh%EMap3Dto2D(ke) PRES_sfc(:) = PRES%val(elem3D%Hslice(:,1),ke2D) - !sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) - sig(:) = PRES%val(:,ke) / PRES00 + sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) + sig(:) = PRES%val(:,ke) / PRES00 lat(:) = lcmesh%lat2D(elem3D%IndexH2Dto3D,ke2D) rtauT(:) = ka + (ks - ka) * max( 0.0_RP, (sig(:) - sigb)/(1.0_RP - sigb) ) * cos(lat(:))**4 @@ -186,30 +201,21 @@ subroutine USER_calc_tendency( atm ) Teq(:) = max(200.0_RP, & ( 315.0_RP - DelT_y * sin(lat(:))**2 - DelPT_z * log(PRES%val(:,ke)/PRES00) * cos(lat(:))**2 ) & * (PRES%val(:,ke)/PRES00)**(Rdry/CPDry) ) + DENS(:) = DENS_hyd%val(:,ke) + DDENS%val(:,ke) + T(:) = PRES%val(:,ke) / ( Rdry * DENS(:) ) - atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMX_p)%local(n)%val(:,ke) & - - rtauV(:) * MOMX%val(:,ke) - atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(MOMY_p)%local(n)%val(:,ke) & - - rtauV(:) * MOMY%val(:,ke) - - atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) = atm%vars%PHY_TEND(RHOH_p)%local(n)%val(:,ke) & - - DENS(:) * CpDry * rtauT(:) * ( PRES%val(:,ke) / (Rdry * DENS(:)) - Teq(:) ) + MOMX%val(:,ke) = MOMX%val(:,ke) / ( 1.0_RP + dt * rtauV ) + MOMY%val(:,ke) = MOMY%val(:,ke) / ( 1.0_RP + dt * rtauV ) + DRHOT%val(:,ke) = DRHOT%val(:,ke) & + - dt * rtauT(:) / gamm * ( 1.0_RP - Teq(:) / T(:) ) * DENS(:) * PT%val(:,ke) & + / ( 1.0_RP + dt * rtauT(:) / gamm * ( 1.0_RP + (gamm - 1.0_RP) * Teq(:) / T(:) ) ) end do - deallocate( DENS, Teq, sig, PRES_sfc ) + deallocate( DENS, T, Teq, sig, PRES_sfc ) deallocate( rtauT, rtauV ) deallocate( lat ) end do - - return - end subroutine USER_calc_tendency - - subroutine USER_update( atm ) - implicit none - - class(AtmosComponent), intent(inout) :: atm - !------------------------------------------ return end subroutine USER_update From eada0a92156b623904f429629cf0cef649228593 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Tue, 15 Jun 2021 16:25:23 +0900 Subject: [PATCH 94/98] Add an eigenvalue analysis of 1D linear advection with DGM --- sample/eigen_analysis/Makefile | 72 +++++ sample/eigen_analysis/test_eigen_analysis.f90 | 253 ++++++++++++++++++ .../visualize/dispersion_dissipation_graph.py | 90 +++++++ 3 files changed, 415 insertions(+) create mode 100644 sample/eigen_analysis/Makefile create mode 100644 sample/eigen_analysis/test_eigen_analysis.f90 create mode 100644 sample/eigen_analysis/visualize/dispersion_dissipation_graph.py diff --git a/sample/eigen_analysis/Makefile b/sample/eigen_analysis/Makefile new file mode 100644 index 00000000..6ecc0e05 --- /dev/null +++ b/sample/eigen_analysis/Makefile @@ -0,0 +1,72 @@ +################################################################################ +# +# Makefile for each test program +# +################################################################################ + +PWD = $(shell pwd) +TOPDIR = $(abspath ../..) +BUILD_DIR = ./.libs +SYSDEP_DIR = $(TOPDIR)/sysdep + +include $(SYSDEP_DIR)/Makedef.$(SCALE_FE_SYS) +include $(TOPDIR)/Mkinclude + +BINNAME = test_eigen_analysis + +OBJS = + +LIBS = $(LIBDIR)/libScaleFECore.a + +SAMPLE_AUX_DIR = ../auxiliary +SAMPLE_AUX_INCLUDE = $(SAMPLE_AUX_DIR)/.libs +SAMPLE_AUX_LIB = $(SAMPLE_AUX_DIR)/libScaleFESampleAux.a + +all: + $(MAKE) envlog + $(MAKE) makedir + $(MAKE) make_sample_aux + $(MAKE) makebin + +makedir: + mkdir -p $(BUILD_DIR) + +makebin: $(BINNAME) + @echo "Complete making." + +run: + export OMP_NUM_THREADS=1 + mkdir -p data + mpirun -n 1 ./$(BINNAME) test.conf + +vis: + python ./visualize/dispersion_dissipation_graph.py + +make_sample_aux: + make -C $(SAMPLE_AUX_DIR) + +$(BINNAME): $(BUILD_DIR)/$(BINNAME).o $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) $(SAMPLE_AUX_LIB) $(LIBS) + $(LD) $(LDFLAGS) $(ADDITIONAL_FFLAGS) -o $@ $^ $(LIBS) $(CONTRIB_LIBS) $(SCALE_NETCDF_LIBS) $(SCALE_MATHLIB_LIBS) $(SCALE_PAPI_LIBS) + +$(BUILD_DIR)/$(BINNAME).o: $(BINNAME).f90 $(patsubst %,$(BUILD_DIR)/%,$(OBJS)) + +distclean: clean + rm -f $(BINNAME) + rm -rf ./data + rm -rf ./visualize/*.png + +clean: + rm -rf $(BUILD_DIR) + +.SUFFIXES: +.SUFFIXES: .o .f90 .mod + +%.mod: %.f90 + $(MAKE) $(patsubst %.f90,%.o,$<) + +$(BUILD_DIR)/%.o: %.f90 + $(FC) $(FFLAGS) $(ADDITIONAL_FFLAGS) -DVERSION_MACRO=\"$(VERSION)\" -I$(BUILD_DIR) -I$(MODDIR) $(CONTRIB_INCLUDE) -I$(SCALEFELIBDIR)/include -I$(SAMPLE_AUX_INCLUDE) $(SCALE_NETCDF_INCLUDE) $(MODDIROPT) $(BUILD_DIR) -o $@ -c $< + +.PHONY : clean distclean allclean + +include $(TOPDIR)/utils/make/Make_environments diff --git a/sample/eigen_analysis/test_eigen_analysis.f90 b/sample/eigen_analysis/test_eigen_analysis.f90 new file mode 100644 index 00000000..d49430d5 --- /dev/null +++ b/sample/eigen_analysis/test_eigen_analysis.f90 @@ -0,0 +1,253 @@ +program test_eigen_analysis + use scale_precision + use scale_const, only: & + PI => CONST_PI + use scale_io + implicit none + + integer, parameter :: pmax = 7 + integer :: p + + real(RP), parameter :: ADV_VEL = 1.0_RP + real(RP), parameter :: BETA_UPWIND = 1.0_RP + real(RP), parameter :: BETA_CENTRAL = 0.0_RP + real(RP), parameter :: Helem = 1.0_RP + + integer, parameter :: nout = 10 + !---------------------------------- + + do p=1, pmax + call eigen_analysis( p, BETA_UPWIND, 'modal', 'weak' ) + call eigen_analysis( p, BETA_UPWIND, 'nodal', 'weak' ) + end do + +contains + + subroutine eigen_analysis( porder, beta, basis_type, form_type ) + use scale_element_line, only: LineElement + use scale_polynominal, only: & + polynominal_genLegendrePoly, & + polynominal_genDLegendrePoly + implicit none + integer, intent(in) :: porder + real(RP), intent(in) :: beta + character(len=*), intent(in) :: basis_type + character(len=*), intent(in) :: form_type + + type(LineElement) :: elem + real(RP) :: KC(porder+1,porder+1) + real(RP) :: KM(porder+1,porder+1) + real(RP) :: KP(porder+1,porder+1) + real(RP) :: Stiff(porder+1,porder+1) + real(RP) :: Minv(porder+1,porder+1) + real(RP) :: phiM1(porder+1) + real(RP) :: phiP1(porder+1) + real(RP) :: P1D_ (porder+1,porder+1) + real(RP) :: DP1D_(porder+1,porder+1) + + integer :: p1, p2 + + integer :: k + integer, parameter :: kmax = 400 + real(RP) :: dwnum + real(RP) :: wnum + complex(RP) :: Mat(porder+1,porder+1) + real(RP) :: cs_kh, si_kh + complex(RP), parameter :: ei = (0.0_RP, 1.0_RP) + + complex(RP) :: dummy(1,1) + complex(RP) :: vr(porder+1,porder+1), w(porder+1), rwork(2*(porder+1)) + real(RP) :: w_r(porder+1), w_i(porder+1), dw_r(porder+1), dw_i(porder+1) + complex(RP), allocatable :: work(:) + integer :: lwork + integer :: info + + real(RP) :: wnum_nondim(kmax) + real(RP) :: wnum_nondim_num(2,kmax,porder+1) + character(len=H_MID) :: filename + !------------------------------------ + + write(*,'(a,i2,a,a)') "Eigen analysis: porder=", porder, ', basis_type: ', trim(basis_type) + + call elem%Init( porder, .false. ) + + if (basis_type == 'nodal' ) then + Minv(:,:) = elem%invM(:,:) + Stiff(:,:) = matmul(elem%M, elem%Sx1(:,:)) + phiM1(:) = 0.0_RP; phiP1(:) = 0.0_RP + phiM1(1) = 1.0_RP; phiP1(porder+1) = 1.0_RP + else if (basis_type == 'modal' ) then + P1D_ (:,:) = Polynominal_GenLegendrePoly( elem%PolyOrder, elem%x1(:) ) + DP1D_(:,:) = polynominal_genDLegendrePoly( elem%PolyOrder, elem%x1(:), P1D_(:,:) ) + ! normalization + do p1=1, porder+1 + P1D_ (:,p1) = P1D_(:,p1) * sqrt(dble(p1-1) + 0.5_RP) + DP1D_(:,p1) = DP1D_(:,p1) * sqrt(dble(p1-1) + 0.5_RP) + end do + Minv(:,:) = 0.0_RP + do p2=1, porder+1 + Minv(p2,p2) = 1.0_RP + phiM1(p2) = P1D_(1,p2) + phiP1(p2) = P1D_(porder+1,p2) + do p1=1, porder+1 + Stiff(p1,p2) = sum( elem%IntWeight_lgl(:) * P1D_(:,p2) * DP1D_(:,p1) ) + end do + end do + else + write(*,*) 'Check! Invalid basis_type:', basis_type + stop + end if + + !-- + call cosntruct_mat( KC, KP, KM, & ! (out) + Stiff, Minv, phiM1, phiP1, porder, beta ) ! (in) + + !-- Calculate eigenvalues + + ! Use routine workspace query to get optimal workspace. + lwork = -1 + call zgeev( 'No left vectors', 'Vectors (right)', porder+1, Mat, porder+1, w, dummy, 1, & + vr, porder+1, dummy, lwork, rwork, info ) + lwork = max( (64+1)*(porder+1), nint(real(dummy(1,1))) ) + allocate( work(lwork) ) + + dwnum = PI * dble(porder + 1) / Helem / dble( kmax ) + dw_r(:) = 0.0_RP; dw_i(:) = 0.0_RP + do k=0, kmax-1 + wnum = dble(k) * dwnum + cs_kh = cos(wnum * Helem) + si_kh = sin(wnum * Helem) + do p2=1, porder+1 + do p1=1, porder+1 + Mat(p1,p2) = 2.0_RP * ( ( ( KM(p1,p2) + KP(p1,p2) ) * cs_kh + KC(p1,p2) ) * ei - ( - KM(p1,p2) + KP(p1,p2) ) * si_kh ) + end do + end do + + call zgeev( 'No left vectors', 'Vectors (right)', porder+1, Mat, porder+1, w, dummy, 1, & + vr, porder+1, work, lwork, rwork, info ) + + if ( info /= 0 ) then + write(*,*) 'Failure in ZGEEV. INFO = ', info + stop + end if + + w_r(:) = real(w(:)) / dble(porder + 1) + w_i(:) = aimag(w(:)) / dble(porder + 1) + if ( k > 0 ) then + call sort_eigenval( w_r, w_i, dw_r, dw_i, & + wnum_nondim_num(1,k,:), wnum_nondim_num(2,k,:), porder+1 ) + end if + wnum_nondim(k+1) = wnum * Helem / dble(porder + 1) + wnum_nondim_num(1,k+1,:) = w_r(:) + wnum_nondim_num(2,k+1,:) = w_i(:) + + ! write(*,*) 'K = ', wnum_nondim(k+1) + ! write(*,*) 'Eigenvalues: Re', wnum_nondim_num(1,k+1,:) + ! write(*,*) 'Eigenvalues: Im', wnum_nondim_num(2,k+1,:) + end do + + !-- + do p1=1, porder+1 + write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '.dat' + open( nout, file=trim(filename), status='replace' ) + write( nout, '(a)') "# K Re(Km) Im(Km)" + do k=1, kmax + write( nout, '(3f15.8)') wnum_nondim(k), wnum_nondim_num(1,k,p1), wnum_nondim_num(2,k,p1) + end do + close( nout ) + end do + + call elem%Final() + + return + end subroutine eigen_analysis + + subroutine cosntruct_mat( K, Kp, Km, & + Stiff, Minv, phiM1, phiP1, porder, beta ) + implicit none + integer, intent(in) :: porder + real(RP), intent(out) :: K (porder+1,porder+1) + real(RP), intent(out) :: Kp(porder+1,porder+1) + real(RP), intent(out) :: Km(porder+1,porder+1) + real(RP), intent(in) :: Stiff(porder+1,porder+1) + real(RP), intent(in) :: Minv(porder+1,porder+1) + real(RP), intent(in) :: phiM1(porder+1) + real(RP), intent(in) :: phiP1(porder+1) + real(RP), intent(in) :: beta + + real(RP) :: bM, bP + real(RP) :: tmpMat (porder+1,porder+1) + real(RP) :: tmpMatM(porder+1,porder+1) + real(RP) :: tmpMatP(porder+1,porder+1) + + integer :: l, m + !------------------------------------------ + + bM = 0.5_RP * ( 1.0_RP - sign(beta, ADV_VEL) ) + bP = 0.5_RP * ( 1.0_RP + sign(beta, ADV_VEL) ) + + do m=1, porder+1 + do l=1, porder+1 + tmpMat (l,m) = Stiff(l,m) + bM * phiM1(m) * phiM1(l) - bP * phiP1(m) * phiP1(l) + tmpMatM(l,m) = bP * phiP1(m) * phiM1(l) + tmpMatP(l,m) = - bM * phiM1(m) * phiP1(l) + end do + end do + + K (:,:) = matmul(Minv, tmpMat ) + Km(:,:) = matmul(Minv, tmpMatM) + Kp(:,:) = matmul(Minv, tmpMatP) + + return + end subroutine cosntruct_mat + + subroutine sort_eigenval( w_r, w_i, dw_r, dw_i, & + wr_prev, wi_prev, n ) + use scale_quicksort, only: QUICKSORT_exec_with_idx + implicit none + integer, intent(in) :: n + real(RP), intent(inout) :: w_r(n) + real(RP), intent(inout) :: w_i(n) + real(RP), intent(inout) :: dw_r(n) + real(RP), intent(inout) :: dw_i(n) + real(RP), intent(in) :: wr_prev(n) + real(RP), intent(in) :: wi_prev(n) + + integer :: p1, p2, nn + real(RP) :: wr_ori(n) + real(RP) :: wi_ori(n) + real(RP) :: dw_ori(2,n) + integer :: loc_min + real(RP) :: diff(n) + logical :: flag(n) + integer :: sorted_ind(n) + !---------------------- + + wr_ori(:) = w_r(:) + wi_ori(:) = w_i(:) + dw_ori(1,:) = dw_r(:) + dw_ori(2,:) = dw_i(:) + flag(:) = .false. + + do p1=1, n + forall(nn=1:n) sorted_ind(nn) = nn + diff(:) = ( (wr_ori(:) - wr_prev(p1)) - dw_ori(1,p1) )**2 & + + ( (wi_ori(:) - wi_prev(p1)) - dw_ori(2,p1) )**2 + call QUICKSORT_exec_with_idx(n, diff(:), sorted_ind(:)) + do p2=1, n + loc_min = sorted_ind(p2) + if ( .not. flag(loc_min) ) then + flag(loc_min) = .true. + w_r(p1) = wr_ori(loc_min) + w_i(p1) = wi_ori(loc_min) + dw_r(p1) = w_r(p1) - wr_prev(p1) + dw_i(p1) = w_i(p1) - wi_prev(p1) + exit + end if + end do + end do + + return + end subroutine sort_eigenval + +end program test_eigen_analysis \ No newline at end of file diff --git a/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py b/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py new file mode 100644 index 00000000..fc906402 --- /dev/null +++ b/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py @@ -0,0 +1,90 @@ +import numpy as np +import xarray as xr +import matplotlib.pyplot as plt + +DATA_DIR = "data/" +OUT_DIR = "visualize/" + +def set_xax(ax): + ax.set_xlim(0.0, np.pi) + ax.set_xticks([0, 0.25*np.pi, 0.5*np.pi, 0.75*np.pi, np.pi]) + ax.set_xticklabels(["0", "$\pi/4$", "$\pi/2$", "$3\pi/4$", "$\pi$"]) + +def create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, fname): + fig = plt.figure(figsize=(10,4)) + + ax1 = fig.add_subplot(1,2, 1, xlabel='K', ylabel='Re(Km)') + ax1.set_title("dispersion") + set_xax(ax1) + ax1.plot(k_nondim, k_nondim, 'k--', label="exact") + for m in range(0,len(km_real_list)): + ax1.plot(k_nondim, km_real_list[m], label=f"mode{m}") + + ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel='Im(Km)') + ax2.set_title("dissipation") + ax2.plot(k_nondim, 0.0*k_nondim, 'k--', label="exact") + set_xax(ax2) + for m in range(0,len(km_aimg_list)): + ax2.plot(k_nondim, km_aimg_list[m], label=f"mode{m}") + ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0) + + plt.subplots_adjust(wspace=0.4) + plt.tight_layout() + plt.savefig(fname) + +def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg_list, fname): + fig = plt.figure(figsize=(10,4)) + + ax1 = fig.add_subplot(1,2, 1, xlabel='K', ylabel='Re(Km)') + ax1.set_title("dispersion") + set_xax(ax1) + ax1.plot(k_nondim, k_nondim, 'k--', label="exact") + for m in porder_list: + ax1.plot(k_nondim, km_real_list[m], label=f"p={m}") + + ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel='Im(Km)') + ax2.plot(k_nondim, 0.0*k_nondim, 'k--', label="exact") + ax2.set_title("dissipation") + set_xax(ax2) + for m in porder_list: + ax2.plot(k_nondim, km_aimg_list[m], label=f"p={m}") + ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0) + + plt.subplots_adjust(wspace=0.4) + plt.tight_layout() + plt.savefig(fname) + +# Create figure for each order of polynomial +for basis_type in ['modal', 'nodal']: + form_type='weak' + file_prefix=f"{DATA_DIR}/eigenval_{basis_type}_{form_type}_" + print(f"graph for each p: {file_prefix} ..") + + for porder in range(1,8): + k_nondim = np.loadtxt(f"{file_prefix}P{porder:02}_Mode01.dat", skiprows=1, usecols=0) + km_real_list = {}; km_aimg_list = {} + for m in range(1,porder+2): + km_real_list[m-1] = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=1) + km_aimg_list[m-1] = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=2) + + create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}.png") + +# Create figure to show the dependence of polynomial order on the numerical dispersion/dissipation +for basis_type in ['modal', 'nodal']: + form_type='weak' + file_prefix=f"{DATA_DIR}/eigenval_{basis_type}_{form_type}_" + print(f"graph porderdep: {file_prefix} ..") + + porder_list = [2, 4, 3, 4, 5] + km_real_list_pysmode = {}; km_aimg_list_pysmode = {} + for porder in porder_list: + for m in range(1,porder+2): + km_real = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=1) + km_aimg = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=2) + if ( abs(km_real[0]) < 1.0E-10 and km_real[1]-km_real[0] > 0.0 ): + km_real_list_pysmode[porder] = km_real + km_aimg_list_pysmode[porder] = km_aimg + + k_nondim = np.loadtxt(f"{file_prefix}P{porder_list[0]:02}_Mode01.dat", skiprows=1, usecols=0) + create_fig_disp_diff_porder_dep( porder_list, k_nondim, km_real_list_pysmode, km_aimg_list_pysmode, + f"{OUT_DIR}/PolyOrderDep_{basis_type}_{form_type}.png") \ No newline at end of file From 2fb7df26172530b9feab5bf46c97ae7cccb95b48 Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 1 Aug 2021 14:22:49 +0900 Subject: [PATCH 95/98] Add full discrete analysis of DG scheme applied for 1D linear advection equation. --- sample/eigen_analysis/test_eigen_analysis | Bin 0 -> 504960 bytes sample/eigen_analysis/test_eigen_analysis.f90 | 310 +++++++++++++++--- .../visualize/dispersion_dissipation_graph.py | 112 ++++++- 3 files changed, 380 insertions(+), 42 deletions(-) create mode 100755 sample/eigen_analysis/test_eigen_analysis diff --git a/sample/eigen_analysis/test_eigen_analysis b/sample/eigen_analysis/test_eigen_analysis new file mode 100755 index 0000000000000000000000000000000000000000..53ff75a5150f9d52d1bb6bb62509295409677e14 GIT binary patch literal 504960 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

  • H0SYo;Jl?6?kgoxghYYz*dD038nrS3IU%L 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 z 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 literal 0 HcmV?d00001 diff --git a/sample/eigen_analysis/test_eigen_analysis.f90 b/sample/eigen_analysis/test_eigen_analysis.f90 index d49430d5..f36b2d9d 100644 --- a/sample/eigen_analysis/test_eigen_analysis.f90 +++ b/sample/eigen_analysis/test_eigen_analysis.f90 @@ -1,44 +1,83 @@ +!------------------------------------------------------------------------------- +!> Program Fourier dispersion / dissipation analysis of DGM +!! +!! @author Team SCALE +!! +!! @par Reference +!! - Alhawwary and Wang 2018: +!! Fourier analysis and evaluation of DG, FD and compact difference methods for conservation laws. +!! Journal of Computational Physics, 373, 835-862. +!! +!< +!------------------------------------------------------------------------------- program test_eigen_analysis use scale_precision use scale_const, only: & PI => CONST_PI use scale_io + use,intrinsic :: iso_fortran_env + + use scale_element_line, only: LineElement + use scale_polynominal, only: & + Polynominal_GenLagrangePoly + use scale_polynominal, only: & + polynominal_genLegendrePoly, & + polynominal_genDLegendrePoly, & + Polynominal_GenLagrangePoly + use scale_linalgebra, only: & + linalgebra_SolveLinEq implicit none integer, parameter :: pmax = 7 integer :: p - real(RP), parameter :: ADV_VEL = 1.0_RP - real(RP), parameter :: BETA_UPWIND = 1.0_RP - real(RP), parameter :: BETA_CENTRAL = 0.0_RP - real(RP), parameter :: Helem = 1.0_RP + real(RP), parameter :: ADV_VEL = 1.0_RP + real(RP), parameter :: BETA_UPWIND = 1.0_RP + real(RP), parameter :: BETA_CENTRAL = 0.0_RP + real(RP), parameter :: Helem = 1.0_RP + real(RP), parameter :: COURANT_NUMBER_fac = 0.5_RP integer, parameter :: nout = 10 + complex(RP), parameter :: ei = (0.0_RP, 1.0_RP) !---------------------------------- + !* Semi-discrete analysis do p=1, pmax call eigen_analysis( p, BETA_UPWIND, 'modal', 'weak' ) call eigen_analysis( p, BETA_UPWIND, 'nodal', 'weak' ) end do + !* full-discrete analysis + + ! p=2, RK3 + ! Note: To obtain the plane-line (for n=100 and k>pi/2) exactly same with that shown in Fig.9(b) of Alhawwary and Wang (2018), + ! CFL need to be sligthly adjusted such that 0.5 * 0.205 although they indicated that 0.5 * 0.209. + call eigen_analysis( 2, BETA_UPWIND, 'modal', 'weak', 'RK3', COURANT_NUMBER_fac * 0.205_RP ) + ! p=2, RK4 + call eigen_analysis( 2, BETA_UPWIND, 'modal', 'weak', 'RK4', COURANT_NUMBER_fac * 0.235_RP ) + ! p=5, RK5 + call eigen_analysis( 5, BETA_UPWIND, 'modal', 'weak', 'RK4', COURANT_NUMBER_fac * 0.073_RP ) + contains - subroutine eigen_analysis( porder, beta, basis_type, form_type ) - use scale_element_line, only: LineElement - use scale_polynominal, only: & - polynominal_genLegendrePoly, & - polynominal_genDLegendrePoly + subroutine eigen_analysis( & + porder, beta, basis_type, form_type, & + tscheme_name, courant_num ) + implicit none integer, intent(in) :: porder real(RP), intent(in) :: beta character(len=*), intent(in) :: basis_type character(len=*), intent(in) :: form_type + character(len=*), intent(in), optional :: tscheme_name + real(RP), intent(in), optional :: courant_num type(LineElement) :: elem real(RP) :: KC(porder+1,porder+1) real(RP) :: KM(porder+1,porder+1) real(RP) :: KP(porder+1,porder+1) real(RP) :: Stiff(porder+1,porder+1) + real(RP) :: Mass(porder+1,porder+1) real(RP) :: Minv(porder+1,porder+1) real(RP) :: phiM1(porder+1) real(RP) :: phiP1(porder+1) @@ -48,30 +87,60 @@ subroutine eigen_analysis( porder, beta, basis_type, form_type ) integer :: p1, p2 integer :: k - integer, parameter :: kmax = 400 + integer, parameter :: kmax = 2000 real(RP) :: dwnum real(RP) :: wnum - complex(RP) :: Mat(porder+1,porder+1) + complex(RP) :: Mat(porder+1,porder+1) real(RP) :: cs_kh, si_kh - complex(RP), parameter :: ei = (0.0_RP, 1.0_RP) complex(RP) :: dummy(1,1) - complex(RP) :: vr(porder+1,porder+1), w(porder+1), rwork(2*(porder+1)) - real(RP) :: w_r(porder+1), w_i(porder+1), dw_r(porder+1), dw_i(porder+1) + complex(RP) :: vr(porder+1,porder+1) + complex(RP) :: w(porder+1) + complex(RP) :: vl(porder+1,porder+1) + real(DP) :: rwork(2*(porder+1)) + real(DP) :: rconde(porder+1), rcondv(porder+1), scale(porder+1) complex(RP), allocatable :: work(:) + real(RP) :: abnrm integer :: lwork - integer :: info + integer :: ihi, ilo, info + integer :: ipiv(porder+1) + + real(RP) :: w_r(porder+1), w_i(porder+1), dw_r(porder+1), dw_i(porder+1) + real(RP) :: w0_r(porder+1), w0_i(porder+1) + integer :: ipiv_eigenval(porder+1) + + complex(RP) :: mu_hat(porder+1) + complex(RP) :: theta(porder+1) + complex(RP) :: EvecMat(porder+1,porder+1) + + + integer, parameter :: tlev_num = 3 + integer, parameter :: tlev_slot(tlev_num) = (/ 1, 10, 100 /) real(RP) :: wnum_nondim(kmax) real(RP) :: wnum_nondim_num(2,kmax,porder+1) + real(RP) :: eigensol_weight(kmax,porder+1) + real(RP) :: AmplifiFac_comb(tlev_num,kmax) + real(RP) :: PhaseError_comb(tlev_num,kmax) character(len=H_MID) :: filename + + complex(RP) :: Ue (porder+1,tlev_num) + complex(RP) :: Ue_num(porder+1,tlev_num) + complex(RP) :: tmpvec1(porder+1) + complex(RP) :: tmpvec2(porder+1) + real(RP) :: gex, gnum + real(RP) :: fac + real(RP) :: phase(porder+1) + integer :: n + complex(RP) :: phase_error_tmp !------------------------------------ write(*,'(a,i2,a,a)') "Eigen analysis: porder=", porder, ', basis_type: ', trim(basis_type) - + if ( present(tscheme_name) ) write(*,'(a,f12.6)') " full discrete: tscheme:" // trim(tscheme_name) // ', courant_num=', courant_num call elem%Init( porder, .false. ) if (basis_type == 'nodal' ) then + Mass(:,:) = elem%M(:,:) Minv(:,:) = elem%invM(:,:) Stiff(:,:) = matmul(elem%M, elem%Sx1(:,:)) phiM1(:) = 0.0_RP; phiP1(:) = 0.0_RP @@ -84,15 +153,16 @@ subroutine eigen_analysis( porder, beta, basis_type, form_type ) P1D_ (:,p1) = P1D_(:,p1) * sqrt(dble(p1-1) + 0.5_RP) DP1D_(:,p1) = DP1D_(:,p1) * sqrt(dble(p1-1) + 0.5_RP) end do - Minv(:,:) = 0.0_RP + Mass(:,:) = 0.0_RP do p2=1, porder+1 - Minv(p2,p2) = 1.0_RP + Mass(p2,p2) = 1.0_RP phiM1(p2) = P1D_(1,p2) phiP1(p2) = P1D_(porder+1,p2) do p1=1, porder+1 Stiff(p1,p2) = sum( elem%IntWeight_lgl(:) * P1D_(:,p2) * DP1D_(:,p1) ) end do end do + Minv(:,:) = Mass(:,:) else write(*,*) 'Check! Invalid basis_type:', basis_type stop @@ -106,62 +176,179 @@ subroutine eigen_analysis( porder, beta, basis_type, form_type ) ! Use routine workspace query to get optimal workspace. lwork = -1 - call zgeev( 'No left vectors', 'Vectors (right)', porder+1, Mat, porder+1, w, dummy, 1, & - vr, porder+1, dummy, lwork, rwork, info ) - lwork = max( (64+1)*(porder+1), nint(real(dummy(1,1))) ) + call zgeevx( 'Balance', 'Vectors (left)', 'Vectors (right)', 'Both reciprocal condition numbers', & + porder+1, Mat, porder+1, w, vl, porder+1, & + vr, porder+1, ilo, ihi, scale, abnrm, rconde, rcondv, dummy, lwork, rwork, info ) + + lwork = max( (128+1)*(porder+1), nint(real(vl(1,1))) ) allocate( work(lwork) ) - dwnum = PI * dble(porder + 1) / Helem / dble( kmax ) + dwnum = PI * dble(porder + 1) / Helem / dble( kmax-1 ) dw_r(:) = 0.0_RP; dw_i(:) = 0.0_RP do k=0, kmax-1 wnum = dble(k) * dwnum cs_kh = cos(wnum * Helem) si_kh = sin(wnum * Helem) + + call calc_muhat( mu_hat(:), & + wnum, elem, basis_type, Minv ) + if ( present(tscheme_name) ) then + do n=1, tlev_num + do p1=1, porder+1 + phase(1) = mod( dble(tlev_slot(n)) * courant_num * wnum * Helem, 2.0_RP * PI ) + Ue(p1,n) = mu_hat(p1) * ( cos(phase(1)) - ei * sin(phase(1)) ) ! * exp(ei * k * 0.0_RP) .. xe=0 + end do + end do + end if + do p2=1, porder+1 do p1=1, porder+1 - Mat(p1,p2) = 2.0_RP * ( ( ( KM(p1,p2) + KP(p1,p2) ) * cs_kh + KC(p1,p2) ) * ei - ( - KM(p1,p2) + KP(p1,p2) ) * si_kh ) + Mat(p1,p2) = 2.0_RP * ( ( ( KM(p1,p2) + KP(p1,p2) ) * cs_kh + KC(p1,p2) ) + ( - KM(p1,p2) + KP(p1,p2) ) * si_kh * ei ) end do end do + if ( present(tscheme_name) ) then + call construct_full_discrete_mat( Mat, & ! (inout) + tscheme_name, courant_num, porder ) ! (in) + end if + + call zgeevx( 'Balance', 'Vectors (left)', 'Vectors (right)', 'Both reciprocal condition numbers', & + porder+1, Mat, porder+1, w, vl, porder+1, vr, porder+1, & + ilo, ihi, scale, abnrm, rconde, rcondv, work, lwork, rwork, info ) - call zgeev( 'No left vectors', 'Vectors (right)', porder+1, Mat, porder+1, w, dummy, 1, & - vr, porder+1, work, lwork, rwork, info ) - if ( info /= 0 ) then - write(*,*) 'Failure in ZGEEV. INFO = ', info + write(*,*) 'Failure in ZGEEVX. INFO = ', info stop end if + + theta(:) = mu_hat(:) + EvecMat(:,:) = vr(:,:) + call zgesv( porder+1, 1, vr, porder+1, ipiv, theta, porder+1, info ) + + if ( present(tscheme_name) ) then + fac = dble(porder + 1) * courant_num + w_r(:) = - aimag(log(w(:))) / fac + w_i(:) = real(log(w(:))) / fac + + do n=1, tlev_num + fac = dble(porder + 1) * courant_num * dble(tlev_slot(n)) + phase(:) = mod( fac * w_r(:), 2.0_RP * PI ) + do p1=1, porder+1 + Ue_num(p1,n) = sum( EvecMat(p1,:) * theta(:) * exp( fac * w_i(:) ) & + * ( cos( phase(:) ) - ei * sin( phase(:) ) ) ) ! * exp(ei * k * 0.0_RP) .. xe=0 + end do + end do + else + w_r(:) = - aimag(w(:)) / dble(porder + 1) + w_i(:) = real(w(:)) / dble(porder + 1) + end if - w_r(:) = real(w(:)) / dble(porder + 1) - w_i(:) = aimag(w(:)) / dble(porder + 1) + w0_r(:) = w_r(:) + w0_i(:) = w_i(:) if ( k > 0 ) then - call sort_eigenval( w_r, w_i, dw_r, dw_i, & - wnum_nondim_num(1,k,:), wnum_nondim_num(2,k,:), porder+1 ) + call sort_eigenval( w_r, w_i, dw_r, dw_i, ipiv_eigenval, & ! (out) + wnum_nondim_num(1,k,:), wnum_nondim_num(2,k,:), porder+1 ) ! (in) + else + forall(n=1:porder+1) ipiv_eigenval(n) = n end if wnum_nondim(k+1) = wnum * Helem / dble(porder + 1) wnum_nondim_num(1,k+1,:) = w_r(:) wnum_nondim_num(2,k+1,:) = w_i(:) + eigensol_weight(k+1,:) = abs(theta(ipiv_eigenval(:))) + + do n=1, tlev_num + tmpvec1(:) = matmul(Mass, Ue (:,n)) + tmpvec2(:) = matmul(Mass, Ue_num(:,n)) + gex = sqrt( real(sum( conjg(Ue (:,n)) * tmpvec1(:) )) ) + gnum = sqrt( real(sum( conjg(Ue_num(:,n)) * tmpvec2(:) )) ) + phase_error_tmp = sum( conjg(Ue_num(:,n)) * tmpvec1(:) ) - ! write(*,*) 'K = ', wnum_nondim(k+1) - ! write(*,*) 'Eigenvalues: Re', wnum_nondim_num(1,k+1,:) - ! write(*,*) 'Eigenvalues: Im', wnum_nondim_num(2,k+1,:) + AmplifiFac_comb(n,k+1) = gnum / gex + PhaseError_comb(n,k+1) = aimag( log( phase_error_tmp ) ) / dble( porder+1 ) + end do end do - !-- + !-- output the results for each mode + do p1=1, porder+1 - write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '.dat' + if ( present( tscheme_name ) ) then + write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '_'//trim(tscheme_name)//'.dat' + else + write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '.dat' + end if open( nout, file=trim(filename), status='replace' ) - write( nout, '(a)') "# K Re(Km) Im(Km)" + write( nout, '(a)') "# K Re(Km) Im(Km) Weight" do k=1, kmax - write( nout, '(3f15.8)') wnum_nondim(k), wnum_nondim_num(1,k,p1), wnum_nondim_num(2,k,p1) + write( nout, '(4f20.14)') wnum_nondim(k), wnum_nondim_num(1,k,p1), wnum_nondim_num(2,k,p1), eigensol_weight(k,p1) end do close( nout ) end do + !-- output the results for combined mode + if ( present( tscheme_name ) ) then + write(filename,'(a,a,a,a,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_combinedmode_'//trim(tscheme_name)//'.dat' + open( nout, file=trim(filename), status='replace' ) + write( nout, '(a)') "# K G(n=1) phi(n=1) G(n=10) phi(n=10) G(n=100) phi(n=100)" + do k=1, kmax + write( nout, '(9f20.14)') wnum_nondim(k), & + AmplifiFac_comb(1,k), PhaseError_comb(1,k), AmplifiFac_comb(2,k), PhaseError_comb(2,k), & + AmplifiFac_comb(3,k), PhaseError_comb(3,k) + end do + close( nout ) + end if + !- call elem%Final() return end subroutine eigen_analysis + !---------------------------- + + subroutine construct_full_discrete_mat( G, & ! (inout) + tscheme_name, courant_num, porder ) + implicit none + + integer, intent(in) :: porder + complex(RP), intent(inout) :: G(porder+1,porder+1) + character(len=*), intent(in) :: tscheme_name + real(RP), intent(in) :: courant_num + + complex(RP) :: A(porder+1,porder+1) + complex(RP) :: Id(porder+1,porder+1) + complex(RP) :: tmpMat(porder+1,porder+1) + + integer :: rk_nstage + integer :: rk_s + integer :: m + !--------------------------------- + + select case( tscheme_name ) + case ( 'RK2' ) + rk_nstage = 2 + case ( 'RK3' ) + rk_nstage = 3 + case ( 'RK4' ) + rk_nstage = 4 + case default + write(*,*) 'Check! Invalid tscheme_name:', tscheme_name + stop + end select + + Id(:,:) = 0.0_RP + do m=1, porder+1 + Id(m,m) = 1.0_RP + end do + + A(:,:) = G(:,:) + G(:,:) = Id(:,:) + tmpMat(:,:) = Id(:,:) + do rk_s=1, rk_nstage + tmpMat(:,:) = courant_num / dble(rk_s) * matmul(tmpMat, A) + G(:,:) = G(:,:) + tmpMat(:,:) + end do + + return + end subroutine construct_full_discrete_mat + subroutine cosntruct_mat( K, Kp, Km, & Stiff, Minv, phiM1, phiP1, porder, beta ) implicit none @@ -201,7 +388,49 @@ subroutine cosntruct_mat( K, Kp, Km, & return end subroutine cosntruct_mat - subroutine sort_eigenval( w_r, w_i, dw_r, dw_i, & + !---------------------------- + + subroutine calc_muhat( muhat, wnum, elem, basis_type, Minv ) + use scale_polynominal, only: Polynominal_GenLegendrePoly + implicit none + type(LineElement), intent(in) :: elem + complex(RP), intent(out) :: muhat(elem%Np) + real(RP), intent(in) :: wnum + character(len=*), intent(in) :: basis_type + real(RP), intent(in) :: Minv(elem%Np,elem%Np) + + complex(RP) :: tmp(elem%Np) + integer, parameter :: Porder_int = 12 + real(RP) :: basis(Porder_int+1,elem%Np) + type(LineElement) :: elem_int + + integer :: pp + real(RP) :: phase(Porder_int+1) + !-------------------------- + + call elem_int%Init(Porder_int, .false.) + + if (basis_type == 'nodal' ) then + basis(:,:) = Polynominal_GenLagrangePoly(elem%PolyOrder, elem%x1(:), elem_int%x1(:)) + else if (basis_type == 'modal' ) then + basis(:,:) = Polynominal_GenLegendrePoly(elem%PolyOrder, elem_int%x1(:)) + ! normalization + do pp=1, elem%PolyOrder+1 + basis(:,pp) = basis(:,pp) * sqrt(dble(pp-1) + 0.5_RP) + end do + end if + + do pp=1, elem%PolyOrder+1 + phase(:) = 0.5_RP * wnum * Helem * elem_int%x1(:) + tmp(pp) = sum( elem_int%IntWeight_lgl(:) * ( cos(phase) + ei * sin(phase) ) * basis(:,pp) ) + end do + muhat(:) = matmul( Minv, tmp ) + + call elem_int%Final() + return + end subroutine calc_muhat + + subroutine sort_eigenval( w_r, w_i, dw_r, dw_i, ipiv, & wr_prev, wi_prev, n ) use scale_quicksort, only: QUICKSORT_exec_with_idx implicit none @@ -210,6 +439,7 @@ subroutine sort_eigenval( w_r, w_i, dw_r, dw_i, & real(RP), intent(inout) :: w_i(n) real(RP), intent(inout) :: dw_r(n) real(RP), intent(inout) :: dw_i(n) + integer, intent(out) :: ipiv(n) real(RP), intent(in) :: wr_prev(n) real(RP), intent(in) :: wi_prev(n) @@ -228,6 +458,7 @@ subroutine sort_eigenval( w_r, w_i, dw_r, dw_i, & dw_ori(1,:) = dw_r(:) dw_ori(2,:) = dw_i(:) flag(:) = .false. + ipiv(:) = -9999 do p1=1, n forall(nn=1:n) sorted_ind(nn) = nn @@ -242,6 +473,7 @@ subroutine sort_eigenval( w_r, w_i, dw_r, dw_i, & w_i(p1) = wi_ori(loc_min) dw_r(p1) = w_r(p1) - wr_prev(p1) dw_i(p1) = w_i(p1) - wi_prev(p1) + ipiv(p1) = loc_min exit end if end do diff --git a/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py b/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py index fc906402..eaed588e 100644 --- a/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py +++ b/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py @@ -5,10 +5,18 @@ DATA_DIR = "data/" OUT_DIR = "visualize/" +# Stability limit based on Table 3 of Alhawwary and Wang (2018). +CFL_max = { + "RK3": [0.409, 0.209, 0.13, 0.089, 0.066], + "RK4": [0.464, 0.235, 0.145, 0.1, 0.073] +} +CourantNumberFac = 0.5 + def set_xax(ax): ax.set_xlim(0.0, np.pi) ax.set_xticks([0, 0.25*np.pi, 0.5*np.pi, 0.75*np.pi, np.pi]) ax.set_xticklabels(["0", "$\pi/4$", "$\pi/2$", "$3\pi/4$", "$\pi$"]) + ax.grid(color='k', linestyle='dotted', linewidth=1) def create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, fname): fig = plt.figure(figsize=(10,4)) @@ -54,6 +62,76 @@ def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg plt.tight_layout() plt.savefig(fname) +def create_fig_sgscompari_porder_dep(porder_list, k_nondim, km_real_list, km_aimg_list, fname): + fig = plt.figure(figsize=(10,4)) + + ax1 = fig.add_subplot(1,2, 1, xlabel='K', ylabel='Re(Km)') + ax1.set_title("dispersion") + set_xax(ax1) + ax1.plot(k_nondim, k_nondim, 'k--', label="exact") + for m in porder_list: + ax1.plot(k_nondim, km_real_list[m], label=f"p={m}") + + ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel='he/(a*(p+1)*Im(Km))') + ax2.set_title("decay time scale [s]") + set_xax(ax2) + ax2.set_yscale("log") + ax2.set_xlim(np.pi/16.0, np.pi) + ax2.set_ylim(5e-1, 1e5) + + he_ov_pplus1 = 200/8.0#10.0 + a = 5.0 + Cs = 0.13 + Dsgs=2.0*he_ov_pplus1 + sabs = 0.15 * (np.pi/Dsgs)**(2.0/3.0) + for m in porder_list: + #print(-he_ov_pplus1/(a * (1e-15 + km_aimg_list[m]))) + ax2.plot(k_nondim, -he_ov_pplus1/(a * (1e-15 + km_aimg_list[m])), label=f"p={m}") + ax2.plot(k_nondim, 1.0/( (k_nondim/he_ov_pplus1)**2 * (Cs*Dsgs)**2*sabs ), label=f"SGS time scale") + ax2.plot(k_nondim, 10.0/( (k_nondim/he_ov_pplus1)**2 * (Cs*Dsgs)**2*sabs ), label=f"10xSGS time scale") + ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0) + + plt.subplots_adjust(wspace=0.4) + plt.tight_layout() + plt.savefig(fname) + +def create_fig_amplification_phase_error(k_nondim, + km_real, km_aimg, amplifiFac_list, phaseError_list, + porder, tscheme_name, fname): + fig = plt.figure(figsize=(10,4)) + + tlev_list = [1, 10, 100] + color_list = ["black", "blue", "cyan"] + + courant_num = CFL_max[tscheme_name][porder-1] * CourantNumberFac + ax1 = fig.add_subplot(1,2, 1, xlabel='K', ylabel='Re(Km)') + ax1.set_yscale("log") + ax1.set_title("Dispersion error") + ax1.set_ylim(1e-10, 1e2) + set_xax(ax1) + for i in range(0,len(tlev_list)): + n = tlev_list[i]; color = color_list[i] + ax1.plot(k_nondim, n*courant_num*(np.abs(km_real-k_nondim)), color=color, linestyle=":", label=f"n={n} (physical mode)") + ax1.plot(k_nondim, np.abs(phaseError_list[:,i]), color=color, linestyle="-", label=f"n={n} (combined mode)") + + ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel='G') + #ax2.plot(k_nondim, np.ones(len(k_nondim)), 'k', label="exact") + ax2.set_title("Amplification factor") + ax2.set_ylim(1e-12, 1e0) + ax2.set_yscale("log") + set_xax(ax2) + for i in range(0,len(tlev_list)): + n = tlev_list[i]; color = color_list[i] + ax2.plot(k_nondim, np.exp(n*(porder+1.0)*courant_num*km_aimg), color=color, linestyle=":", label=f"n={n} (physical mode)") + ax2.plot(k_nondim, amplifiFac_list[:,i], color=color, linestyle="-", label=f"n={n} (combined mode)") + + ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0) + + plt.subplots_adjust(wspace=0.4) + plt.tight_layout() + plt.savefig(fname) + + # Create figure for each order of polynomial for basis_type in ['modal', 'nodal']: form_type='weak' @@ -67,7 +145,7 @@ def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg km_real_list[m-1] = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=1) km_aimg_list[m-1] = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=2) - create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}.png") + # create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}.png") # Create figure to show the dependence of polynomial order on the numerical dispersion/dissipation for basis_type in ['modal', 'nodal']: @@ -75,7 +153,7 @@ def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg file_prefix=f"{DATA_DIR}/eigenval_{basis_type}_{form_type}_" print(f"graph porderdep: {file_prefix} ..") - porder_list = [2, 4, 3, 4, 5] + porder_list = [2, 3, 4, 5, 6, 7] km_real_list_pysmode = {}; km_aimg_list_pysmode = {} for porder in porder_list: for m in range(1,porder+2): @@ -87,4 +165,32 @@ def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg k_nondim = np.loadtxt(f"{file_prefix}P{porder_list[0]:02}_Mode01.dat", skiprows=1, usecols=0) create_fig_disp_diff_porder_dep( porder_list, k_nondim, km_real_list_pysmode, km_aimg_list_pysmode, - f"{OUT_DIR}/PolyOrderDep_{basis_type}_{form_type}.png") \ No newline at end of file + f"{OUT_DIR}/PolyOrderDep_{basis_type}_{form_type}.png") + + # create_fig_sgscompari_porder_dep( porder_list, k_nondim, km_real_list_pysmode, km_aimg_list_pysmode, + # f"{OUT_DIR}/PolyOrderDep_{basis_type}_{form_type}_sgscompari.png") + +# Create figure of full-discrete analysis for p=2 +for tscheme_name in ['RK3']: + for basis_type in ['modal']: + form_type='weak' + file_prefix=f"{DATA_DIR}/eigenval_{basis_type}_{form_type}_" + + print(f"graph porderdep: {file_prefix} ..") + + porder_list = [2] + + for porder in porder_list: + k_nondim = np.loadtxt(f"{file_prefix}P{porder:02}_Mode01_{tscheme_name}.dat", skiprows=1, usecols=0) + amplifiFac_list = np.loadtxt(f"{file_prefix}P{porder:02}_combinedmode_{tscheme_name}.dat", skiprows=1, usecols=[1,3,5]) + phaseError_list = np.loadtxt(f"{file_prefix}P{porder:02}_combinedmode_{tscheme_name}.dat", skiprows=1, usecols=[2,4,6]) + + for m in range(1,porder+2): + km_real = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}_{tscheme_name}.dat", skiprows=1, usecols=1) + km_aimg = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}_{tscheme_name}.dat", skiprows=1, usecols=2) + + if ( abs(km_real[0]) < 1.0E-10 and km_real[1]-km_real[0] > 0.0 ): + k_nondim = np.loadtxt(f"{file_prefix}P{porder_list[0]:02}_Mode01_{tscheme_name}.dat", skiprows=1, usecols=0) + create_fig_amplification_phase_error( + k_nondim, km_real, km_aimg, amplifiFac_list, phaseError_list, + porder, tscheme_name, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}_{tscheme_name}_G_phi.png") From bbb23f4e243b2d16e5d0ad1fe7ef474599aa438c Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sat, 11 Sep 2021 21:04:45 +0900 Subject: [PATCH 96/98] Consider the effect of modal filtering in test_eigen_analysis. --- .github/workflows/FEProject_build.yml | 1 + sample/eigen_analysis/test_eigen_analysis | Bin 504960 -> 0 bytes sample/eigen_analysis/test_eigen_analysis.f90 | 35 +++++- .../visualize/dispersion_dissipation_graph.py | 107 ++++++++++++------ 4 files changed, 105 insertions(+), 38 deletions(-) delete mode 100755 sample/eigen_analysis/test_eigen_analysis diff --git a/.github/workflows/FEProject_build.yml b/.github/workflows/FEProject_build.yml index bde21129..ef52f283 100644 --- a/.github/workflows/FEProject_build.yml +++ b/.github/workflows/FEProject_build.yml @@ -120,6 +120,7 @@ jobs: make -C advect3dGlobal make -C advect3d_hevi make -C euler3d_hevi + make -C eigen_analysis - name: Build model run: | diff --git a/sample/eigen_analysis/test_eigen_analysis b/sample/eigen_analysis/test_eigen_analysis deleted file mode 100755 index 53ff75a5150f9d52d1bb6bb62509295409677e14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 504960 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
  • H0SYo;Jl?6?kgoxghYYz*dD038nrS3IU%L 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 z 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 diff --git a/sample/eigen_analysis/test_eigen_analysis.f90 b/sample/eigen_analysis/test_eigen_analysis.f90 index f36b2d9d..a8e0dea5 100644 --- a/sample/eigen_analysis/test_eigen_analysis.f90 +++ b/sample/eigen_analysis/test_eigen_analysis.f90 @@ -36,6 +36,8 @@ program test_eigen_analysis real(RP), parameter :: BETA_CENTRAL = 0.0_RP real(RP), parameter :: Helem = 1.0_RP real(RP), parameter :: COURANT_NUMBER_fac = 0.5_RP + real(RP), parameter :: MF_alph = 18.0_RP + character(*), parameter :: MF_alph_lbl = "18.0" integer, parameter :: nout = 10 complex(RP), parameter :: ei = (0.0_RP, 1.0_RP) @@ -55,8 +57,10 @@ program test_eigen_analysis call eigen_analysis( 2, BETA_UPWIND, 'modal', 'weak', 'RK3', COURANT_NUMBER_fac * 0.205_RP ) ! p=2, RK4 call eigen_analysis( 2, BETA_UPWIND, 'modal', 'weak', 'RK4', COURANT_NUMBER_fac * 0.235_RP ) - ! p=5, RK5 + ! p=5, RK4 call eigen_analysis( 5, BETA_UPWIND, 'modal', 'weak', 'RK4', COURANT_NUMBER_fac * 0.073_RP ) + ! p=7, RK4 + call eigen_analysis( 7, BETA_UPWIND, 'modal', 'weak', 'RK4', 5.0E-3_RP ) contains @@ -64,6 +68,8 @@ subroutine eigen_analysis( & porder, beta, basis_type, form_type, & tscheme_name, courant_num ) + use scale_element_modalfilter, only: & + ModalFilter implicit none integer, intent(in) :: porder real(RP), intent(in) :: beta @@ -83,6 +89,7 @@ subroutine eigen_analysis( & real(RP) :: phiP1(porder+1) real(RP) :: P1D_ (porder+1,porder+1) real(RP) :: DP1D_(porder+1,porder+1) + type(ModalFilter) :: MFilter integer :: p1, p2 @@ -172,6 +179,13 @@ subroutine eigen_analysis( & call cosntruct_mat( KC, KP, KM, & ! (out) Stiff, Minv, phiM1, phiP1, porder, beta ) ! (in) + call MFilter%Init( elem, 0.0_RP, MF_alph, 16 ) + MFilter%FilterMat(:,:) = 0.0_RP + do p1=1, porder+1 + MFilter%FilterMat(p1,p1) = exp( - MF_alph * ( ((dble(p1-1)/dble(porder) - 0.0_RP)/(1.0_RP - 0.0_RP))**32 ) ) + write(*,*) MFilter%FilterMat(p1,:) + end do + !-- Calculate eigenvalues ! Use routine workspace query to get optimal workspace. @@ -209,6 +223,8 @@ subroutine eigen_analysis( & if ( present(tscheme_name) ) then call construct_full_discrete_mat( Mat, & ! (inout) tscheme_name, courant_num, porder ) ! (in) + + Mat(:,:) = matmul(MFilter%FilterMat(:,:), Mat(:,:)) end if call zgeevx( 'Balance', 'Vectors (left)', 'Vectors (right)', 'Both reciprocal condition numbers', & @@ -271,7 +287,12 @@ subroutine eigen_analysis( & do p1=1, porder+1 if ( present( tscheme_name ) ) then - write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '_'//trim(tscheme_name)//'.dat' + write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '_'//trim(tscheme_name) + if ( MF_alph > 0.0_RP ) then + write(filename,'(3a)') trim(filename), '_MF'//MF_alph_lbl, '.dat' + else + filename = trim(filename)//".dat" + end if else write(filename,'(a,a,a,a,a,i2.2,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_Mode', p1, '.dat' end if @@ -285,7 +306,13 @@ subroutine eigen_analysis( & !-- output the results for combined mode if ( present( tscheme_name ) ) then - write(filename,'(a,a,a,a,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_combinedmode_'//trim(tscheme_name)//'.dat' + write(filename,'(a,a,a,a,a,i2.2,a)') './data/eigenval_', trim(basis_type), '_', trim(form_type), '_P', porder, '_combinedmode_'//trim(tscheme_name) + if ( MF_alph > 0.0_RP ) then + write(filename,'(3a)') trim(filename), '_MF'//MF_alph_lbl, '.dat' + else + filename = trim(filename) // ".dat" + end if + open( nout, file=trim(filename), status='replace' ) write( nout, '(a)') "# K G(n=1) phi(n=1) G(n=10) phi(n=10) G(n=100) phi(n=100)" do k=1, kmax @@ -296,6 +323,8 @@ subroutine eigen_analysis( & close( nout ) end if !- + + call MFilter%Final() call elem%Final() return diff --git a/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py b/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py index eaed588e..d25d3e26 100644 --- a/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py +++ b/sample/eigen_analysis/visualize/dispersion_dissipation_graph.py @@ -12,12 +12,14 @@ } CourantNumberFac = 0.5 + def set_xax(ax): ax.set_xlim(0.0, np.pi) ax.set_xticks([0, 0.25*np.pi, 0.5*np.pi, 0.75*np.pi, np.pi]) ax.set_xticklabels(["0", "$\pi/4$", "$\pi/2$", "$3\pi/4$", "$\pi$"]) ax.grid(color='k', linestyle='dotted', linewidth=1) + def create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, fname): fig = plt.figure(figsize=(10,4)) @@ -40,6 +42,7 @@ def create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, fname): plt.tight_layout() plt.savefig(fname) + def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg_list, fname): fig = plt.figure(figsize=(10,4)) @@ -62,39 +65,57 @@ def create_fig_disp_diff_porder_dep(porder_list, k_nondim, km_real_list, km_aimg plt.tight_layout() plt.savefig(fname) -def create_fig_sgscompari_porder_dep(porder_list, k_nondim, km_real_list, km_aimg_list, fname): + +def create_fig_sgscompari_porder_dep(porder_list, k_nondim, phase_vel_error_list, km_aimg_list, fname): fig = plt.figure(figsize=(10,4)) - ax1 = fig.add_subplot(1,2, 1, xlabel='K', ylabel='Re(Km)') - ax1.set_title("dispersion") + ax1 = fig.add_subplot(1,2, 1, xlabel='K', ylabel='phase speed [m/s]') +# ax1.set_title("phase speed error") set_xax(ax1) - ax1.plot(k_nondim, k_nondim, 'k--', label="exact") - for m in porder_list: - ax1.plot(k_nondim, km_real_list[m], label=f"p={m}") + ax1.set_yscale("log") + ax1.set_xlim(np.pi/16.0, np.pi) + ax1.set_ylim(1e-5, 1e1) - ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel='he/(a*(p+1)*Im(Km))') - ax2.set_title("decay time scale [s]") + ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel=r'inverse of decay time scale [$s^{-1}$]') +# ax2.set_title("decay time scale [s]") set_xax(ax2) ax2.set_yscale("log") ax2.set_xlim(np.pi/16.0, np.pi) - ax2.set_ylim(5e-1, 1e5) + ax2.set_ylim(1e-7, 1e1) - he_ov_pplus1 = 200/8.0#10.0 + #----------------------------------- + he_ov_pplus1 = 200.0 / 8.0 #10.0 a = 5.0 Cs = 0.13 - Dsgs=2.0*he_ov_pplus1 + Dsgs=2.0 * he_ov_pplus1 sabs = 0.15 * (np.pi/Dsgs)**(2.0/3.0) + dsabs = 0.15 * (2.0/15.0)**0.5 * (np.pi/Dsgs)**(5.0/3.0) + + for m in porder_list: - #print(-he_ov_pplus1/(a * (1e-15 + km_aimg_list[m]))) - ax2.plot(k_nondim, -he_ov_pplus1/(a * (1e-15 + km_aimg_list[m])), label=f"p={m}") - ax2.plot(k_nondim, 1.0/( (k_nondim/he_ov_pplus1)**2 * (Cs*Dsgs)**2*sabs ), label=f"SGS time scale") - ax2.plot(k_nondim, 10.0/( (k_nondim/he_ov_pplus1)**2 * (Cs*Dsgs)**2*sabs ), label=f"10xSGS time scale") + r_te_numdiff = - (a * km_aimg_list[m] ) / he_ov_pplus1 + + ax1.plot(k_nondim, phase_vel_error_list[m], label=f"p={m}", color="red" ) + ax2.plot(k_nondim, r_te_numdiff, label=f"p={m}", color="red") + + ax1.plot(k_nondim, 70.0 * phase_vel_error_list[m], label=f"(x70 p={m})", color="red", alpha=0.3) + ax2.plot(k_nondim, 70.0 * r_te_numdiff, label=f"(1/70 p={m})", color="red", alpha=0.3 ) + + ps_sgs_cross_term = np.full(len(k_nondim), (Cs * Dsgs)**2 * dsabs) + ax1.plot(k_nondim, ps_sgs_cross_term, label=r"$S_{p,sgs}$", color="blue" ) + ax1.plot(k_nondim, 0.1 * ps_sgs_cross_term, label=r"$0.1 S_{p,sgs}$", color="blue", linestyle="--" ) + ax1.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0) + + r_te_sgs = (k_nondim/he_ov_pplus1)**2 * (Cs*Dsgs)**2*sabs + ax2.plot(k_nondim, r_te_sgs, label=r"($T_{e,sgs})^{-1}$", color="blue") + ax2.plot(k_nondim, 0.1 * r_te_sgs, label=r"$0.1 (T_{e,sgs})^{-1}$", color="blue", linestyle="--") ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0) plt.subplots_adjust(wspace=0.4) plt.tight_layout() plt.savefig(fname) + def create_fig_amplification_phase_error(k_nondim, km_real, km_aimg, amplifiFac_list, phaseError_list, porder, tscheme_name, fname): @@ -115,10 +136,9 @@ def create_fig_amplification_phase_error(k_nondim, ax1.plot(k_nondim, np.abs(phaseError_list[:,i]), color=color, linestyle="-", label=f"n={n} (combined mode)") ax2 = fig.add_subplot(1,2, 2, xlabel='K', ylabel='G') - #ax2.plot(k_nondim, np.ones(len(k_nondim)), 'k', label="exact") ax2.set_title("Amplification factor") ax2.set_ylim(1e-12, 1e0) - ax2.set_yscale("log") + #ax2.set_yscale("log") set_xax(ax2) for i in range(0,len(tlev_list)): n = tlev_list[i]; color = color_list[i] @@ -145,7 +165,8 @@ def create_fig_amplification_phase_error(k_nondim, km_real_list[m-1] = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=1) km_aimg_list[m-1] = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}.dat", skiprows=1, usecols=2) - # create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}.png") + create_fig_disp_diff(k_nondim, km_real_list, km_aimg_list, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}.png") + # Create figure to show the dependence of polynomial order on the numerical dispersion/dissipation for basis_type in ['modal', 'nodal']: @@ -170,27 +191,43 @@ def create_fig_amplification_phase_error(k_nondim, # create_fig_sgscompari_porder_dep( porder_list, k_nondim, km_real_list_pysmode, km_aimg_list_pysmode, # f"{OUT_DIR}/PolyOrderDep_{basis_type}_{form_type}_sgscompari.png") + # Create figure of full-discrete analysis for p=2 -for tscheme_name in ['RK3']: +for tscheme_name in ['RK4']: for basis_type in ['modal']: form_type='weak' file_prefix=f"{DATA_DIR}/eigenval_{basis_type}_{form_type}_" print(f"graph porderdep: {file_prefix} ..") - porder_list = [2] - - for porder in porder_list: - k_nondim = np.loadtxt(f"{file_prefix}P{porder:02}_Mode01_{tscheme_name}.dat", skiprows=1, usecols=0) - amplifiFac_list = np.loadtxt(f"{file_prefix}P{porder:02}_combinedmode_{tscheme_name}.dat", skiprows=1, usecols=[1,3,5]) - phaseError_list = np.loadtxt(f"{file_prefix}P{porder:02}_combinedmode_{tscheme_name}.dat", skiprows=1, usecols=[2,4,6]) - - for m in range(1,porder+2): - km_real = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}_{tscheme_name}.dat", skiprows=1, usecols=1) - km_aimg = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}_{tscheme_name}.dat", skiprows=1, usecols=2) - - if ( abs(km_real[0]) < 1.0E-10 and km_real[1]-km_real[0] > 0.0 ): - k_nondim = np.loadtxt(f"{file_prefix}P{porder_list[0]:02}_Mode01_{tscheme_name}.dat", skiprows=1, usecols=0) - create_fig_amplification_phase_error( - k_nondim, km_real, km_aimg, amplifiFac_list, phaseError_list, - porder, tscheme_name, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}_{tscheme_name}_G_phi.png") + porder_list = [7] + for MF_suffix in ["", "_MF0.018", "_MF0.18", "_MF18.0" ]: + for porder in porder_list: + k_nondim = np.loadtxt(f"{file_prefix}P{porder:02}_Mode01_{tscheme_name}.dat", skiprows=1, usecols=0) + amplifiFac_list = np.loadtxt(f"{file_prefix}P{porder:02}_combinedmode_{tscheme_name}{MF_suffix}.dat", skiprows=1, usecols=[1,3,5]) + phaseError_list = np.loadtxt(f"{file_prefix}P{porder:02}_combinedmode_{tscheme_name}{MF_suffix}.dat", skiprows=1, usecols=[2,4,6]) + + for m in range(1,porder+2): + km_real = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}_{tscheme_name}{MF_suffix}.dat", skiprows=1, usecols=1) + km_aimg = np.loadtxt(f"{file_prefix}P{porder:02}_Mode{m:02}_{tscheme_name}{MF_suffix}.dat", skiprows=1, usecols=2) + + if ( abs(km_real[0]) < 1.0E-10 and km_real[1]-km_real[0] > 0.0 ): + k_nondim = np.loadtxt(f"{file_prefix}P{porder_list[0]:02}_Mode01_{tscheme_name}{MF_suffix}.dat", skiprows=1, usecols=0) + create_fig_amplification_phase_error( + k_nondim, km_real, km_aimg, amplifiFac_list, phaseError_list, + porder, tscheme_name, f"{OUT_DIR}/P{porder:02}_{basis_type}_{form_type}_{tscheme_name}_G_phi{MF_suffix}.png") + + + ''' + k_nondim = np.loadtxt(f"{file_prefix}P{porder:02}_Mode01_{tscheme_name}{MF_suffix}.dat", skiprows=1, usecols=0) + km_real_list_combmode = {} + km_aimg_list_combmode = {} + + courant_num = 5e-3 + U_VEL = 5.0 + n = 1.0 + km_real_list_combmode[7] = U_VEL * np.abs(phaseError_list[:,0]) / (n * courant_num) + km_aimg_list_combmode[7] = np.log( amplifiFac_list[:,0] ) / (n * (porder+1) * courant_num) + create_fig_sgscompari_porder_dep( porder_list, k_nondim, km_real_list_combmode, km_aimg_list_combmode, + f"{OUT_DIR}/full_disc_P{porder:02}_{basis_type}_{form_type}_{tscheme_name}{MF_suffix}_sgscompari.png") + ''' \ No newline at end of file From 0e175053f7402f53115e96d8a7c2c47cfcea82cf Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 12 Sep 2021 15:41:53 +0900 Subject: [PATCH 97/98] Modify the treatment of surface boundary condition. --- .../scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 | 6 ------ model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 | 10 +++++----- .../atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 index 230ce452..dcd96406 100644 --- a/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 +++ b/FElib/src/fluid_dyn_solver/scale_atm_dyn_dgm_nonhydro3d_heve_numflux.F90 @@ -180,12 +180,6 @@ subroutine atm_dyn_dgm_nonhydro3d_heve_numflux_get_generalvc( & + ( ( GsqrtMOMZ_P(:) / GsqrtV_P(:) & + G13_P(:) * GsqrtMOMX_P(:) + G23_P(:) * GsqrtMOMY_P(:) ) * nz(:,ke) ) & ) / GsqrtDensP(:) - - ! Tentative treatment - where( abs(1.0_RP-nz(:,ke)**2) < 1.0E-10_RP .and. iP(:) > lmesh%Ne * elem%Np ) - VelP(:) = - VelM(:) - GsqrtMOMZ_P(:) = - GsqrtMOMZ_M(:) - 2.0_RP * ( G13_M(:) * GsqrtMOMX_M(:) + G23_M(:) * GsqrtMOMY_M(:) ) - end where dpresM(:) = PRES00 * ( RovP0 * GsqrtRhotM(:) / Gsqrt_M(:) )**gamm & - Phyd_M(:) diff --git a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 index aa192900..59f2572c 100644 --- a/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 +++ b/model/atm_nonhydro3d/src/atmos/mod_atmos_dyn_bnd.F90 @@ -81,7 +81,6 @@ module mod_atmos_dyn_bnd integer, parameter :: domBnd_Top_ID = 6 integer, parameter :: DOM_BND_NUM = 6 - contains subroutine ATMOS_dyn_bnd_setup( this ) use scale_mesh_bndinfo, only: & @@ -170,6 +169,7 @@ subroutine ATMOS_dyn_bnd_finalize( this ) return end subroutine ATMOS_dyn_bnd_finalize + !OCL SERIAL subroutine ATMOS_dyn_bnd_setBCInfo( this, mesh ) implicit none @@ -232,10 +232,10 @@ subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & real(RP), intent(inout) :: DRHOT(elem%Np*lmesh%NeA) real(RP), intent(in) :: DENS_hyd(elem%Np*lmesh%NeA) real(RP), intent(in) :: PRES_hyd(elem%Np*lmesh%NeA) - real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%Ne) + real(RP), intent(in) :: Gsqrt(elem%Np*lmesh%NeA) real(RP), intent(in) :: GsqrtH(elem2D%Np,lmesh2D%Ne) - real(RP), intent(in) :: G13(elem%Np*lmesh%Ne) - real(RP), intent(in) :: G23(elem%Np*lmesh%Ne) + real(RP), intent(in) :: G13(elem%Np*lmesh%NeA) + real(RP), intent(in) :: G23(elem%Np*lmesh%NeA) real(RP), intent(in) :: nx(elem%NfpTot*lmesh%Ne) real(RP), intent(in) :: ny(elem%NfpTot*lmesh%Ne) real(RP), intent(in) :: nz(elem%NfpTot*lmesh%Ne) @@ -286,7 +286,7 @@ subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc( this, & return end subroutine ATMOS_dyn_bnd_applyBC_prgvars_lc - + subroutine ATMOS_dyn_bnd_applyBC_numdiff_odd_lc( this, & ! (in) GxVar, GyVar, GzVar, & ! (inout) is_bound, & ! (out) diff --git a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 index c2c4cb36..1a5630bb 100644 --- a/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 +++ b/model/atm_nonhydro3d/test/case/Held_Suarez/mod_user.F90 @@ -191,7 +191,7 @@ subroutine USER_update( atm ) ke2D = lcmesh%EMap3Dto2D(ke) PRES_sfc(:) = PRES%val(elem3D%Hslice(:,1),ke2D) - sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) + !sig(:) = PRES%val(:,ke) / PRES_sfc(elem3D%IndexH2Dto3D) sig(:) = PRES%val(:,ke) / PRES00 lat(:) = lcmesh%lat2D(elem3D%IndexH2Dto3D,ke2D) From 794418564d6155c4c71b0f7691f6db49c3ac535b Mon Sep 17 00:00:00 2001 From: Yuta Kawai Date: Sun, 12 Sep 2021 16:06:02 +0900 Subject: [PATCH 98/98] Update documentations to release v0.5.0. --- FElib/src/VERSION | 2 +- HISTORY | 21 ++++++++++++++++++++- INSTALL.md | 12 ++++++------ README.md | 10 +++++----- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/FElib/src/VERSION b/FElib/src/VERSION index 6c6aa7cb..79a2734b 100644 --- a/FElib/src/VERSION +++ b/FElib/src/VERSION @@ -1 +1 @@ -0.1.0 \ No newline at end of file +0.5.0 \ No newline at end of file diff --git a/HISTORY b/HISTORY index cc883ec8..125f477e 100644 --- a/HISTORY +++ b/HISTORY @@ -1,8 +1,27 @@ += 2021-09-12 (0.5.0) +* New features + * Add modules to treat 3D cubed sphere mesh + * Add simplified sample programs using our library + * 3D linear advection equation using 3D cubed sphere mesh + * an eigenvalue analysis of 1D linear advection problem when DGM is applied + * Implement a global shallow water model using 2D cubed sphere mesh. + * Implement a global nonhydrostatic fully-compressible atmospheric model using 3D cubed sphere mesh. + * Support both of HEVE and HEVI + * Treat topography in regional and global atmospheric model using the terrain following coordinate. + * Add test suites for global shallow water model + * test cases of Williamson et al.(1992), barotropic instability (Galewsky et al., 2004), and cross-polar flow (Donald and Bates, 1989). + * Add test suites for 3D global atmospheric model + * test cases of sound wave, inertia gravity wave, baroclinic wave, mountain wave, and equatorial wave (described in Tomita et al., 2004) and the Held Suarez test. + * Implement a new regrid tool by unifying INTERP tool into cs2lonlat tool. + * Support history_in and improve data output of axis information +* Fix many bugs + * Fix a bug of default time interval at which restart data is output. + = 2021-05-06 (0.4.0) * New features * Enhance the 3D nonhydrostatic atmospheric model * Support sub-grid scale turbulent process for LES - * Add a test case forthe 3D nonhydrostatic atmospheric model + * Add a test case for the 3D nonhydrostatic atmospheric model * PBL boundary layer turbulence * Rising thermal bubble * Add modules to treat 2D cubed sphere mesh (experimental) diff --git a/INSTALL.md b/INSTALL.md index a9f2e57f..998ee52d 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -11,17 +11,17 @@ This FE library requires following libraries: We confirm that building our codes has succeeded in the following environments: - macOS Mojave - - GNU Fortran 10.2.0 + - GNU Fortran 11.1.0 - OpenMPI 4.1.1 - - LAPACK 3.9.1 - - NetCDF 4.7.4 - - SCALE library 5.4.3 + - LAPACK 3.10.0 + - NetCDF 4.8.0 + - SCALE library 5.4.4 - Ubuntu 20.04 LTS - GNU Fortran 9.3.0 - OpenMPI 4.0.3 - LAPACK 3.7.1 - NetCDF 4.7.3 - - SCALE library 5.4.3 + - SCALE library 5.4.4 Our codes are verified in Oakbridge-CX (intel compiler) and Fugaku. @@ -34,7 +34,7 @@ Our codes are verified in Oakbridge-CX (intel compiler) and Fugaku. - set a directory in which SCALE library is contained - `% export SCALE="~/workspace/scale-5.4.3/"` (for example) + `% export SCALE="~/workspace/scale-5.4.4/"` (for example) - If you use the develop version of SCALE library, set a variable as diff --git a/README.md b/README.md index d87c123a..7180da01 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # FE-project ## What is FE-project? -This project provides a library and some sample programs for some discontinuous Galerkin methods. -Futhermore, some dynamical cores of atmospheric and oceanic model with DGM will be provided. +In this project, we develop a library for fluid simulations with the discontinuous Galerkin method. +We also provide sample programs and atmospheric models for meteorological simulations. - Example of simulation results by nonhydrostatic atmospheric models with nodal DGM @@ -19,13 +19,14 @@ Futhermore, some dynamical cores of atmospheric and oceanic model with DGM will ### Nonhydrostatic atmospheric model - Simple 2D model with only dynamical process -- Regional/Global model with dynamical process and some physical processes +- Regional and Global models ## Simple samples for intrduction to DGM. ### 1D problems - Linear advection equation - various profiles of advected quantity - - linear advection-diffusion equation + - the eigenvalue analysis + - Linear advection-diffusion equation ### 2D problems - Linear advection equation in a rectangle domain @@ -39,7 +40,6 @@ Futhermore, some dynamical cores of atmospheric and oceanic model with DGM will - Euler equation in a cubic domain - Test the propagation of sound waves with HEVI temporal methods - ## Build FE library Please see ``INSTALL.md''.