TessellationTypes.f90 Source File


Source Code

#include "Includes.h"
module TessellationTypes

   use SMConstants
   use Utilities
   use IntegerDataLinkedList
   use ParamfileRegions                , only: readValueInRegion

   implicit none

   public :: DescribeSTLPartitions

   integer, parameter :: FORCING_POINT = 1, NOT_FORCING_POINT = 0
   integer, parameter :: POINT_ON_PLANE = 0, POINT_IN_FRONT_PLANE = 1, POINT_BEHIND_PLANE = 2, NumOfVertices = 3

!
!  **************************************************
!  Main type for a list of points
!  **************************************************
   type PointLinkedList
   
      class(point_type), pointer :: head => null()
      integer                    :: NumOfPoints
      
      contains
         procedure :: add        => PointLinkedList_add
         procedure :: remove     => PointLinkedList_Remove
         procedure :: removeLast => PointLinkedList_RemoveLast
         procedure :: destruct   => PointLinkedList_Destruct
   
   end type PointLinkedList

!
!  **************************************************
!  Main type for a generic point point
!  **************************************************
   type point_type
   
      class(point_type), pointer :: next => null(), prev => null()
      
      real(kind=rp), dimension(NDIM) :: coords, ImagePoint_coords, normal, xi, VectorValue
      real(kind=rp)                  :: theta, dist, Rank, ScalarValue
      integer                        :: index, element_index, NumOfIntersections, &
                                        Translate = 0, partition, objIndex, isForcingPoint, &
                                        STLNum, element_in, faceID 
      integer,       dimension(NDIM) :: local_Position
      logical                        :: delete = .false., isInsideBody = .false., &
                                        forcingPoint = .false., isInsideBox = .false.
      real(kind=RP), allocatable     :: invPhi(:,:), b(:), V(:,:,:), bb(:,:), Q(:,:)
      integer,       allocatable     :: nearestPoints(:) 

      contains
         procedure :: copy => point_type_copy
   
   end type   
   
!
!  **************************************************
!  Main type for a list of points
!  **************************************************
   type ObjectLinkedList
   
      class(object_type), pointer :: head => null()
      integer                     :: NumOfObjs
      
      contains
         procedure :: add        => ObjectLinkedList_add
         procedure :: destruct   => ObjectLinkedList_Destruct
   
   end type ObjectLinkedList 
   
!
!  **************************************************
!  Main type for a generic object
!  **************************************************  
   type Object_type

      class(Object_type), pointer :: next => null(), prev => null()
      
      type(point_type), dimension(:),   allocatable :: vertices
      real(kind=rp),    dimension(NDIM)             :: normal, tangent, coords
      integer                                       :: index, NumOfVertices
      integer,          dimension(2)                :: partition

      contains
         procedure :: copy       => object_type_copy
         procedure :: build      => object_type_build
         procedure :: destruct   => object_type_destruct
                  
   end type Object_type
   
!
!  **************************************************
!  Main type for a STL file reader
!  **************************************************
   type STLfile

      type(Object_type), dimension(:), allocatable :: ObjectsList
      integer                                      :: NumOfObjs, partition,      &
                                                      motionAxis, body,          &
                                                      NumOfObjs_OLD
      real(kind=RP)                                :: angularVelocity, ds,       &
                                                      Velocity,                  & 
                                                      rotationMatrix(NDIM,NDIM), &
                                                      rotationCenter(NDIM)
      logical                                      :: move, show, construct = .false. 
      character(len=LINE_LENGTH)                   :: filename, motionType
   
       contains
          procedure :: ReadTessellation
          procedure :: getRotationaMatrix    => STLfile_getRotationaMatrix
          procedure :: getDisplacement       => STLfile_getDisplacement
          procedure :: Clip                  => STL_Clip
          procedure :: updateNormals         => STL_updateNormals
          procedure :: SetIntegration        => STL_SetIntegration
          procedure :: ComputeVectorIntegral => STL_ComputeVectorIntegral
          procedure :: ComputeScalarIntegral => STL_ComputeScalarIntegral
          procedure :: destroy               => STLfile_destroy
          procedure :: Describe              => Describe_STLfile
          procedure :: Copy                  => STLfile_copy
          procedure :: plot                  => STLfile_plot
          procedure :: SetIntegrationPoints  => STL_SetIntegrationPoints

   end type
   
   
   
   type ObjsDataLinkedList_t
      type(ObjData_t), pointer     :: head => null()
      integer                      :: no_of_entries = 0
      contains
         procedure   :: Add      => ObjsDataLinkedList_Add
         procedure   :: check    => CheckObj
         procedure   :: Destruct => ObjsDataLinkedList_Destruct
    end type ObjsDataLinkedList_t
   
    type ObjData_t
      integer                   :: value 
      type(ObjData_t), pointer  :: next 
    end type ObjData_t


    type ObjsRealDataLinkedList_t
      class(ObjRealData_t), pointer :: head => NULL()
      integer                       :: no_of_entries = 0
      contains
         procedure   :: Add      => ObjsRealDataLinkedList_Add
         procedure   :: check    => CheckReal
         procedure   :: Destruct => ObjsRealDataLinkedList_Destruct
    end type ObjsRealDataLinkedList_t
   
   type ObjRealData_t
      real(kind=RP)                 :: value
      class(ObjRealData_t), pointer :: next 
    end type ObjRealData_t



    interface ObjsDataLinkedList_t
      module procedure  ConstructObjsDataLinkedList
    end interface 
    
    interface ObjsRealDataLinkedList_t
      module procedure  ConstructObjsRealDataLinkedList
    end interface 
   
   
   
   
   
   
   
   interface PointLinkedList
      module procedure :: PointLinkedList_Construct
   end interface

   interface ObjectLinkedList
      module procedure :: ObjectLinkedList_Construct
   end interface
   
   character(len=8) :: ROTATION = "rotation"
   character(len=6) :: LINEAR = "linear"

   contains   

      function ConstructObjsDataLinkedList( )
         implicit none
         type(ObjsDataLinkedList_t) :: ConstructObjsDataLinkedList 

         ConstructObjsDataLinkedList% head => null()
         ConstructObjsDataLinkedList% no_of_entries = 0

      end function ConstructObjsDataLinkedList
      
      function ConstructObjsRealDataLinkedList( )
         implicit none
         type(ObjsRealDataLinkedList_t) :: ConstructObjsRealDataLinkedList 

         ConstructObjsRealDataLinkedList% head => null()
         ConstructObjsRealDataLinkedList% no_of_entries = 0

      end function ConstructObjsRealDataLinkedList

      subroutine ObjsDataLinkedList_Add( this, value ) 
         implicit none
         !-arguments----------------------------------------------
         class(ObjsDataLinkedList_t), intent(inout) :: this
         integer,                     intent(in)    :: value
         !-local-variables----------------------------------------
         type(ObjData_t), pointer :: current
         integer                  :: i

         if ( this% no_of_entries .eq. 0 ) then
            allocate( this% head ) 
            this% head% value = value
            this% no_of_entries = 1
         else
            current => this% head    
            do i = 1, this% no_of_entries-1
               current => current% next
            end do
            allocate(current% next)
            current% next% value = value
            this% no_of_entries = this% no_of_entries + 1 
         end if

      end subroutine ObjsDataLinkedList_Add
      
      subroutine ObjsRealDataLinkedList_Add( this, value ) 
         implicit none
         !-arguments---------------------------------------------
         class(ObjsRealDataLinkedList_t), intent(inout) :: this
         real(kind=RP),                   intent(in)    :: value
         !-local-variables---------------------------------------
         type(ObjRealData_t), pointer  :: current
         integer                       :: i

         if ( this% no_of_entries .eq. 0 ) then
            allocate( this% head ) 
            this% head% value = value
            this% no_of_entries = 1
         else
            current => this% head    
            do i = 1, this% no_of_entries-1
               current => current% next
            end do
            allocate(current% next)
            current% next% value = value
            this% no_of_entries = this% no_of_entries + 1 
         end if

      end subroutine ObjsRealDataLinkedList_Add

      logical function CheckObj( this, value ) result( found )
         implicit none
         !-arguments---------------------------------------------
         class(ObjsDataLinkedList_t), intent(inout) :: this
         integer,                     intent(in)    :: value
         !-local-variables---------------------------------------
         type(ObjData_t), pointer :: current
         integer                  :: i
        
         found = .false.
        
         if( this% no_of_entries .eq.0 ) return
        
         current => this% head
        
         do i = 1, this% no_of_entries
            if( current% value .eq. value ) then
               found = .true.
               exit
            end if
            current => current% next
         end do
     
      end function CheckObj

      logical function CheckReal( this, value ) result( found )
         implicit none
         !-arguments----------------------------------------------
         class(ObjsRealDataLinkedList_t), intent(inout) :: this
         real(kind=RP),                   intent(in)    :: value
         !-local-variables----------------------------------------
         type(ObjRealData_t), pointer :: current
         integer                      :: i
        
         found = .false.
        
         if( this% no_of_entries .eq.0 ) return
        
         current => this% head
        
         do i = 1, this% no_of_entries
            if( almostEqual(current% value,value) ) then
               found = .true.
               exit
            end if
            current => current% next
         end do
     
      end function CheckReal

      elemental subroutine ObjsDataLinkedList_Destruct(this)
         implicit none
         !-arguments---------------------------------------------
         class(ObjsDataLinkedList_t), intent(inout) :: this
         !-local-variables---------------------------------------
         type(ObjData_t), pointer :: data, nextdata
         integer                  :: i

         data => this% head
         do i = 1, this% no_of_entries
            nextdata => data% next

            deallocate(data)
            data => nextdata
         end do
         
         this% no_of_entries = 0

      end subroutine ObjsDataLinkedList_Destruct
      
      elemental subroutine ObjsRealDataLinkedList_Destruct(this)
         implicit none
         !-arguments---------------------------------------------
         class(ObjsRealDataLinkedList_t), intent(inout) :: this
         !-local-variables---------------------------------------
         type(ObjRealData_t), pointer :: data, nextdata
         integer                      :: i

         data => this% head
         do i = 1, this% no_of_entries
            nextdata => data% next

            deallocate(data)
            data => nextdata
         end do
         
         this% no_of_entries = 0

      end subroutine ObjsRealDataLinkedList_Destruct

