!= Module acousticmode_std ! ! Authors:: 杉山耕一朗(SUGIYAMA Ko-ichiro) ! Version:: $Id: acousticmode_std.f90,v 1.4 2015/02/19 02:17:22 sugiyama Exp $ ! Tag Name:: $Name: arare5-20160127-2 $ ! Copyright:: Copyright (C) GFD Dennou Club, 2014. All rights reserved. ! License:: See COPYRIGHT[link:../../COPYRIGHT] module acousticmode_std ! ! 音波モードに関する計算ルーチンを束ねたモジュール ! ! 水平 explicit ! 鉛直 implicit ! ! 微分平均モジュールを用いて計算を行う !モジュール読み込み ! use dc_types, only : DP !暗黙の型宣言禁止 ! implicit none !属性の指定 ! private ! 変数の定義 ! real(DP), save :: beta = 0.5d0 !クランクニコルソン法なら 0.5 ! real(DP), save :: beta = 1.0d0 !クランクニコルソン法なら 0.5 !完全陰解法なら 1 real(DP), save :: AlphaH = 0.0d0 !音波減衰項の減衰係数 (水平方向) real(DP), save :: AlphaV = 0.0d0 !音波減衰項の減衰係数 (鉛直方向) real(DP), allocatable, save :: A(:) !係数行列の対角成分 real(DP), allocatable, save :: B(:) !係数行列の上三角部分 real(DP), allocatable, save :: C(:) !係数行列の下三角部分 real(DP), allocatable, save :: AL1(:) !LU 分解の結果 L (1 次元配列) integer, allocatable, save :: IP(:) !部分ピボット交換の情報を格納 real(DP), allocatable, save :: xyr_CpVPTempBZ(:,:,:) !係数行列の計算に用いる配列 real(DP), allocatable, save :: xyr_CpDensVPTempSQBZ(:,:,:) !係数行列の計算に用いる配列 real(DP), allocatable, save :: xyr_DensVPTempBZ(:,:,:) !係数行列の計算に用いる配列 real(DP), allocatable, save :: xyz_VelSoundSQBZ(:,:,:) !係数行列の計算に用いる配列 real(DP), allocatable, save :: xyz_CpDensVPTempSQBZ(:,:,:) !係数行列の計算に用いる配列 character(*), parameter:: module_name = 'acousticmode_std' ! モジュールの名称. ! Module name ! public ! public acousticmode_std_init public acousticmode_std_exp public acousticmode_std_imp contains subroutine acousticmode_std_exp( & & pyz_VelXN, xqz_VelYN, xyr_VelZN, xyz_ExnerN, & !(IN) & xyz_VelDivN, & !(OUT) & pyz_PGrad, pyz_SWF, & !(OUT) & xqz_PGrad, xqz_SWF & !(OUT) & ) ! モジュール呼び出し ! use gridset, only : imin, &! x 方向の配列の下限 & imax, &! x 方向の配列の上限 & jmin, &! y 方向の配列の下限 & jmax, &! y 方向の配列の上限 & kmin, &! z 方向の配列の下限 & kmax, &! z 方向の配列の上限 & nx, ny, nz use constants, only : CpDry ! 乾燥成分の比熱 use basicset, only : pyz_VPTempBZ, &! 基本場の温位 xqz_VPTempBZ ! 基本場の温位 use axesset, only : pyz_xyz, xqz_xyz use xyz_deriv_module, & & only : xyz_dx_pyz, xyz_dy_xqz, xyz_dz_xyr, & & pyz_dx_xyz, xqz_dy_xyz ! 暗黙の型宣言禁止 ! implicit none ! 変数の宣言 ! real(DP), intent(in) :: pyz_VelXN(imin:imax,jmin:jmax,kmin:kmax) real(DP), intent(in) :: xqz_VelYN(imin:imax,jmin:jmax,kmin:kmax) real(DP), intent(in) :: xyr_VelZN(imin:imax,jmin:jmax,kmin:kmax) real(DP), intent(in) :: xyz_ExnerN(imin:imax,jmin:jmax,kmin:kmax) real(DP), intent(out) :: xyz_VelDivN(imin:imax,jmin:jmax,kmin:kmax) real(DP), intent(out) :: pyz_PGrad(1:nx,1:ny,1:nz) real(DP), intent(out) :: xqz_PGrad(1:nx,1:ny,1:nz) real(DP), intent(out) :: pyz_SWF(1:nx,1:ny,1:nz) real(DP), intent(out) :: xqz_SWF(1:nx,1:ny,1:nz) real(DP) :: aaa_tmp(imin:imax,jmin:jmax,kmin:kmax) !------------------------------------------------------------------ ! 速度の収束を計算 ! xyz_VelDivN = & & xyz_dx_pyz( pyz_VelXN ) & & + xyz_dy_xqz( xqz_VelYN ) & & + xyz_dz_xyr( xyr_VelZN ) !------------------------------------------------------------------ ! X 方向 aaa_tmp = + AlphaH * pyz_dx_xyz( xyz_VelDivN ) pyz_SWF = aaa_tmp(1:nx,1:ny,1:nz) aaa_tmp = - CpDry * pyz_VPTempBZ * pyz_dx_xyz( xyz_ExnerN ) pyz_PGrad = aaa_tmp(1:nx,1:ny,1:nz) !------------------------------------------------------------------ ! Y 方向 aaa_tmp = AlphaH * xqz_dy_xyz( xyz_VelDivN ) xqz_SWF = aaa_tmp(1:nx,1:ny,1:nz) aaa_tmp = - CpDry * xqz_VPTempBZ * xqz_dy_xyz( xyz_ExnerN ) xqz_PGrad = aaa_tmp(1:nx,1:ny,1:nz) end subroutine Acousticmode_std_exp !!!------------------------------------------------------------!!! subroutine acousticmode_std_imp( & & pyz_VelXA, xqz_VelYA, xyr_VelZN, xyz_VelDivN, & !(IN) & xyz_ExnerN, & !(IN) & xyr_DVelZDtNl, xyz_DExnerDtNl, xyz_DExnerDtNs, & !(IN) & xyz_ExnerA, & !(OUT) & xyr_PGrad, xyr_SWF & !(OUT) & ) ! ! 陰解法を用いたエクスナー関数/鉛直速度の計算. ! ! モジュールの読み込み ! use dc_types, only : DP use gridset, only : imin, &! x 方向の配列の下限 & imax, &! x 方向の配列の上限 & jmin, &! y 方向の配列の下限 & jmax, &! y 方向の配列の上限 & kmin, &! z 方向の配列の下限 & kmax, &! z 方向の配列の上限 & nx, ny, nz, &! 物理領域の大きさ & nxny ! 物理領域の大きさ (nx * ny) use constants,only : CpDry ! 乾燥成分の比熱 use timeset, only : DelTimeShort use basicset, only : xyz_VPTempBZ, &!基本場の仮温位 xyr_VPTempBZ !基本場の仮温位 use axesset, only : dz, xyr_xyz use xyz_deriv_module, & & only : xyr_dz_xyz, xyz_dz_xyr, xyz_dx_pyz, xyz_dy_xqz ! 暗黙の型宣言禁止 ! implicit none ! 入出力変数 ! real(DP), intent(in) :: pyz_VelXA(imin:imax,jmin:jmax,kmin:kmax) !速度 u [τ+Δτ] real(DP), intent(in) :: xqz_VelYA(imin:imax,jmin:jmax,kmin:kmax) !速度 v [τ+Δτ] real(DP), intent(in) :: xyr_VelZN(imin:imax,jmin:jmax,kmin:kmax) !速度 w [τ] real(DP), intent(in) :: xyz_VelDivN(imin:imax,jmin:jmax,kmin:kmax) !\Div \Dvect{u} real(DP), intent(in) :: xyz_ExnerN(imin:imax,jmin:jmax,kmin:kmax) !無次元圧力 real(DP), intent(in) :: xyr_DVelZDtNl(imin:imax,jmin:jmax,kmin:kmax) !Z 方向の外力項[t] real(DP), intent(in) :: xyz_DExnerDtNl(imin:imax,jmin:jmax,kmin:kmax) !エクスナー関数の外力項[t] real(DP), intent(in) :: xyz_DExnerDtNs(imin:imax,jmin:jmax,kmin:kmax) !エクスナー関数の外力項[t] real(DP), intent(out) :: xyz_ExnerA(imin:imax,jmin:jmax,kmin:kmax) !無次元圧力[τ+Δτ] real(DP), intent(out) :: xyr_PGrad(1:nx,1:ny,1:nz) real(DP), intent(out) :: xyr_SWF(1:nx,1:ny,1:nz) ! 作業変数定義 ! real(DP) :: D(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: E(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: F(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: F0(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: xyr_DExnerDz(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: xyr_DVelDivDz(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: aaa_tmp(imin:imax,jmin:jmax,kmin:kmax) real(DP) :: dt ! 短い時間格子間隔 integer :: INFO ! 解のコンディション integer :: i, j, k real(DP) :: TX(nz,nxny) !解行列を転置したもの character(1),parameter :: TRANS = 'N' !--------------------------------------------------------------- ! Initialize ! xyz_ExnerA = 0.0d0 dt = DelTimeShort !--------------------------------------------------------------- !行列計算のための係数 ! 共通して現れる微分を先に計算 ! xyr_DExnerDZ = xyr_dz_xyz( xyz_ExnerN ) xyr_DVelDivDZ = xyr_dz_xyz( xyz_VelDivN ) E = & & - ( 1.0d0 - beta ) * xyr_DExnerDZ & & + ( & & AlphaV * xyr_DVelDivDZ & & + xyr_DVelZDtNl & & ) & & / xyr_CpVPTempBZ F0 = & & + xyr_DensVPTempBZ & & * ( & & + xyr_VelZN & & - xyr_CpVPTempBZ * ( 1.0d0 - beta) * xyr_DExnerDZ * dt & & + AlphaV * xyr_DVelDivDZ * dt & & + xyr_DVelZDtNl * dt & & ) F = & & - beta * dt & & * xyz_VelSoundSQBZ & & / xyz_CpDensVPTempSQBZ & & * xyz_dz_xyr( F0 ) & & + xyz_DExnerDtNl * dt & & + xyz_DExnerDtNs * dt D = & & + xyz_ExnerN & & - (1.0d0 - beta) * dt & & * xyz_VelSoundSQBZ & & / xyz_CpDensVPTempSQBZ & & * xyz_dz_xyr( xyr_DensVPTempBZ * xyr_VelZN ) & & - xyz_VelSoundSQBZ * dt & & / (CpDry * xyz_VPTempBZ ) & & * ( xyz_dx_pyz( pyz_VelXA ) + xyz_dy_xqz( xqz_VelYA ) ) & & + F D(:,:,1) = & & + D(:,:,1) & & - beta * (dt * dt) & & * xyz_VelSoundSQBZ(:,:,1) & & / xyz_CpDensVPTempSQBZ(:,:,1) & & * xyr_CpDensVPTempSQBZ(:,:,0) & & * E(:,:,0) & & / dz D(:,:,nz) = & & + D(:,:,nz) & & + beta * (dt * dt) & & * xyz_VelSoundSQBZ(:,:,nz) & & / xyz_CpDensVPTempSQBZ(:,:,nz) & & * xyr_CpDensVPTempSQBZ(:,:,nz) & & * E(:,:,nz) & & / dz !----------------------------------------------------------- !連立一次方程式の解を求める ! LAPACK の仕様に合わせて変形 ! do k = 1, nz do j = 1, ny do i = 1, nx TX(k, i + nx * (j - 1)) = D(i,j,k) end do end do end do !解行列の計算. LAPACK を使用. ! call DGTTRS(TRANS, nz, nxny, C, A, B, AL1, IP, TX, nz, INFO) ! !解のコンディションをチェック. ! ! ! if (INFO /= 0) then ! call MessageNotify("Error", "lapack_linear", "INFO is not 0") ! stop ! end if do k = 1, nz do j = 1, ny do i = 1, nx xyz_ExnerA(i,j,k) = TX(k, i + nx * (j - 1 )) end do end do end do !! ! z 方向の境界条件を与える. 鉛直速度を求める際に微分するため. !! ! !! xyz_ExnerA(:,:,nz+1) = xyz_ExnerA(:,:,nz) !------------------------------------------------------------ ! 鉛直速度 ! aaa_tmp = AlphaV * xyr_dz_xyz( xyz_VelDivN ) xyr_SWF = aaa_tmp(1:nx,1:ny,1:nz) aaa_tmp = & & - CpDry * xyr_VPTempBZ & & * ( & & beta * xyr_dz_xyz( xyz_ExnerA ) & & + (1.0d0 - beta) * xyr_dz_xyz( xyz_ExnerN ) & & ) xyr_PGrad = aaa_tmp(1:nx,1:ny,1:nz) end subroutine Acousticmode_std_imp !!!--------------------------------------------------------------------!!! subroutine acousticmode_std_init( AlphaSound ) ! !エクスナー関数を陰解法で解く際に必要となる, 係数行列の要素を決め, !LU 分解を行う. ! ! モジュール読み込み ! use dc_types, only : DP use dc_message, only : MessageNotify use mpi_wrapper,only : myrank use gridset, only : imin, imax, &! & jmin, jmax, & & kmin, kmax, & & nx, &! x 方向の物理領域の上限 & ny, &! x 方向の物理領域の上限 & nz ! y 方向の物理領域の上限 use constants, only : CpDry ! 乾燥成分の比熱 use timeset, only : DelTimeShort use axesset, only : dx, dy, dz ! 格子間隔 use basicset, only : xyz_VelSoundBZ, &!基本場の音速 & xyz_DensBZ, &!基本場の密度 & xyz_VPTempBZ !基本場の温位 use axesset, only : xyr_xyz !暗黙の型宣言禁止 ! implicit none !変数の定義 ! real(DP), intent(in) :: AlphaSound real(DP) :: r_CpDensVPTempSQBZ(kmin:kmax) real(DP) :: z_VelSoundSQBZ(kmin:kmax) real(DP) :: z_CpDensVPTempSQBZ(kmin:kmax) real(DP) :: dt ! 短い時間格子 integer :: INFO !解のコンディションチェック !---------------------------------------------------------------- ! 初期化 ! 音波減衰項の減衰係数を決める ! ! 気象庁予報課報告別冊 49 p53 に従い, 水平と鉛直とを分けて考える. ! ! AlphaH = AlphaSound * ( Min( dx * dx, dy * dy ) ) / DelTimeShort AlphaH = AlphaSound * ( Min( dx * dx, dy * dy, dz * dz ) ) / DelTimeShort AlphaV = AlphaSound * ( Min( dx * dx, dy * dy, dz * dz ) ) / DelTimeShort !------------------------------------------------------------------- ! 出力 ! if (myrank == 0) then call MessageNotify( "M", module_name, "AlphaH = %f", d=(/AlphaH/) ) call MessageNotify( "M", module_name, "AlphaV = %f", d=(/AlphaV/) ) end if ! 変数名が長すぎたので, 名前を置き換える ! dt = DelTimeShort ! 配列の割り付け ! allocate( A(1:nz) ) allocate( B(2:nz) ) allocate( C(1:nz-1) ) allocate( xyz_VelSoundSQBZ(imin:imax,jmin:jmax,kmin:kmax) ) allocate( xyz_CpDensVPTempSQBZ(imin:imax,jmin:jmax,kmin:kmax) ) allocate( xyr_CpDensVPTempSQBZ(imin:imax,jmin:jmax,kmin:kmax) ) allocate( xyr_DensVPTempBZ(imin:imax,jmin:jmax,kmin:kmax) ) allocate( xyr_CpVPTempBZ(imin:imax,jmin:jmax,kmin:kmax) ) !---------------------------------------------------------------- ! 係数行列および共通して利用される配列の値を決める ! xyz_VelSoundSQBZ = xyz_VelSoundBZ * xyz_VelSoundBZ xyz_CpDensVPTempSQBZ = CpDry * xyz_DensBZ * xyz_VPTempBZ * xyz_VPTempBZ xyr_CpDensVPTempSQBZ = xyr_xyz( xyz_CpDensVPTempSQBZ ) xyr_DensVPTempBZ = xyr_xyz( xyz_DensBZ * xyz_VPTempBZ ) xyr_CpVPTempBZ = xyr_xyz( CpDry * xyz_VPTempBZ ) ! 鉛直方向のみの変数については, 基本場を使うので, ! nx, ny の値で代表させることとした. ! z_VelSoundSQBZ = xyz_VelSoundSQBZ(nx,ny,:) z_CpDensVPTempSQBZ(:) = xyz_CpDensVPTempSQBZ(nx,ny,:) r_CpDensVPTempSQBZ(:) = xyr_CpDensVPTempSQBZ(nx,ny,:) ! ! A(2:nz-1) = & & + 1.0d0 & & + ( beta * beta ) & & * z_VelSoundSQBZ(2:nz-1) & & / z_CpDensVPTempSQBZ(2:nz-1) & & * ( & & r_CpDensVPTempSQBZ(2:nz-1) & & + r_CpDensVPTempSQBZ(1:nz-2) & & ) & & * ( dt * dt ) & & / ( dz * dz ) A(1) = & & + 1.0d0 & & + ( beta * beta ) & & * z_VelSoundSQBZ(1) & & / z_CpDensVPTempSQBZ(1) & & * r_CpDensVPTempSQBZ(1) & & * ( dt * dt ) & & / ( dz * dz ) A(nz) = & & + 1.0d0 & & + ( beta * beta ) & & * z_VelSoundSQBZ(nz) & & / z_CpDensVPTempSQBZ(nz) & & * r_CpDensVPTempSQBZ(nz-1) & & * ( dt * dt ) & & / ( dz * dz ) B(2:nz) = & & - ( beta * beta ) & & * z_VelSoundSQBZ(1:nz-1) & & / z_CpDensVPTempSQBZ(1:nz-1) & & * r_CpDensVPTempSQBZ(1:nz-1) & & * ( dt * dt ) & & / ( dz * dz ) C(1:nz-1) = & & - ( beta * beta ) & & * z_VelSoundSQBZ(2:nz) & & / z_CpDensVPTempSQBZ(2:nz) & & * r_CpDensVPTempSQBZ(1:nz-1) & & * ( dt * dt ) & & / ( dz * dz ) !---------------------------------------------------------------- ! 係数行列を LU 分解 ! ! 配列の割り当て ! allocate( AL1(1:nz-2), IP(1:nz) ) ! 解行列の計算. LAPACK を使用. ! call DGTTRF(nz, C, A, B, AL1, IP, INFO) ! 解のコンディションをチェック. ! if (INFO /= 0) then call MessageNotify("Error", "lapack_linear", "INFO is not 0") stop end if end subroutine Acousticmode_std_init end module Acousticmode_std