adjacency_solver.f90 Source File


This file depends on

sourcefile~~adjacency_solver.f90~~EfferentGraph sourcefile~adjacency_solver.f90 adjacency_solver.f90 sourcefile~terminalcontroler.f90 terminalControler.f90 sourcefile~adjacency_solver.f90->sourcefile~terminalcontroler.f90

Files dependent on this one

sourcefile~~adjacency_solver.f90~~AfferentGraph sourcefile~adjacency_solver.f90 adjacency_solver.f90 sourcefile~unstructuredgrid.f90 unstructuredGrid.f90 sourcefile~unstructuredgrid.f90->sourcefile~adjacency_solver.f90 sourcefile~boxflowfield.f90 boxFlowField.f90 sourcefile~boxflowfield.f90->sourcefile~unstructuredgrid.f90 sourcefile~cellcentercalc_test.f90 cellCenterCalc_test.f90 sourcefile~cellcentercalc_test.f90->sourcefile~unstructuredgrid.f90 sourcefile~dropletmotionsimulation.f90 dropletMotionSimulation.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~unstructuredgrid.f90 sourcefile~flow_field.f90 flow_field.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~flow_field.f90 sourcefile~flow_field.f90->sourcefile~unstructuredgrid.f90 sourcefile~kdtree_test.f90 kdTree_test.f90 sourcefile~kdtree_test.f90->sourcefile~unstructuredgrid.f90 sourcefile~main.f90 MAIN.f90 sourcefile~main.f90->sourcefile~dropletmotionsimulation.f90

Contents

Source Code


Source Code

