modern fortran+MPIでマルチフィジクスをやる際のクラス構造(もとい構想)

こんばんは@soybeanです。
Fortranアドベントカレンダーの記事を拝読していて、大変勉強になります。皆様、ありがとうございます。

さて、21日目はfortranとMPIでマルチフィジクスソルバーを開発する際のクラス構造設計について議論してみたいと思います。


### Who am I?

農学分野のPh.D. candidateです。土質材料ー植物間の力学的相互作用について研究しています。手法としては、構造計算や数値流体力学、計算接触力学あたりを使って現象の理解と予測を行ってきました。
加えて、植物の形態が複雑であり計算不可が大きいため、PCクラスタを構築し運用しています。

### Abstract

マルチフィジクス解析のプログラムを自作する場合に、プログラムの設計は悩ましい問題です。特に、メッシュ、個々の物理場、およびソルバーを、計算リソースの不要な消費を避け、スケーラブルで、可読性を失わない形でまとめるためには多大な試行錯誤が求められます。本項では、やってみなはれ精神に基づき、すべての場の離散化を有限要素法で行う場合を想定した、マルチフィジクス解析プログラムのクラス構造を作ってみました。また、MPIへの適応性も議論します。方法として、単一の初期値境界値問題に対応したFEMDomainクラスというクラス、およびFEMDomainクラス同士の弱連成解析のターゲットとなるFEMIfaceクラスを定義します。ここで、1つのFEMDomainインスタンスは、あらゆる単一の（強連成の）初期値境界値問題について、FEMで離散化され近似解を求める際に必要十分な情報を格納できます。また、FEMIfaceインスタンスはあらゆる複数の（弱連成の）初期値境界値問題について、同様に必要十分な情報を格納できます。ここに、FEMDomainクラスは、Meshクラス（節点座標、要素コネクティビティ、要素材料番号）、MaterialPropクラス（材料パラメータ）、Boundaryクラス（境界条件、初期条件）、ShapeFunctionクラス（形状関数）、ControlParameterクラス（誤差判定に使用するパラメータ、解析ステップ数）を包含（コンポジション）しています。FEMIfaceクラスは、FEMDomainへのポインター等を包含（コンポジション）しています。実際に動かすと、各ソルバーは、強連成ソルバーであればFEMDomainインスタンスを、弱連成ソルバーであればFEMIfaceインスタンスを受け取り、連立方程式へと展開し、物理場を更新したのち、更新された情報をそれぞれ上書きすることで、全体場の更新を行い、マルチフィジクス解析を完了します。あとは、より上位のプログラムで、ソルバーを呼び出す順番を記述すれば、強連成と弱連成の入り混じった解析を行えました。スケーラビリティに関しては、ソルバーを順に呼び出すループを並列化して、FEMDomainの並列読み込みと並列更新を行うことで、MPIを用いた並列計算を実装できます。加えて、大規模計算にあたっては領域分割を行い、個々のsub領域をFEMDomainに、領域のコネクティビティ情報をFEMIfaceに格納することで、MPIを利用できます。以上により、解くべきマルチフィジクス問題をFEMDomain/FEMIfaceの両クラスのインスタンス群に分解・分類することで、計算リソースの節約、スケーラビリティおよび可読性を両立できると考えました。


### 1. Introduction

マルチフィジクス解析のプログラムを自作する場合に、プログラムの設計は悩ましい問題です。特に、メッシュ、個々の物理場、およびソルバーを、計算リソースの不要な消費を避け、スケーラブルで、可読性を失わない形でまとめるためには多大な試行錯誤が求められます。本項では、やってみなはれ精神に基づき、すべての場の離散化を有限要素法で行う場合を想定した、マルチフィジクス解析プログラムのクラス構造を作ってみました。また、MPIへの適応性も議論します。



### 2. Material and Method
方法として、単一の初期値境界値問題に対応したFEMDomainクラスというクラス、