!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
!  This subroutine initializes a points list
!  ------------------------------------------------ 
   function PointLinkedList_Construct(  )
   
      implicit none
      
      type(PointLinkedList) :: PointLinkedList_Construct
      
      PointLinkedList_Construct% head => null()
   
   end function PointLinkedList_Construct
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
!  This subroutine adds a point to a points list
!  ------------------------------------------------ 
   subroutine PointLinkedList_Add( this, point )
      implicit none
      !-arguments-----------------------------------
      class(PointLinkedList) :: this
      type(point_type)       :: point
      !-local-variables-----------------------------
      type(point_type), pointer :: current,    &
                                   currentNext 
   
      if( .not. associated(this% head) ) then 
         allocate(this% head)
         call this% head% copy(point)
         this% head% next => this% head
         this% head% prev => this% head
      else
         current => this% head% prev
         currentNext => current% next
         allocate(currentNext) 
         call currentNext% copy(point)
         currentNext% next => this% head
         currentNext% prev => current
         nullify(current% next)
         current% next => currentNext
         nullify(this% head% prev)
         this% head% prev => currentNext
      end if
      
      nullify(current, currentNext)
   
   end subroutine PointLinkedList_Add
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
!  This subroutine deletes the point p from a points list
!  ------------------------------------------------  
   subroutine PointLinkedList_Remove( this, p )
      implicit none
      !-arguments--------------------------------------------------------------
      class(PointLinkedList),   intent(inout) :: this
      type(point_type), target, intent(inout) :: p
      !-local-variables--------------------------------------------------------
      type(point_type), pointer :: dataNext => null(), dataPrev => null(), &
                                   dataDel => null()
      
      dataDel => p
      
      dataPrev => p% prev; dataNext => p% next
      
      if( associated(dataDel, this% head) ) then
         error stop ":: Head of list can't be deleted here!"
         return
      end if
      
      dataPrev% next => null()
      dataPrev% next => dataNext
      dataNext% prev => null()
      dataNext% prev => dataPrev
   
      nullify(dataPrev, dataNext)
   
   end subroutine PointLinkedList_Remove
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
!  This subroutine deletes the last point from a points list
!  ------------------------------------------------  
   subroutine PointLinkedList_RemoveLast( this )
      implicit none
      !-arguments--------------------------------------------------------
      class(PointLinkedList), intent(inout) :: this
      !-local-variables--------------------------------------------------
      type(point_type), pointer :: data => null(), dataPrev => null()
      
      data => this% head% prev
   
      if( associated(data, this% head) ) then
         error stop ":: Head of list can't be deleted here!"
         return
      end if
      
      dataPrev => data% prev
      
      deallocate(data)
      
      dataPrev% next => null()
      dataPrev% next => this% head
      this% head% prev => null() 
      this% head% prev => dataPrev 
   
      nullify(dataPrev)
   
   end subroutine PointLinkedList_RemoveLast
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
!  This subroutine deletes a point from a points list
!  ------------------------------------------------ 
   subroutine PointLinkedList_Destruct( this )
      implicit none
      !-arguments--------------------------------------
      class(PointLinkedList), intent(inout) :: this
      !-local-variables--------------------------------
      class(point_type), pointer :: current, next 
      integer                    :: i
      
      if( this% NumOfPoints .eq. 0 ) return
      
      current => this% head
      next    => current% next

      do i = 2, this% NumOfPoints
         deallocate(current)
         current => next
         next    => current% next
      end do
      
      this% NumOfPoints = 0
      
   end subroutine PointLinkedList_Destruct
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine copies a point
!  ------------------------------------------------  

   subroutine point_type_copy( this, point )
      implicit none
      !-arguments-------------------------------
      class(point_type), intent(inout) :: this
      type(point_type),  intent(in)    :: point
    
      this% coords            = point% coords
      this% ImagePoint_coords = point% ImagePoint_coords
      this% theta             = point% theta
      this% index             = point% index
      this% element_index     = point% element_index
      this% local_position    = point% local_position
      this% Translate         = point% Translate
      this% partition         = point% partition
   
   end subroutine point_type_copy
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine initializes an objects list
!  ------------------------------------------------  
   function ObjectLinkedList_Construct(  )
      implicit none
      !-local-variables-------------------------------------
      type(ObjectLinkedList) :: ObjectLinkedList_Construct
      
      ObjectLinkedList_Construct% head => null()
      ObjectLinkedList_Construct% NumOfObjs = 0
   
   end function ObjectLinkedList_Construct
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine adds an object to an objects list
!  ------------------------------------------------  

   subroutine ObjectLinkedList_Add( this, object )
      implicit none
      !arguemnts--------------------------------------------
      class(ObjectLinkedList) :: this
      type(Object_type)       :: object
      !-local-variables-------------------------------------
      type(object_type), pointer :: current => null(), &
                                    currentNext => null()
   
      if( .not. associated(this% head) ) then 
         allocate(this% head)
         call this% head% copy(object)
         this% head% next => this% head
         this% head% prev => this% head
      else
         current => this% head% prev
         currentNext => current% next
         allocate(currentNext) 
         call currentNext% copy(object)
         currentNext% next => this% head
         currentNext% prev => current
         nullify(current% next)
         current% next => currentNext
         nullify(this% head% prev)
         this% head% prev => currentNext
         nullify(current, currentNext)
      end if
      
      this% NumOfObjs = this% NumOfObjs + 1
   
   end subroutine ObjectLinkedList_Add
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
!  This subroutine destroys an objects list
!  ------------------------------------------------ 
   subroutine ObjectLinkedList_Destruct( this )
      implicit none
      !arguemnts----------------------------------------
      class(ObjectLinkedList), intent(inout) :: this
      !-local-variables---------------------------------
      type(object_type), pointer :: data => null(), &
                                    dataPrev => null()
      
      if( .not. associated(this% head) ) return
      
      data => this% head% prev
      
      if( .not. associated(data, this% head) ) then
         do
            dataPrev => data% prev   
            call data% destruct()
            deallocate(data)
            data => dataPrev
            if( associated(data, this% head) ) exit
         end do
      end if
      
      deallocate(data)
      
      this% NumOfObjs = this% NumOfObjs - 1
      
      nullify(dataPrev)
      
   end subroutine ObjectLinkedList_Destruct
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine builds an object
!  -----------------------------------------------
   subroutine object_type_build( this, Points, normal, NumOfVertices, index )
      implicit none
      !-arguments---------------------------
      class(Object_type), intent(inout) :: this
      real(kind=RP),      intent(in)    :: Points(:,:)
      real(kind=RP),      intent(in)    :: normal(:)
      integer,            intent(in)    :: NumOfVertices, index
      !-local-variables--------------------------------------
      integer :: i
      
      if( allocated(this% vertices) ) deallocate(this% vertices)
      allocate(this% vertices(NumOfVertices))
      
      do i = 1, NumOfVertices
         this% vertices(i)% coords = Points(:,i)
      end do
      
      this% index            = index 
      this% normal           = normal 
      this% NumOfVertices    = NumOfVertices
      
   end subroutine object_type_build
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine copies an object
!  -----------------------------------------------
   subroutine object_type_copy( this, Object )
    
      implicit none
      !-arguments---------------------------
      class(Object_type), intent(inout) :: this
      type(Object_type),  intent(in)    :: Object
      !-local-variables-----------------------
      integer :: i
      
      allocate(this% vertices(Object% NumOfVertices))
      
      do i = 1, Object% NumOfVertices
         call this% vertices(i)% copy(Object% vertices(i))
      end do
      
      this% index            = Object% index 
      this% normal           = Object% normal 
      this% NumOfVertices    = Object% NumOfVertices
      this% partition        = Object% partition
      
   end subroutine object_type_copy
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine copies an object
!  -----------------------------------------------
   subroutine object_type_destruct( this )
    
      implicit none
      !-arguments---------------------------
      class(Object_type), intent(inout) :: this
      
      deallocate(this% vertices)
      
      this% index  = 0
      this% normal = 0.0_RP 
      this% NumOfVertices = 0
      
   end subroutine object_type_destruct
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine adds an object to a list of objects
!  -----------------------------------------------
   subroutine addObj( ObjList, Object )
   
      implicit none
      !-arguments----------------------------------------------------
      type(Object_type), target, intent(inout) :: ObjList
      type(Object_type),         intent(in)    :: Object
      !-local-variables----------------------------------------------
      type(Object_type), pointer :: Obj=>null(), Objprev => null() 
     
      if( .not. associated(ObjList% next)) then
         call ObjList% copy( Object )
         ObjList% next => ObjList
         ObjList% prev => ObjList
         return
      end if
      
      Obj => ObjList% prev
