diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 77504ba44..139f87654 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -145,9 +145,9 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL Intel ) else() target_compile_options(${PROJECT_NAME} PRIVATE -xHost) endif() -# target_compile_options(${PROJECT_NAME} PRIVATE -g -traceback ) #-check all,noarg_temp_created,bounds,uninit ) #-ftrapuv ) #-init=zero) -# target_compile_options(${PROJECT_NAME} PRIVATE -qopenmp -r8 -i4 -fp-model precise -no-prec-div -no-prec-sqrt -fimf-use-svml -xHost -ip -g -traceback -check all,noarg_temp_created,bounds,uninit ) #-ftrapuv ) #-init=zero) -# target_compile_options(${PROJECT_NAME} PRIVATE -r8 -i4 -fp-model precise -no-prec-div -no-prec-sqrt -fimf-use-svml -ip -g -traceback -check all,noarg_temp_created,bounds,uninit ) #-ftrapuv ) #-init=zero) + #target_compile_options(${PROJECT_NAME} PRIVATE -g -traceback ) #-check all,noarg_temp_created,bounds,uninit ) #-ftrapuv ) #-init=zero) + #target_compile_options(${PROJECT_NAME} PRIVATE -qopenmp -r8 -i4 -fp-model precise -no-prec-div -no-prec-sqrt -fimf-use-svml -xHost -ip -g -traceback -check all,noarg_temp_created,bounds,uninit ) #-ftrapuv ) #-init=zero) + #target_compile_options(${PROJECT_NAME} PRIVATE -r8 -i4 -fp-model precise -no-prec-div -no-prec-sqrt -fimf-use-svml -ip -g -traceback -check all,noarg_temp_created,bounds,uninit ) #-ftrapuv ) #-init=zero) elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL GNU ) # target_compile_options(${PROJECT_NAME} PRIVATE -O3 -finit-local-zero -finline-functions -fimplicit-none -fdefault-real-8 -ffree-line-length-none) diff --git a/src/MOD_MESH.F90 b/src/MOD_MESH.F90 index dd3c40c72..3b307fb57 100644 --- a/src/MOD_MESH.F90 +++ b/src/MOD_MESH.F90 @@ -99,9 +99,9 @@ MODULE MOD_MESH integer, allocatable, dimension(:) :: ind_south, ind_north !#endif -integer :: nn_size -integer, allocatable, dimension(:) :: nn_num -integer, allocatable, dimension(:,:) :: nn_pos +integer :: nn_size +integer, allocatable, dimension(:) :: nn_num +integer, allocatable, dimension(:,:) :: nn_pos !_______________________________________________________________________________ ! Arrays added for ALE implementation: @@ -133,6 +133,11 @@ MODULE MOD_MESH real(kind=WP), allocatable,dimension(:) :: zbar_n_srf real(kind=WP), allocatable,dimension(:) :: zbar_e_srf +!_______________________________________________________________________________ +real(kind=WP), allocatable,dimension(:,:) :: hnode_fc, hnode_new_fc, helem_fc, zbar_3d_n_fc, Z_3d_n_fc +real(kind=WP), allocatable,dimension(:) :: bottom_elem_thickness_fc, bottom_node_thickness_fc +real(kind=WP), allocatable,dimension(:) :: zbar_n_bot_fc, zbar_e_bot_fc + character(:), allocatable :: representative_checksum contains diff --git a/src/associate_mesh_ass.h b/src/associate_mesh_ass.h index 882fc053e..e2b11d0eb 100644 --- a/src/associate_mesh_ass.h +++ b/src/associate_mesh_ass.h @@ -67,3 +67,13 @@ zbar_e_bot(1:myDim_elem2D+eDim_elem2D) => mesh%zbar_e_bot(:) zbar_n_srf(1:myDim_nod2D+eDim_nod2D) => mesh%zbar_n_srf(:) zbar_e_srf(1:myDim_elem2D+eDim_elem2D) => mesh%zbar_e_srf(:) + +hnode_fc(1:mesh%nl-1, 1:myDim_nod2D+eDim_nod2D) => mesh%hnode_fc(:,:) +hnode_new_fc(1:mesh%nl-1, 1:myDim_nod2D+eDim_nod2D) => mesh%hnode_new_fc(:,:) +zbar_3d_n_fc(1:mesh%nl, 1:myDim_nod2D+eDim_nod2D) => mesh%zbar_3d_n_fc(:,:) +Z_3d_n_fc(1:mesh%nl-1, 1:myDim_nod2D+eDim_nod2D) => mesh%Z_3d_n_fc(:,:) +helem_fc(1:mesh%nl-1, 1:myDim_elem2D) => mesh%helem_fc(:,:) +bottom_elem_thickness_fc(1:myDim_elem2D) => mesh%bottom_elem_thickness_fc(:) +bottom_node_thickness_fc(1:myDim_nod2D+eDim_nod2D) => mesh%bottom_node_thickness_fc(:) +zbar_n_bot_fc(1:myDim_nod2D+eDim_nod2D) => mesh%zbar_n_bot_fc(:) +zbar_e_bot_fc(1:myDim_elem2D+eDim_elem2D) => mesh%zbar_e_bot_fc(:) diff --git a/src/associate_mesh_def.h b/src/associate_mesh_def.h index 1410938ad..14988f705 100644 --- a/src/associate_mesh_def.h +++ b/src/associate_mesh_def.h @@ -50,3 +50,14 @@ real(kind=WP), dimension(:) , pointer :: zbar_n_bot real(kind=WP), dimension(:) , pointer :: zbar_e_bot real(kind=WP), dimension(:) , pointer :: zbar_n_srf real(kind=WP), dimension(:) , pointer :: zbar_e_srf + + +real(kind=WP), dimension(:,:), pointer :: hnode_fc +real(kind=WP), dimension(:,:), pointer :: hnode_new_fc +real(kind=WP), dimension(:,:), pointer :: zbar_3d_n_fc +real(kind=WP), dimension(:,:), pointer :: Z_3d_n_fc +real(kind=WP), dimension(:,:), pointer :: helem_fc +real(kind=WP), dimension(:) , pointer :: bottom_elem_thickness_fc +real(kind=WP), dimension(:) , pointer :: bottom_node_thickness_fc +real(kind=WP), dimension(:) , pointer :: zbar_n_bot_fc +real(kind=WP), dimension(:) , pointer :: zbar_e_bot_fc diff --git a/src/oce_adv_tra_hor.F90 b/src/oce_adv_tra_hor.F90 index c7e209dfd..aa3c7fa5d 100644 --- a/src/oce_adv_tra_hor.F90 +++ b/src/oce_adv_tra_hor.F90 @@ -680,14 +680,14 @@ subroutine adv_tra_hor_mfct(vel, ttf, partit, mesh, num_ord, flux, edge_up_dn_gr !___________________________________________________________________ ! use downwind triangle to interpolate Tracer to edge center with - ! fancy scheme --> Linear upwind reconstruction + ! fancy scheme --> Linear downwind reconstruction ! T_n+0.5 = T_n+1 - 1/2*deltax*GRADIENT ! --> GRADIENT = 2/3 GRAD_edgecenter + 1/3 GRAD_downwindtri ! T_n+0.5 = T_n+1 - 2/6*(T_n+1-T_n) + 1/6*gradT_down ! --> edge_up_dn_grad ... contains already elemental tracer gradient ! of up and dn wind triangle ! --> Tmean2 ... edge center interpolated Tracer using tracer - ! gradient info from upwind triangle + ! gradient info from downwind triangle Tmean2=ttf(nz, enodes(2))- & (2.0_WP*(ttf(nz, enodes(2))-ttf(nz,enodes(1)))+ & edge_dxdy(1,edge)*a*edge_up_dn_grad(2,nz,edge)+ & @@ -699,7 +699,7 @@ subroutine adv_tra_hor_mfct(vel, ttf, partit, mesh, num_ord, flux, edge_up_dn_gr ! --> GRADIENT = 2/3 GRAD_edgecenter + 1/3 GRAD_downwindtri ! T_n+0.5 = T_n + 2/6*(T_n+1-T_n) + 1/6*gradT_down ! --> Tmean1 ... edge center interpolated Tracer using tracer - ! gradient info from downwind triangle + ! gradient info from upwind triangle Tmean1=ttf(nz, enodes(1))+ & (2.0_WP*(ttf(nz, enodes(2))-ttf(nz,enodes(1)))+ & edge_dxdy(1,edge)*a*edge_up_dn_grad(1,nz,edge)+ & diff --git a/src/oce_ale.F90 b/src/oce_ale.F90 index 0986f74e9..2fddafe8f 100644 --- a/src/oce_ale.F90 +++ b/src/oce_ale.F90 @@ -243,6 +243,7 @@ subroutine init_ale(dynamics, partit, mesh) zbar_e_bot(1:myDim_elem2D+eDim_elem2D) => mesh%zbar_e_bot(:) zbar_n_srf(1:myDim_nod2D+eDim_nod2D) => mesh%zbar_n_srf(:) zbar_e_srf(1:myDim_elem2D+eDim_elem2D) => mesh%zbar_e_srf(:) + !___initialize______________________________________________________________ hbar = 0.0_WP hbar_old = 0.0_WP @@ -250,6 +251,39 @@ subroutine init_ale(dynamics, partit, mesh) hnode = 0.0_WP hnode_new = 0.0_WP helem = 0.0_WP + + !___________________________________________________________________________ + !PS for debug partial cell + allocate(mesh%hnode_fc(1:nl-1, myDim_nod2D+eDim_nod2D)) + allocate(mesh%hnode_new_fc(1:nl-1, myDim_nod2D+eDim_nod2D)) + allocate(mesh%helem_fc(1:nl-1, myDim_elem2D)) + allocate(mesh%zbar_3d_n_fc(nl,myDim_nod2D+eDim_nod2D)) + allocate(mesh%Z_3d_n_fc(nl-1,myDim_nod2D+eDim_nod2D)) + allocate(mesh%zbar_n_bot_fc(myDim_nod2D+eDim_nod2D)) + allocate(mesh%zbar_e_bot_fc(myDim_elem2D+eDim_elem2D)) + allocate(mesh%bottom_elem_thickness_fc(myDim_elem2D)) + allocate(mesh%bottom_node_thickness_fc(myDim_nod2D+eDim_nod2D)) + + hnode_fc(1:mesh%nl-1, 1:myDim_nod2D+eDim_nod2D) => mesh%hnode_fc(:,:) + hnode_new_fc(1:mesh%nl-1, 1:myDim_nod2D+eDim_nod2D) => mesh%hnode_new_fc(:,:) + zbar_3d_n_fc(1:mesh%nl, 1:myDim_nod2D+eDim_nod2D) => mesh%zbar_3d_n_fc(:,:) + Z_3d_n_fc(1:mesh%nl-1, 1:myDim_nod2D+eDim_nod2D) => mesh%Z_3d_n_fc(:,:) + helem_fc(1:mesh%nl-1, 1:myDim_elem2D) => mesh%helem_fc(:,:) + bottom_elem_thickness_fc(1:myDim_elem2D) => mesh%bottom_elem_thickness_fc(:) + bottom_node_thickness_fc(1:myDim_nod2D+eDim_nod2D) => mesh%bottom_node_thickness_fc(:) + zbar_n_bot_fc(1:myDim_nod2D+eDim_nod2D) => mesh%zbar_n_bot_fc(:) + zbar_e_bot_fc(1:myDim_elem2D+eDim_elem2D) => mesh%zbar_e_bot_fc(:) + + hnode_fc = 0.0_WP + hnode_new_fc = 0.0_WP + helem_fc = 0.0_WP + zbar_3d_n_fc = 0.0_WP + Z_3d_n_fc = 0.0_WP + zbar_n_bot_fc= 0.0_WP + zbar_e_bot_fc= 0.0_WP + bottom_elem_thickness_fc = 0.0_WP + bottom_node_thickness_fc = 0.0_WP + !___________________________________________________________________________ ! calculate thickness of partial bottom layer cells as well as depth depth ! of partial cell bootom layer @@ -301,6 +335,18 @@ subroutine init_ale(dynamics, partit, mesh) ! in case of partial cells bottom mid depth is different from Z(nzmax-1) Z_3d_n(nzmax-1,n) =zbar_3d_n(nzmax-1,n)+(zbar_n_bot(n)-zbar_3d_n(nzmax-1,n))/2; + + !_______________________________________________________________________ + !PS debug partiell cells + zbar_3d_n_fc(1:nzmin-1,n) = zbar(1:nzmin-1); + zbar_3d_n_fc(nzmin ,n) = zbar_n_srf(n); + zbar_3d_n_fc(nzmin+1:nzmax-1,n)= zbar(nzmin+1:nzmax-1); + zbar_3d_n_fc(nzmax ,n) = zbar_n_bot_fc(n); + Z_3d_n_fc(1:nzmin-1 ,n) = Z(1:nzmin-1); + Z_3d_n_fc(nzmin ,n) = zbar_3d_n_fc(nzmin,n)+(zbar_3d_n_fc(nzmin+1,n)-zbar_n_srf(n))/2; + Z_3d_n_fc(nzmin+1:nzmax-2,n) = Z(nzmin+1:nzmax-2); + Z_3d_n_fc(nzmax-1 ,n) = zbar_3d_n_fc(nzmax-1,n)+(zbar_n_bot_fc(n)-zbar_3d_n_fc(nzmax-1,n))/2; + end do end subroutine init_ale @@ -433,6 +479,16 @@ subroutine init_bottom_elem_thickness(partit, mesh) !___________________________________________________________________________ call exchange_elem(zbar_e_bot, partit) + !___________________________________________________________________________ + !PS debug partiell cells + do elem=1, myDim_elem2D + nle=nlevels(elem) + bottom_elem_thickness_fc(elem)=zbar(nle-1)-zbar(nle) + zbar_e_bot_fc(elem) = zbar(nle) + end do + call exchange_elem(zbar_e_bot_fc, partit) + + end subroutine init_bottom_elem_thickness ! ! @@ -450,7 +506,7 @@ subroutine init_bottom_node_thickness(partit, mesh) type(t_partit), intent(inout), target :: partit type(t_mesh) , intent(inout), target :: mesh !___________________________________________________________________________ - integer :: node, nln, elem, elemi, nelem + integer :: node, nln, elem, elemi, nelem, nle real(kind=WP) :: dd real(kind=WP) :: hnbot, tvol !___________________________________________________________________________ @@ -528,9 +584,38 @@ subroutine init_bottom_node_thickness(partit, mesh) ! elemental partial bottom depths nln = nlevels_nod2D(node) nelem = nod_in_elem2d_num(node) - zbar_n_bot(node) = minval(zbar_e_bot(nod_in_elem2d(1:nelem,node))) - bottom_node_thickness(node)= zbar(nln-1)-zbar_n_bot(node) - end do ! --> do node=1, myDim_nod2D+eDim_nod2D + + + ! The bottom topography in FESOM2 is entirly defined on the elements + ! thus also the thickness of the bottom layer on elements is fully + ! defined and valid. BUT therefore the corresponding bottom layer + ! thickness on vertices is less clear + ! + ! --> so far we choose as criteria for the vertices layer thickness + ! that it is equal to the maximum layer thickness of the sorounding + ! element. This has the advantage that no extrapolation when + ! computing the PGF is neccesary. But harbours the risk that the + ! volume of the scalar cluster and the vollume of the sorrounding + ! elements deviates + !PS zbar_n_bot(node) = minval(zbar_e_bot(nod_in_elem2d(1:nelem,node))) + !PS bottom_node_thickness(node)= zbar(nln-1)-zbar_n_bot(node) + + ! --> here we choose the thickness of the vertice bottom cell so that + ! it agrees with the volulme of the sum of the sorrounding element + ! cells + ! A_n_bot * h_n_bot = sum( A_e_bot/3 * h_e_boz) + ! h_n_bot = sum( A_e_bot/3 * h_e_boz) / A_n_bot !!! + bottom_node_thickness(node) = 0.0_WP + do elemi=1,nelem + elem = nod_in_elem2d(elemi,node) + nle = nlevels(elem) + if (nle>=nln) then + bottom_node_thickness(node) = bottom_node_thickness(node) + bottom_elem_thickness(elem)*elem_area(elem)/3.0_WP + end if + end do + bottom_node_thickness(node)= bottom_node_thickness(node)/area(nln-1,node) + zbar_n_bot(node) = zbar(nln-1) - bottom_node_thickness(node) + end do ! --> do node=1, myDim_nod2D !___________________________________________________________________________ ! use full bottom cells @@ -546,6 +631,17 @@ subroutine init_bottom_node_thickness(partit, mesh) call exchange_nod(zbar_n_bot, partit) call exchange_nod(bottom_node_thickness, partit) + !___________________________________________________________________________ + !PS debug partiell cells + do node=1,myDim_nod2D + nln = nlevels_nod2D(node) + zbar_n_bot_fc(node) = zbar(nln) + bottom_node_thickness_fc(node)= zbar(nln-1)-zbar_n_bot_fc(node) + end do + call exchange_nod(zbar_n_bot_fc, partit) + call exchange_nod(bottom_node_thickness_fc, partit) + + end subroutine init_bottom_node_thickness ! ! @@ -755,11 +851,13 @@ subroutine init_thickness_ale(dynamics, partit, mesh) do nz=nzmin,nzmax-1 !!PS hnode(nz,n)=(zbar(nz)-zbar(nz+1)) hnode(nz,n)=(zbar_3d_n(nz,n)-zbar_3d_n(nz+1,n)) + hnode_fc(nz,n)=hnode(nz,n) end do ! set bottom node thickness !!PS hnode(nlevels_nod2D(n)-1,n)=bottom_node_thickness(n) - hnode(nzmax,n)=bottom_node_thickness(n) + hnode( nzmax,n)=bottom_node_thickness( n) + hnode_fc(nzmax,n)=bottom_node_thickness_fc(n) !!PS do nz=nlevels_nod2D(n),nl-1 !!PS --> can skip this, hnode(:,:) is initialised with 0.0_WP @@ -774,13 +872,16 @@ subroutine init_thickness_ale(dynamics, partit, mesh) !!PS do nz=1,nlevels(elem)-2 helem(nzmin,elem)=(zbar_e_srf(elem)-zbar(nzmin+1)) + helem_fc(nzmin,elem)=helem(nzmin,elem) do nz = nzmin+1, nzmax-1 helem(nz,elem)=(zbar(nz)-zbar(nz+1)) + helem_fc(nz,elem)=helem(nz,elem) end do ! set bottom elem thickness !!PS helem(nlevels(elem)-1,elem)=bottom_elem_thickness(elem) - helem(nzmax,elem)=bottom_elem_thickness(elem) + helem( nzmax,elem)=bottom_elem_thickness( elem) + helem_fc(nzmax,elem)=bottom_elem_thickness_fc(elem) !!PS do nz=nlevels(elem),nl-1 !!PS --> can skip this, helem(:,:) is initialised with 0.0_WP @@ -881,16 +982,18 @@ subroutine init_thickness_ale(dynamics, partit, mesh) ! hbar surface elevation linear over verical column !!PS do nz=1,nlevels_nod2D_min(n)-2 do nz=nzmin,nlevels_nod2D_min(n)-2 - hnode(nz,n)=(zbar(nz)-zbar(nz+1))*(1.0_WP+hbar(n)/dd) + hnode( nz,n)=(zbar(nz)-zbar(nz+1))*(1.0_WP+hbar(n)/dd) + hnode_fc(nz,n)=hnode(nz,n) end do ! do not distribute hbar into cells that intersect somehow with ! bottom layer !!PS do nz=nlevels_nod2D_min(n)-1, nlevels_nod2D(n)-1 do nz=nlevels_nod2D_min(n)-1, nzmax-1 - hnode(nz,n)=(zbar(nz)-zbar(nz+1)) + hnode( nz,n)=(zbar(nz)-zbar(nz+1)) + hnode_fc(nz,n)=hnode(nz,n) end do - else + else ! --> in case of cavity ! in case of cavity dont distribute ssh --> cavity-ocean boudnary ! is fixed do nz=nzmin,nzmax-1 @@ -898,7 +1001,8 @@ subroutine init_thickness_ale(dynamics, partit, mesh) end do end if ! set bottom node thickness - hnode(nzmax,n)=bottom_node_thickness(n) + hnode( nzmax,n)=bottom_node_thickness( n) + hnode_fc(nzmax,n)=bottom_node_thickness_fc(n) !!PS --> can skip this, hnode(:,:) is initialised with 0.0_WP !!PS ! layer thickness of bottom layer equal 0 @@ -919,6 +1023,7 @@ subroutine init_thickness_ale(dynamics, partit, mesh) if (nzmin==1) then dhe(elem)=sum(hbar(elnodes))/3.0_WP helem(nzmin,elem)=sum(hnode(nzmin,elnodes))/3.0_WP + helem_fc(nzmin,elem)=helem(nzmin,elem) else dhe = 0.0_WP helem(nzmin,elem)=zbar_e_srf(elem)-zbar(nzmin+1) @@ -928,11 +1033,13 @@ subroutine init_thickness_ale(dynamics, partit, mesh) !!PS do nz=nzmin,nzmax-1 do nz=nzmin+1,nzmax-1 helem(nz,elem)=sum(hnode(nz,elnodes))/3.0_WP + helem_fc(nz,elem)=helem(nz,elem) end do ! elemental bottom layer thickness !!PS helem(nlevels(elem)-1,elem)=bottom_elem_thickness(elem) - helem(nzmax,elem)=bottom_elem_thickness(elem) + helem( nzmax,elem)=bottom_elem_thickness( elem) + helem_fc(nzmax,elem)=bottom_elem_thickness_fc(elem) !!PS --> can skip this, helem(:,:) is initialised with 0.0_WP !!PS ! fill thickness below bottom layer @@ -950,8 +1057,8 @@ subroutine init_thickness_ale(dynamics, partit, mesh) endif !___________________________________________________________________________ - hnode_new=hnode ! Should be initialized, because only variable part is updated. - + hnode_new =hnode ! Should be initialized, because only variable part is updated. + hnode_new_fc=hnode_fc ! Should be initialized, because only variable part is updated. !!PS call check_total_volume(partit, mesh) end subroutine init_thickness_ale @@ -1099,6 +1206,10 @@ subroutine update_thickness_ale(partit, mesh) hnode(nz,n) = hnode_new(nz,n) zbar_3d_n(nz,n) = zbar_3d_n(nz+1,n) + hnode_new(nz,n) Z_3d_n(nz,n) = zbar_3d_n(nz+1,n) + hnode_new(nz,n)/2.0_WP + + hnode_fc(nz,n) = hnode_new_fc(nz,n) + zbar_3d_n_fc(nz,n) = zbar_3d_n_fc(nz+1,n) + hnode_new_fc(nz,n) + Z_3d_n_fc(nz,n) = zbar_3d_n_fc(nz+1,n) + hnode_new_fc(nz,n)/2.0_WP end do end do !$OMP END PARALLEL DO @@ -1117,6 +1228,8 @@ subroutine update_thickness_ale(partit, mesh) elnodes=elem2D_nodes(:, elem) do nz=nzmin, nzmax-1 helem(nz,elem)=sum(hnode(nz,elnodes))/3.0_WP + + helem_fc(nz,elem)=sum(hnode_fc(nz,elnodes))/3.0_WP end do end do !$OMP END PARALLEL DO @@ -1175,11 +1288,14 @@ subroutine restart_thickness_ale(partit, mesh) ! in case its activated, especially when you make a restart from a non ! partiall cell runs towards a simulation with partial cells hnode(nzmax,n) = bottom_node_thickness(n) + hnode_fc(nzmax,n) = bottom_node_thickness_fc(n) !___________________________________________________________________ do nz=nzmax-1,nzmin,-1 zbar_3d_n(nz,n) =zbar_3d_n(nz+1,n) + hnode(nz,n) Z_3d_n(nz,n) =zbar_3d_n(nz+1,n) + hnode(nz,n)/2.0_WP + zbar_3d_n_fc(nz,n) =zbar_3d_n_fc(nz+1,n) + hnode_fc(nz,n) + Z_3d_n_fc(nz,n) =zbar_3d_n_fc(nz+1,n) + hnode_fc(nz,n)/2.0_WP end do end do @@ -1199,12 +1315,14 @@ subroutine restart_thickness_ale(partit, mesh) elnodes=elem2D_nodes(:, elem) do nz=nzmin,nzmax-1 helem(nz,elem)=sum(hnode(nz,elnodes))/3.0_WP + helem_fc(nz,elem)=sum(hnode_fc(nz,elnodes))/3.0_WP end do !___________________________________________________________________ ! be sure elemental bottom thickness has partial cells in it, when ! its used after restart helem(nzmax,elem)=bottom_elem_thickness(elem) + helem_fc(nzmax,elem)=bottom_elem_thickness_fc(elem) !___________________________________________________________________ ! for the first time steps of a restart or initialisation dhe must @@ -1228,18 +1346,23 @@ subroutine restart_thickness_ale(partit, mesh) nzmax = nlevels_nod2D(n)-1 do nz=nzmin,nzmax-1 hnode(nz,n)=(zbar_3d_n(nz,n)-zbar_3d_n(nz+1,n)) + hnode_fc(nz,n)=(zbar_3d_n_fc(nz,n)-zbar_3d_n_fc(nz+1,n)) end do hnode(nzmax,n)=bottom_node_thickness(n) + hnode_fc(nzmax,n)=bottom_node_thickness_fc(n) end do do elem=1,myDim_elem2D nzmin = ulevels(elem) nzmax = nlevels(elem)-1 helem(nzmin,elem)=(zbar_e_srf(elem)-zbar(nzmin+1)) + helem_fc(nzmin,elem)=(zbar_e_srf(elem)-zbar(nzmin+1)) do nz = nzmin+1, nzmax-1 helem(nz,elem)=(zbar(nz)-zbar(nz+1)) + helem_fc(nz,elem)=(zbar(nz)-zbar(nz+1)) end do helem(nzmax,elem)=bottom_elem_thickness(elem) + helem_fc(nzmax,elem)=bottom_elem_thickness_fc(elem) end do endif @@ -1403,7 +1526,10 @@ subroutine init_stiff_mat_ale(partit, mesh) !!PS fy(1:3) = (zbar_e_bot(el(i)))* & !-> cavity !!PS fy(1:3) = (zbar_e_bot(el(i))-zbar(ulevels(el(i))))* & +!PS fy(1:3) = (zbar_e_bot_fc(el(i))-zbar_e_srf(el(i)))* & +!PS fy(1:3) = (zbar_e_bot_fc(el(i))-zbar_e_srf(el(i)))* & fy(1:3) = (zbar_e_bot(el(i))-zbar_e_srf(el(i)))* & + ( gradient_sca(1:3,el(i)) * edge_cross_dxdy(2*i ,ed) & -gradient_sca(4:6,el(i)) * edge_cross_dxdy(2*i-1,ed) ) @@ -1731,6 +1857,8 @@ subroutine compute_ssh_rhs_ale(dynamics, partit, mesh) do nz=nzmin, nzmax c1=c1+alpha*((UV(2,nz,el(1))+UV_rhs(2,nz,el(1)))*deltaX1- & (UV(1,nz,el(1))+UV_rhs(1,nz,el(1)))*deltaY1)*helem(nz,el(1)) +!PS c1=c1+alpha*((UV(2,nz,el(1))+UV_rhs(2,nz,el(1)))*deltaX1- & +!PS (UV(1,nz,el(1))+UV_rhs(1,nz,el(1)))*deltaY1)*helem_fc(nz,el(1)) end do !_______________________________________________________________________ @@ -1747,6 +1875,8 @@ subroutine compute_ssh_rhs_ale(dynamics, partit, mesh) do nz=nzmin, nzmax c2=c2-alpha*((UV(2,nz,el(2))+UV_rhs(2,nz,el(2)))*deltaX2- & (UV(1,nz,el(2))+UV_rhs(1,nz,el(2)))*deltaY2)*helem(nz,el(2)) +!PS c2=c2-alpha*((UV(2,nz,el(2))+UV_rhs(2,nz,el(2)))*deltaX2- & +!PS (UV(1,nz,el(2))+UV_rhs(1,nz,el(2)))*deltaY2)*helem_fc(nz,el(2)) end do end if @@ -1882,6 +2012,7 @@ subroutine compute_hbar_ale(dynamics, partit, mesh) !!PS do nz=1, nlevels(el(1))-1 do nz=nzmin, nzmax c1=c1+(UV(2,nz,el(1))*deltaX1-UV(1,nz,el(1))*deltaY1)*helem(nz,el(1)) +!PS c1=c1+(UV(2,nz,el(1))*deltaX1-UV(1,nz,el(1))*deltaY1)*helem_fc(nz,el(1)) end do !_______________________________________________________________________ ! if ed is not a boundary edge --> calc depth integral: \nabla\int(U_n)dz @@ -1895,6 +2026,7 @@ subroutine compute_hbar_ale(dynamics, partit, mesh) !!PS do nz=1, nlevels(el(2))-1 do nz=nzmin, nzmax c2=c2-(UV(2,nz,el(2))*deltaX2-UV(1,nz,el(2))*deltaY2)*helem(nz,el(2)) +!PS c2=c2-(UV(2,nz,el(2))*deltaX2-UV(1,nz,el(2))*deltaY2)*helem_fc(nz,el(2)) end do end if !_______________________________________________________________________ @@ -2056,10 +2188,12 @@ subroutine vert_vel_ale(dynamics, partit, mesh) ! --> e_vec = (dx,dy), n_vec = (-dy,dx); ! --> h * u*(-dy) + v*dx c1(nz)=( UV(2,nz,el(1))*deltaX1 - UV(1,nz,el(1))*deltaY1 )*helem(nz,el(1)) +!PS c1(nz)=( UV(2,nz,el(1))*deltaX1 - UV(1,nz,el(1))*deltaY1 )*helem_fc(nz,el(1)) ! inflow(outflow) "flux" to control volume of node enodes1 ! is equal to outflow(inflow) "flux" to control volume of node enodes2 if (Fer_GM) then c2(nz)=(fer_UV(2,nz,el(1))*deltaX1- fer_UV(1,nz,el(1))*deltaY1)*helem(nz,el(1)) +!PS c2(nz)=(fer_UV(2,nz,el(1))*deltaX1- fer_UV(1,nz,el(1))*deltaY1)*helem_fc(nz,el(1)) end if end do #if defined(_OPENMP) && !defined(__openmp_reproducible) @@ -2094,8 +2228,10 @@ subroutine vert_vel_ale(dynamics, partit, mesh) nzmax = nlevels(el(2))-1 do nz = nzmax, nzmin, -1 c1(nz)=-(UV(2,nz,el(2))*deltaX2 - UV(1,nz,el(2))*deltaY2)*helem(nz,el(2)) +!PS c1(nz)=-(UV(2,nz,el(2))*deltaX2 - UV(1,nz,el(2))*deltaY2)*helem_fc(nz,el(2)) if (Fer_GM) then c2(nz)=-(fer_UV(2,nz,el(2))*deltaX2-fer_UV(1,nz,el(2))*deltaY2)*helem(nz,el(2)) +!PS c2(nz)=-(fer_UV(2,nz,el(2))*deltaX2-fer_UV(1,nz,el(2))*deltaY2)*helem_fc(nz,el(2)) end if end do #if defined(_OPENMP) && !defined(__openmp_reproducible) @@ -2428,6 +2564,7 @@ subroutine vert_vel_ale(dynamics, partit, mesh) Wvel(nz,n) =Wvel(nz,n) -(zbar_3d_n(nz,n)-dd1)*dddt hnode_new(nz,n)=hnode(nz,n)+(zbar_3d_n(nz,n)-zbar_3d_n(nz+1,n))*dd + hnode_new_fc(nz,n)=hnode_new(nz,n) end do !___________________________________________________________________ @@ -2485,7 +2622,9 @@ subroutine vert_vel_ale(dynamics, partit, mesh) !$OMP END PARALLEL DO !___________________________________________________________________________ call exchange_nod(Wvel, partit) - call exchange_nod(hnode_new, partit) ! Or extend cycles above + call exchange_nod(hnode_new, partit) ! Or extend cycles above + call exchange_nod(hnode_new_fc, partit) ! Or extend cycles above + if (Fer_GM) call exchange_nod(fer_Wvel, partit) !$OMP BARRIER !___________________________________________________________________________ @@ -2739,13 +2878,17 @@ subroutine impl_vert_visc_ale(dynamics, partit, mesh) ! zbar_n(nzmax) is now zbar_e_bot(elem), zbar_n(nzmax)=zbar_e_bot(elem) Z_n(nzmax-1)=zbar_n(nzmax) + helem(nzmax-1,elem)/2.0_WP +!PS zbar_n(nzmax)=zbar_e_bot_fc(elem) +!PS Z_n(nzmax-1)=zbar_n(nzmax) + helem_fc(nzmax-1,elem)/2.0_WP !!PS do nz=nzmax-1,2,-1 do nz=nzmax-1,nzmin+1,-1 zbar_n(nz) = zbar_n(nz+1) + helem(nz,elem) Z_n(nz-1) = zbar_n(nz) + helem(nz-1,elem)/2.0_WP +!PS zbar_n(nz) = zbar_n(nz+1) + helem_fc(nz,elem) +!PS Z_n(nz-1) = zbar_n(nz) + helem_fc(nz-1,elem)/2.0_WP end do - !!PS zbar_n(1) = zbar_n(2) + helem(1,elem) zbar_n(nzmin) = zbar_n(nzmin+1) + helem(nzmin,elem) +!PS zbar_n(nzmin) = zbar_n(nzmin+1) + helem_fc(nzmin,elem) !___________________________________________________________________________ ! Operator diff --git a/src/oce_ale_pressure_bv.F90 b/src/oce_ale_pressure_bv.F90 index e2329f10a..95958bdac 100644 --- a/src/oce_ale_pressure_bv.F90 +++ b/src/oce_ale_pressure_bv.F90 @@ -74,6 +74,19 @@ subroutine pressure_force_4_linfs_easypgf(tracers, partit, mesh) end subroutine end interface end module +module pressure_force_4_linfs_easypgf_fc_interface + interface + subroutine pressure_force_4_linfs_easypgf_fc(tracers, partit, mesh) + USE MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + USE MOD_TRACER + type(t_tracer), intent(in), target :: tracers + type(t_partit), intent(inout), target :: partit + type(t_mesh), intent(in), target :: mesh + end subroutine + end interface +end module module pressure_force_4_linfs_cubicspline_interface interface subroutine pressure_force_4_linfs_cubicspline(partit, mesh) @@ -120,6 +133,19 @@ subroutine pressure_force_4_zxxxx_easypgf(tracers, partit, mesh) end subroutine end interface end module +module pressure_force_4_zxxxx_easypgf_fc_interface + interface + subroutine pressure_force_4_zxxxx_easypgf_fc(tracers, partit, mesh) + USE MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + USE MOD_TRACER + type(t_mesh), intent(in) , target :: mesh + type(t_partit), intent(inout), target :: partit + type(t_tracer), intent(in), target :: tracers + end subroutine + end interface +end module module pressure_force_4_zxxxx_cubicspline_interface interface subroutine pressure_force_4_zxxxx_cubicspline(partit, mesh) @@ -318,9 +344,9 @@ subroutine pressure_bv(tracers, partit, mesh) !!PS do nz=1, nl1 do nz=nzmin, nzmax-1 !___________________________________________________________________ - rho(nz) = bulk_0(nz) + Z_3d_n(nz,node)*(bulk_pz(nz) + Z_3d_n(nz,node)*bulk_pz2(nz)) + rho(nz) = bulk_0(nz) + Z_3d_n_fc(nz,node)*(bulk_pz(nz) + Z_3d_n_fc(nz,node)*bulk_pz2(nz)) !!PS rho(nz)=rho(nz)*rhopot(nz)/(rho(nz)+0.1_WP*Z_3d_n(nz,node))-density_0 - rho(nz) = rho(nz)*rhopot(nz)/(rho(nz)+0.1_WP*Z_3d_n(nz,node)*real(state_equation))-density_ref(nz,node) + rho(nz) = rho(nz)*rhopot(nz)/(rho(nz)+0.1_WP*Z_3d_n_fc(nz,node)*real(state_equation))-density_ref(nz,node) density_m_rho0(nz,node) = rho(nz) !___________________________________________________________________ @@ -328,15 +354,15 @@ subroutine pressure_bv(tracers, partit, mesh) ! --> bring density of surface point adiabatically to the same ! depth level as the deep point --> than calculate bouyancy ! difference - rho_surf=bulk_0(nzmin) + Z_3d_n(nz,node)*(bulk_pz(nzmin) + Z_3d_n(nz,node)*bulk_pz2(nzmin)) + rho_surf=bulk_0(nzmin) + Z_3d_n_fc(nz,node)*(bulk_pz(nzmin) + Z_3d_n_fc(nz,node)*bulk_pz2(nzmin)) !!PS rho_surf=rho_surf*rhopot(nzmin)/(rho_surf+0.1_WP*Z_3d_n(nz,node))-density_0 - rho_surf=rho_surf*rhopot(nzmin)/(rho_surf+0.1_WP*Z_3d_n(nz,node)*real(state_equation)) !-density_ref(nzmin,node) + rho_surf=rho_surf*rhopot(nzmin)/(rho_surf+0.1_WP*Z_3d_n_fc(nz,node)*real(state_equation)) !-density_ref(nzmin,node) !!PS dbsfc1(nz) = -g * ( rho_surf - rho(nz) ) / (rho(nz)+density_0) ! this is also required when KPP is ON !!PS dbsfc1(nz) = -g * density_0_r * ( rho_surf - rho(nz) ) dbsfc1(nz) = -g * ( rho_surf - (rho(nz)+density_ref(nz,node)) ) / (rho(nz)+density_ref(nz,node)) ! this is also required when KPP is ON - db_max = max(dbsfc1(nz)/abs(Z_3d_n(nzmin,node)-Z_3d_n(max(nz, nzmin+1),node)), db_max) + db_max = max(dbsfc1(nz)/abs(Z_3d_n_fc(nzmin,node)-Z_3d_n_fc(max(nz, nzmin+1),node)), db_max) end do dbsfc1(nzmax)=dbsfc1(nzmax-1) @@ -363,8 +389,10 @@ subroutine pressure_bv(tracers, partit, mesh) call par_ex(partit%MPI_COMM_FESOM, partit%mype, 1) end select !_______________________________________________________________ - rho(nz)= bulk_0(nz) + Z_3d_n(nz,node)*(bulk_pz(nz) + Z_3d_n(nz,node)*bulk_pz2(nz)) - rho(nz)=rho(nz)*rhopot(nz)/(rho(nz)+0.1_WP*Z_3d_n(nz,node)*real(state_equation))-density_ref(nz,node) +!PS rho(nz)= bulk_0(nz) + Z_3d_n(nz,node)*(bulk_pz(nz) + Z_3d_n(nz,node)*bulk_pz2(nz)) +!PS rho(nz)=rho(nz)*rhopot(nz)/(rho(nz)+0.1_WP*Z_3d_n(nz,node)*real(state_equation))-density_ref(nz,node) + rho(nz)= bulk_0(nz) + Z_3d_n_fc(nz,node)*(bulk_pz(nz) + Z_3d_n_fc(nz,node)*bulk_pz2(nz)) + rho(nz)=rho(nz)*rhopot(nz)/(rho(nz)+0.1_WP*Z_3d_n_fc(nz,node)*real(state_equation))-density_ref(nz,node) density_m_rho0(nz,node) = rho(nz) end do end if @@ -382,9 +410,9 @@ subroutine pressure_bv(tracers, partit, mesh) ! --> this as a upper pressure boundary condition incase of a ! homogenous ocean, with no fluxes and boundary condition creates ! no pressure gradient errors - hpressure(nzmin, node)=0.5_WP*(zbar_3d_n(1,node)-zbar_3d_n(2,node))*rho(1)*g + hpressure(nzmin, node)=0.5_WP*(zbar_3d_n_fc(1,node)-zbar_3d_n_fc(2,node))*rho(1)*g do nz=2,nzmin - a=0.5_WP*g*(rho(nz-1)*(zbar_3d_n(nz-1,node)-zbar_3d_n(nz,node))+rho(nz)*(zbar_3d_n(nz,node)-zbar_3d_n(nz+1,node))) + a=0.5_WP*g*(rho(nz-1)*(zbar_3d_n_fc(nz-1,node)-zbar_3d_n_fc(nz,node))+rho(nz)*(zbar_3d_n_fc(nz,node)-zbar_3d_n_fc(nz+1,node))) hpressure(nzmin, node)=hpressure(nzmin, node)+a end do @@ -393,7 +421,7 @@ subroutine pressure_bv(tracers, partit, mesh) ! pgf errors !!PS hpressure(nzmin, node)=-Z_3d_n(nzmin,node)*rho(nzmin)*g else - hpressure(nzmin, node)=-Z_3d_n(nzmin,node)*rho(nzmin)*g + hpressure(nzmin, node)=-Z_3d_n_fc(nzmin,node)*rho(nzmin)*g end if !___________________________________________________________________ @@ -402,7 +430,7 @@ subroutine pressure_bv(tracers, partit, mesh) ! why 0.5 ... integrate g*rho*dz vertically, integrate half layer ! thickness of previouse layer and half layer thickness of actual ! layer to integrate pressure on mid depth level of actual layer - a=0.5_WP*g*(rho(nz-1)*hnode(nz-1,node)+rho(nz)*hnode(nz,node)) + a=0.5_WP*g*(rho(nz-1)*hnode_fc(nz-1,node)+rho(nz)*hnode_fc(nz,node)) hpressure(nz, node)=hpressure(nz-1, node)+a end do end if @@ -419,9 +447,9 @@ subroutine pressure_bv(tracers, partit, mesh) ! To be CMOR compliant we add MLD3, which is identical to MLD2, except ! for the critical density threshold at 0.03, rather than 0.125 kg/m³ ! BV frequency: bvfreq(nl,:), squared value is stored - MLD1(node)=Z_3d_n(nzmin+1,node) - MLD2(node)=Z_3d_n(nzmin+1,node) - MLD3(node)=Z_3d_n(nzmin+1,node) + MLD1(node)=Z_3d_n_fc(nzmin+1,node) + MLD2(node)=Z_3d_n_fc(nzmin+1,node) + MLD3(node)=Z_3d_n_fc(nzmin+1,node) MLD1_ind(node)=nzmin+1 MLD2_ind(node)=nzmin+1 MLD3_ind(node)=nzmin+1 @@ -430,12 +458,12 @@ subroutine pressure_bv(tracers, partit, mesh) flag2=.true. flag3=.true. do nz=nzmin+1,nzmax-1 - zmean = 0.5_WP*sum(Z_3d_n(nz-1:nz, node)) + zmean = 0.5_WP*sum(Z_3d_n_fc(nz-1:nz, node)) bulk_up = bulk_0(nz-1) + zmean*(bulk_pz(nz-1) + zmean*bulk_pz2(nz-1)) bulk_dn = bulk_0(nz) + zmean*(bulk_pz(nz) + zmean*bulk_pz2(nz)) rho_up = bulk_up*rhopot(nz-1) / (bulk_up + 0.1_WP*zmean*real(state_equation)) rho_dn = bulk_dn*rhopot(nz) / (bulk_dn + 0.1_WP*zmean*real(state_equation)) - dz_inv = 1.0_WP/(Z_3d_n(nz-1,node)-Z_3d_n(nz,node)) + dz_inv = 1.0_WP/(Z_3d_n_fc(nz-1,node)-Z_3d_n_fc(nz,node)) !_______________________________________________________________ ! squared brunt väisälä frequence N^2 --> N^2>0 stratification is ! stable, vertical elongated parcel is accelaratedtowards @@ -450,26 +478,26 @@ subroutine pressure_bv(tracers, partit, mesh) ! MLD is the shallowest depth where the local buoyancy gradient matches the maximum buoyancy gradient ! between the surface and any discrete depth within the water column. if (bvfreq(nz, node) > db_max .and. flag1) then - MLD1(node) =Z_3d_n(nz, node) + MLD1(node) =Z_3d_n_fc(nz, node) MLD1_ind(node)=nz flag1=.false. end if ! another definition of MLD after Levitus if ((rhopot(nz)-rhopot(nzmin) > sigma_theta_crit) .and. flag2) then - MLD2(node)=MLD2(node)+(Z_3d_n(nz,node)-MLD2(node))/(rhopot(nz)-rhopot(nz-1)+1.e-20)*(rhopot(1)+sigma_theta_crit-rhopot(nz-1)) + MLD2(node)=MLD2(node)+(Z_3d_n_fc(nz,node)-MLD2(node))/(rhopot(nz)-rhopot(nz-1)+1.e-20)*(rhopot(1)+sigma_theta_crit-rhopot(nz-1)) MLD2_ind(node)=nz flag2=.false. elseif (flag2) then - MLD2(node)=Z_3d_n(nz,node) + MLD2(node)=Z_3d_n_fc(nz,node) end if ! another definition of MLD after Griffies 2016 (https://doi.org/10.5194/gmd-9-3231-2016) if ((rhopot(nz)-rhopot(nzmin) > sigma_theta_crit_cmor) .and. flag3) then - MLD3(node)=MLD3(node)+(Z_3d_n(nz,node)-MLD3(node))/(rhopot(nz)-rhopot(nz-1)+1.e-20)*(rhopot(1)+sigma_theta_crit_cmor-rhopot(nz-1)) + MLD3(node)=MLD3(node)+(Z_3d_n_fc(nz,node)-MLD3(node))/(rhopot(nz)-rhopot(nz-1)+1.e-20)*(rhopot(1)+sigma_theta_crit_cmor-rhopot(nz-1)) MLD3_ind(node)=nz flag3=.false. elseif (flag3) then - MLD3(node)=Z_3d_n(nz,node) + MLD3(node)=Z_3d_n_fc(nz,node) end if end do @@ -547,6 +575,8 @@ subroutine pressure_force_4_linfs(tracers, partit, mesh) call pressure_force_4_linfs_cubicspline(partit, mesh) elseif (trim(which_pgf)=='easypgf') then call pressure_force_4_linfs_easypgf(tracers, partit, mesh) + elseif (trim(which_pgf)=='easypgf_fc') then + call pressure_force_4_linfs_easypgf_fc(tracers, partit, mesh) else write(*,*) '________________________________________________________' write(*,*) ' --> ERROR: the choosen form of pressure gradient ' @@ -1429,6 +1459,113 @@ end subroutine pressure_force_4_linfs_easypgf ! ! !=============================================================================== +! Calculate pressure gradient force (PGF) +! First coded by P. Scholz for FESOM2.0, 08.02.2019 +subroutine pressure_force_4_linfs_easypgf_fc(tracers, partit, mesh) + use o_PARAM + use MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + use MOD_TRACER + use o_ARRAYS + use g_config + use densityJM_components_interface + use density_linear_interface + implicit none + type(t_mesh), intent(in) , target :: mesh + type(t_partit), intent(inout), target :: partit + type(t_tracer), intent(in), target :: tracers + integer :: elem, elnodes(3), nle, ule, nlz, idx(3),ni + real(kind=WP) :: int_dp_dx(2), drho_dx, aux_sum + real(kind=WP) :: dx10(3), dx20(3), dx21(3) + real(kind=WP) :: t0(3), dt10(3), dt21(3) + real(kind=WP) :: s0(3), ds10(3), ds21(3) + real(kind=WP) :: rho_at_Zn(3), temp_at_Zn(3), salt_at_Zn(3), drho_dz(3), aux_dref + real(kind=WP) :: rhopot(3), bulk_0(3), bulk_pz(3), bulk_pz2(3) + real(kind=WP) :: dref_rhopot, dref_bulk_0, dref_bulk_pz, dref_bulk_pz2 + real(kind=WP) :: zbar_n(mesh%nl), z_n(mesh%nl-1) + real(kind=WP), dimension(:,:), pointer :: temp, salt +#include "associate_part_def.h" +#include "associate_mesh_def.h" +#include "associate_part_ass.h" +#include "associate_mesh_ass.h" + temp=>tracers%data(1)%values(:,:) + salt=>tracers%data(2)%values(:,:) + + !___________________________________________________________________________ + ! loop over triangular elemments +!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(elem, elnodes, nle, ule, nlz, idx, ni, int_dp_dx, drho_dx, aux_sum, dx10, dx20, dx21, t0, dt10, dt21, s0, ds10, ds21, & +!$OMP rho_at_Zn, temp_at_Zn, salt_at_Zn, drho_dz, aux_dref, rhopot, bulk_0, bulk_pz, bulk_pz2, dref_rhopot, dref_bulk_0, & +!$OMP dref_bulk_pz, dref_bulk_pz2, zbar_n, z_n ) +!$OMP DO + do elem=1, myDim_elem2D + !_______________________________________________________________________ + ! nle...number of mid-depth levels at elem + nle = nlevels(elem)-1 + ule = ulevels(elem) + + ! node indices of elem + elnodes = elem2D_nodes(:,elem) + + !_______________________________________________________________________ + ! calculate mid depth element level --> Z_e + ! nle...number of mid-depth levels at elem + zbar_n = 0.0_WP + Z_n = 0.0_WP + zbar_n(nle+1)= zbar_e_bot_fc(elem) + Z_n(nle) = zbar_n(nle+1) + helem_fc(nle,elem)*0.5_WP + do nlz=nle,ule+1,-1 + zbar_n(nlz) = zbar_n(nlz+1) + helem_fc(nlz,elem) + Z_n(nlz-1) = zbar_n(nlz) + helem_fc(nlz-1,elem)*0.5_WP + end do + zbar_n(ule) = zbar_n(ule+1) + helem_fc(ule,elem) + + + !_______________________________________________________________________ + ! calculate pressure gradient for surface layer + nlz=ule + !___________________________________________________________________ + ! zonal gradients + drho_dx = sum(gradient_sca(1:3,elem)*density_m_rho0(nlz,elnodes)) + aux_sum = drho_dx*helem_fc(nlz,elem)*g/density_0 + pgf_x(nlz,elem) = aux_sum*0.5_WP + int_dp_dx(1) = aux_sum + + !___________________________________________________________________ + ! meridional gradients + drho_dx = sum(gradient_sca(4:6,elem)*density_m_rho0(nlz,elnodes)) + aux_sum = drho_dx*helem_fc(nlz,elem)*g/density_0 + pgf_y(nlz,elem) = aux_sum*0.5_WP + int_dp_dx(2) = aux_sum + + !_______________________________________________________________________ + ! calculate pressure gradient for surface layer +1 until one layer above bottom + do nlz=ule+1,nle + !___________________________________________________________________ + ! - g/rho*int_z^eta( drho/dx|_s - drho/dz'*dz'/dx|_s )*dz' + ! --> in case linfs: dz_dx == 0.0 + ! zonal gradients + drho_dx = sum(gradient_sca(1:3,elem)*density_m_rho0(nlz,elnodes)) + aux_sum = drho_dx*helem_fc(nlz,elem)*g/density_0 + pgf_x(nlz,elem) = int_dp_dx(1) + aux_sum*0.5_WP + int_dp_dx(1) = int_dp_dx(1) + aux_sum + + ! meridional gradients + drho_dx = sum(gradient_sca(4:6,elem)*density_m_rho0(nlz,elnodes)) + aux_sum = drho_dx*helem_fc(nlz,elem)*g/density_0 + pgf_y(nlz,elem) = int_dp_dx(2) + aux_sum*0.5_WP + int_dp_dx(2) = int_dp_dx(2) + aux_sum + + end do ! --> do nlz=1,nle-1 + + end do ! --> do elem=1, myDim_elem2D +!$OMP END DO +!$OMP END PARALLEL +end subroutine pressure_force_4_linfs_easypgf_fc +! +! +! +!=============================================================================== ! Calculate pressure gradient force (PGF) via cubicspline used in FEOSM1.4 ! First coded by Q. Wang for FESOM1.4, adapted by P. Scholz for FESOM2.0, 08.02.2019 subroutine pressure_force_4_linfs_cubicspline(partit, mesh) @@ -1881,8 +2018,8 @@ subroutine pressure_force_4_zxxxx(tracers, partit, mesh) call pressure_force_4_zxxxx_cubicspline(partit, mesh) elseif (trim(which_pgf)=='easypgf' ) then call pressure_force_4_zxxxx_easypgf(tracers, partit, mesh) - elseif (trim(which_pgf)=='easypgf_fullbc' ) then - call pressure_force_4_zxxxx_easypgf(tracers, partit, mesh) + elseif (trim(which_pgf)=='easypgf_fc' ) then + call pressure_force_4_zxxxx_easypgf_fc(tracers, partit, mesh) else write(*,*) '________________________________________________________' write(*,*) ' --> ERROR: the choosen form of pressure gradient ' @@ -2795,7 +2932,7 @@ end subroutine pressure_force_4_zxxxx_easypgf ! ! !=============================================================================== -subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) +subroutine pressure_force_4_zxxxx_easypgf_fc(tracers, partit, mesh) use o_PARAM use MOD_MESH USE MOD_PARTIT @@ -2846,13 +2983,13 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) ! nle...number of mid-depth levels at elem zbar_n = 0.0_WP Z_n = 0.0_WP - zbar_n(nle+1)= zbar_e_bot(elem) - Z_n(nle) = zbar_n(nle+1) + helem(nle,elem)*0.5_WP + zbar_n(nle+1)= zbar_e_bot_fc(elem) + Z_n(nle) = zbar_n(nle+1) + helem_fc(nle,elem)*0.5_WP do nlz=nle,ule+1,-1 - zbar_n(nlz) = zbar_n(nlz+1) + helem(nlz,elem) - Z_n(nlz-1) = zbar_n(nlz) + helem(nlz-1,elem)*0.5_WP + zbar_n(nlz) = zbar_n(nlz+1) + helem_fc(nlz,elem) + Z_n(nlz-1) = zbar_n(nlz) + helem_fc(nlz-1,elem)*0.5_WP end do - zbar_n(ule) = zbar_n(ule+1) + helem(ule,elem) + zbar_n(ule) = zbar_n(ule+1) + helem_fc(ule,elem) !_______________________________________________________________________ aux_dref = density_0 @@ -2909,9 +3046,9 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) ! --> do second order newtonian surface boundary interpolation !___________________________________________________________________ ! compute interpolation coefficients - dx10(ni) = Z_3d_n(nlz+1,elnodes(ni))-Z_3d_n(nlz ,elnodes(ni)) - dx21(ni) = Z_3d_n(nlz+2,elnodes(ni))-Z_3d_n(nlz+1,elnodes(ni)) - dx20(ni) = Z_3d_n(nlz+2,elnodes(ni))-Z_3d_n(nlz ,elnodes(ni)) + dx10(ni) = Z_3d_n_fc(nlz+1,elnodes(ni))-Z_3d_n_fc(nlz ,elnodes(ni)) + dx21(ni) = Z_3d_n_fc(nlz+2,elnodes(ni))-Z_3d_n_fc(nlz+1,elnodes(ni)) + dx20(ni) = Z_3d_n_fc(nlz+2,elnodes(ni))-Z_3d_n_fc(nlz ,elnodes(ni)) !!PS f0(ni) = density_m_rho0(nlz ,elnodes(ni)) !!PS df10(ni) = density_m_rho0(nlz+1,elnodes(ni))-density_m_rho0(nlz ,elnodes(ni)) @@ -2927,13 +3064,13 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) !___________________________________________________________________ ! interpoalte vertice temp and salinity to elemental level Z_n temp_at_Zn(ni) = t0(ni) & - + dt10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n(nlz,elnodes(ni))) & + + dt10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n_fc(nlz,elnodes(ni))) & + (dx10(ni)*dt21(ni)-dx21(ni)*dt10(ni))/(dx20(ni)*dx21(ni)*dx10(ni))* & - (Z_n(nlz)-Z_3d_n(nlz+1,elnodes(ni)))*(Z_n(nlz)-Z_3d_n(nlz,elnodes(ni))) + (Z_n(nlz)-Z_3d_n_fc(nlz+1,elnodes(ni)))*(Z_n(nlz)-Z_3d_n_fc(nlz,elnodes(ni))) salt_at_Zn(ni) = s0(ni) & - + ds10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n(nlz,elnodes(ni))) & + + ds10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n_fc(nlz,elnodes(ni))) & + (dx10(ni)*ds21(ni)-dx21(ni)*ds10(ni))/(dx20(ni)*dx21(ni)*dx10(ni))* & - (Z_n(nlz)-Z_3d_n(nlz+1,elnodes(ni)))*(Z_n(nlz)-Z_3d_n(nlz,elnodes(ni))) + (Z_n(nlz)-Z_3d_n_fc(nlz+1,elnodes(ni)))*(Z_n(nlz)-Z_3d_n_fc(nlz,elnodes(ni))) !___________________________________________________________________ ! compute density from state equation select case(state_equation) @@ -2958,9 +3095,9 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) ! --> do normal interpolation !___________________________________________________________________ ! compute interpolation coefficients - dx10(ni) = Z_3d_n(nlz ,elnodes(ni))-Z_3d_n(nlz-1,elnodes(ni)) - dx21(ni) = Z_3d_n(nlz+1,elnodes(ni))-Z_3d_n(nlz ,elnodes(ni)) - dx20(ni) = Z_3d_n(nlz+1,elnodes(ni))-Z_3d_n(nlz-1,elnodes(ni)) + dx10(ni) = Z_3d_n_fc(nlz ,elnodes(ni))-Z_3d_n_fc(nlz-1,elnodes(ni)) + dx21(ni) = Z_3d_n_fc(nlz+1,elnodes(ni))-Z_3d_n_fc(nlz ,elnodes(ni)) + dx20(ni) = Z_3d_n_fc(nlz+1,elnodes(ni))-Z_3d_n_fc(nlz-1,elnodes(ni)) !!PS f0(ni) = density_m_rho0(nlz-1,elnodes(ni)) !!PS df10(ni) = density_m_rho0(nlz ,elnodes(ni))-density_m_rho0(nlz-1,elnodes(ni)) @@ -2976,13 +3113,13 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) !___________________________________________________________________ ! interpoalte vertice temp and salinity to elemental level Z_n temp_at_Zn(ni) = t0(ni) & - + dt10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n(nlz-1,elnodes(ni))) & + + dt10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes(ni))) & + (dx10(ni)*dt21(ni)-dx21(ni)*dt10(ni))/(dx20(ni)*dx21(ni)*dx10(ni))* & - (Z_n(nlz)-Z_3d_n(nlz,elnodes(ni)))*(Z_n(nlz)-Z_3d_n(nlz-1,elnodes(ni))) + (Z_n(nlz)-Z_3d_n_fc(nlz,elnodes(ni)))*(Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes(ni))) salt_at_Zn(ni) = s0(ni) & - + ds10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n(nlz-1,elnodes(ni))) & + + ds10(ni)/dx10(ni)*(Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes(ni))) & + (dx10(ni)*ds21(ni)-dx21(ni)*ds10(ni))/(dx20(ni)*dx21(ni)*dx10(ni))* & - (Z_n(nlz)-Z_3d_n(nlz,elnodes(ni)))*(Z_n(nlz)-Z_3d_n(nlz-1,elnodes(ni))) + (Z_n(nlz)-Z_3d_n_fc(nlz,elnodes(ni)))*(Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes(ni))) !___________________________________________________________________ ! compute density from state equation select case(state_equation) @@ -3012,13 +3149,13 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) !_______________________________________________________________________ ! zonal surface pressure gradients drho_dx = sum(gradient_sca(1:3,elem)*rho_at_Zn) - aux_sum = drho_dx*helem(nlz,elem)*g/density_0 + aux_sum = drho_dx*helem_fc(nlz,elem)*g/density_0 pgf_x(nlz,elem) = aux_sum*0.5_WP int_dp_dx(1) = aux_sum !_______________________________________________________________________ ! meridional surface pressure gradients drho_dy = sum(gradient_sca(4:6,elem)*rho_at_Zn) - aux_sum = drho_dy*helem(nlz,elem)*g/density_0 + aux_sum = drho_dy*helem_fc(nlz,elem)*g/density_0 pgf_y(nlz,elem) = aux_sum*0.5_WP int_dp_dx(2) = aux_sum @@ -3036,9 +3173,9 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) !___________________________________________________________________ ! compute interpolation coefficients - dx10 = Z_3d_n(nlz ,elnodes)-Z_3d_n(nlz-1,elnodes) - dx21 = Z_3d_n(nlz+1,elnodes)-Z_3d_n(nlz ,elnodes) - dx20 = Z_3d_n(nlz+1,elnodes)-Z_3d_n(nlz-1,elnodes) + dx10 = Z_3d_n_fc(nlz ,elnodes)-Z_3d_n_fc(nlz-1,elnodes) + dx21 = Z_3d_n_fc(nlz+1,elnodes)-Z_3d_n_fc(nlz ,elnodes) + dx20 = Z_3d_n_fc(nlz+1,elnodes)-Z_3d_n_fc(nlz-1,elnodes) !!PS f0 = density_m_rho0(nlz-1,elnodes) !!PS df10 = density_m_rho0(nlz ,elnodes)-density_m_rho0(nlz-1,elnodes) @@ -3054,15 +3191,15 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) !___________________________________________________________________ ! interpoalte vertice temp and salinity to elemental level Z_n temp_at_Zn = t0 & - + dt10/dx10*(Z_n(nlz)-Z_3d_n(nlz-1,elnodes)) & + + dt10/dx10*(Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes)) & + (dx10*dt21-dx21*dt10)/(dx20*dx21*dx10)* & - ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n(nlz,elnodes))*& - ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n(nlz-1,elnodes)) + ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n_fc(nlz,elnodes))*& + ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes)) salt_at_Zn = s0 & - + ds10/dx10*(Z_n(nlz)-Z_3d_n(nlz-1,elnodes)) & + + ds10/dx10*(Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes)) & + (dx10*ds21-dx21*ds10)/(dx20*dx21*dx10)* & - ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n(nlz,elnodes))*& - ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n(nlz-1,elnodes)) + ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n_fc(nlz,elnodes))*& + ((/1.0_WP,1.0_WP,1.0_WP/)*Z_n(nlz)-Z_3d_n_fc(nlz-1,elnodes)) !___________________________________________________________________ ! compute density from state equation select case(state_equation) @@ -3089,14 +3226,14 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) !___________________________________________________________________ ! zonal gradients drho_dx = sum(gradient_sca(1:3,elem)*rho_at_Zn) - aux_sum = drho_dx*helem(nlz,elem)*g/density_0 + aux_sum = drho_dx*helem_fc(nlz,elem)*g/density_0 pgf_x(nlz,elem) = int_dp_dx(1) + aux_sum*0.5_WP int_dp_dx(1) = int_dp_dx(1) + aux_sum !___________________________________________________________________ ! meridional gradients drho_dy = sum(gradient_sca(4:6,elem)*rho_at_Zn) - aux_sum = drho_dy*helem(nlz,elem)*g/density_0 + aux_sum = drho_dy*helem_fc(nlz,elem)*g/density_0 pgf_y(nlz,elem) = int_dp_dx(2) + aux_sum*0.5_WP int_dp_dx(2) = int_dp_dx(2) + aux_sum end do ! --> do nlz=2,nle-1 @@ -3149,7 +3286,7 @@ subroutine pressure_force_4_zxxxx_easypgf_fullbc(tracers, partit, mesh) end do ! --> do elem=1, myDim_elem2D !$OMP END DO !$OMP END PARALLEL -end subroutine pressure_force_4_zxxxx_easypgf_fullbc +end subroutine pressure_force_4_zxxxx_easypgf_fc ! ! ! @@ -3403,7 +3540,8 @@ subroutine sw_alpha_beta(TF1,SF1, partit, mesh) t1 = TF1(nz,n)*1.00024_WP s1 = SF1(nz,n) !!PS p1 = abs(Z(nz)) - p1 = abs(Z_3d_n(nz,n)) +!PS p1 = abs(Z_3d_n(nz,n)) + p1 = abs(Z_3d_n_fc(nz,n)) t1_2 = t1*t1 t1_3 = t1_2*t1 @@ -3705,7 +3843,7 @@ subroutine init_ref_density(partit, mesh) density_ref(:, node) = 0.0_WP nzmin = 1 nzmax = nlevels_nod2d(node)-1 - auxz=min(0.0,Z_3d_n(nzmin,node)) + auxz=min(0.0,Z_3d_n_fc(nzmin,node)) !_______________________________________________________________________ call densityJM_components(density_ref_T, density_ref_S, bulk_0, bulk_pz, bulk_pz2, rhopot, partit, mesh) @@ -3714,7 +3852,7 @@ subroutine init_ref_density(partit, mesh) !_______________________________________________________________________ do nz=nzmin+1,nzmax - auxz=Z_3d_n(nz,node) + auxz=Z_3d_n_fc(nz,node) rho = bulk_0 + auxz*bulk_pz + auxz*bulk_pz2 density_ref(nz,node) = rho*rhopot/(rho+0.1_WP*auxz) end do diff --git a/src/oce_ale_vel_rhs.F90 b/src/oce_ale_vel_rhs.F90 index 1ec929fe5..11a53b99b 100644 --- a/src/oce_ale_vel_rhs.F90 +++ b/src/oce_ale_vel_rhs.F90 @@ -159,6 +159,7 @@ subroutine compute_vel_rhs(ice, dynamics, partit, mesh) call par_ex(partit%MPI_COMM_FESOM, partit%mype, 1) elseif (dynamics%momadv_opt==2) then call momentum_adv_scalar(dynamics, partit, mesh) +!PS call momentum_adv_scalar_test(dynamics, partit, mesh) end if !___________________________________________________________________________ ! Update the rhs @@ -428,6 +429,261 @@ subroutine momentum_adv_scalar(dynamics, partit, mesh) !$OMP END DO !$OMP END PARALLEL end subroutine momentum_adv_scalar +! +! Momentum advection on scalar control volumes with ALE adaption--> exchange zinv(nz) +! against hnode(nz,node) +!_______________________________________________________________________________ +subroutine momentum_adv_scalar_test(dynamics, partit, mesh) + USE MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + use MOD_DYN + USE o_PARAM + use g_comm_auto + IMPLICIT NONE + type(t_dyn) , intent(inout), target :: dynamics + type(t_partit), intent(inout), target :: partit + type(t_mesh) , intent(in) , target :: mesh + !___________________________________________________________________________ + integer :: n, nz, el1, el2 + integer :: nl1, nl2, ul1, ul2, nod(2), el, ed, k, nle, ule + real(kind=WP) :: un1(1:mesh%nl-1), un2(1:mesh%nl-1) + real(kind=WP) :: wu(1:mesh%nl), wv(1:mesh%nl) + !___________________________________________________________________________ + ! pointer on necessary derived types + real(kind=WP), dimension(:,:,:), pointer :: UV, UV_rhsAB, UVnode_rhs + real(kind=WP), dimension(:,:) , pointer :: Wvel_e +#include "associate_part_def.h" +#include "associate_mesh_def.h" +#include "associate_part_ass.h" +#include "associate_mesh_ass.h" + UV =>dynamics%uv(:,:,:) + UV_rhsAB =>dynamics%uv_rhsAB(:,:,:) + UVnode_rhs=>dynamics%work%uvnode_rhs(:,:,:) + Wvel_e =>dynamics%w_e(:,:) + + !___________________________________________________________________________ + ! Use Gauss -Theorem to compute advection operator (v_vec*div)*v_vec + ! + ! --> Int( div*F_vec )dV = Sum( F_vec + n_vec * dA) + ! + !___________________________________________________________________________ + ! 1st. compute vertical momentum advection component: w*du/dz, w*dv/dz +!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(n, nz, el1, el2, nl1, nl2, ul1, ul2, nod, el, ed, k, nle, ule, un1, un2, wu, wv) +!$OMP DO + do n=1,myDim_nod2d + nl1 = nlevels_nod2D(n)-1 + ul1 = ulevels_nod2D(n) + wu(1:nl1+1) = 0._WP + wv(1:nl1+1) = 0._WP + + !_______________________________________________________________________ + ! loop over adjacent elements of vertice n + do k=1,nod_in_elem2D_num(n) + el = nod_in_elem2D(k,n) + !___________________________________________________________________ + nle = nlevels(el)-1 + ule = ulevels(el) + + !___________________________________________________________________ + ! accumulate horizontal velocities at full depth levels (top and + ! bottom faces of prism) + ! account here also for boundary condition below cavity --> + ! horizontal velocity at cavity-ocean interce ule (if ule>1) must be + ! zero ??? + if (ule==1) then + wu(ule) = wu(ule) + UV(1, ule, el)*elem_area(el) + wv(ule) = wv(ule) + UV(2, ule, el)*elem_area(el) + end if + + ! interpolate horizontal velocity from mid-depth levels to full + ! depth levels of upper and lower prism faces and average over adjacent + ! elements of vertice n + wu(ule+1:nle) = wu(ule+1:nle) + 0.5_WP*(UV(1, ule+1:nle, el)+UV(1, ule:nle-1, el))*elem_area(el) + wv(ule+1:nle) = wv(ule+1:nle) + 0.5_WP*(UV(2, ule+1:nle, el)+UV(2, ule:nle-1, el))*elem_area(el) + enddo + + !_______________________________________________________________________ + ! multiply w*du and w*dv + wu(ul1:nl1) = wu(ul1:nl1)*Wvel_e(ul1:nl1, n) + wv(ul1:nl1) = wv(ul1:nl1)*Wvel_e(ul1:nl1, n) + + !_______________________________________________________________________ + ! compute w*du/dz, w*dv/dz + do nz=ul1,nl1 + ! Here 1/3 because 1/3 of the area is related to the node --> comes from + ! averaging the elemental velocities + UVnode_rhs(1,nz,n) = - (wu(nz) - wu(nz+1) ) / (3._WP*hnode(nz, n)) + UVnode_rhs(2,nz,n) = - (wv(nz) - wv(nz+1) ) / (3._WP*hnode(nz, n)) + + enddo + + !_______________________________________________________________________ + ! To get a clean checksum, set the remaining values to zero + UVnode_rhs(1:2, nl1+1:nl-1 , n) = 0._WP + UVnode_rhs(1:2, 1:ul1-1, n) = 0._WP + end do +!$OMP END DO + + !___________________________________________________________________________ + ! 2nd. compute horizontal advection component: u*du/dx, u*dv/dx & v*du/dy, v*dv/dy + ! loop over triangle edges +!$OMP DO + do ed=1, myDim_edge2D + nod = edges(:,ed) + el1 = edge_tri(1,ed) + el2 = edge_tri(2,ed) + ul1 = ulevels(el1) + nl1 = nlevels(el1)-1 + + !_______________________________________________________________________ + ! compute horizontal normal velocity with respect to the edge from triangle + ! centroid towards triangel edge mid-pointe for element el1 + ! .o. + ! ./ \. + ! ./ el1 \. + ! ./ x \. + ! ./ |-------\.-----------------edge_cross_dxdy(1:2,ed) --> (dx,dy) + ! / |->n_vec \ + ! nod(1) o----------O----------o nod(2) + ! \. |->n_vec ./ + ! \. |------./------------------edge_cross_dxdy(3:4,ed) --> (dx,dy) + ! \. x ./ + ! \. el2 ./ + ! \. ./ + ! ° + un1(ul1:nl1) = ( UV(2, ul1:nl1, el1)*edge_cross_dxdy(1, ed) & + - UV(1, ul1:nl1, el1)*edge_cross_dxdy(2, ed) ) * helem(ul1:nl1, el1) + + !_______________________________________________________________________ + ! compute horizontal normal velocity with respect to the edge from triangle + ! centroid towards triangel edge mid-pointe for element el2 when it is valid + ! --> if its a boundary triangle el2 will be not valid + if (el2>0) then ! --> el2 is valid element + nl2 = nlevels(el2)-1 + ul2 = ulevels(el2) + + un2(ul2:nl2) = ( - UV(2, ul2:nl2, el2)*edge_cross_dxdy(3, ed) & + + UV(1, ul2:nl2, el2)*edge_cross_dxdy(4, ed) ) * helem(ul1:nl1, el2) + + ! fill with zeros to combine the loops + ! Usually, no or only a very few levels have to be filled. In this case, + ! computing "zeros" is cheaper than the loop overhead. + un1(nl1+1:max(nl1,nl2)) = 0._WP + un2(nl2+1:max(nl1,nl2)) = 0._WP + un1(1:ul1-1) = 0._WP + un2(1:ul2-1) = 0._WP + +#if defined(__openmp_reproducible) +!$OMP ORDERED +#endif + + ! first edge node + ! Do not calculate on Halo nodes, as the result will not be used. + ! The "if" is cheaper than the avoided computiations. + if (nod(1) <= myDim_nod2d) then +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(nod(1))) +#endif + do nz=min(ul1,ul2), max(nl1,nl2) + ! add w*du/dz+(u*du/dx+v*du/dy) & w*dv/dz+(u*dv/dx+v*dv/dy) + UVnode_rhs(1, nz, nod(1)) = UVnode_rhs(1, nz, nod(1)) + (un1(nz)*UV(1, nz, el1) + un2(nz)*UV(1, nz, el2))/hnode(nz, nod(1)) + UVnode_rhs(2, nz, nod(1)) = UVnode_rhs(2, nz, nod(1)) + (un1(nz)*UV(2, nz, el1) + un2(nz)*UV(2, nz, el2))/hnode(nz, nod(1)) + end do +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(nod(1))) +#endif + endif ! --> if (nod(1) <= myDim_nod2d) then + + ! second edge node + if (nod(2) <= myDim_nod2d) then +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(nod(2))) +#endif + do nz=min(ul1,ul2), max(nl1,nl2) + ! add w*du/dz+(u*du/dx+v*du/dy) & w*dv/dz+(u*dv/dx+v*dv/dy) + UVnode_rhs(1, nz, nod(2)) = UVnode_rhs(1, nz, nod(2)) - (un1(nz)*UV(1, nz, el1) + un2(nz)*UV(1, nz, el2))/hnode(nz, nod(2)) + UVnode_rhs(2, nz, nod(2)) = UVnode_rhs(2, nz, nod(2)) - (un1(nz)*UV(2, nz, el1) + un2(nz)*UV(2, nz, el2))/hnode(nz, nod(2)) + end do +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(nod(2))) +#endif + endif ! --> if (nod(2) <= myDim_nod2d) then + + !_______________________________________________________________________ + ! el2 is not a valid element --> ed is a boundary edge, there is only + ! the contribution from el1 + else + ! first edge node + if (nod(1) <= myDim_nod2d) then +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(nod(1))) +#endif + do nz=ul1, nl1 + ! add w*du/dz+(u*du/dx+v*du/dy) & w*dv/dz+(u*dv/dx+v*dv/dy) + UVnode_rhs(1, nz, nod(1)) = UVnode_rhs(1, nz, nod(1)) + un1(nz)*UV(1, nz, el1)/hnode(nz, nod(1)) + UVnode_rhs(2, nz, nod(1)) = UVnode_rhs(2, nz, nod(1)) + un1(nz)*UV(2, nz, el1)/hnode(nz, nod(1)) + end do ! --> do nz=ul1, nl1 +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(nod(1))) +#endif + endif ! --> if (nod(1) <= myDim_nod2d) then + + ! second edge node + if (nod(2) <= myDim_nod2d) then +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(nod(2))) +#endif + do nz=ul1, nl1 + ! add w*du/dz+(u*du/dx+v*du/dy) & w*dv/dz+(u*dv/dx+v*dv/dy) + UVnode_rhs(1, nz, nod(2)) = UVnode_rhs(1, nz, nod(2)) - un1(nz)*UV(1, nz, el1)/hnode(nz, nod(2)) + UVnode_rhs(2, nz, nod(2)) = UVnode_rhs(2, nz, nod(2)) - un1(nz)*UV(2, nz, el1)/hnode(nz, nod(2)) + end do ! --> do nz=ul1, nl1 +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(nod(2))) +#endif + endif ! --> if (nod(2) <= myDim_nod2d) then + endif ! --> if (el2>0) then +#if defined(__openmp_reproducible) +!$OMP END ORDERED +#endif + end do ! --> do ed=1, myDim_edge2D +!$OMP END DO + + !___________________________________________________________________________ + ! divide total nodal advection by scalar area +!$OMP DO + do n=1,myDim_nod2d + nl1 = nlevels_nod2D(n)-1 + ul1 = ulevels_nod2D(n) + UVnode_rhs(1, ul1:nl1,n) = UVnode_rhs(1, ul1:nl1,n) * areasvol_inv(ul1:nl1, n) + UVnode_rhs(2, ul1:nl1,n) = UVnode_rhs(2, ul1:nl1,n) * areasvol_inv(ul1:nl1, n) + end do !-->do n=1,myDim_nod2d +!$OMP END DO + + !___________________________________________________________________________ +!$OMP MASTER + call exchange_nod(UVnode_rhs, partit) +!$OMP END MASTER +!$OMP BARRIER + + !___________________________________________________________________________ + ! convert total nodal advection from vertice --> elements +!$OMP DO + do el=1, myDim_elem2D + nl1 = nlevels(el)-1 + ul1 = ulevels(el) + UV_rhsAB(1:2,ul1:nl1,el) = UV_rhsAB(1:2,ul1:nl1,el) & + + ( UVnode_rhs(1:2, ul1:nl1, elem2D_nodes(1,el)) & + + UVnode_rhs(1:2, ul1:nl1, elem2D_nodes(2,el)) & + + UVnode_rhs(1:2, ul1:nl1, elem2D_nodes(3,el)) & + )*elem_area(el) / 3.0_WP + + end do ! --> do el=1, myDim_elem2D +!$OMP END DO +!$OMP END PARALLEL +end subroutine momentum_adv_scalar_test + ! =================================================================== diff --git a/src/oce_dyn.F90 b/src/oce_dyn.F90 index 928520965..19b127c24 100755 --- a/src/oce_dyn.F90 +++ b/src/oce_dyn.F90 @@ -198,7 +198,10 @@ subroutine viscosity_filter(option, dynamics, partit, mesh) SELECT CASE (option) CASE (5) if (flag_debug .and. partit%mype==0) print *, achar(27)//'[37m'//' --> call visc_filt_bcksct'//achar(27)//'[0m' - call visc_filt_bcksct(dynamics, partit, mesh) +!PS call visc_filt_bcksct(dynamics, partit, mesh) +!PS call visc_filt_bcksct_test(dynamics, partit, mesh) +!PS call visc_filt_bcksct_test2(dynamics, partit, mesh) + call visc_filt_bcksct_test3(dynamics, partit, mesh) CASE (6) if (flag_debug .and. partit%mype==0) print *, achar(27)//'[37m'//' --> call visc_filt_bilapl'//achar(27)//'[0m' call visc_filt_bilapl(dynamics, partit, mesh) @@ -350,6 +353,583 @@ end subroutine visc_filt_bcksct ! ! !_______________________________________________________________________________ +SUBROUTINE visc_filt_bcksct_test(dynamics, partit, mesh) + USE MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + use MOD_DYN + USE o_PARAM + USE g_CONFIG + USE g_comm_auto + IMPLICIT NONE + type(t_dyn) , intent(inout), target :: dynamics + type(t_partit), intent(inout), target :: partit + type(t_mesh) , intent(in) , target :: mesh + !___________________________________________________________________________ + real(kind=8) :: u1, v1, len, vi + integer :: nz, ed, el(2), elnodes(3),k, elem, nzmin, nzmax, nznobot + ! still to be understood but if you allocate these arrays statically the results will be different: + real(kind=8) :: update_u(mesh%nl-1), update_v(mesh%nl-1) + !___________________________________________________________________________ + ! pointer on necessary derived types + real(kind=WP), dimension(:,:,:), pointer :: UV, UV_rhs + real(kind=WP), dimension(:,:) , pointer :: U_c, V_c, U_b, V_b +#include "associate_part_def.h" +#include "associate_mesh_def.h" +#include "associate_part_ass.h" +#include "associate_mesh_ass.h" + UV => dynamics%uv( :,:,:) + UV_rhs => dynamics%uv_rhs(:,:,:) + U_c => dynamics%work%u_c(:,:) + V_c => dynamics%work%v_c(:,:) + U_b => dynamics%work%u_b(:,:) + V_b => dynamics%work%v_b(:,:) + + !___________________________________________________________________________ + ! An analog of harmonic viscosity operator. + ! Same as visc_filt_h, but with the backscatter. + ! Here the contribution from squared velocities is added to the viscosity. + ! The contribution from boundary edges is neglected (free slip). +!$OMP PARALLEL DO + do elem=1, myDim_elem2D+eDim_elem2D + U_b(:, elem) = 0.0_WP + V_b(:, elem) = 0.0_WP + U_c(:, elem) = 0.0_WP + V_c(:, elem) = 0.0_WP + end do +!$OMP END PARALLEL DO + +!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(u1, v1, len, vi, nz, ed, el, elnodes, k, elem, nzmin, nzmax, nznobot, update_u, update_v) +!$OMP DO + do ed=1, myDim_edge2D+eDim_edge2D + + ! no contribution from boundary edges + if(myList_edge2D(ed)>edge2D_in) cycle + + ! local index of element that contribute to edge + el=edge_tri(:,ed) + + ! characteristic length scale + len=sqrt(sum(elem_area(el))) + + nzmax = minval(nlevels(el)) + nzmin = maxval(ulevels(el)) + do nz=nzmin,nzmax-1 + ! compute delta_u und delta_v over edge + u1=UV(1,nz,el(1))-UV(1,nz,el(2)) + v1=UV(2,nz,el(1))-UV(2,nz,el(2)) + + ! compute viscosity over the edge ed: A_hor ~ L * |delta_u^2 = deltav^2| + vi=dt*max(dynamics%visc_gamma0, & + max(dynamics%visc_gamma1*sqrt(u1*u1+v1*v1), & + dynamics%visc_gamma2*(u1*u1+v1*v1)) & + )*len + + ! compute A_hor * vec_v + update_u(nz)=u1*vi + update_v(nz)=v1*vi + end do + + !_______________________________________________________________________ + ! contribution from edge towards center trinagle + ! + !---O---------------------O---------------------O-------- + ! \. ./ \. ./ + ! \. o_ ./ \. o ./ + ! \. \__ ./__ \. ./ + ! \. ./ \_oUb1 \. ./ + ! \. ./ \. ./ + ! ---O.--------edge--------O--- + ! \. ./ + ! \. oUb2 ./ + ! \. ./ + ! \. ./ + ! \. ./ + ! O + ! +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(el(1))) +#else +!$OMP ORDERED +#endif + U_b(nzmin:nzmax-1, el(1))=U_b(nzmin:nzmax-1, el(1))-update_u(nzmin:nzmax-1)/elem_area(el(1)) + V_b(nzmin:nzmax-1, el(1))=V_b(nzmin:nzmax-1, el(1))-update_v(nzmin:nzmax-1)/elem_area(el(1)) +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(el(1))) + call omp_set_lock (partit%plock(el(2))) +#endif + U_b(nzmin:nzmax-1, el(2))=U_b(nzmin:nzmax-1, el(2))+update_u(nzmin:nzmax-1)/elem_area(el(2)) + V_b(nzmin:nzmax-1, el(2))=V_b(nzmin:nzmax-1, el(2))+update_v(nzmin:nzmax-1)/elem_area(el(2)) +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(el(2))) +#else +!$OMP END ORDERED +#endif + end do +!$OMP END DO +!$OMP MASTER + call exchange_elem(U_b, partit) + call exchange_elem(V_b, partit) +!$OMP END MASTER +!$OMP BARRIER + + !___________________________________________________________________________ + ! first: Compute smoothed viscous term first smooth toward nodes and + ! scalar cluster cell +!$OMP DO + DO ed=1, myDim_nod2D + nzmin = ulevels_nod2D(ed) + nzmax = nlevels_nod2D(ed) + DO nz=nzmin, nzmax-1 + vi=0.0_WP + u1=0.0_WP + v1=0.0_WP + DO k=1, nod_in_elem2D_num(ed) + elem=nod_in_elem2D(k,ed) + if(nlevels(elem)-1 < nz .or. nz + ! substract large scale dissipation --> remains with grid scale dissipation +!$OMP DO + do elem=1, myDim_elem2D + elnodes=elem2D_nodes(:,elem) + nzmin = ulevels(elem) + nzmax = nlevels(elem)-1 + + ! determine depth level of element where it verically not touches the + ! bottom topography + nznobot = nzmax-1 + + ! determine the depth level of the element where it is horizontally not + ! in touch with the bottom topography via a vertice, face or an edge + nznobot = min(nznobot, minval(nlevels_nod2D_min(elnodes)-1) - 1) + +!PS do nz=nzmin, nzmax +!PS UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) -dynamics%visc_easybsreturn*sum(U_c(nz,nelem))/3.0_WP +!PS UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) -dynamics%visc_easybsreturn*sum(V_c(nz,nelem))/3.0_WP +!PS end do + + ! reinject energy only in cells that have no contact to the bottom + do nz=nzmin, nznobot + UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) - dynamics%visc_easybsreturn*sum(U_c(nz,elnodes))/3.0_WP + UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) - dynamics%visc_easybsreturn*sum(V_c(nz,elnodes))/3.0_WP + end do + + ! do not insert additionasl energy in the bottom cell + do nz=nznobot+1,nzmax + UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) + UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) + end do + end do +!$OMP END DO +!$OMP END PARALLEL +end subroutine visc_filt_bcksct_test +! +! +!_______________________________________________________________________________ +SUBROUTINE visc_filt_bcksct_test2(dynamics, partit, mesh) + USE MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + use MOD_DYN + USE o_PARAM + USE g_CONFIG + USE g_comm_auto + IMPLICIT NONE + type(t_dyn) , intent(inout), target :: dynamics + type(t_partit), intent(inout), target :: partit + type(t_mesh) , intent(in) , target :: mesh + !___________________________________________________________________________ + real(kind=8) :: u1, v1, len, vi + integer :: nz, ed, el(2), elnodes(3),k, elem, nzmin, nzmax, nznobot + ! still to be understood but if you allocate these arrays statically the results will be different: + real(kind=8) :: update_u(mesh%nl-1), update_v(mesh%nl-1) + !___________________________________________________________________________ + ! pointer on necessary derived types + real(kind=WP), dimension(:,:,:), pointer :: UV, UV_rhs + real(kind=WP), dimension(:,:) , pointer :: U_c, V_c, U_b, V_b +#include "associate_part_def.h" +#include "associate_mesh_def.h" +#include "associate_part_ass.h" +#include "associate_mesh_ass.h" + UV => dynamics%uv( :,:,:) + UV_rhs => dynamics%uv_rhs(:,:,:) + U_c => dynamics%work%u_c(:,:) + V_c => dynamics%work%v_c(:,:) + U_b => dynamics%work%u_b(:,:) + V_b => dynamics%work%v_b(:,:) + + !___________________________________________________________________________ + ! An analog of harmonic viscosity operator. + ! Same as visc_filt_h, but with the backscatter. + ! Here the contribution from squared velocities is added to the viscosity. + ! The contribution from boundary edges is neglected (free slip). +!$OMP PARALLEL DO + do elem=1, myDim_elem2D+eDim_elem2D + U_b(:, elem) = 0.0_WP + V_b(:, elem) = 0.0_WP + U_c(:, elem) = 0.0_WP + V_c(:, elem) = 0.0_WP + end do +!$OMP END PARALLEL DO + +!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(u1, v1, len, vi, nz, ed, el, elnodes, k, elem, nzmin, nzmax, nznobot, update_u, update_v) +!$OMP DO + do ed=1, myDim_edge2D+eDim_edge2D + + ! no contribution from boundary edges + if(myList_edge2D(ed)>edge2D_in) cycle + + ! local index of element that contribute to edge + el=edge_tri(:,ed) + + ! characteristic length scale + len=sqrt(sum(elem_area(el))) + + nzmax = minval(nlevels(el)) + nzmin = maxval(ulevels(el)) + do nz=nzmin,nzmax-1 + ! compute delta_u und delta_v over edge + u1=UV(1,nz,el(1))-UV(1,nz,el(2)) + v1=UV(2,nz,el(1))-UV(2,nz,el(2)) + + ! compute viscosity over the edge ed: A_hor ~ L * |delta_u^2 = deltav^2| + vi=dt*max(dynamics%visc_gamma0, & + max(dynamics%visc_gamma1*sqrt(u1*u1+v1*v1), & + dynamics%visc_gamma2*(u1*u1+v1*v1)) & + )*len + + ! compute A_hor * vec_v + update_u(nz)=u1*vi + update_v(nz)=v1*vi + end do + + !_______________________________________________________________________ + ! contribution from edge towards center trinagle + ! + !---O---------------------O---------------------O-------- + ! \. ./ \. ./ + ! \. o_ ./ \. o ./ + ! \. \__ ./__ \. ./ + ! \. ./ \_oUb1 \. ./ + ! \. ./ \. ./ + ! ---O.--------edge--------O--- + ! \. ./ + ! \. oUb2 ./ + ! \. ./ + ! \. ./ + ! \. ./ + ! O + ! +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(el(1))) +#else +!$OMP ORDERED +#endif + U_b(nzmin:nzmax-1, el(1))=U_b(nzmin:nzmax-1, el(1))-update_u(nzmin:nzmax-1)/elem_area(el(1)) + V_b(nzmin:nzmax-1, el(1))=V_b(nzmin:nzmax-1, el(1))-update_v(nzmin:nzmax-1)/elem_area(el(1)) +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(el(1))) + call omp_set_lock (partit%plock(el(2))) +#endif + U_b(nzmin:nzmax-1, el(2))=U_b(nzmin:nzmax-1, el(2))+update_u(nzmin:nzmax-1)/elem_area(el(2)) + V_b(nzmin:nzmax-1, el(2))=V_b(nzmin:nzmax-1, el(2))+update_v(nzmin:nzmax-1)/elem_area(el(2)) +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(el(2))) +#else +!$OMP END ORDERED +#endif + end do +!$OMP END DO +!$OMP MASTER + call exchange_elem(U_b, partit) + call exchange_elem(V_b, partit) +!$OMP END MASTER +!$OMP BARRIER + + !___________________________________________________________________________ + ! first: Compute smoothed viscous term first smooth toward nodes and + ! scalar cluster cell +!$OMP DO + DO ed=1, myDim_nod2D + nzmin = ulevels_nod2D(ed) + nzmax = nlevels_nod2D(ed) + DO nz=nzmin, nzmax-1 + vi=0.0_WP + u1=0.0_WP + v1=0.0_WP + DO k=1, nod_in_elem2D_num(ed) + elem=nod_in_elem2D(k,ed) + if(nlevels(elem)-1 < nz .or. nz + ! substract large scale dissipation --> remains with grid scale dissipation +!$OMP DO + do elem=1, myDim_elem2D + elnodes=elem2D_nodes(:,elem) + nzmin = ulevels(elem) + nzmax = nlevels(elem)-1 + +!PS ! determine depth level of element where it verically not touches the +!PS ! bottom topography +!PS nznobot = nzmax-1 +!PS +!PS ! determine the depth level of the element where it is horizontally not +!PS ! in touch with the bottom topography via a vertice, face or an edge +!PS nznobot = min(nznobot, minval(nlevels_nod2D_min(elnodes)-1) - 1) + + do nz=nzmin, nzmax + vi=0.0_WP + u1=0.0_WP + v1=0.0_WP + do k=1, 3 + vi=vi + area(nz, elnodes(k)) * hnode(nz, elnodes(k)) + u1=u1 + U_c( nz, elnodes(k)) * area(nz, elnodes(k)) * hnode(nz, elnodes(k)) + v1=v1 + V_c( nz, elnodes(k)) * area(nz, elnodes(k)) * hnode(nz, elnodes(k)) + end do + u1 = u1/vi + v1 = v1/vi + UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) - dynamics%visc_easybsreturn*u1/3.0_WP + UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) - dynamics%visc_easybsreturn*v1/3.0_WP + end do + +!PS ! reinject energy only in cells that have no contact to the bottom +!PS do nz=nzmin, nznobot +!PS UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) - dynamics%visc_easybsreturn*sum(U_c(nz,elnodes))/3.0_WP +!PS UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) - dynamics%visc_easybsreturn*sum(V_c(nz,elnodes))/3.0_WP +!PS end do +!PS +!PS ! do not insert additionasl energy in the bottom cell +!PS do nz=nznobot+1,nzmax +!PS UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) +!PS UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) +!PS end do + end do +!$OMP END DO +!$OMP END PARALLEL +end subroutine visc_filt_bcksct_test2 +! +! +!_______________________________________________________________________________ +SUBROUTINE visc_filt_bcksct_test3(dynamics, partit, mesh) + USE MOD_MESH + USE MOD_PARTIT + USE MOD_PARSUP + use MOD_DYN + USE o_PARAM + USE g_CONFIG + USE g_comm_auto + IMPLICIT NONE + type(t_dyn) , intent(inout), target :: dynamics + type(t_partit), intent(inout), target :: partit + type(t_mesh) , intent(in) , target :: mesh + !___________________________________________________________________________ + real(kind=8) :: u1, v1, h1, len, vi + integer :: nz, ed, el(2), elnodes(3),k, elem, nzmin, nzmax, nznobot + ! still to be understood but if you allocate these arrays statically the results will be different: + real(kind=8) :: update_u(mesh%nl-1), update_v(mesh%nl-1) + !___________________________________________________________________________ + ! pointer on necessary derived types + real(kind=WP), dimension(:,:,:), pointer :: UV, UV_rhs + real(kind=WP), dimension(:,:) , pointer :: U_c, V_c, U_b, V_b +#include "associate_part_def.h" +#include "associate_mesh_def.h" +#include "associate_part_ass.h" +#include "associate_mesh_ass.h" + UV => dynamics%uv( :,:,:) + UV_rhs => dynamics%uv_rhs(:,:,:) + U_c => dynamics%work%u_c(:,:) + V_c => dynamics%work%v_c(:,:) + U_b => dynamics%work%u_b(:,:) + V_b => dynamics%work%v_b(:,:) + + !___________________________________________________________________________ + ! An analog of harmonic viscosity operator. + ! Same as visc_filt_h, but with the backscatter. + ! Here the contribution from squared velocities is added to the viscosity. + ! The contribution from boundary edges is neglected (free slip). +!$OMP PARALLEL DO + do elem=1, myDim_elem2D+eDim_elem2D + U_b(:, elem) = 0.0_WP + V_b(:, elem) = 0.0_WP + U_c(:, elem) = 0.0_WP + V_c(:, elem) = 0.0_WP + end do +!$OMP END PARALLEL DO + +!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(u1, v1, h1, len, vi, nz, ed, el, elnodes, k, elem, nzmin, nzmax, nznobot, update_u, update_v) +!$OMP DO + do ed=1, myDim_edge2D+eDim_edge2D + + ! no contribution from boundary edges + if(myList_edge2D(ed)>edge2D_in) cycle + + ! local index of element that contribute to edge + el=edge_tri(:,ed) + + ! characteristic length scale + len=sqrt(sum(elem_area(el))) + + nzmax = minval(nlevels(el)) + nzmin = maxval(ulevels(el)) + do nz=nzmin,nzmax-1 + ! compute delta_u und delta_v over edge + u1=UV(1,nz,el(1))-UV(1,nz,el(2)) + v1=UV(2,nz,el(1))-UV(2,nz,el(2)) + h1= (helem(nz, el(1)) + helem(nz, el(2))) * 0.5_WP + ! compute viscosity over the edge ed: A_hor ~ L * |delta_u^2 = deltav^2| + vi=dt*max(dynamics%visc_gamma0, & + max(dynamics%visc_gamma1*sqrt(u1*u1+v1*v1), & + dynamics%visc_gamma2*(u1*u1+v1*v1)) & + )*len + + ! compute A_hor * vec_v + update_u(nz)=u1*vi*h1 + update_v(nz)=v1*vi*h1 + end do + + !_______________________________________________________________________ + ! contribution from edge towards center trinagle + ! + !---O---------------------O---------------------O-------- + ! \. ./ \. ./ + ! \. o_ ./ \. o ./ + ! \. \__ ./__ \. ./ + ! \. ./ \_oUb1 \. ./ + ! \. ./ \. ./ + ! ---O.--------edge--------O--- + ! \. ./ + ! \. oUb2 ./ + ! \. ./ + ! \. ./ + ! \. ./ + ! O + ! +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_set_lock(partit%plock(el(1))) +#else +!$OMP ORDERED +#endif + U_b(nzmin:nzmax-1, el(1))=U_b(nzmin:nzmax-1, el(1))-update_u(nzmin:nzmax-1)/elem_area(el(1)) + V_b(nzmin:nzmax-1, el(1))=V_b(nzmin:nzmax-1, el(1))-update_v(nzmin:nzmax-1)/elem_area(el(1)) +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(el(1))) + call omp_set_lock (partit%plock(el(2))) +#endif + U_b(nzmin:nzmax-1, el(2))=U_b(nzmin:nzmax-1, el(2))+update_u(nzmin:nzmax-1)/elem_area(el(2)) + V_b(nzmin:nzmax-1, el(2))=V_b(nzmin:nzmax-1, el(2))+update_v(nzmin:nzmax-1)/elem_area(el(2)) +#if defined(_OPENMP) && !defined(__openmp_reproducible) + call omp_unset_lock(partit%plock(el(2))) +#else +!$OMP END ORDERED +#endif + end do +!$OMP END DO +!$OMP MASTER + call exchange_elem(U_b, partit) + call exchange_elem(V_b, partit) +!$OMP END MASTER +!$OMP BARRIER + + !___________________________________________________________________________ + ! first: Compute smoothed viscous term first smooth toward nodes and + ! scalar cluster cell +!$OMP DO + DO ed=1, myDim_nod2D + nzmin = ulevels_nod2D(ed) + nzmax = nlevels_nod2D(ed) + DO nz=nzmin, nzmax-1 + vi=0.0_WP + u1=0.0_WP + v1=0.0_WP + DO k=1, nod_in_elem2D_num(ed) + elem=nod_in_elem2D(k,ed) + if(nlevels(elem)-1 < nz .or. nz + ! substract large scale dissipation --> remains with grid scale dissipation +!$OMP DO + do elem=1, myDim_elem2D + elnodes=elem2D_nodes(:,elem) + nzmin = ulevels(elem) + nzmax = nlevels(elem)-1 + +!PS ! determine depth level of element where it verically not touches the +!PS ! bottom topography +!PS nznobot = nzmax-1 +!PS +!PS ! determine the depth level of the element where it is horizontally not +!PS ! in touch with the bottom topography via a vertice, face or an edge +!PS nznobot = min(nznobot, minval(nlevels_nod2D_min(elnodes)-1) - 1) + + do nz=nzmin, nzmax + UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+(U_b(nz,elem) - dynamics%visc_easybsreturn*sum(U_c(nz,elnodes))/3.0_WP)/helem(nz,elem) + UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+(V_b(nz,elem) - dynamics%visc_easybsreturn*sum(V_c(nz,elnodes))/3.0_WP)/helem(nz,elem) + end do + +!PS ! reinject energy only in cells that have no contact to the bottom +!PS do nz=nzmin, nznobot +!PS UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) - dynamics%visc_easybsreturn*sum(U_c(nz,elnodes))/3.0_WP +!PS UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) - dynamics%visc_easybsreturn*sum(V_c(nz,elnodes))/3.0_WP +!PS end do +!PS +!PS ! do not insert additionasl energy in the bottom cell +!PS do nz=nznobot+1,nzmax +!PS UV_rhs(1,nz,elem)=UV_rhs(1,nz,elem)+U_b(nz,elem) +!PS UV_rhs(2,nz,elem)=UV_rhs(2,nz,elem)+V_b(nz,elem) +!PS end do + end do +!$OMP END DO +!$OMP END PARALLEL +end subroutine visc_filt_bcksct_test3 +! +! +!_______________________________________________________________________________ ! Strictly energy dissipative and momentum conserving version ! Viscosity depends on velocity Laplacian, i.e., on an analog of ! the Leith viscosity (Lapl==second derivatives) diff --git a/src/oce_mesh.F90 b/src/oce_mesh.F90 index 653785313..ecf00ca79 100755 --- a/src/oce_mesh.F90 +++ b/src/oce_mesh.F90 @@ -2849,8 +2849,4 @@ subroutine check_total_volume(partit, mesh) write(*,*) ' > Total ocean volume elem:', vol_e, ' m^3' end if - end subroutine check_total_volume -! -! -!_______________________________________________________________________________ diff --git a/src/oce_muscl_adv.F90 b/src/oce_muscl_adv.F90 index 2a1270f7f..5989a5491 100755 --- a/src/oce_muscl_adv.F90 +++ b/src/oce_muscl_adv.F90 @@ -523,3 +523,225 @@ SUBROUTINE fill_up_dn_grad(twork, partit, mesh) !$OMP END DO !$OMP END PARALLEL END SUBROUTINE fill_up_dn_grad +! +! +!_______________________________________________________________________________ +SUBROUTINE fill_up_dn_grad_test(twork, partit, mesh) +! ttx, tty elemental gradient of tracer +USE o_PARAM +USE MOD_MESH +USE MOD_PARTIT +USE MOD_PARSUP +USE MOD_TRACER +USE o_ARRAYS +IMPLICIT NONE +integer :: edge, nz, k +integer :: elem, elem1, ednodes(2), edelems(2), nzmin, nzmax, ednzmin, ednzmax +real(kind=WP) :: tvol, tx, ty +type(t_mesh), intent(in), target :: mesh +type(t_partit), intent(inout), target :: partit +type(t_tracer_work), intent(inout), target :: twork +#include "associate_part_def.h" +#include "associate_mesh_def.h" +#include "associate_part_ass.h" +#include "associate_mesh_ass.h" + !___________________________________________________________________________ + ! loop over edge segments +!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(edge, nz, edelems, elem, ednzmin, ednzmax, nzmin, nzmax) +!$OMP DO + do edge=1, myDim_edge2D + ! local index of element that contribute to edge + edelems=edge_tri(:,edge) + ednodes=edges(:,edge) + !_______________________________________________________________________ + ! estimate at which levels edge exists + ! O + ! ./ \. + ! ./ \. + ! ./ \. + ! ./ o<-----\.-------------triangle indice edelems(1) + ! ./ \. + ! ---------O.--------edge--------O------------- + ! \. ./ + ! \. o<-----./-------------triangle indice edelems(2) + ! \. ./ + ! \. ./ + ! \. ./ + ! O + ! edge exist at certain depth level only if one of the elements el(1) or + ! el(2) exist at this depth level. + + ! upper/lower level of elemts that contribute to edge at lest one of these + ! triangles has to exist at at a certain depth level, so that this edge + ! can exist at this depth level + ednzmin = ulevels(edelems(1)) + ednzmax = nlevels(edelems(1))-1 + if (edelems(2)>0) then ! --> if el(2)==0 than edge is boundary edge + ednzmin = min(ednzmin, ulevels(edelems(2)) ) + ednzmax = max(ednzmax, nlevels(edelems(2))-1) + end if + + ! + ! + !_______________________________________________________________________ + !############################# UPWIND TRIANGLE ######################### + !case when edge has upwind triangle + elem = twork%edge_up_dn_tri(1,edge) + if (elem .ne. 0.0_WP) then ! --> edge upwind triangle exist + nzmin = max(ednzmin, ulevels(elem) ) + nzmax = min(ednzmax, nlevels(elem)-1) + + !___________________________________________________________________ + ! edge exists above the level of the upwind triangle + ! reconstruct tracer gradient from adjacent triangles towards + ! edge node 1 + do nz=ednzmin, ulevels(elem)-1 + tvol=0.0_WP + tx =0.0_WP + ty =0.0_WP + do k=1, nod_in_elem2D_num(ednodes(1)) + elem1=nod_in_elem2D(k,ednodes(1)) + if(nlevels(elem1)-1 < nz .or. nz edge upwind triangle does not exist at all + ! reconstruct tracer gradient from adjacent triangles towards + ! edge node 1 + else + do nz=ednzmin, ednzmax + tvol=0.0_WP + tx =0.0_WP + ty =0.0_WP + do k=1, nod_in_elem2D_num(ednodes(1)) + elem1=nod_in_elem2D(k,ednodes(1)) + if(nlevels(elem1)-1 < nz .or. nz edge downwind triangle exist + nzmin = max(ednzmin, ulevels(elem) ) + nzmax = min(ednzmax, nlevels(elem)-1) + + !___________________________________________________________________ + ! edge exists above the level of the downwind triangle + ! reconstruct tracer gradient from adjacent triangles towards + ! edge node 1 + do nz=ednzmin, ulevels(elem)-1 + tvol=0.0_WP + tx =0.0_WP + ty =0.0_WP + do k=1, nod_in_elem2D_num(ednodes(2)) + elem1=nod_in_elem2D(k,ednodes(2)) + if(nlevels(elem1)-1 < nz .or. nz edge downwind triangle does not exist at all + ! reconstruct tracer gradient from adjacent triangles towards + ! edge node 2 + else + do nz=ednzmin, ednzmax + tvol=0.0_WP + tx =0.0_WP + ty =0.0_WP + do k=1, nod_in_elem2D_num(ednodes(2)) + elem1=nod_in_elem2D(k,ednodes(2)) + if(nlevels(elem1)-1 < nz .or. nz edge=1, myDim_edge2D +!$OMP END DO +!$OMP END PARALLEL +end subroutine fill_up_dn_grad_test + diff --git a/src/oce_tracer_mod.F90 b/src/oce_tracer_mod.F90 index f374ca5d2..e08fe377c 100755 --- a/src/oce_tracer_mod.F90 +++ b/src/oce_tracer_mod.F90 @@ -48,6 +48,7 @@ SUBROUTINE init_tracers_AB(tr_num, tracers, partit, mesh) if (flag_debug .and. partit%mype==0) print *, achar(27)//'[38m'//' --> call fill_up_dn_grad'//achar(27)//'[0m' call fill_up_dn_grad(tracers%work, partit, mesh) +!PS call fill_up_dn_grad_test(tracers%work, partit, mesh) call exchange_nod_end(partit) ! tr_z halos should have arrived by now. if (flag_debug .and. partit%mype==0) print *, achar(27)//'[38m'//' --> call tracer_gradient_elements'//achar(27)//'[0m' diff --git a/src/write_step_info.F90 b/src/write_step_info.F90 index a9c5cfd78..ff980a1e5 100644 --- a/src/write_step_info.F90 +++ b/src/write_step_info.F90 @@ -416,6 +416,16 @@ subroutine check_blowup(istep, ice, dynamics, tracers, partit, mesh) found_blowup_loc=1 write(*,*) '___CHECK FOR BLOW UP___________ --> mstep=',istep write(*,*) ' --STOP--> found temperture becomes NaN or <-5.0, >60' + + + write(*,*) 'zbar_3d_n = ',zbar_3d_n(:,n) + write(*,*) 'zbar_3d_n_fc= ',zbar_3d_n_fc(:,n) + write(*,*) 'Z_3d_n = ',Z_3d_n(:,n) + write(*,*) 'Z_3d_n_fc = ',Z_3d_n_fc(:,n) + write(*,*) 'hnode = ',hnode(:,n) + write(*,*) 'hnode_fc = ',hnode_fc(:,n) + + write(*,*) 'mype = ',mype write(*,*) 'mstep = ',istep write(*,*) 'node = ',n