```fortran


    type::FEMDomain_
        type(ShapeFunction_)    :: ShapeFunction
        type(Mesh_)             :: Mesh
        type(MaterialProp_)     :: MaterialProp
        type(Boundary_)         :: Boundary
        type(ControlParameter_) :: ControlPara
        real(real64) :: RealTime
        character*200 :: FilePath
        character*200 :: FileName
        character*9 :: Dtype
		character*20 :: SolverType
		character*200 :: Category1 
		character*200 :: Category2
		character*200 :: Category3
		integer(int32) :: timestep
    contains
        procedure,public :: Init   => InitializeFEMDomain
        procedure,public :: Delete => DeallocateFEMDomain
        procedure,public :: Export => ExportFEMDomain
		procedure,public :: Import => ImportFEMDomain
		procedure,public :: ImportMesh => ImportMeshFEMDomain

		procedure,public :: Resize => resizeFEMDomain
        procedure,public :: Merge  => MergeFEMDomain
        procedure,public :: AddDBoundCondition => AddDBoundCondition
        procedure,public :: AddNBoundCondition => AddNBoundCondition
        procedure,public :: AddTBoundCondition => AddTBoundCondition
        procedure,public :: AddMaterialID => AddMaterialID
        procedure,public :: SetDataType => SetDataType
        procedure,public :: SetSolver => SetSolver 
        procedure,public :: SetName => SetName 
        procedure,public :: SetUp      => SetUpFEMDomain
        procedure,public :: InitDBC => InitDBC
        procedure,public :: InitNBC => InitNBC
		procedure,public :: InitTBC => InitTBC
		procedure,public :: AddNBC => AddNBCFEMDomain 
        procedure :: MeltingSkelton => MeltingSkeltonFEMDomain
        procedure,public :: SetControlPara =>  SetControlParaFEMDomain
        procedure,public :: GmshPlotMesh => GmshPlotMesh
		procedure,public :: GmshPlotContour => GmshPlotContour
		procedure,public :: GmshPlotVector => GmshPlotVector 
        procedure,public :: GmshPlotContour2D => GmshPlotContour2D
        procedure,public :: GnuplotPlotContour  => GnuplotPlotContour   
		procedure,public :: GnuplotExportStress => GnuplotExportStress  
		procedure,public :: getDBCVector => getDBCVectorFEMDomain
		procedure,public :: move => moveFEMDomain
		procedure,public :: rotate => rotateFEMDomain
		procedure,public :: meshing => meshingFEMDomain
		procedure,public :: convertMeshType => convertMeshTypeFEMDomain

		! for debug
		procedure,public :: CheckConnectivity => CheckConnedctivityFEMDomain
        
    end type FEMDomain_

```


およびFEMDomainクラス同士の弱連成解析のターゲットとなるFEMIfaceクラスを定義します。

