GeometryClass.f90 Source File


Source Code

module GeometryClass
   use SMConstants
   use PhysicsStorage
   use NodalStorageClass
   use HexMeshClass
   use FTValueDictionaryClass
   use getInputData_MOD
   use FileReadingUtilities      , only: getFileName, getRealArrayFromString

   private
   public   Geometry_t, Construct

   type Geometry_t
      character(len=LINE_LENGTH) :: solutionName
      contains
         procedure ::  Construct => Geometry_Construct      
         procedure ::  Compute => Geometry_Compute      
         procedure ::  Describe => Geometry_Describe
   end type Geometry_t

   type, extends(Geometry_t)  :: Cube_t
      integer                    :: Npoints
      real(kind=RP)              :: L
      real(kind=RP)              :: xc(NDIM)
      real(kind=RP), allocatable :: x(:,:,:,:)
      real(kind=RP), allocatable :: U(:,:,:,:)
      contains
         procedure ::  Construct => Cube_Construct
         procedure ::  Compute => Cube_Compute
         procedure ::  Describe => Cube_Describe
   end type Cube_t

   type, extends(Geometry_t)  :: Cylinder_t

   end type Cylinder_t

   interface Construct
      module procedure ConstructGeometry
   end interface

   contains
      function ConstructGeometry(mesh, spA, controlVariables)
         implicit none
         class(HexMesh),           intent(in)    :: mesh
         class(NodalStorage_t),      intent(in)    :: spA(0:)
         class(FTValueDictionary), intent(in)    :: controlVariables
         class(Geometry_t),        pointer       :: ConstructGeometry
!
!        Allocate memory for the geometry
!        --------------------------------
         select case ( trim(controlVariables % StringValueForKey(GeometryKey,LINE_LENGTH)) )
         case ("Cube")
            allocate(Cube_t   :: ConstructGeometry)
         end select
!
!        Construct the class components
!        ------------------------------
         call ConstructGeometry % Construct(mesh, spA, controlVariables)
!
!        Add the solution file name
!        --------------------------
         ConstructGeometry % solutionName = trim(getFileName(trim(controlVariables % StringValueForKey(SolutionFileKey,LINE_LENGTH)))) 
!
!        Describe
!        --------
         call ConstructGeometry % Describe
   
      end function ConstructGeometry
!
!//////////////////////////////////////////////////////////
!
!     Geometry procedures
!     -------------------
!
!//////////////////////////////////////////////////////////
!
   subroutine Geometry_Construct(self, mesh, spA, controlVariables)
      implicit none
      class(Geometry_t),        intent(inout) :: self
      class(HexMesh),           intent(in)    :: mesh
      class(NodalStorage_t),      intent(in)    :: spA(0:)
      class(FTValueDictionary), intent(in)    :: controlVariables
!
!     -------------------------------
!     The template class does nothing
!     -------------------------------
!
   end subroutine Geometry_Construct

   subroutine Geometry_Compute(self, mesh, spA)
      implicit none
      class(Geometry_t),        intent(inout) :: self
      class(HexMesh),           intent(in)    :: mesh
      class(NodalStorage_t),      intent(in)    :: spA(0:)
!
!     -------------------------------
!     The template class does nothing
!     -------------------------------
!
   end subroutine Geometry_Compute

   subroutine Geometry_Describe(self)
      implicit none
      class(Geometry_t),   intent(in)  :: self
!
!     -------------------------------
!     The template class does nothing
!     -------------------------------
!
   end subroutine Geometry_Describe
!
!///////////////////////////////////////////////////////////////////////////
!
!     Cube procedures
!     ---------------
!
!///////////////////////////////////////////////////////////////////////////
!
   subroutine Cube_Construct(self, mesh, spA, controlVariables)
      implicit none
      class(Cube_t),            intent(inout) :: self
      class(HexMesh),           intent(in)    :: mesh
      class(NodalStorage_t),      intent(in)    :: spA(0:)
      class(FTValueDictionary), intent(in)    :: controlVariables
