dropletMotionSimulation.f90 Source File


This file depends on

sourcefile~~dropletmotionsimulation.f90~~EfferentGraph sourcefile~dropletmotionsimulation.f90 dropletMotionSimulation.f90 sourcefile~conditionvalue.f90 conditionValue.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~conditionvalue.f90 sourcefile~dropletequation.f90 dropletEquation.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~dropletequation.f90 sourcefile~dropletgenerator.f90 dropletGenerator.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~dropletgenerator.f90 sourcefile~flow_field.f90 flow_field.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~flow_field.f90 sourcefile~path_operator.f90 path_operator.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~path_operator.f90 sourcefile~terminalcontroler.f90 terminalControler.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~terminalcontroler.f90 sourcefile~timekeeper.f90 timeKeeper.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~timekeeper.f90 sourcefile~unstructuredgrid.f90 unstructuredGrid.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~unstructuredgrid.f90 sourcefile~virusdroplet.f90 virusDroplet.f90 sourcefile~dropletmotionsimulation.f90->sourcefile~virusdroplet.f90 sourcefile~simplefile_reader.f90 simpleFile_reader.f90 sourcefile~dropletequation.f90->sourcefile~simplefile_reader.f90 sourcefile~vector.f90 vector.f90 sourcefile~dropletequation.f90->sourcefile~vector.f90 sourcefile~dropletgenerator.f90->sourcefile~dropletequation.f90 sourcefile~dropletgenerator.f90->sourcefile~virusdroplet.f90 sourcefile~array.f90 array.f90 sourcefile~dropletgenerator.f90->sourcefile~array.f90 sourcefile~dropletgenerator.f90->sourcefile~simplefile_reader.f90 sourcefile~flow_field.f90->sourcefile~path_operator.f90 sourcefile~flow_field.f90->sourcefile~unstructuredgrid.f90 sourcefile~unstructuredgrid.f90->sourcefile~path_operator.f90 sourcefile~adjacency_solver.f90 adjacency_solver.f90 sourcefile~unstructuredgrid.f90->sourcefile~adjacency_solver.f90 sourcefile~unstructuredgrid.f90->sourcefile~array.f90 sourcefile~kdtree.f90 kdTree.f90 sourcefile~unstructuredgrid.f90->sourcefile~kdtree.f90 sourcefile~scffile_reader.f90 SCFfile_reader.f90 sourcefile~unstructuredgrid.f90->sourcefile~scffile_reader.f90 sourcefile~sctfile_reader.f90 SCTfile_reader.f90 sourcefile~unstructuredgrid.f90->sourcefile~sctfile_reader.f90 sourcefile~unstructuredelement.f90 unstructuredElement.f90 sourcefile~unstructuredgrid.f90->sourcefile~unstructuredelement.f90 sourcefile~unstructuredgrid.f90->sourcefile~vector.f90 sourcefile~vtkmesh_operator.f90 vtkMesh_operator.f90 sourcefile~unstructuredgrid.f90->sourcefile~vtkmesh_operator.f90 sourcefile~adjacency_solver.f90->sourcefile~terminalcontroler.f90 sourcefile~kdtree.f90->sourcefile~terminalcontroler.f90 sourcefile~sort.f90 sort.f90 sourcefile~kdtree.f90->sourcefile~sort.f90 sourcefile~scffile_reader.f90->sourcefile~terminalcontroler.f90 sourcefile~vtkmesh_operator.f90->sourcefile~unstructuredelement.f90

Files dependent on this one

sourcefile~~dropletmotionsimulation.f90~~AfferentGraph sourcefile~dropletmotionsimulation.f90 dropletMotionSimulation.f90 sourcefile~main.f90 MAIN.f90 sourcefile~main.f90->sourcefile~dropletmotionsimulation.f90

Contents


Source Code