```fortran


    type,extends(FEMDomain_) :: FEMDomainPointer_
        type(FEMDomain_),pointer :: FEMDomainp

    end type


    type :: FEMIface_
        type(ShapeFunction_)    :: ShapeFunction1,ShapeFunction2
        type(Mesh_)             :: Mesh1,Mesh2 ! Mesh[12]%ElemNod is a LOCAL node pointer, not a DIRECT pointer for each domains
        type(MaterialProp_)     :: MaterialProp
        type(ControlParameter_) :: ControlPara
        type(FEMDomainPointer_),allocatable :: FEMDomains(:)
        real(real64),allocatable     :: NTN_NodCoord(:,:)
        real(real64),allocatable     :: NTS_NodCoord(:,:)
        real(real64),allocatable     :: STS_NodCoord(:,:)
        real(real64),allocatable     :: NTN_Val(:,:)
        real(real64),allocatable     :: NTS_Val(:,:)
        real(real64),allocatable     :: STS_Val(:,:)
        integer(int32),allocatable     :: NTN_ElemNod(:,:)
        integer(int32),allocatable     :: NTS_ElemNod(:,:)
        integer(int32),allocatable     :: STS_ElemNod(:,:)
        integer(int32),allocatable     :: NTN_Active(:)
        integer(int32),allocatable     :: NTS_Active(:)
        integer(int32),allocatable     :: STS_Active(:)
        real(real64),allocatable     :: NTN_Value(:,:)
        real(real64),allocatable     :: NTS_Value(:,:)
        real(real64),allocatable     :: STS_Value(:,:)
        integer(int32),allocatable     :: NTS_SegmentID(:,:)
        integer(int32),allocatable     :: GloNodPoint1(:,:),GloNodPoint2(:,:)
        
        integer(int32)                 :: DomainID1
        integer(int32)                 :: DomainID2
        integer(int32)                 :: DomainID3
        integer(int32)                 :: TimeStep
        integer(int32)                 :: NumOfImportedDomain
        character*200           :: FilePathDomain1
        character*200           :: FilePathDomain2
        character*200           :: FilePath

        character*200 :: FileNameDomain1
        character*200 :: FileNameDomain2
        character*200 :: FileName
        character*9   :: Dtype
        character*20  :: SolverType

        
    contains 
        procedure :: Init => InitializeFEMIface
        procedure :: setFEMDomain => setFEMDomainFEMIface 
        procedure :: Delete => DeallocateFEMIface
        procedure :: Import => ImportFEMIface
        procedure :: GetFEMIface => GetFEMIfaceFromFEMDomains
        procedure :: Export => ExportFEMIface
        procedure :: GmshPlotMesh => GmshPlotMeshFEMIface
        procedure :: GmshPlotNTS  => GmshPlotNTSFEMIface
        procedure :: GetNTNelement => GetNTNelement
        procedure :: GetNTSelement => GetNTSelement
        procedure :: GetGlobalNodePointer => GetGlobalNodePointerNTS
        procedure :: updateTimestep => updateTimestepIface
    end type

```


ここで、1つのFEMDomainインスタンスは、あらゆる単一の（強連成の）初期値境界値問題について、FEMで離散化され近似解を求める際に必要十分な情報を格納できます。また、FEMIfaceインスタンスはあらゆる複数の（弱連成の）初期値境界値問題について、同様に必要十分な情報を格納できます。

ここに、FEMDomainクラスは、

Meshクラス（節点座標、要素コネクティビティ、要素材料番号）、

```fortran

    type:: Mesh_
        real(8),allocatable::NodCoord(:,:)
        real(8),allocatable::NodCoordInit(:,:)
        integer,allocatable::ElemNod(:,:)

        integer,allocatable::FacetElemNod(:,:)
        integer,allocatable::NextFacets(:,:)
        integer,allocatable::SurfaceLine2D(:)
        integer,allocatable::ElemMat(:)
        integer,allocatable::SubMeshNodFromTo(:,:)
        integer,allocatable::SubMeshElemFromTo(:,:)
        integer,allocatable::SubMeshSurfFromTo(:,:)
        integer :: surface

        !for Interfaces
        integer,allocatable::GlobalNodID(:)

        character*70::ElemType
        character*70 ErrorMsg
    contains
        procedure :: Init => InitializeMesh
        procedure :: Delete => DeallocateMesh
        procedure :: Copy => CopyMesh
        procedure :: import => importMeshObj 
        procedure :: ImportElemNod => ImportElemNod
        procedure :: ImportNodCoord => ImportNodCoord
        procedure :: ImportElemMat => ImportElemMat

        procedure :: resize => resizeMeshobj
        procedure :: GetFacetElement => GetFacetElement
        procedure :: GetSurface => GetSurface
        procedure :: GetInterface => GetInterface
        procedure :: GetInterfaceElemNod => GetInterfaceElemNod
        procedure :: GetBoundingBox     => GetBoundingBox
        procedure :: GetFacetElemInsideBox => GetFacetElemInsideBox
        procedure :: GetInterSectBox => GetInterSectBox
        procedure :: GetNextFacets => GetNextFacets
        procedure :: MergeMesh => MergeMesh
        procedure :: ExportElemNod => ExportElemNod
        procedure :: ExportNodCoord => ExportNodCoord
        procedure :: ExportSurface2D => ExportSurface2D
        procedure :: DisplayMesh => DisplayMesh 
        procedure :: ShowMesh => ShowMesh 
        procedure :: MeltingSkelton => MeltingSkeltonMesh 
        procedure :: getNumOfDomain => getNumOfDomainMesh
        procedure :: SortFacet    => SortFacetMesh 
        procedure :: Meshing    => MeshingMesh
        procedure :: getCircumscribedCircle => getCircumscribedCircleMesh
        procedure :: getCircumscribedTriangle => getCircumscribedTriangleMesh
        procedure :: removeCircumscribedTriangle => removeCircumscribedTriangleMesh
    
        procedure :: DelauneygetNewNode => DelauneygetNewNodeMesh 
        procedure :: DelauneygetNewTriangle => DelauneygetNewTriangleMesh 
        procedure :: DelauneyremoveOverlaps => DelauneyremoveOverlapsMesh 
        procedure :: RemoveFailedTriangle => RemoveFailedTriangleMesh
        procedure :: GetElemType => GetElemTypeMesh 

        procedure :: convertMeshType => ConvertMeshTypeMesh
        procedure :: convertTetraToHexa => convertTetraToHexaMesh 
        procedure :: convertTriangleToRectangular => convertTriangleToRectangularMesh 
        procedure :: removeOverlappedNode =>removeOverlappedNodeMesh
    end type Mesh_
```



