From 36730a88c0dd34e1f84417d8edca46bca4b8d123 Mon Sep 17 00:00:00 2001 From: Marco de Bruine Date: Tue, 1 Sep 2020 15:02:30 +0200 Subject: [PATCH] Added boundary nudging of scalar fields --- src/modnudgeboundary.f90 | 126 ++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/src/modnudgeboundary.f90 b/src/modnudgeboundary.f90 index 858222dd..01a74712 100644 --- a/src/modnudgeboundary.f90 +++ b/src/modnudgeboundary.f90 @@ -27,14 +27,16 @@ module modnudgeboundary public :: initnudgeboundary, nudgeboundary, exitnudgeboundary save - logical :: lnudge_boundary = .false. ! Switch boundary nudging - logical :: lperturb_boundary = .false. ! Switch perturbation of thl near boundary + logical :: lnudge_boundary = .false. ! Switch boundary nudging of thermodynamics + logical :: lnudge_boundary_sv = .false. ! Switch boundary nudging of scalars + logical :: lperturb_boundary = .false. ! Switch perturbation of thl near boundary logical :: lnudge_w = .true. ! Nudge w to zero or not real, dimension(:,:), allocatable :: nudge_factor ! Nudging factor (0-1) near lateral boundaries real, dimension(:,:), allocatable :: perturb_factor ! Perturbing factor (0-1) near lateral boundaries - real, dimension(:,:,:,:), allocatable :: lbc_u, lbc_v, lbc_thl, lbc_qt ! Input for nudging to external field + real, dimension(:,:,:,:), allocatable :: lbc_u, lbc_v, lbc_thl, lbc_qt ! Input for nudging to external field + real, dimension(:,:,:,:,:), allocatable :: lbc_sv ! Input for nudging scalars to external field ! Boundary nudging settings: real :: nudge_offset=0, nudge_width=0, nudge_radius=0, nudge_tau=-1 @@ -47,6 +49,9 @@ module modnudgeboundary real :: dt_input_lbc=-1 integer :: lbc_index=1 + real :: dt_input_lbc_sv=-1 + integer :: lbc_index_sv=1 + contains @@ -112,17 +117,17 @@ end subroutine calc_weighting_factor subroutine initnudgeboundary use modmpi, only : myid, mpierr, comm3d, mpi_logical, mpi_int, my_real - use modglobal, only : ifnamopt, fname_options, imax, jmax, dx, dy, i1, j1, k1, ih, jh, lwarmstart, kmax, zf, checknamelisterror + use modglobal, only : ifnamopt, fname_options, imax, jmax, dx, dy, i1, j1, k1, ih, jh, lwarmstart, kmax, zf, checknamelisterror, nsv use modboundary, only : boundary implicit none integer :: ierr, k ! Read namelist settings - namelist /NAMNUDGEBOUNDARY/ lnudge_boundary, lperturb_boundary, lnudge_w, & + namelist /NAMNUDGEBOUNDARY/ lnudge_boundary, lnudge_boundary_sv, lperturb_boundary, lnudge_w, & & nudge_offset, nudge_width, nudge_radius, nudge_tau, & & perturb_offset, perturb_width, perturb_radius, perturb_ampl, perturb_zmax, & - & dt_input_lbc, perturb_blocksize + & dt_input_lbc, dt_input_lbc_sv, perturb_blocksize if (myid==0) then open(ifnamopt, file=fname_options, status='old', iostat=ierr) @@ -133,6 +138,7 @@ subroutine initnudgeboundary end if call MPI_BCAST(lnudge_boundary, 1, mpi_logical, 0, comm3d, mpierr) + call MPI_BCAST(lnudge_boundary_sv,1, mpi_logical, 0, comm3d, mpierr) call MPI_BCAST(lperturb_boundary, 1, mpi_logical, 0, comm3d, mpierr) call MPI_BCAST(lnudge_w, 1, mpi_logical, 0, comm3d, mpierr) @@ -150,6 +156,7 @@ subroutine initnudgeboundary call MPI_BCAST(perturb_zmax, 1, my_real, 0, comm3d, mpierr) call MPI_BCAST(dt_input_lbc, 1, my_real, 0, comm3d, mpierr) + call MPI_BCAST(dt_input_lbc_sv, 1, my_real, 0, comm3d, mpierr) if (lnudge_boundary) then if (myid==0) then @@ -168,12 +175,20 @@ subroutine initnudgeboundary allocate( lbc_v (2-ih:i1+ih, 2-jh:j1+jh, k1, 2) ) allocate( lbc_thl(2-ih:i1+ih, 2-jh:j1+jh, k1, 2) ) allocate( lbc_qt (2-ih:i1+ih, 2-jh:j1+jh, k1, 2) ) + if (lnudge_boundary_sv) allocate( lbc_sv (2-ih:i1+ih, 2-jh:j1+jh, k1, nsv, 2) ) ! Read the first two input times call read_new_LBCs(0.) call read_new_LBCs(dt_input_lbc) lbc_index = 1 + if (lnudge_boundary_sv) then + ! Read the first two input times for scalars + call read_new_LBCs_sv(0.) + call read_new_LBCs_sv(dt_input_lbc_sv) + lbc_index_sv = 1 + end if + ! Hack - read full initial 3D field if (.not. lwarmstart) call read_initial_fields @@ -205,14 +220,18 @@ end subroutine initnudgeboundary subroutine read_initial_fields ! BvS - this should really go somewhere else, probably modstartup... - use modfields, only : u0, v0, um, vm, thlm, thl0, qtm, qt0 + use modfields, only : u0, v0, um, vm, thlm, thl0, qtm, qt0, sv0, svm use modsurfdata, only : tskin - use modglobal, only : i1, j1, iexpnr, kmax + use modglobal, only : i1, j1, iexpnr, kmax, nsv use modmpi, only : myidx, myidy implicit none + integer :: isv + character(80) :: input_file = 'lbc000h00m_x___y___.___' + character(80) :: input_file_sv = 'lbcsv000h00m_x___y___.___' + write(input_file(13:15), '(i3.3)') myidx write(input_file(17:19), '(i3.3)') myidy write(input_file(21:23), '(i3.3)') iexpnr @@ -232,6 +251,23 @@ subroutine read_initial_fields thlm (2:i1,2:j1,1:kmax) = thl0 (2:i1,2:j1,1:kmax) qtm (2:i1,2:j1,1:kmax) = qt0 (2:i1,2:j1,1:kmax) + if (lnudge_boundary_sv) then + + write(input_file_sv(15:17), '(i3.3)') myidx + write(input_file_sv(19:21), '(i3.3)') myidy + write(input_file_sv(23:25), '(i3.3)') iexpnr + + print*,'Reading initial field: ', input_file_sv + + open(777, file=input_file_sv, form='unformatted', status='unknown', action='read', access='stream') + do isv = 1,nsv + read(777) sv0(2:i1,2:j1,1:kmax,isv) + end do + close(777) + + svm (2:i1,2:j1,1:kmax,1:nsv) = sv0(2:i1,2:j1,1:kmax,1:nsv) + endif + end subroutine read_initial_fields @@ -277,21 +313,59 @@ subroutine read_new_LBCs(time) end subroutine read_new_LBCs + subroutine read_new_LBCs_sv(time) + + use modglobal, only : i1, j1, iexpnr, kmax, nsv + use modmpi, only : myidx, myidy, nprocx, nprocy + + implicit none + real, intent(in) :: time !< Input: time to read (seconds) + integer :: ihour, imin, isv + + character(80) :: input_file = 'lbcsv___h__m_x___y___.___' + + ! Only the MPI tasks at the domain edges read the LBCs: + if (myidx == 0 .or. myidx == nprocx-1 .or. myidy == 0 .or. myidy == nprocy-1) then + + ! File name to read + ihour = floor(time/3600) + imin = floor((time-ihour*3600)/3600.*60.) + write(input_file( 6: 8), '(i3.3)') ihour + write(input_file(10:11), '(i2.2)') imin + write(input_file(15:17), '(i3.3)') myidx + write(input_file(19:21), '(i3.3)') myidy + write(input_file(23:25), '(i3.3)') iexpnr + + print*,'Processing LBC for scalars: ', input_file + + ! Copy old second time to new first time + lbc_sv(:,:,:,:,1) = lbc_sv(:,:,:,:,2) + + ! Read new LBC for next time + open(777, file=input_file, form='unformatted', status='unknown', action='read', access='stream') + do isv = 1,nsv + read(777) lbc_sv (2:i1,2:j1,1:kmax,isv,2) + end do + close(777) + + end if + + end subroutine read_new_LBCs_sv subroutine nudgeboundary - use modglobal, only : i1, j1, imax, jmax, kmax, rdt, cu, cv, eps1, rtimee - use modfields, only : u0, up, v0, vp, w0, wp, thl0, thlp, qt0, qtp + use modglobal, only : i1, j1, imax, jmax, kmax, rdt, cu, cv, eps1, rtimee, nsv + use modfields, only : u0, up, v0, vp, w0, wp, thl0, thlp, qt0, qtp, sv0, svp use modmpi, only : myidx, myidy, nprocx, nprocy !#ifdef __INTEL_COMPILER -!use ifport +use ifport !#endif implicit none - integer :: i, j, k, blocki, blockj, subi, subj - real :: tau_i, perturbation, t0, t1, tfac - real :: lbc_u_int, lbc_v_int, lbc_w_int, lbc_t_int, lbc_q_int + integer :: i, j, k, blocki, blockj, subi, subj, isv + real :: tau_i, perturbation, t0, t1, tfac, tfac_sv + real :: lbc_u_int, lbc_v_int, lbc_w_int, lbc_t_int, lbc_q_int, lbc_sv_int if (lnudge_boundary) then @@ -307,11 +381,25 @@ subroutine nudgeboundary call read_new_LBCs(lbc_index*dt_input_lbc) end if + ! Read new LBC for scalars (if required) + if (lnudge_boundary_sv) then + if (rtimee > lbc_index_sv*dt_input_lbc_sv) then + lbc_index_sv = lbc_index_sv + 1 + call read_new_LBCs_sv(lbc_index_sv*dt_input_lbc_sv) + end if + end if + ! Calculate time interpolation factor t0 = (lbc_index - 1) * dt_input_lbc ! Time of previous boundary t1 = (lbc_index ) * dt_input_lbc ! Time of next boundary tfac = 1.-(rtimee - t0) / (t1 - t0) ! Interpolation factor + if (lnudge_boundary_sv) then + t0 = (lbc_index_sv - 1) * dt_input_lbc_sv ! Time of previous boundary + t1 = (lbc_index_sv ) * dt_input_lbc_sv ! Time of next boundary + tfac_sv = 1.-(rtimee - t0) / (t1 - t0) ! Interpolation factor + end if + if (myidx == 0 .or. myidx == nprocx-1 .or. myidy ==0 .or. myidy == nprocy-1) then do k=1,kmax do j=2,j1 @@ -324,6 +412,13 @@ subroutine nudgeboundary lbc_q_int = tfac * lbc_qt (i,j,k,1) + (1.-tfac) * lbc_qt (i,j,k,2) lbc_w_int = 0. + if (lnudge_boundary_sv) then + do isv = 1,nsv + lbc_sv_int = tfac_sv * lbc_sv (i,j,k,isv,1) + (1.-tfac_sv) * lbc_sv (i,j,k,isv,2) + svp(i,j,k,isv) = svp(i,j,k,isv) + nudge_factor(i,j) * tau_i * (lbc_sv_int - sv0(i,j,k,isv)) + end do + end if + ! Nudge the boundaries up(i,j,k) = up(i,j,k) + nudge_factor(i,j) * tau_i * (lbc_u_int - (u0(i,j,k)+cu)) vp(i,j,k) = vp(i,j,k) + nudge_factor(i,j) * tau_i * (lbc_v_int - (v0(i,j,k)+cv)) @@ -374,7 +469,8 @@ subroutine exitnudgeboundary implicit none if (lnudge_boundary) then deallocate( nudge_factor, lbc_u, lbc_v, lbc_thl, lbc_qt ) - if (lperturb_boundary) deallocate( perturb_factor ) + if (lnudge_boundary_sv) deallocate( lbc_sv ) + if (lperturb_boundary) deallocate( perturb_factor ) end if end subroutine exitnudgeboundary