module dropletMotionSimulation
    !!author: Yuta Ida
    !!飛沫運動シミュレーションモジュール
    use virusDroplet_m
    use dropletGenerator_m
    use dropletEquation_m
    use flow_field_m
    use timeKeeper_m
    implicit none

    private

    type(TimeKeeper) tK

    logical :: startFlag = .false.

    logical :: adhesionSwitch = .true.
    integer :: coalescenceLimit=10000, num_divide=4
    character(:), allocatable :: radiusDistributionFilename

    public RunDropletsSimulation, read_basicSettingOnSimulation

    contains

    subroutine simulationSetUp(case_dir, droplets, dropletSolver, dropGenerator, flow_field, n_start, n_end, outputInterval)
        !!シミュレーションの条件ファイルを読み込み、諸々の変数を初期化して引数として返す
        use virusDroplet_m
        use conditionValue_m
        character(*), intent(in) :: case_dir
            !!ケースディレクトリ名

        type(virusDroplet_t), allocatable, intent(out) :: droplets(:)
            !!飛沫構造体配列

        type(DropletEquationSolver), target, intent(out) :: dropletSolver
            !!飛沫の運動方程式クラス

        type(DropletGenerator), intent(out) :: dropGenerator
            !!飛沫発生源クラス
        
        type(FlowField), intent(out) :: flow_field
            !!流れ場クラス

        integer, intent(out) :: n_start, n_end

        integer, intent(out) :: outputInterval

        type(conditionValue_t) condVal

        call create_CaseDirectory(case_dir)

        condVal = read_condition(case_dir)

        n_end = condVal%stepEnd
        outputInterval = condVal%outputInterval
        print*, 'n_end =',n_end
        print*, 'output interval =', outputInterval

        dropletSolver = DropletEquationSolver_( &
                            condVal%dt, condVal%L, condVal%U, &
                            condVal%direction_g, condVal%T, condVal%RH &
                        )

        n_start = max(condVal%restart, 0)

        dropGenerator = DropletGenerator_( &
                            dropletSolver, radiusDistributionFilename, case_dir, &
                            generationRate = condVal%periodicGeneration &
                        )

        if(condVal%restart <= 0) then

            if(condVal%isInitialDistributionSpecified()) then

                droplets = read_backup(case_dir//'/'//condVal%initialDistributionFName)

            else

                droplets = dropGenerator%generateDroplet(condVal%num_drop, dropletSolver%TimeStep2RealTime(n_start, .false.))

            end if

            call output_droplet_process(case_dir=case_dir, initial=.true., droplets=droplets, &
                timeStep=n_start, real_time=dropletSolver%TimeStep2RealTime(n_start, .true.))   !この時点では、飛沫の参照セルは見つかっていない

        else

            print*, '**RESTART**'

            block
                character(255) fname

                write(fname,'("'//case_dir//'/backup/backup_", i0, ".bu")') condVal%restart
                droplets = read_backup(trim(fname))   !ここで自動割り付け

            end block

        end if

        print*, 'num_droplets =', size(droplets)

        call checkpoint

        if(condVal%isMeshFileSpecified()) then
            flow_field = FlowField_( &                !流れ場の取得
                dropletSolver%TimeStep2RealTime(step=n_start, dimension=.false.), &
                condVal%PATH2FlowFile, condVal%DT_FLOW, condVal%OFFSET, condVal%INTERVAL_FLOW, &
                condVal%LoopHead, condVal%LoopTail, &
                condVal%meshFile &
            )

        else
            flow_field = FlowField_( &                !流れ場の取得
                dropletSolver%TimeStep2RealTime(step=n_start, dimension=.false.), &
                condVal%PATH2FlowFile, condVal%DT_FLOW, condVal%OFFSET, condVal%INTERVAL_FLOW, &
                condVal%LoopHead, condVal%LoopTail &
            )

        end if
            
        if(condVal%restart <= 0) call first_refCellSearch(droplets, flow_field)  !ここでようやく飛沫の参照セル探索

    end subroutine

    subroutine read_basicSettingOnSimulation
        !!シミュレーションの基礎的な設定ファイルを読み込む
        integer n_unit
        character(23) :: fname ='option/basicSetting.nml'
        character(255) radiusDistributionFNAME
        namelist /basicSetting/ coalescenceLimit, adhesionSwitch, num_divide, radiusDistributionFNAME

        print*, 'READ : ', fname
        
        open(newunit=n_unit, file=fname, status='old', action='read')
            read(n_unit, nml=basicSetting)
        close(n_unit)

        radiusDistributionFilename = trim(radiusDistributionFNAME)

    end subroutine

    subroutine RunDropletsSimulation(case_name)
        !!飛沫運動シミュレーションの実行

        character(*), intent(in) :: case_name
            !!ケースディレクトリ名

        type(virusDroplet_t), allocatable :: mainDroplets(:)
        type(DropletEquationSolver), target :: dropletSolver
        type(DropletGenerator) dropGenerator
        type(FlowField) flow_field
        integer n, n_start, n_end, outputInterval
        double precision timeInSimulation
        integer last_coalescenceStep
        logical generationFlag

        call simulationSetUp(case_name, mainDroplets, dropletSolver, dropGenerator, flow_field, n_start, n_end, outputInterval)

        last_coalescenceStep = n_start
        
        print '("*******************************************")'
        print '("            START step_loop                ")'
        print '("*******************************************")'

        do n = n_start + 1, n_end           !ステップ数だけループ
            timeInSimulation = dropletSolver%TimeStep2RealTime(n, .false.)
            
            call dropGenerator%periodicGeneration(mainDroplets, timeInSimulation, generationFlag)

            if(adhesionSwitch) call adhesion_check(mainDroplets, flow_field)

            call survival_check(mainDroplets, timeInSimulation)           !生存率に関する処理

            call coalescence_process(mainDroplets, n, last_coalescenceStep, generationFlag)        !飛沫間の合体判定

            call Calculation_Droplets(mainDroplets, dropletSolver, flow_field)     !飛沫の運動計算

            if (mod(n, outputInterval) == 0) then

                block
                    double precision real_time

                    real_time = dropletSolver%TimeStep2RealTime(n, .true.)
                    
                    call output_droplet_process(case_dir=case_name, &
                        initial=.false., droplets=mainDroplets, timeStep=n, real_time=real_time)

                    call periodicOutput(n, n_end, mainDroplets, real_time, flow_field%get_nearerSearchFalseRate())

                end block

            end if

            if(n==n_end) exit
            call check_FlowFieldUpdate(timeInSimulation, flow_field, mainDroplets)        !流れ場の更新チェック

        end do

        print '("*******************************************")'
        print '("             END step_loop                 ")'
        print '("*******************************************")'

        call output_ResultSummary(case_name, mainDroplets, dropletSolver, flow_field, n_start, n_end, outputInterval)

    end subroutine

    subroutine check_FlowFieldUpdate(time, flow_field, droplets)
        !!現時点のシミュレーション時刻から流れ場の更新が必要かを判定し、必要であれば更新する
        !!更新時、付着飛沫の移動も行う(移動格子への考慮)
        double precision, intent(in) :: time
            !!現時点のシミュレーション時刻
        type(FlowField), intent(inout) ::  flow_field
        type(virusDroplet_t), intent(inout) ::  droplets(:)

        call flow_field%set_time(time)

        if(flow_field%isUpdateTiming()) then
            call flow_field%update()   !流れ場の更新
            call dropletOnBoundary(droplets, flow_field)
        end if

    end subroutine

    subroutine first_refCellSearch(droplets, flow_field)
        !!飛沫の参照セル探索化
        !!初期飛沫は一箇所に密集していることを利用した時間短縮機能を実装
        type(virusDroplet_t), intent(inout) :: droplets(:)
        type(FlowField), intent(inout) ::  flow_field
        integer j, num_drop
        logical success
        real position(3)

        print*, 'first_refCellSearch occured!'

        num_drop = size(droplets)

        j = 1
        droplets(j)%refCellID = flow_field%nearest_cell(real(droplets(j)%position(:)))

        droplets(j+1:)%refCellID = droplets(j)%refCellID !時間短縮を図る

        do j = 2, num_drop
            position = real(droplets(j)%position(:))
            call flow_field%search_refCELL(position, droplets(j)%refCellID, stat=success)
            if(.not.success) droplets(j+1:)%refCellID = droplets(j)%refCellID
        end do
        
        ! call mainMesh%sort()

    end subroutine
   
    subroutine adhesion_check(droplets, flow_field)
        !!流れ場境界面への飛沫付着判定
        use unstructuredGrid_m
        type(virusDroplet_t), intent(inout) :: droplets(:)
        type(FlowField), intent(in) ::  flow_field
        integer i

        do i = 1, size(droplets)
            if(droplets(i)%isFloating()) then
                call flow_field%adhesionCheckOnBound( &
                    droplets(i)%position, droplets(i)%get_radius(), droplets(i)%refCellID, &
                    stat=droplets(i)%adhesBoundID &
                    )
                if (droplets(i)%adhesBoundID >= 1) call droplets(i)%stop_droplet()
            end if
        end do
            
        call area_check(droplets, flow_field)

    end subroutine

    subroutine area_check(droplets, flow_field)
        !!流れ場のバウンディングボックスへの飛沫付着判定
        type(virusDroplet_t), intent(inout) :: droplets(:)
        type(FlowField), intent(in) ::  flow_field
        logical check
        real areaMin(3), areaMax(3)
        integer i, J

        call flow_field%get_MinMaxOfGrid(areaMin, areaMax)

        do i = 1, size(droplets)
            check = .false.
            do J = 1, 3
        
                if(droplets(i)%position(J) < areaMin(J)) then
                    droplets(i)%position(J) = areaMin(J)
                    check = .true.
                else if(droplets(i)%position(J) > areaMax(J)) then
                    droplets(i)%position(J) = areaMax(J)
                    check = .true.
                end if

            end do

            if (check) call droplets(i)%stop_droplet()

        end do

    end subroutine
                      
    subroutine dropletOnBoundary(droplets, flow_field)
        !!流れ場境界面の移動に合わせて付着飛沫も移動させる
        use unstructuredGrid_m
        type(virusDroplet_t), intent(inout) :: droplets(:)
        type(FlowField), intent(in) ::  flow_field
        integer vn, JB

        ! print*, 'CALL:dropletOnBoundary'

        do vn = 1, size(droplets)
        
            if (droplets(vn)%isFloating()) cycle !付着していないならスルー
    
            JB = droplets(vn)%adhesBoundID
            if (JB > 0) then
                droplets(vn)%position(:) &
                    = droplets(vn)%position(:) &
                    + flow_field%get_movementVectorOfBoundarySurface(JB) !面重心の移動量と同じだけ移動
            end if
        
        end do

        ! call area_check(dGroup)

        ! print*, 'FIN:dropletOnBoundary'

    end subroutine

    subroutine Calculation_Droplets(droplets, dropletSolver, flow_field)
        !!飛沫の運動に関する一連の処理
        !!蒸発方程式、運動方程式を解いたあと、飛沫の参照セル探索を行う
        type(virusDroplet_t), intent(inout) :: droplets(:)
        type(DropletEquationSolver), intent(in) :: dropletSolver
        type(FlowField), intent(in) ::  flow_field
        integer vn, targetID
        double precision velAir(3)
        real position(3)

        !!$omp parallel do
        do vn = 1, size(droplets)

            if(droplets(vn)%isFloating())then

                call evaporationProcess(droplets(vn), dropletSolver)    !蒸発方程式関連の処理
               
                velAir(:) = flow_field%get_flowVelocityInCELL(droplets(vn)%refCellID)
                call dropletSolver%solve_motionEquation(&
                    droplets(vn)%position(:), droplets(vn)%velocity(:), velAir(:), droplets(vn)%get_radius())
        
                position = real(droplets(vn)%position(:))
                call flow_field%search_refCELL(position, droplets(vn)%refCellID)
            
            else 
                targetID = droplets(vn)%coalescenceID()
                if(targetID > 0) then
                    !合体飛沫の片割れも移動させる
                    droplets(vn)%position = droplets(targetID)%position
                    droplets(vn)%velocity = droplets(targetID)%velocity
                end if
            end if

        end do
        !!$omp end parallel do

    end subroutine

    subroutine evaporationProcess(droplet, dropletSolver)
        !!CALCULATE droplet evaporation
        use virusDroplet_m
        type(virusDroplet_t), intent(inout) :: droplet
        type(DropletEquationSolver), intent(in) :: dropletSolver
        double precision dr
      
        if (.not.droplet%isEvaporating()) return  !半径が最小になったものを除く
    
        dr = dropletSolver%evaporationEq(droplet%get_radius())  !半径変化量
        
        call droplet%evaporation(dr)
      
    end subroutine

    subroutine output_droplet_process(case_dir, initial, droplets, timeStep, real_time)
        !!飛沫情報のファイル出力
        !!VTK, CSV, backupファイルを出力
        character(*), intent(in) :: case_dir
        logical, intent(in) :: initial
        type(virusDroplet_t), intent(in) :: droplets(:)
        integer, intent(in) :: timeStep
        double precision, intent(in) :: real_time
        character(22), parameter :: IniDistributionFName = 'InitialDistribution.bu'

        character(255) fname

        write(fname,'("'//case_dir//'/VTK/drop_", i0, ".vtk")') timeStep
        call output_droplet_VTK(droplets, fname, deadline=initial)

        fname = case_dir//'/particle.csv'
        call output_droplet_CSV(droplets, fname, real_time, initial)

        if(initial) then
            fname = case_dir//'/backup/'//IniDistributionFName
        else
            write(fname,'("'//case_dir//'/backup/backup_", i0, ".bu")') timeStep
        end if
        call output_backup(droplets, trim(fname))

    end subroutine

    subroutine coalescence_process(mainDroplets, timeStep, last_coalescenceStep, generationFlag)
        !!飛沫間の合体判定プロセス
        !!一定期間合体が起こらなければ以降は判定をオフにする機能付き(計算コスト削減のため)
        use terminalControler_m

        type(virusDroplet_t), intent(inout) :: mainDroplets(:)
            !!メインの飛沫構造体配列

        integer, intent(in) :: timeStep
            !!時間ステップ

        integer, intent(inout) ::  last_coalescenceStep
            !! 最後に合体が起こったときの時間ステップ

        logical, intent(in) ::  generationFlag
            !! 飛沫が新たに発生したか否か

        integer numFloating, num_coalescence

        numFloating = dropletCounter(mainDroplets, 'floating')
        if(generationFlag) last_coalescenceStep = timeStep - 1    !飛沫発生が起こったら前ステップに付着が起こったことにする(付着判定再起動のため)

        !最後の合体から指定ステップが経過したら、以降は合体が起こらないとみなしてリターン
        if((timeStep - last_coalescenceStep) > coalescenceLimit) return

        call set_formatTC('(" Coalescence_check [step:", i10, "/", i10, "]")')
        call print_progress([timeStep, last_coalescenceStep + coalescenceLimit])

        ! call mainDroplet%coalescence_check(stat = num_coalescence)
        call divideAreaCoalescence_process(mainDroplets = mainDroplets, num_coales = num_coalescence)

        if(num_coalescence >= 1) last_coalescenceStep = timeStep

    end subroutine

    subroutine divideAreaCoalescence_process(mainDroplets, num_coales)
        !!飛沫をいくつかのエリアに分割し、それぞれで別々に合体判定を行う(計算コスト削減のため)
        type(virusDroplet_t), intent(inout) :: mainDroplets(:)
            !! メインの飛沫構造体配列

        integer, intent(out) :: num_coales
            !!合体が起こった回数

        type(virusDroplet_t), allocatable :: droplets(:)
        integer i, j, k, id, m, stat_coales
        integer, allocatable :: ID_array(:)
        double precision AreaMin(3), AreaMax(3), width(3), delta(3), min_cdn(3), max_cdn(3)
        double precision, parameter :: deltaRatio = 1.d-2

        num_coales = 0
        if(num_divide <= 0) return

        call get_dropletsArea(mainDroplets, AreaMin, AreaMax)

        ! AreaMin(:) = AreaMin(:) - 1.d-9 ;print*, 'AreaMin:',AreaMin
        ! AreaMax(:) = AreaMax(:) + 1.d-9 ;print*, 'AreaMax:',AreaMax
        width(:) = (AreaMax(:) - AreaMin(:)) / dble(num_divide)   !;print*, 'width:',width
        delta(:) = (AreaMax(:) - AreaMin(:))*deltaRatio

        do k = 1, num_divide
            min_cdn(3) = AreaMin(3) + width(3)*dble(k-1) - delta(3)
            max_cdn(3) = AreaMin(3) + width(3)*dble(k) + delta(3)
            do j = 1, num_divide
                min_cdn(2) = AreaMin(2) + width(2)*dble(j-1) - delta(2)
                max_cdn(2) = AreaMin(2) + width(2)*dble(j) + delta(2)
                do i = 1, num_divide
                    min_cdn(1) = AreaMin(1) + width(1)*dble(i-1) - delta(1)
                    max_cdn(1) = AreaMin(1) + width(1)*dble(i) + delta(1)

                    ID_array = dropletIDinBox(mainDroplets, min_cdn, max_cdn, status=0)
                    ! print*, 'divide_stat :', size(ID_array), min_cdn, max_cdn
                    droplets = mainDroplets(ID_array)  !分割エリア内の飛沫を抽出(ここでIDが変わる)
                    call coalescence_check(droplets, stat=stat_coales)  !分割エリア内で合体判定
                    num_coales = num_coales + stat_coales

                    block
                        integer coalesID
                        do m = 1, size(ID_array)
                            id = ID_array(m)
                            mainDroplets(id) = droplets(m)  !飛沫情報をもとのIDに格納

                            coalesID = droplets(m)%coalescenceID()
                            !合体飛沫については、合体先ID(coalesID)ももとのIDに戻す必要がある
                            if(coalesID > 0) mainDroplets(id)%coalesID = ID_array(coalesID)
                        end do
                    end block

                end do
            end do
        end do

    end subroutine

    subroutine checkpoint
        !! 計算条件確認のためのチェックポイント

        character(1) input

        do while(.not.startFlag)
            print*, 'Do you want to start the calculation? (y/n)'
            read(5,*) input

            select case(input)
            case('y')
                startFlag = .true.

            case('n')
                stop

            end select

        end do

        tK = TimeKeeper_()

    end subroutine

    subroutine create_CaseDirectory(case_dir)
        !!連番ファイル出力用のディレクトリを作成
        use path_operator_m
        character(*), intent(in) :: case_dir

        call make_directory(case_dir//'/VTK')
        call make_directory(case_dir//'/backup')
        
    end subroutine

    subroutine periodicOutput(nowStep, endStep, droplets, real_time, nearerSearchFalseRate)
        !!一定のステップ周期で飛沫情報をコンソールに出力する
        use terminalControler_m
        integer, intent(in) :: nowStep
            !!現在の時間ステップ

        integer, intent(in) :: endStep
            !!終了時間ステップ

        type(virusDroplet_t), intent(in) :: droplets(:)
            !!飛沫構造体配列

        double precision, intent(in) :: real_time
            !!シミュレーション時刻[sec]

        real, intent(in) ::  nearerSearchFalseRate
            !!飛沫の参照セル探索(時間短縮版)の成功率

        print*, '[Start Date] ' // tk%startDateAndTime()
        print '(" ** It will take", f8.2, " minites **")', real(endStep - nowStep)/(60.*real(nowStep)/tK%erapsedTime())
        print*, 'Now_Step_Time =', real_time, '[sec]'
        print*, '# floating :', dropletCounter(droplets, 'floating'), '/', dropletCounter(droplets, 'total')
        if(nearerSearchFalseRate >= 1.) print*, '# searchFalseRate :', nearerSearchFalseRate, '%'
        print '("====================================================")'
        call reset_formatTC

    end subroutine

    subroutine output_ResultSummary(case_dir, droplets, dropletSolver, flow_field, n_start, n_end, outputInterval)
        !!シミュレーション結果のサマリーをファイル出力
        use dropletEquation_m
        character(*), intent(in) :: case_dir
        type(virusDroplet_t), allocatable, intent(in) :: droplets(:)
        type(DropletEquationSolver), target, intent(in) :: dropletSolver
        type(FlowField), intent(in) :: flow_field
        integer, intent(in) :: n_start, n_end, outputInterval
        integer n_unit, cnt
        real erapsed_time
        character(50) fname
        logical existance
        double precision TimeStart, TimeEnd
        character(:), allocatable :: startDAT, endDAT
        
        erapsed_time = tk%erapsedTime()

        startDAT = '[Start Date] ' // tk%startDateAndTime()
        endDAT = '[ END  Date] ' // nowDateAndTime()
        print*, startDAT
        print*, endDAT

        fname = case_dir//'/ResultSummary.txt'
        inquire(file=fname, exist=existance)
        cnt = 0
        do while(existance)
            cnt = cnt + 1
            write(fname,'("'//case_dir//'/ResultSummary_", i0, ".txt")') cnt
            inquire(file=fname, exist=existance)
        end do

        TimeStart = dropletSolver%TimeStep2RealTime(step=n_start, dimension=.true.)
        TimeEnd = dropletSolver%TimeStep2RealTime(step=n_end, dimension=.true.)

        open(newunit=n_unit, file=fname, status='new')
            write(n_unit,*)'*******************************************'
            write(n_unit,*)'*                                         *'
            write(n_unit,*)'*             Result Summary              *'
            write(n_unit,*)'*                                         *'
            write(n_unit,*)'*******************************************'
            write(n_unit,'(A)') '======================================================='
            write(n_unit,*) startDAT
            write(n_unit,*) endDAT
            write(n_unit, '(A18, F15.3, 2X, A)') 'Erapsed Time =', erapsed_time, '[sec]'
            write(n_unit, '(A18, F15.3, 2X, A)') 'Cost of Calc =', &
                    erapsed_time / (TimeEnd - TimeStart), '[sec/sec]'
            write(n_unit,'(A)') '======================================================='
            write(n_unit, '(A18, 2(F15.3,2x,A))') 'Time [sec] =', TimeStart, '-', TimeEnd
            write(n_unit, '(A18, 2(I15,2x,A))') 'Step =', n_start, '-', n_end !計算回数
            write(n_unit,'(A18, I15)') 'OutputInterval =', outputInterval
            write(n_unit,'(A)') '======================================================='
            write(n_unit,'(A18, I15)') '#Droplets =', dropletCounter(droplets, 'total')
            write(n_unit,'(A18, I15)') 'floating =', dropletCounter(droplets, 'floating')
            write(n_unit,'(A18, I15)') 'death =', dropletCounter(droplets, 'death') !生存率で消滅
            write(n_unit,'(A18, I15)') 'coalescence =', dropletCounter(droplets, 'coalescence') !生存率で消滅
            write(n_unit,'(A18, I15)') 'adhesion =', dropletCounter(droplets, 'adhesion') !付着したすべてのウイルス数
            write(n_unit,'(A)') '======================================================='
            write(n_unit,'(A18, F18.2)') 'Temp [degC] =', dropletSolver%dropletEnvironment('Temperature')
            write(n_unit,'(A18, F18.2)') 'RH [%] =', dropletSolver%dropletEnvironment('RelativeHumidity')
            write(n_unit,'(A18, 2X, A)') 'Used FlowFile :', flow_field%get_defaultFlowFileName()
            write(n_unit, '(A18, I15,2x,A, f8.3,2x,A)') 'SearchFalseInfo :', flow_field%get_num_nearerSearchFalse(), &
                    ' (', flow_field%get_nearerSearchFalseRate(), '%)'

        close(n_unit)
        
    end subroutine

    ! double precision function TimeOnSimu(dropletSolver, dimension)
    !     type(DropletEquationSolver), target, intent(in) :: dropletSolver
    !     logical, intent(in), optional :: dimension

    !     if(present(dimension)) then
    !         TimeOnSimu = dropletSolver%TimeStep2RealTime(timeStep, dimension)
    !     else
    !         TimeOnSimu = dropletSolver%TimeStep2RealTime(timeStep, .false.)
    !     end if

    ! end function

    ! subroutine random_set    !実行時刻に依存した乱数シードを指定する
    !     implicit none
    !     integer :: seedsize, i
    !     integer, allocatable :: seed(:)

    !     print*, 'call:random_set'
    
    !     call random_seed(size=seedsize) !シードのサイズを取得。(コンパイラごとに異なるらしい)
    !     allocate(seed(seedsize)) !新シード配列サイズの割り当て
    
    !     do i = 1, seedsize
    !         call system_clock(count=seed(i)) !時間を新シード配列に取得
    !     end do
    
    !     call random_seed(put=seed(:)) !新シードを指定
          
    ! end subroutine random_set

end module dropletMotionSimulation