MaterialPropクラス（材料パラメータ）

```fortran


    type :: MaterialProp_
        real(real64),allocatable::MatPara(:,:)
        integer(int32) :: NumOfMatPara
        integer(int32) :: NumOfMaterial    
        
        character*40 :: MaterialType

        character*70 ErrorMsg
    contains
        procedure :: Init => initializeMaterial
        procedure :: Delete => DeallocateMaterialProp
    end type MaterialProp_


```

Boundaryクラス（境界条件、初期条件）、


```fortran


    type::Boundary_
        real(real64),allocatable::DBoundVal(:,:)
        real(real64),allocatable::NBoundVal(:,:)  
        real(real64),allocatable::TBoundVal(:,:)  
        real(real64),allocatable::TBoundElemGpVal(:,:,:)      
        
        real(real64),allocatable::DBoundValInc(:,:)
        real(real64),allocatable::NBoundValInc(:,:)  
        real(real64),allocatable::TBoundValInc(:,:)

        integer(int32),allocatable::DBoundNodID(:,:)
        integer(int32),allocatable::NBoundNodID(:,:)
        integer(int32),allocatable::TBoundNodID(:,:)
        integer(int32),allocatable::TBoundElemID(:)

        integer(int32),allocatable::DBoundNum(:)
        integer(int32),allocatable::NBoundNum(:)
        integer(int32),allocatable::TBoundNum(:)
        integer(int32),allocatable::TBoundElemNum(:)


        character*70 :: ErrorMsg
    contains
        procedure :: Init => InitializeBoundary
        procedure :: Delete => DeallocateBoundary
        procedure :: CheckDataType => CheckDatatypeBoundary
        procedure :: RemoveOverlap => DeleteOverlapBoundary
        procedure :: ImportDBound => ImportDBound
        procedure :: ImportNBound => ImportNBound
        procedure :: MergeDBound => MergeDBound
        procedure :: MergeNBound => MergeNBound

        procedure :: removeDBC => removeDBCBoundary        
        procedure :: removeNBC => removeNBCBoundary
        procedure :: removeTBC => removeTBCBoundary        
    end type Boundary_


```


ShapeFunctionクラス（形状関数）、