!
!     ---------------
!     Local variables
!     ---------------
!
      integer     :: i, j, k, eID
      real(kind=RP)  :: NDOF
      real(kind=RP)  :: volume, xintegral(3)
      real(kind=RP), allocatable :: xc(:)

!
!     Compute domain volume
!     ---------------------
      volume = 0.0_RP
   
      do eID = 1, mesh % no_of_elements
         associate( e => mesh % elements(eID) ) 
         associate(spAxi   => NodalStorage(e % Nxyz(1)), &
                   spAeta  => NodalStorage(e % Nxyz(2)), &
                   spAzeta => NodalStorage(e % Nxyz(3)) )
         do k = 0, e % Nxyz(3)   ; do j = 0, e % Nxyz(2)    ; do i = 0, e % Nxyz(1)
            volume = volume + spAxi % w(i) * spAeta % w(j) * spAzeta % w(k) * e % geom % jacobian(i,j,k)
         end do                  ; end do                   ; end do
         end associate
         end associate
      end do
!
!     Get the number of points
!     ------------------------
      if ( controlVariables % ContainsKey(NPointsKey) ) then
         self % Npoints = controlVariables % IntegerValueForKey(NPointsKey)
         self % Npoints = self % Npoints + mod(self % Npoints,2)
      else
!
!        Perform an estimation based on the number of DOFs
!        -------------------------------------------------         
         NDOF = 0

         do eID = 1, mesh % no_of_elements
            associate( e => mesh % elements(eID) ) 
            NDOF = NDOF + (e % Nxyz(1) + 1)*(e % Nxyz(2) + 1)*(e % Nxyz(3) + 1)
            end associate
         end do

         self % Npoints = NDOF ** (1.0_RP / 3.0_RP)
         self % Npoints = self % Npoints + mod(self % Npoints,2)
      end if
!
!     Get the cube length
!     -------------------
      if ( controlVariables % ContainsKey(CubeLengthKey) ) then
         self % L = controlVariables % DoublePrecisionValueForKey(CubeLengthKey)
      else
!
!        Perform an estimation based on the domain volume
!        ------------------------------------------------
         self % L = (volume) ** (1.0_RP / 3.0_RP)

      end if
         
!
!     Get the cube center
!     -------------------
      if ( controlVariables % ContainsKey(CubeCenterKey) ) then
         xc = getRealArrayFromString( controlVariables % StringValueForKey(CubeCenterKey, LINE_LENGTH)) 
         self % xc = xc

      else
!
!        Perform an estimation based on the domain centroid
!        --------------------------------------------------
         xintegral = 0.0_RP
         do eID = 1, mesh % no_of_elements
            associate( e => mesh % elements(eID) ) 
            associate(spAxi   => NodalStorage(e % Nxyz(1)), &
                      spAeta  => NodalStorage(e % Nxyz(2)), &
                      spAzeta => NodalStorage(e % Nxyz(3)) )
            do k = 0, e % Nxyz(3)   ; do j = 0, e % Nxyz(2)    ; do i = 0, e % Nxyz(1)
               xintegral = xintegral + spAxi % w(i) * spAeta % w(j) * spAzeta % w(k) * e % geom % jacobian(i,j,k) &
                                       * e % geom % x(:,i,j,k)
            end do                  ; end do                   ; end do
            end associate
            end associate
         end do
         self % xc = xintegral / volume

      end if

   end subroutine Cube_Construct

   subroutine Cube_Compute(self, mesh, spA)
         implicit none
         class(Cube_t),    intent(inout)  :: self
         class(HexMesh),   intent(in)  :: mesh
         class(NodalStorage_t), intent(in)  :: spA(0:)
!
!        ---------------
!        Local variables
!        ---------------
!
         integer, allocatable       :: elems(:,:,:)
         real(kind=RP), allocatable :: xi(:,:,:,:)
         integer                    :: fid, i, j, k, n, neighs(7), lastelement
         real(kind=RP), allocatable :: x(:,:,:,:), U(:,:,:,:)
         real(kind=RP)              :: Q(NCONS)
         real(kind=RP)              :: dx
         logical                    :: success
         character(len=LINE_LENGTH) :: solutionFile