MODULE adjacencySolver_m
    !!セルの隣接関係解決モジュール
    IMPLICIT NONE
    private

    integer, parameter, public :: None = -1
        !!整数配列中の欠損値の表現

    integer, parameter :: max_adjacent=5  !想定される最大隣接セル数(プリズムは最大5つのセルと隣接)
    integer, parameter :: max_boundFace=4  !想定される最大境界面数(プリズムの5つの面のうち、すべて境界面はありえないので4)

    !>ハーフフェイス構造体
    type halfFace_t
        integer :: nodeID(4) = None, pairID = None, ID_sum = 0, ownerCellID(2) = None
    end type

    public solve_BoundaryAndAdjacency

    contains

    function get_halfFaceArray(cellVertices) result(halfFaceArray)
        !!各セルごとにハーフフェイスをカウントし、配列に格納
        integer, intent(in) :: cellVertices(:,:)
        type(halfFace_t), allocatable :: halfFaceArray(:)
        INTEGER II,JJJ, j, n, JJJMX, num_halfFace, num_cell, vertexID
        character(5), allocatable :: cellType(:)
        character(5), parameter :: tetra='tetra', prism='prism', pyramid='pyrmd'    !キーワード
        integer, allocatable :: halfFaceVerticesID(:,:)

        !以下、各ハーフフェイス頂点の順番を表す配列。
        !例えば、テトラは4つの頂点から構成されており、ハーフフェイスも4つ。
        !1つ目のハーフフェイスは、4つの頂点のうち 1,2,3 番目のものを頂点とする。
        !以降、 2,3,4, 3,4,1, 4,1,2 番目を頂点とし、4つのハーフフェイスの定義が完了する。
        integer, parameter :: halfFaceVerticesID_inTetra(3,4) = reshape(&
            [1,2,3, 2,3,4, 3,4,1, 4,1,2], shape(halfFaceVerticesID_inTetra))

        integer, parameter :: halfFaceVerticesID_inPrism(4,5) = reshape(&
            [1,2,3,None, 4,5,6,None, 1,2,4,5, 2,3,5,6, 3,1,6,4], shape(halfFaceVerticesID_inPrism))

        integer, parameter :: halfFaceVerticesID_inPyramid(4,5) = reshape(&
            [5,1,2,None, 5,2,3,None, 5,3,4,None, 5,4,1,None, 1,2,3,4], shape(halfFaceVerticesID_inPyramid))
                           
            
        num_cell = size(cellVertices, dim=2)    !cellVerticesには、(6xセル数)の配列が入ってきている想定
        if(num_cell <= 0) then
            print*, 'ERROR_num_cells', num_cell
            error stop
        end if

        allocate(cellType(num_cell))
        DO II = 1, num_cell
            select case(count(cellVertices(:,II)/=None))    !頂点数(配列内のNoneでない要素数)で場合分け
            case(4) !頂点数が4個:テトラ
                cellType(II) = tetra

            case(6) !頂点数が6個:プリズム
                cellType(II) = prism

            case(5) !頂点数が5個:ピラミッド
                cellType(II) = pyramid

            case default
                print*, '**CEll VERTICES ERROR**'
                error stop
            end select
        END DO

        num_halfFace = count(cellType==tetra)*4 + count(cellType==prism)*5 + count(cellType==pyramid)*5
            !半面数:テトラ数×4 (+プリズム数×5 +ピラミッド数×5)
    
        allocate(halfFaceArray(num_halfFace))
            
        JJJ = 0
        
        DO II = 1, num_cell
            select case(cellType(II))
            case(tetra)
                halfFaceVerticesID = halfFaceVerticesID_inTetra
            case(prism)
                halfFaceVerticesID = halfFaceVerticesID_inPrism
            case(pyramid)
                halfFaceVerticesID = halfFaceVerticesID_inPyramid
            end select

            !halfFaceVerticesIDは2次元配列で、(頂点、ハーフフェイス)

            do j = 1, size(halfFaceVerticesID, dim=2)!ハーフフェイスの数だけループ
                JJJ = JJJ + 1   !ハーフフェイスの絶対IDをカウント

                do n = 1, size(halfFaceVerticesID, dim=1)!あるハーフフェイスにおける頂点数だけループ
                    vertexID = halfFaceVerticesID(n,j)
                    if(vertexID/=None) halfFaceArray(JJJ)%nodeID(n) = cellVertices(vertexID, II)
                end do

                halfFaceArray(JJJ)%ownerCellID(1) = II  !現在はセルIIに着目しているので、自明ながらオーナーセルもII

                halfFaceArray(JJJ)%ID_sum = sum(halfFaceArray(JJJ)%nodeID(:))   !IDの和を格納(あとで使う)

            end do
            
        END DO    
              
        JJJMX = JJJ
        
        if (JJJMX == num_halfFace) then
            print*, 'JJJMX / num_halfFace =', JJJMX, '/', num_halfFace
        else
            print*, 'JJJMX_ERROR:', JJJMX, num_halfFace
            error stop
        end if
            
    end function
    
    subroutine check_halfFace(halfFaceArray, num_BoundFaces)
        !!各ハーフフェイスに対して相方を探す
        !!相方がみつかれば、相方のセルと隣接していることがわかる
        !!相方のいないハーフフェイスは境界面
        use terminalControler_m
        type(halfFace_t), intent(inout) :: halfFaceArray(:)
        integer, intent(out) :: num_BoundFaces
        INTEGER match, width, numNode, faceID, groupID,num_group, maxID_sum, num_halfFace
        integer checkCounter, faceCounter, i,j, faceID1,faceID2, num_face, k,l
        integer, allocatable :: faceID_array(:)
        type faceGroup_t
            integer, allocatable :: faceID(:)
        end type faceGroup_t
        type(faceGroup_t), allocatable :: faceGroup(:)
        ! real time1, time2

        ! call cpu_time(time1)

        print*,'START-FACE CHECK!' !同一面の探索
        
        num_halfFace = size(halfFaceArray)
        num_group = num_halfFace/5000 + 1   !面グループ数(1グループ数に約5000枚面が入るようにする)(この値は経験則)
    
        allocate(faceGroup(num_group))
        allocate(faceID_array(num_halfFace), source=0)

        maxID_sum = maxval(halfFaceArray(:)%ID_sum)
        width = maxID_sum/num_group + 1   !1グループの幅(最大節点番号和を面グループ数で割る)
          
        checkCounter = 0
        call set_formatTC('("DIVIDE halfFace [ #group : ",i6," / ",i6," ]")')
        do groupID = 1, num_group  !面をグループに分ける
            call print_progress([groupID, num_group])
            faceID_array(:) = 0
            faceCounter = 1
            do faceID = 1, num_halfFace
                if((halfFaceArray(faceID)%ID_sum > (groupID-1)*width) &
                    .and.(halfFaceArray(faceID)%ID_sum <= groupID*width)) then

                    faceID_array(faceCounter) = faceID
                    faceCounter = faceCounter + 1
                    checkCounter = checkCounter + 1
                    
                end if
            end do
            faceGroup(groupID)%faceID = faceID_array(1 : faceCounter-1)
        end do

        if(checkCounter /= num_halfFace) then
            print*, 'faceCounter_ERROR:', checkCounter, num_halfFace
            error stop
        end if
          
        num_BoundFaces = 0
        call set_formatTC('("CHECK halfFace [ #group : ",i6," / ",i6," ]")')
        !!$omp parallel do private(faceID1,faceID2, match, k,l, num_face,numNode) reduction(+:num_BoundFaces)
        do groupID = 1, num_group
            call print_progress([groupID, num_group])
            num_face = size(faceGroup(groupID)%faceID)

            face1 : do i = 1, num_face
                faceID1 = faceGroup(groupID)%faceID(i)
                if(halfFaceArray(faceID1)%ownerCellID(2) /= None) cycle face1 !面共有セル探索が済んでいる場合スキップ
                if(halfFaceArray(faceID1)%nodeID(4) == None) then
                    numNode = 3   !三角形面
                else
                    numNode = 4   !四角形面
                end if
        
                face2 :do j = i+1, num_face
                    faceID2 = faceGroup(groupID)%faceID(j)
                    if(halfFaceArray(faceID2)%ownerCellID(2) /= None) cycle face2 !面共有セル探索が済んでいる場合スキップ
                    if((numNode == 3) .and. (halfFaceArray(faceID2)%nodeID(4) /= None)) cycle face2 !三角形面を注目中に四角形面が現れればスキップ
            
                    match = 0
                    do k = 1, numNode
                        do l = 1, numNode
                            if(halfFaceArray(faceID1)%nodeID(k) == halfFaceArray(faceID2)%nodeID(l)) match = match + 1  !点IDが一致すればカウント
                        end do
                    end do
            
                    if(match < numNode) cycle face2 !節点数と同じ回数一致しなければスキップ(必要十分条件)
            
                    !ここまでくれば同一の2面発見
            
                    halfFaceArray(faceID1)%ownerCellID(2) = halfFaceArray(faceID2)%ownerCellID(1)
                    halfFaceArray(faceID2)%ownerCellID(2) = halfFaceArray(faceID1)%ownerCellID(1)
            
                    cycle face1 !共有セルが見つかったので次の面へ
        
                end do face2
        
                ! halfFaceArray(faceID1)%ownerCellID(2) = 0 !共有セルが見つからなかった:境界面
                num_BoundFaces = num_BoundFaces + 1  !境界面カウント
        
            end do face1
    
        end do
        !!$omp end parallel do
        
        print*,'# Boundary Face =', num_BoundFaces

        print*,'END-FACE CHECK!'

        ! call cpu_time(time2)
        ! print*, time2 - time1
        ! error stop

    END subroutine check_halfFace

    subroutine find_boundFaceInformation(halfFaceArray, num_boundFace, cellBoundFaces, triangleBoundFaceVertices)
        !!境界面のみを取り出し、配列に格納
        !!四角形面であったとしても、最初の3点だけ抽出し、三角形面にして返す
        type(halfFace_t), intent(in) :: halfFaceArray(:)
        integer, intent(in) :: num_boundFace
        INTEGER II,JJJ,JB
        integer, intent(out) :: cellBoundFaces(:,:)
        integer, allocatable :: NoB(:)
        integer, allocatable, intent(out) :: triangleBoundFaceVertices(:,:)

        allocate(NoB(size(cellBoundFaces, dim=2)), source=0)
        allocate(triangleBoundFaceVertices(3, num_BoundFace))

        JB = 0
        DO JJJ = 1, size(halfFaceArray)
            if (halfFaceArray(JJJ)%ownerCellID(2) /= None) cycle   !第二オーナーが存在:境界面ではない:スルー

            JB = JB +1
            II = halfFaceArray(JJJ)%ownerCellID(1) !JJが属する要素番号
            NoB(II) = NoB(II) +1 !IIが所有する境界面数カウント
            cellBoundFaces(NoB(II),II) = JB !IIが所有する境界面番号

            triangleBoundFaceVertices(1:3, JB) = halfFaceArray(JJJ)%nodeID(1:3) !四角形面であったとしても、最初の3点だけ抽出

        END DO
       
    end subroutine
        
    subroutine find_adjacentCellID(halfFaceArray, adjacentCellIDArray)
        !!隣接関係を配列に格納
        type(halfFace_t), intent(in) :: halfFaceArray(:)
        integer, intent(out) :: adjacentCellIDArray(:,:)
        integer II, JJJ
        integer, allocatable :: num_adjacent(:)

        allocate(num_adjacent(size(adjacentCellIDArray)), source=0)

        do JJJ = 1, size(halfFaceArray)
            if (halfFaceArray(JJJ)%ownerCellID(2) == None) cycle !第2オーナーが未発見のハーフフェイス:境界面:スルー

            II = halfFaceArray(JJJ)%ownerCellID(1)
            num_adjacent(II) = num_adjacent(II) + 1
            adjacentCellIDArray(num_adjacent(II), II) = halfFaceArray(JJJ)%ownerCellID(2)

        end do

    end subroutine

    subroutine solve_BoundaryAndAdjacency(cellVertices, cellBoundFaces, triangleBoundFaceVertices, adjacentCellIDArray)
        !!境界面と隣接関係を、それぞれ配列に格納

        integer, intent(in) :: cellVertices(:,:)
            !!セルの頂点ID配列(頂点ID,セルID)

        integer, allocatable, intent(out) :: cellBoundFaces(:,:)
            !!セルの境界面ID配列(境界面ID,セルID)

        integer, allocatable, intent(out) :: triangleBoundFaceVertices(:,:)
            !!境界面の頂点ID配列(頂点ID,境界面ID)

        integer, allocatable, intent(out) :: adjacentCellIDArray(:,:)
            !!セルの隣接セルID配列(隣接セルID,セルID)

        type(halfFace_t), allocatable :: halfFaceArray(:)
        integer num_cell, num_BoundFace

        print*, '~ SolvingAdjacency is Required. ~'

        halfFaceArray = get_halfFaceArray(cellVertices)    !ハーフフェイスのセッティング

        call check_halfFace(halfFaceArray, num_BoundFace)  !同一面のチェック

        num_cell = size(cellVertices, dim=2)
        allocate(cellBoundFaces(max_boundFace, num_cell), source=None)
        allocate(adjacentCellIDArray(max_adjacent, num_cell), source=None)
        call find_boundFaceInformation(halfFaceArray, num_BoundFace, cellBoundFaces, triangleBoundFaceVertices)   !境界面情報

        call find_adjacentCellID(halfFaceArray, adjacentCellIDArray)   !セル隣接情報

    end subroutine

END MODULE adjacencySolver_m