```fortran


    type::ShapeFunction_
        
        real(real64),allocatable::Nmat(:)
        real(real64),allocatable::dNdgzi(:,:)
        real(real64),allocatable::dNdgzidgzi(:,:)
        real(real64),allocatable::gzi(:)
        real(real64),allocatable::GaussPoint(:,:)
        real(real64),allocatable::GaussIntegWei(:)
        real(real64),allocatable::Jmat(:,:),JmatInv(:,:)
        real(real64),allocatable::ElemCoord(:,:)
        real(real64),allocatable::ElemCoord_n(:,:)
        real(real64),allocatable::du(:,:)

        real(real64) :: detJ

        integer(int32) :: NumOfNode
        integer(int32) :: NumOfOrder
        integer(int32) :: NumOfDim
        integer(int32) :: NumOfGp
        integer(int32) :: GpID
        integer(int32) :: ierr
        integer(int32) :: currentGpID
        
        character*70::ElemType
        character(len=60):: ErrorMsg
    contains
        procedure :: init => initShapeFunction
        procedure :: update => updateShapeFunction

        procedure :: SetType => SetShapeFuncType
        procedure :: GetAll  => GetAllShapeFunc
        procedure :: Deallocate => DeallocateShapeFunction
        procedure :: getType => getShapeFuncType 
        procedure :: GetGaussPoint => GetGaussPoint
    end type ShapeFunction_


```


ControlParameterクラス（誤差判定に使用するパラメータ、解析ステップ数）

```fortran

    type::ControlParameter_
        real(real64) :: Tol
        integer(int32) :: SimMode
        integer(int32) :: ItrTol
        integer(int32) :: Timestep
    contains
        procedure,public :: SetControlPara => SetControlPara
    end type ControlParameter_



```




を包含（コンポジション）しています。FEMIfaceクラスは、FEMDomainへのポインター等を包含（コンポジション）しています。



### 3. Results and Discussion

実際に動かすプログラムは、非常にスッキリします。

```fortran

program main
    use SimulatorClass
    
    implicit none ! 美しくない一文
    
    type(Field_),target     :: world
    integer,parameter       :: TotalStep=40
    real(8),parameter       :: time=1.0d0
    
    call world%Import()
    call Simulator(world,OptionalStep=TotalStep,OptionalTime=time)
    call world%Export()
    
end program 

```


Simulator内に格納された各ソルバーは、強連成ソルバーであればFEMDomainインスタンスを、弱連成ソルバーであればFEMIfaceインスタンスを受け取り、連立方程式へと展開し、物理場を更新したのち、更新された情報をそれぞれ上書きすることで、全体場の更新を行い、マルチフィジクス解析を完了します。

ここに、Simulatorクラスは各種ソルバーをコンポジットしているクラスです。

```fortran


    type :: Simulator_
        type(DiffusionEq_) ,allocatable :: DiffusionEq_Array(:)
        type(FiniteDeform_),allocatable :: FiniteDeform_Array(:)
        type(MultiPhysics_)  ,allocatable :: MultiPhysics_Array(:)
        type(ContactMechanics_),allocatable :: ContactMechanics_Array(:)
    contains
        procedure :: Deploy => DeploySimulator
        procedure :: SetTime => SetSimulatorTime
        procedure :: Run => RunSimulation
        procedure :: Display => DisplaySimulation
    end type


```

ここに、Simulatorメソッドは、ソルバー群をFEMDomain/FEMIface群にデプロイし、時間を進めます。

```fortran


subroutine Simulator(world,OptionalStep,OptionalTime,SolverType)
    class(Field_),target,intent(inout)   :: world
    type(Simulator_),target             :: sim
    type(MPI_) :: mpidata
    integer(int32),intent(in)  :: OptionalStep
    real(real64),intent(in)  :: OptionalTime
    character(*),optional,intent(in)::SolverType
    integer(int32)                 :: i,Step,ierr
    real(real64)                 :: time

    step=OptionalStep
    time=OptionalTime

    call sim%Deploy(world)
    call sim%SetTime(world,time,step)
    do i=1,step
        call sim%Run(world,i,SolverType=SolverType)
        call sim%Display(world,i)
    enddo

end subroutine

```

