eos_database.F90       coverage:  100.00 %func     75.82 %block


     1) module EOSDatabase_module
     2)  
     3)   use PFLOTRAN_Constants_module
     4)   use Lookup_Table_module
     5) 
     6)   implicit none
     7)   
     8)   private
     9)  
    10) #include "petsc/finclude/petscsys.h"
    11)  
    12)   PetscInt, parameter, public :: EOS_DENSITY = 1
    13)   PetscInt, parameter, public :: EOS_ENTHALPY = 2
    14)   PetscInt, parameter, public :: EOS_VISCOSITY = 3 
    15)   !add here other properties and derivatives and increase MAX_PROP_NUM
    16)   PetscInt, parameter, public :: MAX_PROP_NUM = 3
    17) 
    18)   type, public :: eos_database_type 
    19)     character(len=MAXWORDLENGTH) :: dbase_name
    20)     character(len=MAXWORDLENGTH) :: file_name
    21)     PetscInt :: num_dp   ! number of pressure intervals
    22)     PetscInt :: num_dt   ! number of temperature intervals
    23)     PetscInt :: num_prop ! number of properties in the database
    24)     PetscReal :: dp      ! uniform pressure interval
    25)     PetscReal :: dt      ! uniform temperature interval 
    26)     PetscInt :: data_to_prop_map(MAX_PROP_NUM) !map the data idx to the prop. 
    27)     PetscInt :: prop_to_data_map(MAX_PROP_NUM) !map the prop to the dat idx
    28)     PetscReal, pointer :: data(:,:)
    29)     class(lookup_table_uniform_type), pointer :: lookup_table
    30)   contains
    31)     procedure, public :: Read => EOSDatabaseRead 
    32)     procedure, public :: EOSProp => EOSPropLinearInterp
    33)     procedure, public :: EOSPropPresent
    34)   end type
    35) 
    36)   public :: EOSDatabaseCreate, &
    37)             EOSDatabaseDestroy
    38) 
    39) contains
    40) 
    41) ! ************************************************************************** !
    42) 
    43) function EOSDatabaseCreate(filename,dbase_name)
    44)   ! 
    45)   ! Author: Paolo Orsini
    46)   ! Date: 12/11/15
    47)   ! 
    48) 
    49)   implicit none
    50) 
    51)   class(eos_database_type), pointer :: EOSDatabaseCreate
    52)   character(len=MAXWORDLENGTH) :: filename
    53)   character(len=*) :: dbase_name
    54) 
    55)   allocate(EOSDatabaseCreate)
    56)   EOSDatabaseCreate%dbase_name = dbase_name 
    57)   EOSDatabaseCreate%file_name = filename
    58)   EOSDatabaseCreate%num_dp = UNINITIALIZED_INTEGER
    59)   EOSDatabaseCreate%num_dt = UNINITIALIZED_INTEGER
    60)   EOSDatabaseCreate%dp = UNINITIALIZED_DOUBLE
    61)   EOSDatabaseCreate%dt = UNINITIALIZED_DOUBLE 
    62)   EOSDatabaseCreate%data_to_prop_map(1:MAX_PROP_NUM) = UNINITIALIZED_INTEGER
    63)   EOSDatabaseCreate%prop_to_data_map(1:MAX_PROP_NUM) = UNINITIALIZED_INTEGER
    64) 
    65)   nullify(EOSDatabaseCreate%lookup_table)
    66)   nullify(EOSDatabaseCreate%data)
    67) 
    68) end function EOSDatabaseCreate
    69) 
    70) ! ************************************************************************** !
    71) 
    72) subroutine EOSDatabaseRead(this,option)
    73)   ! 
    74)   ! Author: Paolo Orsini
    75)   ! Date: 12/11/15
    76)   ! 
    77)   ! Reads the the an EOS database from a text file for one or more 
    78)   ! phase properties.  
    79)   ! 
    80)   ! Database format (for look up table)
    81)   ! Header: NUM_DP, NUM_DT and DATA_LIST_ORDER
    82)   ! DATA
    83)   ! column 1 = pressure
    84)   ! column 2 = temperature
    85)   ! column 2+1, column 2+n: properties in the order given in DATA_LIST_ORDER
    86)   !
    87)   ! The dataset must be followed by NUM_DP * NUM_DT lines, not interrupted
    88)   ! by a commented line. 
    89)   ! Each line must include P,T, and all properties listed in DATA_LIST_ORDER
    90)   !
    91)   ! each property listed depends on P and T, prop(P,T). 
    92)   !
    93)   ! temperature values must be equispaced (same dt in the entire table) 
    94)   ! pressure values must be equispaced (same dp in the entire table)
    95)   ! The data must be ordered so for growing P and T, with T looping faster.
    96)   !
    97)   ! This format repeates unnecessary P and T values in favours o readibility
    98)   ! and creation of small dataset by hand. Inefficient for for large datasets.
    99)   ! 
   100) 
   101)   use Option_module
   102)   use Input_Aux_module
   103)   use String_module
   104) 
   105)   implicit none
   106) 
   107)   class(eos_database_type) :: this
   108)   type(option_type) :: option
   109) 
   110)   character(len=MAXWORDLENGTH) :: keyword, word
   111)   character(len=MAXSTRINGLENGTH) :: error_string = 'EOS_DATABASE'
   112)   character(len=MAXSTRINGLENGTH) :: string 
   113)   PetscInt :: prop_idx, prop_count, i_idx, j_idx 
   114)   PetscInt :: data_size
   115)   PetscReal :: tempreal
   116)   PetscBool :: pres_present, temp_present
   117) 
   118)   type(input_type), pointer :: input_table
   119) 
   120) 
   121)   if (len_trim(this%file_name) < 1) then
   122)     option%io_buffer = 'FILENAME must be specified for EOS_DATABASE.'
   123)     call printErrMsg(option)
   124)   endif
   125) 
   126)   input_table => InputCreate(IUNIT_TEMP,this%file_name,option)
   127)   input_table%ierr = 0
   128) 
   129)   !if ( option%myrank == 0 ) then
   130)     option%io_buffer = 'Reading database = ' // this%file_name
   131)     call printMsg(option) 
   132)   !end if
   133) 
   134)   !reading the database file header
   135)   do
   136) 
   137)     call InputReadPflotranString(input_table,option)
   138)     !if (InputCheckExit(input_table,option)) exit
   139)     if (InputError(input_table)) exit
   140) 
   141)     call InputReadWord(input_table,option,keyword,PETSC_TRUE)
   142)     call InputErrorMsg(input_table,option,'keyword',error_string)
   143)     call StringToUpper(keyword)   
   144)     select case(keyword)
   145)       case('NUM_DP')
   146)         call InputReadInt(input_table,option,this%num_dp)
   147)         call InputErrorMsg(input_table,option,'number of dp',error_string)
   148)       case('NUM_DT')
   149)         call InputReadInt(input_table,option,this%num_dt)
   150)         call InputErrorMsg(input_table,option,'number of dt',error_string)        
   151)       case('DATA_LIST_ORDER')  
   152)         pres_present = PETSC_FALSE; temp_present = PETSC_FALSE;
   153)         prop_idx = 0
   154)         do 
   155)           call InputReadPflotranString(input_table,option)
   156)           if (InputCheckExit(input_table,option)) exit
   157)           call InputReadWord(input_table,option,word,PETSC_TRUE)
   158)           select case(word)
   159)             case('PRESSURE')
   160)               pres_present = PETSC_TRUE
   161)             case('TEMPERATURE')
   162)               temp_present = PETSC_TRUE 
   163)             case('DENSITY')
   164)               prop_idx = prop_idx + 1
   165)               this%data_to_prop_map(prop_idx) = EOS_DENSITY 
   166)               this%prop_to_data_map(EOS_DENSITY) = prop_idx 
   167)             case('ENTHALPY')
   168)               prop_idx = prop_idx + 1
   169)               this%data_to_prop_map(prop_idx) = EOS_ENTHALPY 
   170)               this%prop_to_data_map(EOS_ENTHALPY) = prop_idx 
   171)             case('VISCOSITY')
   172)               prop_idx = prop_idx + 1
   173)               this%data_to_prop_map(prop_idx) = EOS_VISCOSITY 
   174)               this%prop_to_data_map(EOS_VISCOSITY) = prop_idx 
   175)             case default
   176)               error_string = trim(error_string) // ': ' // this%file_name // &
   177)               ': DATA_LIST_ORDER'
   178)               call InputKeywordUnrecognized(keyword,error_string,option)
   179)           end select
   180)         end do
   181)         this%num_prop = prop_idx
   182)         if (.not.pres_present) then
   183)           option%io_buffer = 'PRESSURE must be present in any EOS_DATABASE.'
   184)           call printErrMsg(option)
   185)         end if
   186)         if (.not.temp_present) then
   187)           option%io_buffer = 'TEMPERATURE must be present in any EOS_DATABASE.'
   188)           call printErrMsg(option)
   189)         end if
   190)       case('DATA')
   191)         exit   
   192)       case default
   193)         error_string = trim(error_string) // ': ' // this%file_name
   194)         call InputKeywordUnrecognized(keyword,error_string,option)
   195)     end select
   196) 
   197)   end do
   198) 
   199)   data_size = this%num_dp * this%num_dt
   200) 
   201)   this%num_prop = prop_idx
   202)   allocate(this%data(prop_idx,data_size))
   203) 
   204)   !create lookup table  
   205)   this%lookup_table => LookupTableCreateUniform(TWO_INTEGER)
   206)   this%lookup_table%dims(1) = this%num_dt
   207)   this%lookup_table%dims(2) = this%num_dp
   208)   allocate(this%lookup_table%axis1%values(this%num_dt))
   209)   this%lookup_table%axis1%values(1:this%num_dt) = UNINITIALIZED_DOUBLE
   210)   allocate(this%lookup_table%axis2%values(this%num_dp))
   211)   this%lookup_table%axis2%values(1:this%num_dp) = UNINITIALIZED_DOUBLE
   212) 
   213)   !TODO
   214)   ! start loading data - at the moment using Input facility, however this file
   215)   ! can be large. TODO. Implement more efficient solutions:
   216)   ! - using read(,) without InputReadDouble filter
   217)   ! - adding the option of reading a .h5 file where the database is defined  
   218) 
   219)   ! go to data - first time to load axis1 and 2 values
   220)   string = "DATA"
   221)   call InputFindStringInFile(input_table,option,string)
   222) 
   223)   do j_idx = 1,this%num_dp 
   224)        
   225)     do i_idx = 1, this%num_dt
   226)       call InputReadPflotranString(input_table,option)
   227) 
   228)       call InputReadDouble(input_table,option,tempreal) 
   229)       call InputErrorMsg(input_table,option, &
   230)                            'VALUE', 'EOS_DATABASE PRESS_VALUE') 
   231)       ! convert MPa in Pa
   232)       this%lookup_table%axis2%values(j_idx) = tempreal * 1.0d6
   233)    
   234)       ! this is repeated this%num_dp times - not efficient
   235)       call InputReadDouble(input_table,option, &
   236)                            this%lookup_table%axis1%values(i_idx))
   237)       call InputErrorMsg(input_table,option, &
   238)                          'VALUE', 'EOS_DATABASE TEMP_VALUE') 
   239)     
   240)       prop_count = i_idx + (j_idx-1) * this%num_dt
   241)       do prop_idx = 1,this%num_prop
   242)         call InputReadDouble(input_table,option,this%data(prop_idx,prop_count))
   243)         call InputErrorMsg(input_table,option,&
   244)                            'VALUE','EOS_DATABASE PROP_VALUE')
   245)       end do      
   246) 
   247)     end do
   248) 
   249)   end do
   250) 
   251)   call InputDestroy(input_table)
   252) 
   253) end subroutine EOSDatabaseRead
   254) 
   255) ! ************************************************************************** !
   256) function EOSPropPresent(this,prop_iname)
   257)   ! 
   258)   ! Author: Paolo Orsini
   259)   ! Date: 12/18/15
   260)   ! 
   261)   ! Checks if a property is defined in the database
   262) 
   263)   implicit none
   264) 
   265)   class(eos_database_type) :: this
   266)   PetscInt, intent(in) :: prop_iname
   267)   PetscBool :: EOSPropPresent
   268)                                         
   269)   EOSPropPresent = Initialized(this%prop_to_data_map(prop_iname))
   270) 
   271) end function EOSPropPresent
   272) 
   273) ! ************************************************************************** !
   274) 
   275) subroutine EOSPropLinearInterp(this,T,P,prop_iname,prop_value,ierr)
   276)   ! 
   277)   ! Author: Paolo Orsini
   278)   ! Date: 12/12/15
   279)   ! 
   280)   ! interpolates a single EOS property from the EOS database
   281)   ! Note: when more properties must be extracted from the same EOS database,
   282)   !       i.e. properties listed for the same values and range of P and T,
   283)   !       all propoertis should be extracted at the same time to perform  
   284)   !       only once the look up operations, which are: 
   285)   !       (a) LookupTableIndexUniform, i.e. axis look up
   286)   !       (b) P,T location checks within a single 2D domain, (p,p+dp; t,t+dt)
   287)   !           currently done within LookupTableInterpolate2DUniform
   288)   !
   289)   !       TODO: add a method lookup_table to extract mulitdimensional data 
   290)   !             at the same time (data plus function)
   291) 
   292)   implicit none
   293) 
   294)   class(eos_database_type) :: this
   295)   PetscReal, intent(in) :: T        ! temperature [C]
   296)   PetscReal, intent(in) :: P        ! pressure [Pa]
   297)   PetscInt, intent(in) :: prop_iname
   298)   PetscReal, intent(out) :: prop_value ! database units (SI) 
   299)   PetscErrorCode, intent(out) :: ierr
   300) 
   301)   !PetscReal :: EOSEOSProp !property given in units specified in the database
   302)   
   303)   ierr = 0
   304)   !insert check P and/or T out of range 
   305)   ! T smaller then minimum T in the database
   306)   ! errors here a passed back to the EOSxxxPhase module
   307)   ! and to ModeXXXComputeAuxVar where cells ids are available to check where
   308)   ! P and T are out of range. 
   309)   ! TODO: (i) define error id identifiers for each EOSPhase, or for all EOSs.
   310)   !       (ii) define a function that handles errors ids and print error message.
   311)   !       (iii) can then remove the print statment below
   312)   !       note: need to minimise the number if-checks for efficiency. 
   313)   if ( T < this%lookup_table%axis1%values(1) ) then 
   314)     ierr = 101
   315)     print*, "EOSEOSProp - T smaller than min val in EOSdatabase"
   316)     print*, "Temp val [°C] = ", T
   317)     stop  
   318)   end if 
   319)   if ( T > this%lookup_table%axis1%values(this%num_dt) ) then
   320)     ierr = 102
   321)     print*, "EOSEOSProp - T larger than max val in EOSdatabase"
   322)     print*, "Temp val [°C] = ", T
   323)     stop  
   324)   end if
   325)   if ( P < this%lookup_table%axis2%values(1) ) then
   326)     ierr = 103
   327)     print*, "EOSEOSProp - P smaller than min val in EOSdatabase"
   328)     print*, "Press val [Mpa] = ", P*1.d-6
   329)     stop  
   330)   end if
   331)   if ( P > this%lookup_table%axis2%values(this%num_dp) ) then
   332)     ierr = 104
   333)     print*, "EOSEOSProp - P larger than max val in EOSdatabase"
   334)     print*, "Press val [Mpa] = ", P*1.d-6
   335)     stop  
   336)   end if
   337) 
   338)   this%lookup_table%data => this%data(this%prop_to_data_map(prop_iname),:)
   339) 
   340)                              !T       P      optional
   341)   !this%lookup_table%Sample(lookup1,lookup2,lookup3) 
   342)   prop_value = this%lookup_table%Sample(T,P) 
   343) 
   344)   nullify(this%lookup_table%data)
   345) 
   346) end subroutine EOSPropLinearInterp
   347) 
   348) ! ************************************************************************** !
   349) 
   350) subroutine EOSDatabaseDestroy(eos_database)
   351)   ! 
   352)   ! Author: Paolo Orsini
   353)   ! Date: 12/14/15
   354)   ! 
   355)   ! destroys EOS database
   356) 
   357)   use Utility_module
   358) 
   359)   implicit none
   360) 
   361)   class(eos_database_type), pointer :: eos_database
   362) 
   363)   if (.not.associated(eos_database)) return
   364) 
   365)   !deallocate(eos_database%data)
   366)   !nullify(eos_database%data) 
   367)   call DeallocateArray(eos_database%data)
   368) 
   369)   call LookupTableDestroy(eos_database%lookup_table) 
   370) 
   371)   deallocate(eos_database)
   372)   nullify(eos_database)
   373) 
   374) end subroutine EOSDatabaseDestroy
   375) 
   376) ! ************************************************************************** !
   377) 
   378) end module EOSDatabase_module

generated by
Intel(R) C++/Fortran Compiler code-coverage tool
Web-Page Owner: Nobody