!            
!     previous point
!     ------------
      Objprev => ObjList% prev
      
      Obj => Obj% next
      allocate(Obj)
      
      Obj% next => ObjList
      Obj% prev => Objprev
      
      Objprev% next => Obj
      
      call Obj% copy( Object )
      
      ObjList% prev => null()
      ObjList% prev => Obj
      
      if( associated(Obj% prev, ObjList) ) then
         ObjList% next => Obj 
      end if
      
      nullify(Obj, Objprev)
      
   end subroutine addObj
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine describes the .stl file
!  -----------------------------------------------
   subroutine Describe_STLfile( this, filename )
      use Headers
      use MPI_Process_Info
      use PhysicsStorage
      implicit none
      !-arguments-----------------------------------
      class(STLfile),   intent(inout) :: this
      character(len=*), intent(in)    :: filename

      if( MPI_Process% isRoot) then
       
         write(STD_OUT,'(/)')
         call Section_Header("Reading stl file")
         write(STD_OUT,'(/)')
         call SubSection_Header('Stl file "' // trim(fileName) // '"')
      
         write(STD_OUT,'(30X,A,A35,I10)') "->" , "Number of objects: " , this% NumOfObjs
         if( this% move ) then
            write(STD_OUT,'(30X,A,A35,A10)') "->" , "Motion: " , this% motionType
            if( this% motionType .eq. ROTATION ) then 
               write(STD_OUT,'(30X,A,A35,F10.3,A)') "->" , "Angular Velocity: " , this% angularVelocity, " rad/s."
               write(STD_OUT,'(30X,A,A35,F10.3,A,F10.3,A,F10.3,A)') "->" , "Center of rotation: [" , this% rotationCenter(1), ',', & 
                                                                                                     this% rotationCenter(2), ',', & 
                                                                                                     this% rotationCenter(3), ']'
            elseif( this% motionType .eq. LINEAR ) then
               write(STD_OUT,'(30X,A,A35,F10.3,A)') "->" , "Translation Velocity: " , this% Velocity, " m/s."
            end if
            write(STD_OUT,'(30X,A,A35,I10)') "->" , "Axis of motion: " , this% motionAxis
         end if
         
      end if
   
   end subroutine Describe_STLfile
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine describes the .stl file
!  -----------------------------------------------
   subroutine DescribeSTLPartitions( partition, NumOfObjs )
      use Headers
      use MPI_Process_Info
      implicit none
      !-arguments--------------------------------
      integer, intent(in) :: partition, NumOfObjs
      !-local-variables--------------------------
      character(len=LINE_LENGTH) :: myString
      
      if( .not. MPI_Process% doMPIAction ) return

      write(myString,'(i100)') partition+1
      
      if( partition .eq. 0 ) then
         write(STD_OUT,'(/)')
         call Section_Header("stl partitions")
         write(STD_OUT,'(/)')
      end if
      
      call SubSection_Header('partition ' // trim(adjustl(myString)))
      write(STD_OUT,'(30X,A,A32,I10)') "->" , "Number of objects: " , NumOfObjs
      
   end subroutine DescribeSTLPartitions
!
!/////////////////////////////////////////////////////////////////////////////////////////////
!  
!  -------------------------------------------------
! This subroutine reads the .stl file
!  -----------------------------------------------
   subroutine  ReadTessellation( this, filename )
      use PhysicsStorage
      implicit none
      !-arguments---------------------------------------
      class(STLfile),             intent(inout) :: this
      character(len=*),           intent(in)    :: filename
      !-local-variables---------------------------------
      integer              :: i, j, funit, NumOfTri,   &
                              fileStat, NumOfVertices
      integer*2            :: padding
      real*4, dimension(3) :: norm, vertex
      character(len=80)    :: header

      NumOfVertices = 3 
      
      this% partition = 1
      
      funit = UnusedUnit()
      open(unit=funit,file='MESH/'//trim(filename)//'.stl',status='old',access='stream',form='unformatted', iostat=fileStat)
      
      if( fileStat .ne. 0 ) then
         print *, "Read Tessellation: file '",trim(filename),"' not found"
         error stop
      end if
      
      this% filename = filename

      read(funit) header
      read(funit) NumOfTri
      
      this% NumOfObjs = NumOfTri

      allocate(this% ObjectsList(NumOfTri))

      associate( Objs => this% ObjectsList )
      
      do i = 1, NumOfTri
         read(funit) norm(1), norm(2), norm(3)
         Objs(i)% normal = norm
         allocate(Objs(i)% vertices(NumOfVertices))
         do j = 1, NumOfVertices
            read(funit) vertex(1), vertex(2), vertex(3)
            Objs(i)% vertices(j)% coords = vertex  !/Lref -> always 1           
         end do
         read(funit) padding
         Objs(i)% index = i
         Objs(i)% NumOfVertices = NumOfVertices
         Objs(i)% partition = 1
      end do
        
      end associate   
       
      close(unit=funit)

   end subroutine  ReadTessellation

   subroutine STL_SetIntegrationPoints( this )

      implicit none

      class(STLfile), intent(inout) :: this 

      real(kind=RP) :: tmp(NDIM,NumOfVertices)
      integer       :: i, j, indeces(3)

      do i = 1, this% NumOfObjs
         associate( obj => this% ObjectsList(i) )
         do j = 1, NumOfVertices
            tmp(:,j) = obj% vertices(j)% coords
         end do 
         deallocate(obj% vertices)
         allocate(obj% vertices(NumOfVertices+4))
         obj% vertices(NumOfVertices+4)% coords = 0.0_RP
         indeces =(/ 2, 3, 1 /)
         do j = 1, NumOfVertices
            obj% vertices(j)% coords = tmp(:,j)
            obj% vertices(NumOfVertices+j)% coords = 0.5_RP*(tmp(:,j) + tmp(:,indeces(j)))
            obj% vertices(NumOfVertices+4)% coords = obj% vertices(NumOfVertices+4)% coords + &
                                                     tmp(:,j)
         end do
         obj% vertices(NumOfVertices+4)% coords = obj% vertices(NumOfVertices+4)% coords/3.0_RP
         end associate
      end do

   end subroutine STL_SetIntegrationPoints  


   subroutine STLfile_plot( this, iter )
      use MPI_Process_Info
      use PhysicsStorage
      implicit none
      !-arguments----------------------------------------------
      class(STLfile), intent(inout) :: this
      integer,        intent(in)    :: iter
      !-local-variables----------------------------------------
      character(len=LINE_LENGTH)     :: filename
      integer                        :: i, j, funit
      integer*2                      :: padding = 0
      real*4, dimension(3)           :: norm, vertex
      character(len=80)              :: header = repeat(' ',80)
            
      funit = UnusedUnit()
      
      write(filename,'(A,A,I10.10)') trim(this% filename),'_', iter
      
      open(funit,file='MESH/'//trim(filename)//'.stl', status='unknown',access='stream',form='unformatted')
 
      write(funit) header, this% NumOfObjs 
      
      do i = 1, this% NumOfObjs
         norm = this% ObjectsList(i)% normal
         write(funit) norm(1), norm(2), norm(3)
         do j = 1, NumOfVertices      
            vertex = this% ObjectsList(i)% vertices(j)% coords * Lref
            write(funit) vertex(1), vertex(2), vertex(3)
         end do
         write(funit) padding      
      end do

      close(funit)
   
   end subroutine STLfile_plot

   subroutine STLfile_copy( this, STL )

      implicit none 

      class(STLfile), intent(inout) :: this
      type(STLfile),  intent(in)    :: STL

      integer :: NumOfObjs, i, j

      NumOfObjs = STL% NumOfObjs

      this% NumOfObjs = NumOfObjs

      allocate( this% ObjectsList(NumOfObjs) )

!$omp parallel
!$omp do schedule(runtime) private(j)
      do i = 1, NumOfObjs
         allocate(this% ObjectsList(i)% vertices(NumOfVertices))
         do j = 1, NumOfVertices
            this% ObjectsList(i)% vertices(j)% coords = STL% ObjectsList(i)% vertices(j)% coords
         end do
         this% ObjectsList(i)% normal        = STL% ObjectsList(i)% normal
         this% ObjectsList(i)% index         = STL% ObjectsList(i)% index
         this% ObjectsList(i)% NumOfVertices = NumOfVertices
         this% ObjectsList(i)% partition     = 1
      end do
!$omp end do
!$omp end parallel
   end subroutine STLfile_copy
  
   subroutine STLfile_GetMotionInfo( this, STLfilename, NumOfSTL )
      use FileReadingUtilities
      use FTValueDictionaryClass
      use PhysicsStorage
      implicit none
      !-arguments-------------------------------------------------------
      type(STLfile),           intent(inout) :: this
      character(len=*),        intent(in)    :: STLfilename
      integer,                 intent(in)    :: NumOfSTL
      !-local-arguments-------------------------------------------------
      integer                    :: i
      integer,       allocatable :: motionAxis_STL
      real(kind=RP), allocatable :: angularVelocity_STL, Velocity_STL, &
                                    RC_x_STL, RC_y_STL, RC_z_STL
      character(len=LINE_LENGTH) :: in_label, paramFile,  &
                                    motion_STL, STL_name 

      this% move = .false.

      do i = 1, NumOfSTL
      
         write(in_label , '(A,I0)') "#define stl motion ", i

         call get_command_argument(1, paramFile)
         call readValueInRegion ( trim ( paramFile )  , "stl name"          , STL_name           , in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "type"              , motion_STL         , in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "angular velocity"  , angularVelocity_STL, in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "velocity"          , Velocity_STL       , in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "motion axis"       , motionAxis_STL     , in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "rotation center x" , RC_x_STL           , in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "rotation center y" , RC_y_STL           , in_label, "#end" ) 
         call readValueInRegion ( trim ( paramFile )  , "rotation center z" , RC_z_STL           , in_label, "#end" ) 

         if( trim(STLfilename) .ne. trim(STL_name) ) cycle

         this% move = .true.

         select case( trim(motion_STL) )
           case( "rotation" )
               this% motionType = ROTATION
            case( "linear" )
               this% motionType = LINEAR
            case default
               print *, "STLfile_GetMotionInfo: motion not recognized. Available motions are ", ROTATION," or ",LINEAR,"."
               error stop
         end select
         
         if( allocated(angularVelocity_STL) ) then
            this% angularVelocity = angularVelocity_STL
         elseif( this% motionType .eq. ROTATION ) then
            print *, "STLfile_GetMotionInfo: 'angular velocity' must be specified for ", ROTATION, " motion."
            error stop            
         end if
         
         if( allocated(Velocity_STL) ) then
            this% Velocity = Velocity_STL
         elseif( this% motionType .eq. LINEAR ) then
            print *, "STLfile_GetMotionInfo: 'velocity' must be specified for ", LINEAR, " motion."
            error stop            
         end if
         
         if( allocated(motionAxis_STL) ) then
            this% motionAxis = motionAxis_STL
            if( this% motionAxis .gt. 3 .or. this% motionAxis .lt. 1 ) then
               print *, "STLfile_GetMotionInfo: 'motion axis' =", this% motionAxis, " not valid:"
               print *, "select 1 for x-axis, 2 for y-axis or 3 for z-axis."
               error stop                
            end if
         elseif( this% move ) then
            print *, "STLfile_GetMotionInfo: 'motion axis' must be specified."
            error stop            
         end if

         if( this% motionType .eq. ROTATION ) then 
            if( .not. allocated(RC_x_STL) ) then 
               print *, "STLfile_GetMotionInfo: 'rotation center' must be specified."
               error stop 
            end if 
            this% rotationCenter(1) = RC_x_STL
            this% rotationCenter(2) = RC_y_STL
            this% rotationCenter(3) = RC_z_STL
         end if 
         
         return

      end do
 
   end subroutine STLfile_GetMotionInfo
   
   subroutine STLfile_getRotationaMatrix( this, t, angle )
      use PhysicsStorage
      use FluidData
      implicit none
      !-arguments-----------------------------
      class(STLfile),           intent(inout):: this
      real(kind=RP),            intent(in)   :: t
      real(kind=RP),  optional, intent(in)   :: angle 
      !-local-variables-----------------------
      real(kind=RP) :: time, theta

      if( present(angle) ) then 

         this% rotationMatrix = 0.0_RP
         theta = PI/180.0_RP*angle 

         select case( this% motionAxis )
            case( IX )
               this% rotationMatrix(1,1) = 1.0_RP
               this% rotationMatrix(2,2) = cos(theta)
               this% rotationMatrix(2,3) = -sin(theta)
               this% rotationMatrix(3,2) = sin(theta)
               this% rotationMatrix(3,3) = cos(theta)
            case( IY ) 
               this% rotationMatrix(2,2) = 1.0_RP
               this% rotationMatrix(1,1) = cos(theta)
               this% rotationMatrix(1,3) = sin(theta)
               this% rotationMatrix(3,1) = -sin(theta)
               this% rotationMatrix(3,3) = cos(theta)
            case( IZ )
               this% rotationMatrix(3,3) = 1.0_RP
               this% rotationMatrix(1,1) = cos(theta)
               this% rotationMatrix(1,2) = -sin(theta)
               this% rotationMatrix(2,1) = sin(theta)
               this% rotationMatrix(2,2) = cos(theta)
         end select
         return
      end if     
#if defined(NAVIERSTOKES)
      time = t * Lref/refValues% V
   
      theta = this% angularVelocity * time
   
      this% rotationMatrix = 0.0_RP
   
      select case( this% motionAxis )
         case( IX )
            this% rotationMatrix(1,1) = 1.0_RP
            this% rotationMatrix(2,2) = cos(theta)
            this% rotationMatrix(2,3) = -sin(theta)
            this% rotationMatrix(3,2) = sin(theta)
            this% rotationMatrix(3,3) = cos(theta)
         case( IY ) 
            this% rotationMatrix(2,2) = 1.0_RP
            this% rotationMatrix(1,1) = cos(theta)
            this% rotationMatrix(1,3) = sin(theta)
            this% rotationMatrix(3,1) = -sin(theta)
            this% rotationMatrix(3,3) = cos(theta)
         case( IZ )
            this% rotationMatrix(3,3) = 1.0_RP
            this% rotationMatrix(1,1) = cos(theta)
            this% rotationMatrix(1,2) = -sin(theta)
            this% rotationMatrix(2,1) = sin(theta)
            this% rotationMatrix(2,2) = cos(theta)
      end select
#endif       
   end subroutine STLfile_getRotationaMatrix
   
   subroutine STLfile_getDisplacement( this, t )
      use FluidData
      use PhysicsStorage
      implicit none
      !-arguments-----------------------------
      class(STLfile), intent(inout):: this
      real(kind=RP),  intent(in)   :: t

      real(kind=RP) :: time 
#if defined(NAVIERSTOKES)
      time = t * Lref/refValues% V
   
      this% ds = this% Velocity * time

      this% ds = this% ds/Lref
#endif
   end subroutine STLfile_getDisplacement

   subroutine STL_updateNormals( this )
      use MappedGeometryClass
      implicit none
      !-arguments------------------------------------
      class(STLfile), intent(inout):: this
      !-local-variables------------------------------
      real(kind=rp) :: du(NDIM), dv(NDIM), dw(NDIM)
      integer       :: i 
!$omp parallel
!$omp do schedule(runtime) private(du,dv,dw)
      do i = 1, this% NumOfObjs
         du = this% ObjectsList(i)% vertices(2)% coords - this% ObjectsList(i)% vertices(1)% coords
         dw = this% ObjectsList(i)% vertices(3)% coords - this% ObjectsList(i)% vertices(1)% coords
         call vcross(du,dw,dv)
         this% ObjectsList(i)% normal = dv/norm2(dv)      
      end do
!$omp end do
!$omp end parallel 
   end subroutine STL_updateNormals
   
   subroutine STLfile_destroy( this )
   
      implicit none
      !-arguments------------------------------
      class(STLfile), intent(inout) :: this
      !-local-variables------------------------
      integer :: i
      
      do i = 1, this% NumOfObjs
         deallocate(this% ObjectsList(i)% vertices)
      end do
      
      deallocate(this% ObjectsList)  

      this% NumOfObjs = 0
   
   end subroutine STLfile_destroy
!//////////////////////////////////////////////
!
!   Procedures form STL triangles splitting   
!   
!//////////////////////////////////////////////
! SPLITTING TRIANGLES 
   subroutine STL_Clip( this, minplane, maxplane, axis, describe )
      implicit none
      !-arguments--------------------------------------------------------------------
      class(STLfile), intent(inout) :: this
      real(kind=RP),  intent(in)    :: minplane, maxplane
      integer,        intent(in)    :: axis
      logical,        intent(in)    :: describe
      !-local-variables--------------------------------------------------------------
      type(ObjectLinkedList)     :: ObjectsLinkedList, ObjectsLinkedListFinal
      type(object_type), pointer :: obj 
      real(kind=RP)              :: minplane_point(NDIM), maxplane_point(NDIM),   & 
                                    minplane_normal(NDIM), maxplane_normal(NDIM), &
                                    Objmax, Objmin, vertices(NDIM,3)
      integer                    :: i, j

      minplane_point  = 0.0_RP
      maxplane_point  = 0.0_RP
      minplane_normal = 0.0_RP
      maxplane_normal = 0.0_RP
      
      minplane_point(axis)  = minplane
      maxplane_point(axis)  = maxplane
      minplane_normal(axis) = -1.0_RP
      maxplane_normal(axis) =  1.0_RP
 
      ObjectsLinkedList      = ObjectLinkedList_Construct()
      ObjectsLinkedListFinal = ObjectLinkedList_Construct()

      do i = 1, this% NumOfObjs
          call ClipPloy( this% ObjectsList(i), maxplane_normal, maxplane_point, ObjectsLinkedList )
      end do

      obj => ObjectsLinkedList% head 

      do i = 1, ObjectsLinkedList% NumOfObjs
         call ClipPloy( obj, minplane_normal, minplane_point, ObjectsLinkedListFinal )
         obj => obj% next 
      end do  
      
      call ObjectsLinkedList% destruct()       

      call this% destroy()

      this% partition = 1
      this% NumOfObjs = ObjectsLinkedListFinal% NumOfObjs
  
      allocate(this% ObjectsList(this% NumOfObjs))
 
      obj => ObjectsLinkedListFinal% head 

      do i = 1, this% NumOfObjs
         allocate(this% ObjectsList(i)% vertices(obj% NumOfVertices))
         do j = 1, obj% NumOfVertices
            this% ObjectsList(i)% vertices(j)% coords = obj% vertices(j)% coords
         end do
         this% ObjectsList(i)% normal        = obj% normal
         this% ObjectsList(i)% index         = i
         this% ObjectsList(i)% NumOfVertices = obj% NumOfVertices
         this% ObjectsList(i)% partition     = 1
         obj => obj% next 
      end do 

      call ObjectsLinkedListFinal% destruct()

      if( describe ) call this% describe(this% filename)

      call this% plot(0)

   end subroutine STL_Clip

   subroutine ClipPloy( obj, plane_normal, plane_point, ObjectsLinkedList )
      use MappedGeometryClass
      implicit none
      !-arguments--------------------------------------------------------------------
      type(object_type),      intent(in)    :: obj
      real(kind=rp),          intent(in)    :: plane_normal(:), plane_point(:)
      type(ObjectLinkedList), intent(inout) :: ObjectsLinkedList
      !-local-variables--------------------------------------------------------------
      real(kind=RP)     :: PointFront(NDIM,4), PointBack(NDIM,4)
      type(object_type) :: objBack
      real(kind=RP)     :: PointA(NDIM), PointB(NDIM), Point_inters(NDIM), v(NDIM),u(NDIM),W(NDIM)
      integer           :: PointA_Is, PointB_Is, n_front, n_back, i 

      n_front = 0; n_back = 0
      
      pointA = obj% vertices(obj% NumOfVertices)% coords
      
      PointA_Is = Point_wrt_Plane( plane_normal, plane_point, pointA )
   
      do i = 1, obj% NumOfVertices
         PointB    = obj% vertices(i)% coords
         PointB_Is = Point_wrt_Plane( plane_normal, plane_point, pointB )
         if( PointB_Is .eq. POINT_IN_FRONT_PLANE ) then
            if( PointA_Is .eq. POINT_BEHIND_PLANE ) then
               Point_inters = EdgePlaneIntersection( plane_normal, plane_point, PointA, PointB )
               n_front = n_front + 1
               n_back  = n_back + 1
               PointFront(:,n_front) = Point_Inters
               PointBack(:,n_back) = Point_Inters
            end if
            n_front = n_front + 1
            PointFront(:,n_front) = PointB
         elseif( PointB_Is .eq. POINT_BEHIND_PLANE ) then
            if( PointA_Is .eq. POINT_IN_FRONT_PLANE ) then
               Point_inters = EdgePlaneIntersection( plane_normal, plane_point, PointA, PointB )
               n_front = n_front + 1
               n_back  = n_back + 1
               PointFront(:,n_front) = Point_Inters
               PointBack(:,n_back) = Point_Inters
            elseif( PointA_Is .eq. POINT_ON_PLANE ) then
               n_back  = n_back + 1
               PointBack(:,n_back) = PointA
            end if
            n_back  = n_back + 1
            PointBack(:,n_back) = PointB 
         else
            n_front = n_front + 1
            PointFront(:,n_front) = PointB
            if( PointA_Is .eq. POINT_BEHIND_PLANE ) then
               n_back  = n_back + 1
               PointBack(:,n_back) = PointB 
            end if
         end if
         PointA    = PointB
         PointA_Is = PointB_Is 
      end do
      
      ! take only back elements !! 
      if( n_back .eq. 3 ) then
         call objBack% build( PointBack(:,1:n_back), obj% normal, obj% NumOfVertices, obj% index )
         call ObjectsLinkedList% add(objBack)
         call objBack% destruct()
      elseif( n_back .eq. 4 ) then
         call objBack% build( PointBack(:,1:n_back-1), obj% normal, obj% NumOfVertices, obj% index )
         call ObjectsLinkedList% add(objBack)
         call objBack% destruct()
         call objBack% build( PointBack(:,(/n_back-1,n_back,1/)), obj% normal, obj% NumOfVertices, obj% index )
         call ObjectsLinkedList% add(objBack)
         call objBack% destruct()
      elseif( n_back .eq. 0 ) then 
      else
         print *, "ClipPloy:: wrong number of vertices: ", n_back
         error stop
      end if 
   
   end subroutine ClipPloy

   subroutine STL_SetIntegration( this, NumOfInterPoints )
      use MPI_Process_Info
      implicit none 

      class(STLfile), intent(inout) :: this 
      integer,        intent(in)    :: NumOfInterPoints

      integer :: i, j

      if( .not. MPI_Process% isRoot ) return 
 
      do i = 1, this% NumOfObjs
         do j = 1, NumOfVertices + 4
            allocate( this% ObjectsList(i)% vertices(j)% nearestPoints(NumOfInterPoints),           &
                      this% ObjectsList(i)% vertices(j)% invPhi(NumOfInterPoints,NumOfInterPoints), &
                      this% ObjectsList(i)% vertices(j)% b(NumOfInterPoints)                        )
         end do 
      end do 
 
   end subroutine STL_SetIntegration

   function STL_ComputeScalarIntegral( this )

      implicit none 

      class(STLfile), intent(inout) :: this 
      real(kind=RP)                 :: STL_ComputeScalarIntegral

      real(kind=RP) :: ScalarVar(NumOfVertices+4)
      integer       :: i, j

      STL_ComputeScalarIntegral = 0.0_RP

      do i = 1, this% NumOfObjs
         associate( obj => this% ObjectsList(i) )
         do j = 1, NumOfVertices+4
            ScalarVar(j) = obj% vertices(j)% ScalarValue
         end do
         STL_ComputeScalarIntegral = STL_ComputeScalarIntegral + TriangleScalarIntegral( obj, ScalarVar )
         end associate
      end do

   end function STL_ComputeScalarIntegral

   function STL_ComputeVectorIntegral( this )

      implicit none 

      class(STLfile), intent(inout) :: this 
      real(kind=RP)                 :: STL_ComputeVectorIntegral(NDIM)

      real(kind=RP) :: VectorVar(NDIM,NumOfVertices+4)
      integer       :: i, j

      STL_ComputeVectorIntegral = 0.0_RP

      do i = 1, this% NumOfObjs
         associate( obj => this% ObjectsList(i) )
         do j = 1, NumOfVertices+4
            VectorVar(:,j) = obj% vertices(j)% VectorValue
         end do
         STL_ComputeVectorIntegral = STL_ComputeVectorIntegral + TriangleVectorIntegral( obj, VectorVar )
         end associate
      end do

   end function STL_ComputeVectorIntegral

   function TriangleScalarIntegral( obj, ScalarVar ) result( Val )
      use MappedGeometryClass
      implicit none 

      type(object_type), intent(in) :: obj 
      real(kind=RP),     intent(in) :: ScalarVar(NumOfVertices+4)
      real(kind=RP)                 :: Val

      real(kind=RP) :: AB(NDIM), AC(NDIM), S(NDIM), A

      AB = obj% vertices(2)% coords - obj% vertices(1)% coords 
      AC = obj% vertices(3)% coords - obj% vertices(1)% coords 

      call vcross(AB,AC,S)

      A = 0.5_RP * norm2(S)

      Val = A/60.0_RP * ( 27.0_RP * ScalarVar(NumOfVertices+4) +                    &
                           3.0_RP * sum(ScalarVar(1:NumOfVertices)) +               &
                           8.0_RP * sum(ScalarVar(NumOfVertices+1:NumOfVertices+3)) )

   end function TriangleScalarIntegral

   function TriangleVectorIntegral( obj, VectorVar ) result( Val )
      use MappedGeometryClass
      implicit none 

      type(object_type), intent(in) :: obj 
      real(kind=RP),     intent(in) :: VectorVar(NDIM,NumOfVertices+4)
      real(kind=RP)                 :: Val(NDIM)

      real(kind=RP) :: AB(NDIM), AC(NDIM), S(NDIM), A

      AB = obj% vertices(2)% coords - obj% vertices(1)% coords 
      AC = obj% vertices(3)% coords - obj% vertices(1)% coords 

      call vcross(AB,AC,S)

      A = 0.5_RP * norm2(S)

      Val = A/60.0_RP * ( 27.0_RP * VectorVar(:,NumOfVertices+4) +                    &
                           3.0_RP * sum(VectorVar(:,1:NumOfVertices)) +               &
                           8.0_RP * sum(VectorVar(:,NumOfVertices+1:NumOfVertices+3)) )

   end function TriangleVectorIntegral
   
   integer function Point_wrt_Plane( plane_normal, plane_point, point ) result( PointIs )
      use MappedGeometryClass
      implicit none
      !-arguments-----------------------------------------------------------------
      real(kind=RP), dimension(:), intent(in) :: plane_normal, plane_point, point
      !-local-variables-----------------------------------------------------------
      real(kind=RP) :: d, eps
   
      d = dot_product(plane_normal,point) - dot_product(plane_normal,plane_point)
      
      if( d > EPSILON(eps) ) then
         PointIs = POINT_IN_FRONT_PLANE
      elseif( d < -EPSILON(eps) ) then
         PointIs = POINT_BEHIND_PLANE
      else 
         PointIs = POINT_ON_PLANE
      end if
   
   end function Point_wrt_Plane
  
   function EdgePlaneIntersection( plane_normal, plane_point, PointA, PointB ) result( Point_inters )
      use MappedGeometryClass
      implicit none
      !-arguments-----------------------------------------------------------------
      real(kind=RP), intent(in) :: plane_normal(:), plane_point(:), &
                                   PointA(:), PointB(:)
      real(kind=RP)             :: Point_inters(NDIM)
      !-local-variables-----------------------------------------------------------
      real(kind=RP) :: B_A(NDIM), d, t
 
      B_A = PointB - PointA
      
      d = dot_product(plane_normal,plane_point)
      
      t = ( d - dot_product(plane_normal,PointA) )/dot_product(plane_normal,B_A)
 
      Point_inters = PointA + t*B_A 
 
   end function EdgePlaneIntersection
!//////////////////////////////////////////////
   
   subroutine TecFileHeader( FileName, Title, I, J, K, funit, DATAPACKING, ZONETYPE )
   
      implicit none
      !-arguments------------------------------------------------------
      character(len=*), intent(in)  :: FileName, Title, DATAPACKING
      integer,          intent(in)  :: I, J, K
      character(len=*), optional    :: ZONETYPE
      integer,          intent(out) :: funit
   
      funit = UnusedUnit()
   
      open(funit,file=trim(FileName)//'.tec', status='unknown')
      
      write(funit,"(A9,A,A)") 'TITLE = "',trim(Title),'"'
      write(funit,"(A23)") 'VARIABLES = "x","y","z"'
      if( present(ZONETYPE) ) then
         write(funit,"(A7,I0,A3,I0,A3,I0,A14,A,A11,A)") 'ZONE I=',I,',J=',J,',K=',K,', DATAPACKING=',trim(DATAPACKING),', ZONETYPE=',trim(ZONETYPE)
      else
         write(funit,"(A7,I0,A3,I0,A3,I0,A14,A)") 'ZONE I=',I,',J=',J,',K=',K,', DATAPACKING=',trim(DATAPACKING)
      end if
      
   end subroutine TecFileHeader

   subroutine PolynomialVector( x, y, z, v )
   
      implicit none 

      real(kind=rp), intent(in)    :: x, y, z 
      real(kind=rp), intent(inout) :: v(:)

      integer :: n_of_points 

      n_of_points = size(v)

      select case( n_of_points )  
         case( 3 )                    !1st order
            v(1) = 1.0_RP 
            v(2) = x 
            v(3) = y 
            !v(4) = z 
         case( 6 )                    !2nd order
            v(1)  = 1.0_RP 
            v(2)  = x 
            v(3)  = y 
            !v(4)  = z
            v(4)  = POW2(x) 
            v(5)  = POW2(y) 
            !v(7)  = POW2(z)
            v(6)  = x*y          
            !v(9)  = x*z          
            !v(10) = z*y 
         case( 10 )                    !3rd order
            v(1)  = 1.0_RP 
            v(2)  = x 
            v(3)  = y 
            !v(4)  = z
            v(4)  = POW2(x) 
            v(5)  = POW2(y) 
            !v(7)  = POW2(z)
            v(6)  = x*y          
            !v(9)  = x*z          
            !v(10) = z*y 
            v(7) = POW3(x) 
            v(8) = POW3(y) 
            !v(13) = POW3(z)
            v(9) = POW2(x)*y          
            !v(15) = POW2(x)*z          
            v(10) = POW2(y)*x         
            !v(17) = POW2(y)*z         
            !v(18) = POW2(z)*x         
            !v(19) = POW2(z)*y         
            !v(20) = x*y*z         
         case( 17 )                    !4th order
            v(1)  = 1.0_RP 
            v(2)  = x 
            v(3)  = y 
            !v(4)  = z
            v(4)  = POW2(x) 
            v(5)  = POW2(y) 
            !v(7)  = POW2(z)
            v(6)  = x*y          
            !v(9)  = x*z          
            !v(10) = z*y 
            v(7) = POW3(x) 
            v(8) = POW3(y) 
            !v(13) = POW3(z)
            v(9) = POW2(x)*y          
            !v(15) = POW2(x)*z          
            v(10) = POW2(y)*x         
            !v(17) = POW2(y)*z         
            v(11) = POW2(z)*x         
            v(12) = POW2(z)*y         
            !v(20) = x*y*z
            v(13) = POW2(x)*POW2(x)         
            v(14) = POW2(y)*POW2(y)         
            !v(23) = POW2(z)*POW2(z)
            v(15) = POW3(x)*y         
            !v(25) = POW3(x)*z
            v(16) = POW3(y)*x         
            !v(27) = POW3(y)*z
            !v(28) = POW3(z)*x         
            !v(29) = POW3(z)*y               
            !v(30) = POW2(x)*y*z          
            !v(31) = POW2(y)*x*z          
            !v(32) = POW2(z)*x*y 
            v(17) = POW2(x)*POW2(y) 
            !v(34) = POW2(x)*POW2(z)          
            !v(35) = POW2(y)*POW2(z)            
      end select 

   end subroutine PolynomialVector

   subroutine buildMatrixPolySpline( Phi, P, P_T, V )

      implicit none 

      real(kind=rp), intent(in)    :: Phi(:,:), P(:,:), P_T(:,:)
      real(kind=rp), intent(inout) :: V(:,:)

      integer :: start, final 

      V = 0.0_RP 
      
      V(1:size(Phi,1),1:size(Phi,2)) = Phi 
      start = size(Phi,2)+1; final = start + size(P,2)-1
      V(1:size(Phi,1),start:final) = P 
      start = size(Phi,1)+1; final = start + size(P_T,1)-1
      V(start:final,1:size(Phi,2)) = P_T  

   end subroutine buildMatrixPolySpline

   real(kind=rp) function EvaluateInterp( coeff, x, y, z ) result( value )

      implicit none
      
      real(kind=rp), intent(in) :: coeff(:), x, y, z
      
      real(kind=rp) :: v(size(coeff))

      call PolynomialVector( x, y, z, v )

      value = dot_product(coeff,v)

   end function EvaluateInterp

end module TessellationTypes