ここに、FieldクラスはFEMDomain群とFEMIface群をコンポジットしているクラスです。

```fortran



    type :: Field_
        type(FEMDomain_),allocatable::FEMDomainArray(:)
        type(FEMIface_) ,allocatable::FEMIfaceArray(:)
        type(FieldObjName_),allocatable::FieldList(:)
        integer(int32),allocatable::Timestep(:)
        real(real64),allocatable::RealTime(:)
        integer(int32) :: NumberOfObject,NumberOfIface

        character*200 :: FolderName
        character*200 :: DomainListName
        character*200 :: IfaceListName
    contains
        procedure :: Import => ImportField
        procedure :: show   => showField
        procedure :: Export => ExportField
        procedure :: Shift  => ShiftField

        procedure :: linkDomainToIface => linkDomainToIfaceField
    end type

```

ソルバー群のFieldインスタンスへのデプロイは、ポインタでポイントすることで行います。


```fortran



subroutine DeploySimulator(sim,field)
    type(Field_),target,intent(inout)  :: field
    class(Simulator_),intent(inout) :: sim
    integer(int32) :: i,j,n,DomainNum,ierr

    if(.not.allocated(sim%DiffusionEq_Array) ) then
        call InitializeSimulator(sim,field)
    endif

    n=size(field%FEMDomainArray,1)
    DomainNum=n
    do i=1,n
        if(trim(field%FEMDomainArray(i)%SolverType)=="DiffusionEq_" )then
            sim%DiffusionEq_Array(i)%FEMDomain => field%FEMDomainArray(i)
        elseif(trim(field%FEMDomainArray(i)%SolverType)=="FiniteDeform_" )then
            sim%FiniteDeform_Array(i)%FEMDomain => field%FEMDomainArray(i)
        else
            print *, "DeploySolver >> Invalid Solver Name : ",trim(field%FEMDomainArray(i)%SolverType)
            stop
        endif
    enddo

    n=size(field%FEMIfaceArray,1)

    do i=1,n
        if(trim(field%FEMIfaceArray(i) %SolverType)=="SyncMesh_" .or. &
            trim(field%FEMIfaceArray(i)%SolverType)=="syncmesh_" )then
            sim%MultiPhysics_Array(i)%FEMIFace => field%FEMIfaceArray(i)

            do j=1, DomainNum
                if(trim(sim%MultiPhysics_Array(i)%FEMIFace%FileNameDomain1) == &
                    trim(field%FEMDomainArray(j)%FileName)  )then
                    sim%MultiPhysics_Array(i)%FEMDomain1 => field%FEMDomainArray(j)
                    
                endif
                if(trim(sim%MultiPhysics_Array(i)%FEMIFace%FileNameDomain2) == &
                    trim(field%FEMDomainArray(j)%FileName)  )then
                    sim%MultiPhysics_Array(i)%FEMDomain2 => field%FEMDomainArray(j)
                endif
            enddo
        elseif(trim(field%FEMIfaceArray(i) %SolverType)=="ContactMechanics_" .or. &
            trim(field%FEMIfaceArray(i)%SolverType)=="contactmechanics_" )then
            sim%ContactMechanics_Array(i)%FEMIFace => field%FEMIfaceArray(i)
            do j=1, DomainNum
                if(trim(sim%ContactMechanics_Array(i)%FEMIFace%FileNameDomain1) == &
                    trim(field%FEMDomainArray(j)%FileName)  )then
                    sim%ContactMechanics_Array(i)%FEMDomain1 => field%FEMDomainArray(j)
                    
                endif
                if(trim(sim%ContactMechanics_Array(i)%FEMIFace%FileNameDomain2) == &
                    trim(field%FEMDomainArray(j)%FileName)  )then
                    
                    sim%ContactMechanics_Array(i)%FEMDomain2 => field%FEMDomainArray(j)
                endif
            enddo

        
        else
            print *, "DeploySolver >> Invalid Solver Name : ",trim(field%FEMIfaceArray(i) %SolverType)
            stop "debug"
        endif
    enddo
end subroutine




```

