IGMBaseLib 1.0
|
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