kdTree.f90 Source File


This file depends on

sourcefile~~kdtree.f90~~EfferentGraph sourcefile~kdtree.f90 kdTree.f90 sourcefile~sort.f90 sort.f90 sourcefile~kdtree.f90->sourcefile~sort.f90 sourcefile~terminalcontroler.f90 terminalControler.f90 sourcefile~kdtree.f90->sourcefile~terminalcontroler.f90

Files dependent on this one

sourcefile~~kdtree.f90~~AfferentGraph sourcefile~kdtree.f90 kdTree.f90 sourcefile~kdtree_test.f90 kdTree_test.f90 sourcefile~kdtree_test.f90->sourcefile~kdtree.f90 sourcefile~unstructuredgrid.f90 unstructuredGrid.f90 sourcefile~kdtree_test.f90->sourcefile~unstructuredgrid.f90 sourcefile~unstructuredgrid.f90->sourcefile~kdtree.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~main.f90 MAIN.f90 sourcefile~main.f90->sourcefile~dropletmotionsimulation.f90

Contents

Source Code


Source Code

module kdTree_m
    !!author: Shohei Kishi, Hikaru Konishi, Tatsuya Miyoshi, Yuta Ida
    !!kd-treeモジュール
    use sort_m
    implicit none
    private

    type :: node_in_kdTree_t
        private
        integer :: parent_ID = 0, child_ID_1 = 0, child_ID_2 = 0, cell_ID = 0
        integer depth
        integer, allocatable :: cellID_array(:)
    end type

    type, public :: kdTree
        private
        type(node_in_kdTree_t), allocatable :: node(:)
        contains
        procedure set_relation, saveAsDOT, saveAsTXT, read_kdTree
        procedure :: search => search_kdtree
    end type

    public kdTree_

    contains

    type(kdTree) function kdTree_(xyz_origin)
        use terminalControler_m
        real, intent(in) :: xyz_origin(:,:) !セル重心座標配列(3, num_cell)
        type(content_t), allocatable :: x_origin(:), y_origin(:), z_origin(:)
        type(content_t), allocatable :: array_pre(:), array_sorted(:)
        integer, allocatable :: leftChildIDArray(:), rightChildIDArray(:)
        integer centerID, i, num_node
        integer parentID, child1ID, child2ID
        integer depth, ID_counter

        ID_counter = 1

        num_node = size(xyz_origin, dim=2)
        allocate(kdTree_%node(num_node))

        !各軸に対してコンテンツ配列に
        x_origin = real2content(xyz_origin(1,:))
        y_origin = real2content(xyz_origin(2,:))
        z_origin = real2content(xyz_origin(3,:))

        kdTree_%node(1)%cellID_array = x_origin(:)%originID
        kdTree_%node(1)%depth = 0 !最初は深さゼロ

        call set_formatTC('("CREATING kd-tree [ #node : ",i7," / ",i7," ]")')
        do i = 1, num_node
            call print_progress([i, num_node])

            parentID = i

            depth = kdTree_%node(i)%depth

            !各軸を切り替えながら、コンテンツ配列から要素を抽出
            select case(mod(depth, 3))
            case(0)
                array_pre = x_origin(kdTree_%node(i)%cellID_array)
            case(1)
                array_pre = y_origin(kdTree_%node(i)%cellID_array)
            case(2)
                array_pre = z_origin(kdTree_%node(i)%cellID_array)
            end select

            ! array_sorted = heap_sort(array_pre)
            ! print '(*(i0, x))', array_sorted(:)%originID
            ! print '(*(g0, x))', array_sorted(:)%value

            array_sorted = merge_sort(array_pre)

            centerID = int(size(array_sorted)/2)+1
            kdTree_%node(i)%cell_ID = array_sorted(centerID)%originID     !ヒープソート結果の中央値
            leftChildIDArray = array_sorted(:centerID-1)%originID   !左側配列のIDだけ取り出す
            rightChildIDArray = array_sorted(centerID+1:)%originID  !右側配列のIDだけ取り出す

            if(size(leftChildIDArray) >= 1) then 
                ID_counter = ID_counter + 1
                child1ID = ID_counter
                kdTree_%node(child1ID)%cellID_array = leftChildIDArray
                call kdTree_%set_relation(parentID, child1ID, 'left')
            end if

            if(size(rightChildIDArray) >= 1) then
                ID_counter = ID_counter + 1
                child2ID = ID_counter
                kdTree_%node(child2ID)%cellID_array = rightChildIDArray
                call kdTree_%set_relation(parentID, child2ID, 'right')
            end if

        end do

        ! call print_tree(kdTree, xyz_origin)

    end function

    subroutine set_relation(self, parent_ID, child_ID, lr)
        class(kdTree) self
        integer, intent(in) :: parent_ID, child_ID
        character(*), intent(in) :: lr

        self%node(child_ID)%parent_ID = parent_ID
        self%node(child_ID)%depth = self%node(parent_ID)%depth + 1

        select case(lr)
        case('left')
            self%node(parent_ID)%child_ID_1 = child_ID
        case('right')
            self%node(parent_ID)%child_ID_2 = child_ID
        case default
            print '("relation ERROR")'
            error stop
        end select

    end subroutine

    !>探索サブルーチン
    subroutine search_kdTree(self, xyz, droplet_position, nearest_ID)
        class(kdTree), intent(in) :: self
        real, intent(in) :: xyz(:,:) 
        real, intent(in) :: droplet_position(3)
        integer depth, switch, parentID, nextChildID, i, leftChildID, rightChildID
        integer, intent(out) :: nearest_ID
        real mindist
        logical, allocatable :: NotYetCompared(:)
        integer, allocatable :: cellIDarray(:)

        parentID = 1

        do
            depth = self%node(parentID)%depth
            switch = mod(depth,3)+1
            if(droplet_position(switch) <= xyz(switch, self%node(parentID)%cell_ID)) then 
                nextChildID = self%node(parentID)%child_ID_1
            else 
                nextChildID = self%node(parentID)%child_ID_2
            end if

            if(nextChildID == 0) then
                exit
            else
                parentID = nextChildID
            end if

        end do

        ! このnearest_IDは最近傍末端ノードのcellID
        nearest_ID = self%node(parentID)%cell_ID
        
        ! 比較済みか未比較かを判別するlogical配列を用意
        ! 最初はすべて比較していないのでtrueで初期化
        allocate(NotYetCompared(size(self%node)))
        NotYetCompared(:) = .true.

        mindist = norm2(xyz(:,nearest_ID)-droplet_position(:))
        ! 末端ノードとの比較が終わったのでfalse
        NotYetCompared(self%node(parentID)%cell_ID) = .false.

        do
            ! 注目する親ノードIDを更新
            parentID = self%node(parentID)%parent_ID
            depth = self%node(parentID)%depth
            switch = mod(depth,3)+1
            
            leftChildID = self%node(parentID)%child_ID_1
            rightChildID = self%node(parentID)%child_ID_2

            ! 右もしくは左の子が存在しない場合の処理。存在しないときの子ノードIDは0となる
            ! self%node(0)%cell_IDは存在しないので、除外する。
            if(leftChildID == 0 .or. rightChildID == 0) then
                allocate(cellIDarray(1))
                cellIDarray(1) = self%node(parentID)%cell_ID
            else
                ! 注目している親の左の子をまだ比較していないならtrue
                if(NotYetCompared(self%node(leftChildID)%cell_ID)) then
                    ! 注目する親とそれに付随する左の子すべてのcellIDを返す
                    allocate(cellIDarray(size(self%node(leftChildID)%cellID_array)+1))
                    cellIDarray(1) = self%node(parentID)%cell_ID
                    cellIDarray(2:) = self%node(leftChildID)%cellID_array
                else
                    ! 注目する親とそれに付随する右の子すべてのcellIDを返す
                    allocate(cellIDarray(size(self%node(rightChildID)%cellID_array)+1))
                    cellIDarray(1) = self%node(parentID)%cell_ID
                    cellIDarray(2:) = self%node(rightChildID)%cellID_array
                end if
            end if

            ! (末端ノード-飛沫座標)<=(末端ノードの親の注目(switch)座標-飛沫の注目(switch)座標)
            if(mindist <= abs(xyz(switch,self%node(parentID)%cell_ID)-droplet_position(switch))) then
                ! 注目している親と左or右のすべての子をfalse
                NotYetCompared(cellIDarray) = .false.
            else
                do i = 1, size(cellIDarray)
                    ! (注目している親および左or右のすべての子-飛沫座標)を比較
                    if(norm2(xyz(:,cellIDarray(i))-droplet_position(:)) <= mindist) then
                        mindist = norm2(xyz(:,cellIDarray(i))-droplet_position(:))
                        nearest_ID = cellIDarray(i)
                    end if
                    NotYetCompared(cellIDarray(i)) = .false.
                end do
            end if

            deallocate(cellIDarray)

            if(parentID == 1) then
                exit
            end if

        end do

        deallocate(NotYetCompared)

    end subroutine

    subroutine saveAsDOT(self, xyz, fname)
        class(kdTree), intent(in) :: self
        real, intent(in) :: xyz(:,:)
        character(*), intent(in) :: fname
        integer n_unit
        integer i
        character(1), parameter :: dq = '"'

        open(newunit=n_unit, file=fname)
        write(n_unit, '("graph {")')

        write(n_unit, '(4x, "node [")')
        write(n_unit, '(2(4x), "shape = record,")')
        write(n_unit, '(4x, "];")')
          
        write(n_unit, '()')

        ! node define
        do i = 1, size(self%node)
            write(n_unit, '(4x, i0, "[label = ", A, "{", i0, "| cell ID : ", i0, "|", 3(f10.5), "}", A, "];")') &
                i, dq, i, self%node(i)%cell_ID, xyz(:, self%node(i)%cell_ID), dq
        end do

        write(n_unit, '()')

        ! edge define
        do i = 1, size(self%node)
            if(self%node(i)%child_ID_1 /= 0) then
                write(n_unit, '(4x, i0, " -- ", i0, ";")') i, self%node(i)%child_ID_1
            end if
            if(self%node(i)%child_ID_2 /= 0) then
                write(n_unit, '(4x, i0, " -- ", i0, ";")') i, self%node(i)%child_ID_2
            end if
        end do


        write(n_unit, '("}")')

    end subroutine

    subroutine saveAsTXT(self, fname)
        class(kdTree), intent(in) :: self
        character(*), intent(in) :: fname
        character(size(self%node)) fmt
        integer i, n_unit, iimx

        iimx = size(self%node)    

        open(newunit=n_unit, file = fname)
            write(n_unit,'(I0)') iimx
            do i = 1, iimx    
                write(n_unit,'(7(1x,I0))') i, self%node(i)%cell_ID, self%node(i)%parent_ID, &
                self%node(i)%child_ID_1, self%node(i)%child_ID_2, self%node(i)%depth, &
                size(self%node(i)%cellID_array)
            end do
            write(n_unit,'()')
            do i = 1, size(self%node)
                write(fmt,'("("I0"(1x,I0))")') size(self%node(i)%cellID_array)
                write(n_unit,fmt) self%node(i)%cellID_array
            end do
        close(n_unit)        

    end subroutine

    subroutine read_kdTree(self, fname)
        class(kdTree), intent(inout) :: self
        character(*), intent(in) :: fname
        integer i, n_unit, iimx
        integer, allocatable :: nodeID(:), cellID_arraySize(:)
        
        open(newunit = n_unit, file = fname)

            read(n_unit,*) iimx
            allocate(self%node(iimx))
            allocate(nodeID(iimx))
            allocate(cellID_arraySize(iimx))

            do i = 1, iimx
                read(n_unit,*) nodeID(i), self%node(i)%cell_ID, self%node(i)%parent_ID, &
                self%node(i)%child_ID_1, self%node(i)%child_ID_2, self%node(i)%depth, &
                cellID_arraySize(i)
            end do
            read(n_unit,'()')
            do i = 1, iimx
                allocate(self%node(i)%cellID_array(cellID_arraySize(i)))
                read(n_unit,*) self%node(i)%cellID_array
            end do

        close(n_unit)

        ! do i = 1, iimx
        !     print'(6(1x,I0))', nodeID(i), self%node(i)%cell_ID, self%node(i)%parent_ID, &
        !     self%node(i)%child_ID_1, self%node(i)%child_ID_2, self%node(i)%depth
        ! end do
        ! do i = 1, iimx
        !     print *, self%node(i)%cellID_array
        ! end do

    end subroutine

end module