スケーラビリティに関しては、ソルバーを順に呼び出すループを並列化して、FEMDomainの並列読み込みと並列更新を行うことで、MPIを用いた並列計算を実装できます。加えて、大規模計算にあたっては領域分割を行い、個々のsub領域をFEMDomainに、領域のコネクティビティ情報をFEMIfaceに格納することで、MPIを利用できます。これらの詳細な実装については今後折をみて行いたいと考えています。

また、おまけとして、MPIを呼ぶためのクラスを作りました。

```fortran


    type :: comment
        character*200 :: comment
    endtype
    
    type:: MPI_

    
        integer(int32) :: ierr
        integer(int32) :: MyRank
        integer(int32) :: PeTot
        integer(int32) :: Comm1
        integer(int32) :: Comm2
        integer(int32) :: Comm3
        integer(int32) :: Comm4
        integer(int32) :: Comm5
        integer(int32),allocatable::Comm(:),key(:)
        integer(int32),allocatable::Stack(:,:),localstack(:)
        integer(int32) :: LapTimeStep
        real(real64) :: stime
        real(real64) :: etime
        real(real64) :: laptime(1000)
        type(comment) :: comments(1000)

    contains
        procedure :: Start => StartMPI
        procedure :: Barrier => BarrierMPI
        procedure, Pass ::  readMPIInt
        procedure, Pass ::  readMPIReal
        generic ::  read =>   readMPIInt,readMPIReal
        
        procedure, Pass :: BcastMPIInt
        procedure, Pass :: BcastMPIReal
        generic  :: Bcast => BcastMPIInt, BcastMPIReal

        procedure, Pass :: GatherMPIInt 
        procedure, Pass :: GatherMPIReal 
        generic :: Gather => GatherMPIInt, GatherMPIReal 


        procedure, Pass :: ScatterMPIInt 
        procedure, Pass :: ScatterMPIReal 
        generic :: Scatter => ScatterMPIInt, ScatterMPIReal 
 

        procedure, Pass :: AllGatherMPIInt 
        procedure, Pass :: AllGatherMPIReal 
        generic :: AllGather => AllGatherMPIInt, AllGatherMPIReal 

        procedure, Pass :: AlltoAllMPIInt 
        procedure, Pass :: AlltoAllMPIReal 
        generic :: AlltoAll => AlltoAllMPIInt, AlltoAllMPIReal 
        

        procedure, Pass :: ReduceMPIInt 
        procedure, Pass :: ReduceMPIReal 
        generic :: Reduce => ReduceMPIInt, ReduceMPIReal 

        procedure, Pass :: AllReduceMPIInt 
        procedure, Pass :: AllReduceMPIReal 
        generic :: AllReduce => AllReduceMPIInt, AllReduceMPIReal 

        procedure :: createStack => createStackMPI
        procedure :: showStack   => showStackMPI
        procedure :: free  => freeMPI 
        procedure :: split => splitMPI 
        procedure :: copy  => copyMPI 
        procedure :: End => EndMPI
        procedure :: getLapTime => getLapTimeMPI
        procedure :: showLapTime => showLapTimeMPI
        procedure :: GetInfo => GetMPIInfo
    end type    


```

こちらのクラスを使うと、簡単にMPIできます。

```fortran

program main
 use MPIClass
 implicit none

 type(MPI_)::mpid

 call mpid%start()

 print *, "My rank is :: ", mpid%MyRank
 
 call mpid%end()

end program 
```


### 4. Conclusion
以上により、解くべきマルチフィジクス問題をFEMDomain/FEMIfaceの両クラスのインスタンス群に分解・分類することで、計算リソースの節約、スケーラビリティおよび可読性を両立できると考えました。


### Acknowledgements

### Implementation

https://github.com/kazulagi/SiCroF.git