IGMBaseLib 1.0
|
00001 00034 module STDGrid_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 ! 円周率. PI. 00048 00049 ! 線形代数 00050 ! Linear algebra 00051 ! 00052 use igmcore_linear_algebra, only: & 00053 & vec_length, rotateZ 00054 00055 ! 座標変換 00056 ! Coordinate conversion 00057 ! 00058 use igmcore_coordinate_conversion, only: & 00059 & geo_to_orth_pos 00060 00061 ! 球面三角関数 00062 ! Spherical trigonometry 00063 ! 00064 use igmcore_spherical_trigonometry, only: & 00065 & spherical_penta_area, & 00066 & spherical_hex_area 00067 00068 ! 正二十面体格子データの管理 00069 ! Manager of Icosahedral grid data 00070 ! 00071 use IcGrid2D_FVM_Manager, only: & 00072 & IcGrid2D_FVM, & 00073 & paste_margin_width, calc_icosahedron_vertex, set_rcregion_bounds, & 00074 & get_IdMin, get_EffSize_Min, get_EffSize_Max, get_IcRadius, & 00075 & generate_CV5_GPindex, generate_CV6_GPindex, & 00076 & ICOSAHEDRON_VERTEX_NUM, RC_REGIONS_NUM 00077 00078 ! 宣言文 ; Declaration statements 00079 ! 00080 implicit none 00081 private 00082 00083 ! 公開手続き 00084 ! Public procedures 00085 ! 00086 public :: construct_STDGrid 00087 public :: calc_STDGrid_GP_vertex, calc_CV_vertex, calc_CV_Area 00088 public :: project_on_sphere 00089 00090 contains 00091 00092 ! 00103 subroutine construct_STDGrid(icgrid) 00104 00105 ! 宣言文 ; Declaration statements 00106 ! 00107 type(IcGrid2D_FVM), intent(inout) :: icgrid 00108 00109 ! 実行文 ; Executable statements 00110 ! 00111 00112 call calc_STDGrid_GP_vertex(icgrid) 00113 call calc_CV_vertex(icgrid) 00114 call calc_CV_Area(icgrid) 00115 00116 end subroutine construct_STDGrid 00117 00118 ! 00133 subroutine calc_STDGrid_GP_vertex( & 00134 & icgrid & ! (inout) 00135 & ) 00136 00137 ! 宣言文 ; Declaration statements 00138 ! 00139 type(IcGrid2D_FVM), intent(inout) :: icgrid 00140 00141 ! 作業変数 00142 ! Work variables 00143 ! 00144 real(DP) :: orth_icvertex(ICOSAHEDRON_VERTEX_NUM, 3) 00145 integer :: ringID 00146 integer :: rcID 00147 00148 integer :: EMin, EMax 00149 integer :: upper_IDs(6) = (/ 2, 3, 4, 5, 6, 2 /) 00150 integer :: lower_IDs(6) = (/ 7, 8, 9, 10, 11, 7 /) 00151 00152 ! 実行文 ; Executable statements 00153 ! 00154 00155 !write(*,*) 'calc STDGP_vertex' 00156 ! (単位)正二十面体の 12 個の頂点の座標を計算する. 00157 call calc_icosahedron_vertex(orth_icvertex) 00158 00159 ! 球の半径分だけ拡大する 00160 orth_icvertex(:,:) = get_IcRadius(icgrid) * orth_icvertex(:,:) 00161 00162 ! 各矩形領域の端にあたる格子点が, 正二十面体の頂点に重なるように, 座標を設定する. 00163 do ringID=1,5 00164 ! 上側の矩形領域に対して 00165 call set_rcregion_bounds( & 00166 & self=icgrid, & ! (inout) 00167 & rcID=ringID, & ! (in) 00168 & top=orth_icvertex(1,:), & ! (in) 00169 & left=orth_icvertex(upper_IDs(ringID),:), & ! (in) 00170 & bottom=orth_icvertex(lower_IDs(ringID), :), & ! (in) 00171 & right=orth_icvertex(upper_IDs(ringID+1),:) ) ! (in) 00172 00173 ! 下側の矩形領域に対して 00174 call set_rcregion_bounds( & 00175 & self=icgrid, & ! (inout) 00176 & rcID=ringID+5, & ! (in) 00177 & top=orth_icvertex(upper_IDs(ringID+1),:), & ! (in) 00178 & left=orth_icvertex(lower_IDs(ringID),:), & ! (in) 00179 & bottom=orth_icvertex(12,:), & ! (in) 00180 & right=orth_icvertex(lower_IDs(ringID+1),:) ) ! (in) 00181 00182 end do 00183 00184 ! 配列インデックスの境界に関する情報を取得 00185 EMin = get_EffSize_Min(icgrid) 00186 EMax = get_EffSize_Max(icgrid) 00187 00188 ! 各矩形領域の端の格子点座標が決まったので, それをもとに再帰的に各矩形領域を分割していく. 00189 do rcID=1, RC_REGIONS_NUM 00190 call split_rectangle_region( & 00191 & rc_AGrid=icgrid%rcs_AGrid(rcID, EMin:EMax,EMin:EMax,:), & ! (inout) 00192 & ic_radius=get_IcRadius(icgrid), & ! (in) 00193 & row1=EMin, row2=EMax, & ! (in) 00194 & col1=EMin, col2=EMax ) ! (in) 00195 end do 00196 00197 ! のりしろを貼り合わせる 00198 call paste_margin_width(icgrid) 00199 00200 end subroutine calc_STDGrid_GP_vertex 00201 00202 ! 00217 subroutine calc_CV_vertex(icgrid) 00218 00219 ! 宣言文 ; Declaration statements 00220 ! 00221 type(IcGrid2D_FVM), intent(inout) :: icgrid 00222 00223 ! 作業変数 00224 ! Work variable 00225 ! 00226 integer :: CV6_GPindx(6, 3, 2) 00227 integer :: CV5_GPindx(5, 3, 2) 00228 integer :: rcID, i, j, cvID 00229 integer :: EMin, EMax, idMin 00230 real(DP) :: ic_radius 00231 00232 ! 実行文 ; Executable statemnets 00233 ! 00234 00235 ! write(*,*) 'calc STDCV_vertex' 00236 00237 ! 配列インデックスの境界に関する情報を取得 00238 EMin = get_EffSize_Min(icgrid) 00239 EMax = get_EffSize_Max(icgrid) 00240 idMin = get_IdMin(icgrid) 00241 ! 半径の取得 00242 ic_radius = get_IcRadius(icgrid) 00243 00244 ! 各格子点について, そのコントロールボリュームの頂点座標を計算する. 00245 do rcID=1, RC_REGIONS_NUM 00246 do j=EMin, EMax 00247 do i=EMin, EMax 00248 00249 if ( ( rcID > 5 .and. i==EMin .and. j==EMin ) .or. ( i==EMin .and. j== EMax ) & 00250 & .or. ( i==EMax .and. j== EMin ) .or. ( rcID <= 5 .and. i==EMax .and. j== EMax ) ) then 00251 ! 矩形領域の左右端の特異格子点のコントロールボリュームの頂点(5個)座標を求める. 00252 00253 CV5_GPindx(:,:,:) = generate_CV5_GPindex(icgrid, GP_i=i, GP_j=j, rcID=rcID ) 00254 do cvID=1,5 00255 icgrid%rcs_CV(rcID,i,j,cvID, 1:3) = & 00256 & calc_each_CV_vertex( icgrid%rcs_AGrid(rcID,:,:,:), CV5_GPindx(cvID,:,:), ic_radius, idMin ) 00257 end do 00258 00259 else if( rcID <= 5 .and. i==EMin .and. j==EMin ) then 00260 ! 北極にある格子点が持つコントロールボリュームの頂点(5個)座標を求める. 00261 do cvID=1,5 00262 icgrid%rcs_CV(rcID,EMin,EMin, cvID, :) = & 00263 & ( icgrid%rcs_AGrid(cvID,EMin,EMin, :) & 00264 & + icgrid%rcs_AGrid(cvID,EMin+1,EMin, :) & 00265 & + icgrid%rcs_AGrid(cvID,EMin,EMin+1, :) & 00266 & ) / 3.0d0 00267 00268 call project_on_sphere( ic_radius, icgrid%rcs_CV(rcID,i,j,cvID,:) ) 00269 end do 00270 00271 else if( rcID > 5 .and. i==EMax .and. j== EMax ) then 00272 ! 南極にある格子点が持つコントロールボリュームの頂点(5個)座標を求める. 00273 do cvID=1,5 00274 icgrid%rcs_CV(rcID,EMax,EMax, cvID, :) = & 00275 & ( icgrid%rcs_AGrid(11-cvID,EMax,EMax, :) & 00276 & + icgrid%rcs_AGrid(11-cvID,EMax-1,EMax, :) & 00277 & + icgrid%rcs_AGrid(11-cvID,EMax,EMax-1, :) & 00278 & ) / 3.0d0 00279 00280 call project_on_sphere(ic_radius, icgrid%rcs_CV(rcID,i,j,cvID,:)) 00281 end do 00282 00283 else 00284 ! 特異点以外の格子点のコントロールボリュームの頂点(6個)座標を求める. 00285 CV6_GPindx(:,:,:) = generate_CV6_GPindex(icgrid, GP_i=i, GP_j=j, rcID=rcID ) 00286 00287 do cvID=1,6 00288 icgrid%rcs_CV(rcID,i,j,cvID, 1:3) = & 00289 & calc_each_CV_vertex(icgrid%rcs_AGrid(rcID,:,:,:), CV6_GPindx(cvID,:,:), ic_radius, idMin) 00290 end do 00291 00292 end if 00293 end do 00294 end do 00295 end do 00296 00297 end subroutine calc_CV_vertex 00298 00299 ! 00314 subroutine calc_CV_Area( & 00315 & icgrid & 00316 & ) 00317 00318 ! 宣言文 ; Declaration statements 00319 ! 00320 type(IcGrid2D_FVM), intent(inout) :: icgrid 00321 00322 00323 ! 作業変数 00324 ! Work variables 00325 ! 00326 integer :: rcID, i, j 00327 integer :: EMin, EMax, idMin, k 00328 real(DP) :: ic_radius 00329 real(DP) :: CV5(5, 3), CV6(6, 3) 00330 00331 ! 実行文 ; Executable statements 00332 ! 00333 00334 ! write(*,*) 'calc CV_Area' 00335 00336 ! 配列インデックスの境界に関する情報を取得 00337 EMin = get_EffSize_Min(icgrid) 00338 EMax = get_EffSize_Max(icgrid) 00339 ! 半径の取得 00340 ic_radius = get_IcRadius(icgrid) 00341 00342 ! それぞれの格子点について, それに付随するコントールボリュームの面積を求める. 00343 do rcID=1,RC_REGIONS_NUM 00344 do j=EMin, EMax 00345 do i=EMin, EMax 00346 if ( ( i==EMin .and. j==EMin ) .or. ( i==EMax .and. j== EMin ) .or. & 00347 & ( i==EMin .and. j== EMax ) .or. ( i==EMax .and. j== EMax ) ) then 00348 ! 特異格子点のコントールボリューム(頂点数 5 個)に対して 00349 00350 CV5(:,:) = icgrid%rcs_CV(rcID,i,j,1:5, :) 00351 00352 icgrid%rcs_CVArea(rcID,i,j) = & 00353 & spherical_penta_area( ic_radius, CV5(1,:), CV5(2,:), CV5(3,:),CV5(4,:),CV5(5,:) ) 00354 00355 else 00356 ! 通常の格子点のコントールボリューム(頂点数 6 個)に対して 00357 00358 CV6(:,:) = icgrid%rcs_CV(rcID,i,j,1:6, :) 00359 00360 icgrid%rcs_CVArea(rcID,i,j) = & 00361 & spherical_hex_area( ic_radius, CV6(1,:), CV6(2,:), CV6(3,:),CV6(4,:),CV6(5,:), CV6(6,:) ) 00362 00363 end if 00364 end do 00365 end do 00366 end do 00367 00368 end subroutine calc_CV_Area 00369 00370 00371 !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00372 ! 00373 ! モジュール外非公開手続き 00374 ! 00375 !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00376 00377 ! 00398 recursive subroutine split_rectangle_region( & 00399 & rc_AGrid, & ! (inout) 00400 & ic_radius, row1, row2, col1, col2 & ! (in) 00401 & ) 00402 00403 ! 宣言文 ; Declaration statements 00404 ! 00405 real(DP), intent(inout) :: rc_AGrid(:,:,:) 00406 real(DP), intent(in) :: ic_radius 00407 integer, intent(in) :: row1 00408 integer, intent(in) :: row2 00409 integer, intent(in) :: col1 00410 integer, intent(in) :: col2 00411 00412 ! 作業変数 00413 ! Work variable 00414 ! 00415 integer mid_row, mid_col 00416 00417 ! 実行文 ; Executable statements 00418 ! 00419 00420 if( mod(row1+row2, 2) == 1 ) then 00421 ! 分割予定の格子点が存在しないので, 再帰処理を終了する. 00422 return 00423 end if 00424 00425 ! 対象の矩形領域の各辺の中点と矩形領域内の中心点の座標を計算する. 00426 mid_row = (row1 + row2) / 2 00427 mid_col = (col1 + col2) / 2 00428 00429 rc_AGrid(row1, mid_col, :) = 0.5d0 * ( rc_AGrid(row1, col1, :) + rc_AGrid(row1, col2, :) ) 00430 rc_AGrid(row2, mid_col, :) = 0.5d0 * ( rc_AGrid(row2, col1, :) + rc_AGrid(row2, col2, :) ) 00431 rc_AGrid(mid_row, col1, :) = 0.5d0 * ( rc_AGrid(row1, col1, :) + rc_AGrid(row2, col1, :) ) 00432 rc_AGrid(mid_row, col2, :) = 0.5d0 * ( rc_AGrid(row1, col2, :) + rc_AGrid(row2, col2, :) ) 00433 rc_AGrid(mid_row, mid_col, :) = 0.5d0 * ( rc_AGrid(row2, col1, :) + rc_AGrid(row1, col2, :) ) 00434 00435 ! 平面図形として矩形平面上に存在する 5 点を, 原点を中心として球面上に射影する. 00436 call project_on_sphere(ic_radius, rc_AGrid(row1, mid_col, :)) 00437 call project_on_sphere(ic_radius, rc_AGrid(row2, mid_col, :)) 00438 call project_on_sphere(ic_radius, rc_AGrid(mid_row, col1, :)) 00439 call project_on_sphere(ic_radius, rc_AGrid(mid_row, col2, :)) 00440 call project_on_sphere(ic_radius, rc_AGrid(mid_row, mid_col, :)) 00441 00442 ! 頂点の座標が決まった4つの矩形を, それぞれさらに分割する. 00443 call split_rectangle_region(rc_AGrid, ic_radius, row1, mid_row, col1, mid_col) 00444 call split_rectangle_region(rc_AGrid, ic_radius, row1, mid_row, mid_col, col2) 00445 call split_rectangle_region(rc_AGrid, ic_radius, mid_row, row2, col1, mid_col) 00446 call split_rectangle_region(rc_AGrid, ic_radius, mid_row, row2, mid_col, col2) 00447 00448 end subroutine split_rectangle_region 00449 00450 ! 00463 subroutine project_on_sphere( & 00464 & radius, & ! (in) 00465 & vec & ! (inout) 00466 & ) 00467 00468 ! 宣言文 ; Declaration statements 00469 ! 00470 real(8), intent(in) :: radius ! 正二十面体格子を内包する球の半径 00471 real(8), intent(inout) :: vec(3) ! 射影したい点の位置ベクトル 00472 00473 ! 実行文 ; Executable statements 00474 ! 00475 00476 vec = radius / vec_length(vec) * vec 00477 end subroutine project_on_sphere 00478 00479 ! 00499 function calc_each_CV_vertex( & 00500 & rc_AGrid, GP3_index, ic_radius, idMin & ! (in) 00501 & ) result(cv_pt) 00502 00503 ! 宣言文 ; Declaration statements 00504 ! 00505 integer, intent(in) :: idMin 00506 real(DP), intent(in) :: rc_AGrid(idMin:,idMin:,:) 00507 integer, intent(in) :: GP3_index(:,:) 00508 real(DP), intent(in) :: ic_radius 00509 real(DP) cv_pt(3) 00510 00511 ! 作業変数 00512 ! Work variables 00513 ! 00514 integer k 00515 00516 ! 実行文 ; Executable statements 00517 ! 00518 00519 cv_pt(:) = 0.0d0 00520 00521 do k=1,3 00522 cv_pt(:) = cv_pt(:) + rc_AGrid(GP3_index(k, 1), GP3_index(k, 2), :) 00523 end do 00524 00525 cv_pt(:) = cv_pt(:) / 3.0d0 00526 call project_on_sphere(ic_radius, cv_pt(:)) 00527 00528 end function calc_each_CV_vertex 00529 00530 end module STDGrid_Builder