!
!        ************************
!        Construct auxiliary mesh
!        ************************
!
         allocate(elems(0:self % Npoints,0:self % Npoints,0:self % Npoints))
         allocate(xi(NDIM,0:self % Npoints,0:self % Npoints,0:self % Npoints))
         allocate(x(NDIM,0:self % Npoints,0:self % Npoints,0:self % Npoints))
         allocate(U(3,0:self % Npoints,0:self % Npoints,0:self % Npoints))

         lastelement = 1

!$omp parallel private(n,neighs,success,Q) firstprivate(lastelement) shared(x,xi,U,elems,mesh,spA)
!$omp do collapse(3) 
         do k = 0, self % Npoints ; do j = 0, self % Npoints  ; do i = 0, self % Npoints
!
!           Get coordinates
!           ---------------
            x(1,i,j,k) = self % xc(1) - 0.5_RP * self % L + self % L * i / self % Npoints
            x(2,i,j,k) = self % xc(2) - 0.5_RP * self % L + self % L * j / self % Npoints
            x(3,i,j,k) = self % xc(3) - 0.5_RP * self % L + self % L * k / self % Npoints
!
!           Get the neighbours. This achieves a (very) large speedup
!           --------------------------------------------------------
            neighs(1) = lastelement
            do n = 1, 6
               if ( mesh % elements(lastelement) % NumberOfConnections(n) .ne. 0 ) then
                  neighs(n+1) = mesh % elements(lastelement) % Connection(n) % globID     ! TODO: Careful if you are using MPI
               else
                  neighs(n+1) = -1
               end if
            end do
!
!           Get the local coordinates and check
!           -----------------------------------
            success = mesh % FindPointWithCoords(x(:,i,j,k),elems(i,j,k),xi(:,i,j,k),neighs)
            if ( .not. success ) then
               print*, "Not success in element ", i,j,k
               error stop
            end if

            lastelement = elems(i,j,k)
!
!           Get the solution in this point
!           ------------------------------
            Q = mesh % elements(elems(i,j,k)) % EvaluateSolutionAtPoint(NCONS,xi(:,i,j,k)) 
            U(1:3,i,j,k) = Q(IRHOU:IRHOW) / Q(IRHO)
         end do            ; end do             ; end do
!$omp end do
!$omp end parallel

!
!        Write a tecplot file
!        --------------------
         write(solutionFile,'(A,A)') trim(self % solutionName), ".cube.tec"
         open(newunit = fid, file = trim(solutionFile), status = "unknown", action = "write") 

         write(fid,'(A)') 'TITLE = "PRUEBA"'
         write(fid,'(A)') 'VARIABLES = "x" "y" "z" "U" "V" "W"'
         write(fid,'(A,I0,A,I0,A,I0,A)') 'ZONE I=',self % Npoints+1,", J=",self % Npoints+1,", K=",self % Npoints+1, ", F=POINT"
         do k = 0, self % Npoints ; do j = 0, self % Npoints  ; do i = 0, self % Npoints
            write(fid,'(6(ES24.16,1X))') x(1:3,i,j,k), U(1:3,i,j,k)
         end do            ; end do             ; end do 
         close(fid)

   end subroutine Cube_Compute

   subroutine Cube_Describe(self)
      use Headers
      implicit none
      class(Cube_t), intent(in)  :: self
      
      write(STD_OUT,'(/)')
      call Section_Header("Interpolation to new geometry")
      write(STD_OUT,'(/)')
      call Subsection_Header("Describing the cube geometry")

      write(STD_OUT,'(30X,A,A30,A,ES10.3,A,ES10.3,A,ES10.3,A)') "->", "Cube centroid: ","[",self % xc(1),", ",self % xc(2),", ",self % xc(3),"]."
      write(STD_OUT,'(30X,A,A30,ES10.3,A)') "->", "Cube side length: ", self % L, "."
      write(STD_OUT,'(30X,A,A30,I0,A)') "->", "Number of points per side: ", self % Npoints, "."
      
   end subroutine Cube_Describe

end module GeometryClass