IGMBaseLib 1.0

src/core/grid/SPRGCGrid_Builder.f90

Go to the documentation of this file.
00001 
00034 module SPRGCGrid_Builder
00035 
00036   ! モジュール引用 ; Use statements
00037   !
00038 
00039   ! 種類型パラメタ
00040   ! Kind type parameter
00041   !
00042   use dc_types, only: DP         ! 倍精度実数型. Double precision.
00043 
00044   ! 数学定数
00045   ! Mathematic
00046   !
00047   use igmcore_math, only: PI   ! 円周率
00048 
00049   ! 線形代数
00050   ! Linear algebra
00051   !
00052   use igmcore_linear_algebra, only: &
00053     & vec_length, vec_normarize, &
00054     & cross
00055 
00056   ! 球面三角法
00057   ! Spherical trigonometry
00058   !
00059   use igmcore_spherical_trigonometry, only: &
00060     & geodesic_arc_length
00061 
00062   ! 正二十面体格子データの管理
00063   ! Manager of Icosahedral grid data
00064   !
00065   use IcGrid2D_FVM_Manager, only: &
00066     & IcGrid2D_FVM, &
00067     & paste_margin_width, generate_CV5_GPindex, &
00068     & get_idMin, get_idMax, get_EffSize_Min, get_EffSize_Max, &
00069     & get_IcRadius, get_glevel, &
00070     & check_pole, NOT_POLE_FLAG, &
00071     & RC_REGIONS_NUM
00072 
00073 
00074   ! STD-GC-grid の構築
00075   ! STD-GC-grid construction
00076   !
00077   use STDGCGrid_Builder, only: &
00078     & calc_STDGrid_GP_vertex, calc_CV_vertex, calc_CV_Area, &
00079     & move_GP_into_CVGravPt, project_on_sphere
00080 
00081   ! 宣言文 ; Declaration statements
00082   !
00083   implicit none
00084   private
00085 
00086   ! 公開手続き
00087   ! Public procedures
00088   !
00089   public :: construct_SPRGCGrid, set_iteration_limiter
00090 
00091   ! 非公開変数
00092   ! Private variables
00093   !
00094 
00097   real(DP) :: eq_d
00098 
00101   real(DP) :: radius
00102 
00105   real(DP) :: beta = 0.4d0
00106 
00107   ! ばねの振動の減衰のふるまいがおよそ臨界減衰となるように,
00108   ! 摩擦定数とバネ定数を選ぶ.
00109 
00112   real(DP) :: alpha = 2000.0d0
00113 
00116   real(DP) :: k = 1.0d06
00117 
00120   real(DP) :: dt = 0.001d0
00121 
00124   integer :: end_tstep = 20000
00125 
00130   logical :: tstep_limiter = .false.
00131 
00134 
00137   integer :: conv_check_step = 100
00138 
00141   integer, allocatable :: GP_IJ(:,:,:,:,:)
00142 
00143 contains
00144 
00145 !
00156 subroutine construct_SPRGCGrid( &
00157   & icgrid,     &  ! (inout)
00158   & tstep_limit &  ! (in)
00159   & )
00160 
00161   ! 宣言文 ; Declaration statements
00162   !
00163   type(IcGrid2D_FVM), intent(inout) :: icgrid
00164   integer, intent(in), optional :: tstep_limit
00165 
00166   ! 作業変数
00167   ! Work variables
00168   !
00169   integer :: glevel
00170 
00171   ! 実行文 ; Executable statements
00172   !
00173 
00174   radius = get_IcRadius(icgrid)
00175   glevel = get_glevel(icgrid)
00176 
00177   !
00178   if ( present(tstep_limit) ) then
00179     tstep_limiter = .false.
00180     end_tstep = tstep_limit
00181   end if
00182 
00183   ! つり合いの状態における, 近傍の格子点までの距離の推定値を定める.
00184   ! ( Tomita,etal(2001)の式(23) )
00185   eq_d = beta * 2.0d0 * PI * radius / ( 10.0d0 * 2.0d0**( glevel-1 ) )
00186 
00187   ! SPR-GC-grid を生成する.
00188   !
00189 
00190   ! 最初に STD-grid の格子点座標を求める.
00191   call calc_STDGrid_GP_vertex(icgrid)
00192   ! バネ力学を用いて, STD-grid の格子の空間分布を準一様にする.
00193   call modify_STDGrid_with_spring_dyn(icgrid)
00194 
00195   ! 改良した格子でコントールボリュームの格子位置, 面積を求める.
00196   call calc_CV_vertex(icgrid)
00197   call calc_CV_Area(icgrid)
00198 
00199   ! 格子位置を, コントールボリュームの重心位置に移動させる.
00200   call move_GP_into_CVGravPt(icgrid)
00201 
00202 end subroutine construct_SPRGCGrid
00203 
00204 !
00221 subroutine set_iteration_limiter( &
00222   & limiter_flag &  ! (in)
00223   & )
00224 
00225   ! 宣言文 ; Declaration statement
00226   !
00227   logical, intent(in)  :: limiter_flag
00228 
00229   ! 実行文 ; Executable statement
00230   !
00231   tstep_limiter = limiter_flag
00232 
00233 end subroutine set_iteration_limiter
00234 
00235 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00236 !
00237 ! モジュール非公開手続き
00238 !
00239 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00240 
00241 !
00268 subroutine modify_STDGrid_with_spring_dyn( &
00269   & icgrid )                                    ! (inout)
00270 
00271   ! 宣言文 ; Declaration statements
00272   !
00273   type(IcGrid2D_FVM), intent(inout) :: icgrid
00274 
00275   ! 作業変数
00276   ! Work variables
00277   !
00278   integer :: idMin,  idMax
00279   integer :: EMin,  EMax
00280   integer :: rcID, i, j
00281   integer :: pt_num
00282 
00283   ! 実行文 ; Executable statements
00284   !
00285 
00286   !write(*,*) 'modify STD-GC-grid'
00287   ! 配列の境界インデックスを取得
00288   idMin = get_idMin(icgrid)
00289   idMax = get_idMax(icgrid)
00290   EMin = get_EffSize_Min(icgrid)
00291   EMax = get_EffSize_Max(icgrid)
00292 
00293   ! バネ力学を利用して, STD-grid の格子位置を改良する.
00294   !
00295 
00296   allocate(GP_IJ(RC_REGIONS_NUM, EMin:EMax, EMin:EMax, 6, 2))
00297 
00298   do rcID=1, RC_REGIONS_NUM
00299     do j=EMin, EMax
00300       do i=EMin, EMax
00301            if( ( rcID > 5 .and. i==EMin .and. j==EMin ) .or. ( i==EMin .and. j==EMax ) .or. &
00302             & ( i==EMax .and. j==EMin ) .or. ( rcID <= 5 .and. i==EMax .and. j==EMax )     &
00303             &       ) then
00304             pt_num = 5
00305             GP_IJ(rcID,i,j, 1:pt_num,:) = generate_near_GP5index(icgrid, rcID,i,j)
00306           else
00307             pt_num = 6
00308             GP_IJ(rcID,i,j, 1:pt_num,:) = generate_near_GP6index(rcID,i,j, EMin, EMax)
00309           end if
00310       end do
00311     end do
00312   end do
00313 
00314   call move_GP_with_spring_dyn(icgrid, idMin, idMax, EMin, EMax)
00315   deallocate(GP_IJ)
00316 
00317 end subroutine modify_STDGrid_with_spring_dyn
00318 
00319 !!!!!!!!!!!!!!!!!!!!!!!!!!!
00320 !
00321 ! 非公開手続き
00322 !
00323 !!!!!!!!!!!!!!!!!!!!!!!!!!!!
00324 
00325 !
00348 subroutine move_GP_with_spring_dyn( &
00349   & icgrid,                           & ! (inout)
00350   & idMin, idMax, EMin, EMax )        ! (in)
00351 
00352   ! 宣言文 ; Declaration statements
00353   !
00354 
00355   type(IcGrid2D_FVM), intent(inout) :: icgrid
00356   integer, intent(in) :: idMin,  idMax
00357   integer, intent(in) :: EMin,  EMax
00358 
00359 
00360   ! 作業変数
00361   ! Work variables
00362   !
00363   integer :: tstep
00364   integer rcID, i,j, k, convrecID
00365   real(DP) :: GP(6,3)
00366   integer :: pt_num
00367   real(DP) :: w0(RC_REGIONS_NUM, idMin:idMax, idMin:idMax, 1:3)
00368 
00369   integer, parameter :: DCONV_REC_NUM = 20
00370   integer, parameter :: DCONV_PLUS_ULIMIT = 10
00371   real(DP) :: conv_max, conv, conv_rec, conv_total
00372   real(DP) :: dconv_recs(DCONV_REC_NUM);
00373   integer :: dconv_plus_counter = 0
00374   logical :: conv_flag = .false.
00375 
00376   ! 実行文 ; Executable statements
00377   !
00378 
00379   !
00380   tstep = 1
00381   ! 初期速度の設定
00382   w0(:,:,:,:) = 0.0d0
00383 
00384   do
00385     do rcID=1, RC_REGIONS_NUM
00386       !$omp parallel do private(i, k, GP, pt_num)
00387       do j=EMin,EMax
00388         do i=EMin,EMax
00389           if( ( rcID > 5 .and. i==EMin .and. j==EMin ) .or. ( i==EMin .and. j==EMax ) .or. &
00390             & ( i==EMax .and. j==EMin ) .or. ( rcID <= 5 .and. i==EMax .and. j==EMax )     &
00391             &       ) then
00392              ! 特異点
00393              ! 格子点(rcID,i,j)の近傍にある格子点 5 個の格子点を求める.
00394             pt_num = 5
00395           else
00396              ! 格子点(rcID,i,j)の近傍にある格子点 6 個の格子点を求める.
00397             pt_num = 6
00398           end if
00399 
00400           if( check_pole(icgrid, rcID,i,j) == NOT_POLE_FLAG ) then
00401             do k=1,pt_num
00402               GP(k,1:3) = icgrid%rcs_AGrid(rcID, GP_IJ(rcID,i,j,k,1), GP_IJ(rcID,i,j,k,2), 1:3)
00403             end do
00404 
00405              ! 常微分方程式系を一タイムスッテプ分時間積分して, 一タイムスッテプ後の格子点位置を計算する.
00406             call integ_ode_1step_spring_dynamics( &
00407                  & r0=icgrid%rcs_AGrid(rcID,i,j,:), w0=w0(rcID,i,j,:), &
00408                  & GP=GP(1:pt_num,:), pt_num=pt_num &
00409                  & )
00410 
00411             call project_on_sphere( radius, icgrid%rcs_AGrid(rcID,i,j,:))
00412           end if
00413 
00414         end do ! for i
00415       end do ! for j
00416     end do ! for rcID
00417 
00418     ! 次のタイムステップに移る前に, のりしろを貼り合わせる.
00419     call paste_margin_width(icgrid)
00420 
00421     ! 収束判定
00422     if ( mod(tstep, conv_check_step) == 0 ) then
00423 
00424       !
00425       call check_global_convergence(icgrid, conv_total, conv_max, EMin, EMax)
00426 
00427       convrecID = mod(int(tstep / conv_check_step), DCONV_REC_NUM)+1
00428       dconv_recs(convrecID) = ( conv_total - conv_rec ) / abs(conv_max)
00429       conv_rec = conv_total
00430 
00431       if ( int(tstep / conv_check_step) > DCONV_REC_NUM ) then
00432         if ( sum(dconv_recs) > 0.0d0 ) then
00433            dconv_plus_counter = dconv_plus_counter + 1
00434              if ( dconv_plus_counter > DCONV_PLUS_ULIMIT ) then
00435                conv_flag = .true.
00436              end if
00437         end if
00438       end if
00439 
00440     end if
00441 
00442     if ( mod(tstep, 500) == 0 ) then
00443       write(*,*) '-- tstep:', tstep, '/', end_tstep
00444       write(*,*) '* conv_max=', conv_max, ', dconv=', sum(dconv_recs) / DCONV_REC_NUM
00445       write(*,*) '* conv_total=', conv_total,  ', dconv_plus_counter=', dconv_plus_counter
00446      ! write(*,*) conv_total / ( RC_REGIONS_NUM * ( (EMax - EMin + 1)**2 -4 ) )
00447     end if
00448 
00449     if ( ( tstep_limiter .and. ( tstep > end_tstep ) ) .or. conv_flag ) then
00450       write(*,*) tstep, tstep_limiter, end_tstep
00451       exit
00452     end if
00453 
00454     tstep = tstep + 1
00455   end do ! 時間積分ループ
00456 
00457   ! 反復回数と収束の程度を表す値を出力する.
00458   !
00459 
00460   write(*,*) 'SPR-GC-grid generation: the number of interation=', tstep
00461   write(*,*) 'The value for checking convergence:', conv_max
00462 
00463 end subroutine move_GP_with_spring_dyn
00464 
00465 !
00482 subroutine check_global_convergence( &
00483   & icgrid,                   &  ! (in)
00484   & conv_total_ave, conv_max, &  ! (out)
00485   & EMin, EMax                &  ! (in)
00486   & )
00487 
00488   ! 宣言文 ; Declaration statements
00489   !
00490   type(IcGrid2D_FVM), intent(in) :: icgrid
00491   real(DP), intent(out) :: conv_total_ave
00492   real(DP), intent(out) :: conv_max
00493   integer, intent(in) :: EMin
00494   integer, intent(in) :: EMax
00495 
00496   ! 作業変数
00497   ! Work variables
00498   !
00499   integer rcID, i, j, k
00500   real(DP) :: GP(6,3)
00501   real(DP) :: conv
00502   integer :: pt_num
00503 
00504   ! 実行文 ; Executable statements
00505   !
00506 
00507   conv_max = 0.0d0
00508   conv_total_ave = 0.0d0
00509 
00510   do rcID=1, RC_REGIONS_NUM
00511     !$omp parallel do private(i, k, GP, conv, pt_num) reduction(+:conv_total_ave)
00512     do j=EMin,EMax
00513       do i=EMin, EMax
00514         if(  .not. ( ( i==EMin .and. j==EMin ) .or. ( i==EMin .and. j==EMax ) .or. &
00515           &         ( i==EMax .and. j==EMin ) .or. ( i==EMax .and. j==EMax ) )    &
00516           &         ) then
00517 
00518           pt_num = 6
00519           do k=1,pt_num
00520             GP(k,1:3) = icgrid%rcs_AGrid(rcID, GP_IJ(rcID,i,j,k,1), GP_IJ(rcID,i,j,k,2), 1:3)
00521           end do
00522 
00523           conv = check_convergence(icgrid%rcs_AGrid(rcID,i,j,:), GP(1:pt_num,:), pt_num)
00524           conv_total_ave = conv_total_ave + conv
00525 
00526           if( conv  > conv_max ) then
00527             conv_max = conv
00528           end if
00529         end if
00530 
00531       end do
00532     end  do
00533   end do
00534 
00535   conv_total_ave = conv_total_ave / ( RC_REGIONS_NUM * ( (EMax - EMin + 1)**2 -4 ) )
00536 
00537 end subroutine check_global_convergence
00538 
00539 !
00560 function check_convergence( &
00561   & r0, pts, pt_num &  ! (in)
00562   & ) result(val)
00563 
00564   ! 宣言文 ; Declaration statement
00565   !
00566   real(8), intent(in) :: r0(3)    !
00567   integer, intent(in) :: pt_num
00568   real(8), intent(in) :: pts(pt_num, 3) !
00569   real(8) val
00570 
00571   ! 作業変数
00572   ! Work variables
00573   !
00574   real(8) vec(3)
00575   integer i
00576 
00577   ! 実行文 ; Executable statement
00578   !
00579   vec = 0.0d0
00580 
00581   do i=1, pt_num
00582     vec(:) = vec(:) + &
00583        ( geodesic_arc_length(radius, r0, pts(i,:) ) - eq_d ) * calc_ei(r0(1:3), pts(i,1:3))
00584   end do
00585 
00586   val = vec_length(vec)
00587 
00588 end function check_convergence
00589 
00590 !
00609 function generate_near_GP6index( &
00610   & rcID, GP0_i, GP0_j, EMin, EMax &  ! (in)
00611   & ) result(GP6Id)
00612 
00613   ! 宣言文 ; Declaration statements
00614   !
00615 
00616   integer, intent(in) :: rcID
00617   integer, intent(in) :: GP0_i
00618   integer, intent(in) :: GP0_j
00619   integer :: EMin,  EMax
00620   integer GP6Id(6, 2)
00621 
00622   ! 作業変数
00623   ! Work variables
00624   !
00625   integer i,j
00626   integer :: GP6IdShape(2) = (/ 6, 2 /)
00627 
00628   ! 実行文 ; Executable statements
00629   !
00630 
00631   i = GP0_i; j = GP0_j
00632   if ( rcID <= 5 .and. j==EMin ) then
00633     GP6Id(:,:) = reshape( (/ i,i-1,i-1,i-1,i,i+1, j-1,j-1,j,j+1,j+1,j /), GP6IdShape)
00634 
00635   else if ( rcID <= 5 .and. i==EMin ) then
00636     GP6Id(:,:) = reshape( (/ i,i-1,i-1,i,i+1,i+1, j-1,j-1,j,j+1,j,j-1 /), GP6IdShape)
00637 
00638   else if ( rcID > 5 .and. i==EMax ) then
00639     GP6Id(:,:) = reshape( (/ i+1,i+1,i,i-1,i-1,i, j,j+1,j+1,j+1,j,j-1 /), GP6IdShape)
00640 
00641   else if ( rcID > 5 .and. j==EMax ) then
00642     GP6Id(:,:) = reshape( (/ i+1,i+1,i+1,i,i-1,i, j-1,j,j+1,j+1,j,j-1 /), GP6IdShape)
00643 
00644   else
00645     GP6Id(:,:) = reshape( (/ i,i-1,i-1,i,i+1,i+1, j-1,j,j+1,j+1,j,j-1 /), GP6IdShape)
00646   end if
00647 
00648 end function generate_near_GP6index
00649 
00650 !
00667 function generate_near_GP5index( &
00668   & icgrid,            &  ! (inout)
00669   & rcID, GP0_i, GP0_j &  ! (in)
00670   & ) result(GP5Id)
00671 
00672   ! 宣言文 ; Declaration statements
00673   !
00674   type(IcGrid2D_FVM), intent(inout) :: icgrid
00675   integer, intent(in) :: rcID
00676   integer, intent(in) :: GP0_i
00677   integer, intent(in) :: GP0_j
00678   integer GP5Id(5, 2)
00679 
00680   ! 作業変数
00681   ! Work variables
00682   !
00683   integer :: tmp_GP5Id(5,3,2)
00684 
00685   ! 実行文 ; Executable statements
00686   !
00687 
00688   tmp_GP5Id(:,:,:) = generate_CV5_GPindex(icgrid, GP0_i, GP0_j, rcID)
00689   GP5Id(1:5, 1:2) = tmp_GP5Id(1:5, 2, 1:2)
00690 
00691 end function generate_near_GP5index
00692 
00693 !
00724 subroutine integ_ode_1step_spring_dynamics( &
00725   & r0, w0,    &  ! (inout)
00726   & GP, pt_num &  ! (in)
00727   & )
00728 
00729   !
00730   ! 宣言文 ; Declaration statements
00731   !
00732 
00733   real(DP), intent(inout) :: r0(3)
00734   real(DP), intent(inout) :: w0(3)
00735   integer, intent(in) :: pt_num
00736   real(DP), intent(in) :: GP(pt_num,3)
00737 
00738   ! 作業変数
00739   ! Work variables
00740   !
00741   real(DP) r0_(3), w0_(3)
00742   real(DP) k1(2,3), k2(2,3), k3(2,3)
00743 
00744   ! 実行文 ; Executable statements
00745   !
00746 
00747   !
00748   ! 連立常微分方程式(Tomita etal, (2001) の式(20), (21) )を, 3 次の Runge=Kutta 法を使って解く.
00749   !
00750 
00751   ! k1 を求める.
00752   k1(1, 1:3) = f1(r0(:), w0(:))
00753   k1(2, 1:3) = f2(r0(:), w0(:), GP(:,:), pt_num, alpha, k, eq_d, radius)
00754 
00755   ! k2 を求める.
00756   r0_(:) = r0(:) + 0.5d0 * dt * k1(1,:)
00757   w0_(:) = w0(:) + 0.5d0 * dt * k1(2,:)
00758   k2(1, 1:3) = f1(r0_(:), w0_(:))
00759   k2(2, 1:3) = f2(r0_(:), w0_(:), GP(:,:), pt_num, alpha, k, eq_d, radius)
00760 
00761   ! k3 を求める.
00762   r0_(:) = r0(:) - dt * k1(1,:) + 2.0d0 * dt * k2(1,:)
00763   w0_(:) = w0(:) - dt * k1(2,:) + 2.0d0 * dt * k2(2,:)
00764   k3(1, 1:3) = f1(r0_(:), w0_(:))
00765   k3(2, 1:3) = f2(r0_(:), w0_(:), GP(:,:), pt_num, alpha, k, eq_d, radius)
00766 
00767   ! 質点の位置ベクトルと速度ベクトルを次のタイムレベルに更新する.
00768   r0(:) = r0(:) + ( k1(1,:) + 4.0d0 * k2(1,:) + k3(1,:) ) * dt / 6.0d0
00769   w0(:) = w0(:) + ( k1(2,:) + 4.0d0 * k2(2,:) + k3(2,:) ) * dt / 6.0d0
00770 
00771 end subroutine integ_ode_1step_spring_dynamics
00772 
00773 !
00793 function f1( &
00794   & r0, w0 &  ! (in)
00795   & ) result(val)
00796 
00797   ! 宣言文 ; Declaration statements
00798   !
00799   real(DP), intent(in) :: r0(3)
00800   real(DP), intent(in) :: w0(3)
00801   real(DP) val(3)
00802 
00803   ! 実行文 ; Executable statements
00804   !
00805   val(1:3) = w0(1:3)
00806 
00807 end function f1
00808 
00809 !
00842 function f2( &
00843   & r0, w0, pts, pt_num, alpha, k, eq_d, radius &  ! (in)
00844   & ) result(val)
00845 
00846   ! 宣言文 ; Declaration statements
00847   !
00848 
00849   real(DP), intent(in) :: r0(3)
00850   real(DP), intent(in) :: w0(3)
00851   integer, intent(in) :: pt_num
00852   real(DP), intent(in) :: pts(pt_num,3)
00853   real(DP), intent(in) :: alpha
00854   real(DP), intent(in) :: k
00855   real(DP), intent(in) :: eq_d
00856   real(DP), intent(in) :: radius
00857   real(8) val(1:3)
00858 
00859   ! 作業変数
00860   ! Work variables
00861   !
00862   real(8) tmpv(3)
00863   integer i
00864 
00865   ! 実行文 ; Executable statements
00866   !
00867 
00868   tmpv(:) = 0.0d0
00869   do i=1, pt_num
00870     tmpv(:) = tmpv(:) + &
00871           ( geodesic_arc_length(radius, r0(1:3), pts(i,1:3)) - eq_d ) * calc_ei(r0(:), pts(i,:))
00872   end do
00873 
00874   ! M=1
00875   val(1:3) = k * tmpv(1:3) - alpha * w0(1:3)
00876 
00877 end function f2
00878 
00879 !
00894 function calc_ei( &
00895   & r0, ri &  ! (in)
00896   & ) result(e)
00897 
00898   ! 宣言文 ; Declaration statements
00899   !
00900   real(8), intent(in) :: r0(3)
00901   real(8), intent(in) :: ri(3)
00902   real(8) e(3)
00903 
00904   ! 実行文 ; Executable statements
00905   !
00906   e(:) = cross( cross(r0(:), ri(:) ), r0)
00907   call vec_normarize(e(:))
00908 
00909 end function calc_ei
00910 
00911 end module SPRGCGrid_Builder
 All Classes Namespaces Files Functions Variables