units.F90       coverage:  85.71 %func     84.96 %block


     1) module Units_module
     2) 
     3)   use PFLOTRAN_Constants_module
     4) 
     5)   implicit none
     6)   
     7)   private
     8)   
     9) #include "petsc/finclude/petscsys.h"
    10)   
    11)   public :: UnitsConvertToInternal, UnitsConvertToExternal
    12)   
    13) contains
    14) 
    15) ! ************************************************************************** !
    16) 
    17) function UnitsConvertToInternal(units,internal_units,option)
    18)   ! 
    19)   ! Converts given units to pflotran internal units
    20)   ! 
    21)   ! Author: Glenn Hammond
    22)   ! Date: 01/21/09
    23)   ! Notes: Updated/modified by Jenn Frederick 1/25/2016
    24)   ! 
    25) 
    26)   use Option_module
    27) 
    28)   implicit none
    29)   
    30)   character(len=*) :: units
    31)   character(len=MAXWORDLENGTH) :: internal_units
    32)   type(option_type) :: option
    33) 
    34)   character(len=MAXSTRINGLENGTH) :: units_buff
    35)   character(len=MAXSTRINGLENGTH) :: internal_units_buff1
    36)   character(len=MAXSTRINGLENGTH) :: internal_units_buff2
    37)   character(len=MAXSTRINGLENGTH) :: error_msg
    38)   PetscBool :: multi_option, successful, error
    39)   PetscInt :: length, ind_or, ind_dash, num_options
    40)   PetscReal :: conversion_factor, UnitsConvertToInternal
    41) 
    42)   units_buff = trim(units)
    43)   internal_units_buff1 = trim(internal_units)
    44)   internal_units_buff2 = trim(internal_units)
    45)   multi_option = PETSC_FALSE
    46)   successful = PETSC_FALSE
    47)   conversion_factor = 1.d0
    48)   UnitsConvertToInternal = 1.d0
    49)   num_options = 0
    50)   ind_or = 1
    51)   length = 0
    52) 
    53)   do while(ind_or /= 0)
    54)     length = len_trim(internal_units_buff1)
    55)     ind_or = index(trim(internal_units_buff1),"|")   
    56)     if (ind_or == 0) then
    57)       call UnitsConvertParse(units_buff,internal_units_buff1, &
    58)                              conversion_factor,error,error_msg)
    59)       if (.not.error) successful = PETSC_TRUE
    60)       if (successful) exit
    61)     else
    62)       multi_option = PETSC_TRUE
    63)       num_options = num_options + 1
    64)       internal_units_buff2 = internal_units_buff1(1:(ind_or-1))
    65)       call UnitsConvertParse(units_buff,internal_units_buff2, &
    66)                              conversion_factor,error,error_msg)
    67)       if (.not.error) successful = PETSC_TRUE
    68)       if (successful) exit
    69)       internal_units_buff1 = internal_units_buff1((ind_or+1):length)
    70)     endif
    71)   enddo
    72)   
    73)   if (.not.successful) then
    74)     option%io_buffer = error_msg
    75)     call printErrMsg(option)
    76)   endif
    77) 
    78)   UnitsConvertToInternal = conversion_factor
    79) 
    80) end function UnitsConvertToInternal
    81) 
    82) ! ************************************************************************** !
    83) 
    84) subroutine UnitsConvertParse(units,internal_units,units_conversion, &
    85)                              error,error_msg)
    86)   ! 
    87)   ! Parses user's and internal units into numerator and denominator 
    88)   ! (if they exist) and gets the conversion factor from user's units
    89)   ! to internal Pflotran units.
    90)   ! 
    91)   ! Author: Jenn Frederick
    92)   ! Date: 02/15/2016
    93)   ! 
    94) 
    95)   use Option_module
    96) 
    97)   implicit none
    98) 
    99)   character(len=MAXWORDLENGTH) :: units, internal_units
   100)   PetscReal :: units_conversion
   101)   PetscBool :: error
   102)   character(len=MAXSTRINGLENGTH) :: error_msg
   103)   
   104)   ! A maximum of 3 numerators/denominators are accepted 
   105)   character(len=MAXSTRINGLENGTH) :: numerator_units
   106)   character(len=MAXSTRINGLENGTH) :: denominator_units
   107)   character(len=MAXSTRINGLENGTH) :: numerator_internal_units
   108)   character(len=MAXSTRINGLENGTH) :: denominator_internal_units
   109)   PetscReal :: numerator_conv_factor, denominator_conv_factor
   110)   PetscBool :: set_units_denom, set_internal_units_denom
   111)   PetscInt :: length, ind
   112)   
   113)   error = PETSC_FALSE
   114)   set_units_denom = PETSC_FALSE
   115)   set_internal_units_denom = PETSC_FALSE
   116)   numerator_conv_factor = 1.d0
   117)   denominator_conv_factor = 1.d0
   118)   units_conversion = 1.d0
   119)   numerator_units = ''
   120)   denominator_units = ''
   121)   numerator_internal_units = ''
   122)   denominator_internal_units = ''
   123) 
   124)   length = len(units)
   125)   ind = index(trim(units),"/")   
   126)   if (ind == 0) then
   127)   ! numerator(s) only
   128)     numerator_units = trim(units)
   129)   else
   130)   ! denominator(s) also exists
   131)     set_units_denom = PETSC_TRUE
   132)     numerator_units = units(1:(ind-1))
   133)     denominator_units = units((ind+1):length)
   134)   endif
   135) 
   136)   length = len_trim(internal_units)
   137)   ind = index(trim(internal_units),"/")
   138)   if (ind == 0) then
   139)   ! numerator(s) only
   140)     numerator_internal_units = trim(internal_units)
   141)   else
   142)   ! denominator(s) also exists
   143)     set_internal_units_denom = PETSC_TRUE
   144)     numerator_internal_units = internal_units(1:(ind-1))
   145)     denominator_internal_units = internal_units((ind+1):length)
   146)   endif
   147) 
   148)   ! check if provided units structure matches internal units structure
   149)   if (set_units_denom .neqv. set_internal_units_denom) then
   150)     if ((.not.set_units_denom) .and. (set_internal_units_denom)) then
   151)       error_msg = 'Units provided do not match the expected &
   152)                    &unit structure (numerator/denominator). &
   153)                    &A unit denominator was expected, but was not given: ' &
   154)                    // trim(units)
   155)       error = PETSC_TRUE
   156)     endif
   157)     if ((set_units_denom) .and. (.not.set_internal_units_denom)) then
   158)       error_msg = 'Units provided do not match the expected &
   159)                    &unit structure (numerator/denominator). &
   160)                    &A unit denominator was not expected, but was given: ' &
   161)                    // trim(units)
   162)       error = PETSC_TRUE
   163)     endif
   164)   endif
   165) 
   166)   if (error) return
   167)   call UnitsConvert(numerator_units,numerator_internal_units, &
   168)                     numerator_conv_factor,error,error_msg)
   169) 
   170)   if (error) return
   171)   if (set_internal_units_denom) then
   172)     call UnitsConvert(denominator_units,denominator_internal_units, &
   173)                       denominator_conv_factor,error,error_msg)
   174)   endif
   175) 
   176)   if (error) return
   177)   units_conversion = numerator_conv_factor/denominator_conv_factor
   178) 
   179) end subroutine UnitsConvertParse
   180) 
   181) ! ************************************************************************** !
   182) 
   183) subroutine UnitsConvert(units_user,units_internal,units_conversion, &
   184)                         error,error_msg)
   185)   ! 
   186)   ! Converts units given by the user to pflotran internal units
   187)   ! 
   188)   ! Author: Glenn Hammond; Jenn Frederick (updated)
   189)   ! Date: 01/21/09; 2/15/2016 (updated)
   190)   ! 
   191) 
   192)   use Option_module
   193)   
   194)   implicit none
   195) 
   196)   character(len=MAXWORDLENGTH) :: units_user
   197)   character(len=MAXWORDLENGTH) :: units_internal
   198)   PetscReal :: units_conversion
   199)   PetscBool :: error
   200)   character(len=MAXSTRINGLENGTH) :: error_msg
   201)    
   202)   ! a maximum of 3 unit categories are allowed
   203)   character(len=MAXWORDLENGTH) :: unit_user(3)
   204)   character(len=MAXWORDLENGTH) :: unit_user_cat(3)
   205)   character(len=MAXSTRINGLENGTH) :: unit_user_buff
   206)   character(len=MAXWORDLENGTH) :: unit_internal(3)
   207)   character(len=MAXWORDLENGTH) :: unit_internal_cat(3)
   208)   character(len=MAXSTRINGLENGTH) :: unit_internal_buff
   209) 
   210)   PetscInt :: length, ind_dash
   211)   PetscInt :: k, j
   212)   PetscInt :: num_user_units, num_internal_units
   213)   PetscReal :: conv_user_to_SI, conv_internal_to_SI
   214)   PetscReal :: conversion_user, conversion_internal
   215) 
   216)   error = PETSC_FALSE
   217)   conv_user_to_SI = 1.d0
   218)   conv_internal_to_SI = 1.d0
   219)   conversion_user = 1.d0
   220)   conversion_internal = 1.d0
   221)   units_conversion = 1.d0 
   222) 
   223) ! ======== SEPARATE OUT GIVEN UNITS ================================= !
   224)   unit_user_buff = trim(units_user)
   225)   unit_user(:) = 'not_assigned'
   226)   unit_user_cat(:) = 'not_assigned'
   227)   num_user_units = 0
   228)   ind_dash = 1
   229)   k = 1
   230)   do while (ind_dash /= 0)
   231)     length = len_trim(unit_user_buff)
   232)     ind_dash = index(trim(unit_user_buff),"-")
   233)     if (ind_dash == 0) then
   234)       unit_user(k) = trim(unit_user_buff)
   235)     else
   236)       unit_user(k) = unit_user_buff(1:(ind_dash-1))
   237)       unit_user_buff = unit_user_buff((ind_dash+1):length)
   238)     endif
   239)     k = k + 1
   240)     if (k > 3) then
   241)       error_msg = 'Maximum number of user units exceeded. &
   242)                   &Unit numerators or denominators are limited to a &
   243)                   &maximum of 3 units each.' 
   244)       error = PETSC_TRUE
   245)     endif
   246)   enddo
   247)   if (error) return
   248)   num_user_units = k - 1
   249) 
   250) ! ======== SEPARATE OUT INTERNAL UNITS ============================== !
   251)   unit_internal_buff = trim(units_internal)
   252)   unit_internal(:) = 'not_assigned'
   253)   unit_internal_cat(:) = 'not_assigned'
   254)   num_internal_units = 0
   255)   k = 1
   256)   ind_dash = 1
   257)   do while (ind_dash /= 0)
   258)     length = len_trim(unit_internal_buff)
   259)     ind_dash = index(trim(unit_internal_buff),"-")
   260)     if (ind_dash == 0) then
   261)       unit_internal(k) = trim(unit_internal_buff)
   262)     else
   263)       unit_internal(k) = unit_internal_buff(1:(ind_dash-1))
   264)       unit_internal_buff = unit_internal_buff((ind_dash+1):length)
   265)     endif
   266)     k = k + 1
   267)     if (k > 3) then
   268)       error_msg = 'Maximum number of internal units exceeded. &
   269)                   &Unit numerators or denominators are limited to a &
   270)                   &maximum of 3 units each.' 
   271)       error = PETSC_TRUE
   272)     endif
   273)   enddo
   274)   if (error) return
   275)   num_internal_units = k - 1
   276) 
   277) 
   278) ! ======== GET UNIT CATEGORIES OF GIVEN AND INTERNAL UNITS ========== !
   279)   call UnitsCategory(unit_user,unit_user_cat,error,error_msg)
   280)   if (error) return
   281)   call UnitsCategory(unit_internal,unit_internal_cat,error,error_msg)
   282)   if (error) return
   283) 
   284) ! ======== CHECK IF UNIT CATEGORIES ALIGN =========================== !
   285)   call UnitsCategoryCheck(unit_user_cat,unit_internal_cat,error,error_msg)
   286)   if (error) return
   287) 
   288) ! ======== CONVERT INTERNAL UNITS TO SI ============================= !
   289)   k = 1
   290)   do while (k < (num_internal_units + 1))
   291)     call UnitsConvertToSI(unit_internal(k),conversion_internal,error,error_msg)
   292)     if (error) exit
   293)     conv_internal_to_SI = conv_internal_to_SI * conversion_internal
   294)     k = k + 1
   295)   enddo
   296)   if (error) return
   297) 
   298) ! ======== CONVERT USER UNITS TO SI ================================= !
   299)   k = 1
   300)   do while (k < (num_user_units + 1))
   301)     call UnitsConvertToSI(unit_user(k),conversion_user,error,error_msg)
   302)     if (error) exit
   303)     conv_user_to_SI = conv_user_to_SI * conversion_user
   304)     k = k + 1
   305)   enddo
   306)   if (error) return
   307) 
   308) ! ======== CONVERT USER UNITS TO INTERNAL UNITS ===================== !
   309)   units_conversion = conv_user_to_SI / conv_internal_to_SI
   310) 
   311) end subroutine UnitsConvert
   312) 
   313) ! ************************************************************************** !
   314) 
   315) subroutine UnitsCategory(unit,unit_category,error,error_msg)
   316)   ! 
   317)   ! Gives the unit category of the given units.
   318)   ! 
   319)   ! Author: Jenn Frederick
   320)   ! Date: 02/15/2016
   321)   ! 
   322) 
   323)   use Option_module
   324)   
   325)   implicit none
   326)  
   327)   ! a maximum of 3 unit categories are allowed
   328)   character(len=MAXWORDLENGTH) :: unit(3)
   329)   character(len=MAXWORDLENGTH) :: unit_category(3)
   330)   PetscBool :: error
   331)   character(len=MAXSTRINGLENGTH) :: error_msg
   332) 
   333)   PetscInt :: k 
   334) 
   335)   k = 1
   336)   error = PETSC_FALSE
   337) 
   338)   do while (k < 4)
   339)     select case(trim(unit(k)))
   340)       case('cm^3','l','L','ml','mL','dm^3','m^3','gal','gallon')
   341)         unit_category(k) = 'volume'
   342)       case('cm^2','dm^2','m^2','km^2')
   343)         unit_category(k) = 'area'
   344)       case('km','m','met','meter','dm','cm','mm')
   345)         unit_category(k) = 'length'
   346)       case('s','sec','second','min','minute','h','hr','hour','d','day','w', &
   347)            'week','mo','month','y','yr','year')
   348)         unit_category(k) = 'time'
   349)       case('J','kJ','MJ')
   350)         unit_category(k) = 'energy'
   351)       case('W','kW','MW')
   352)         unit_category(k) = 'power'
   353)       case('mol','mole','moles','kmol')
   354)         unit_category(k) = 'molar_mass'
   355)       case('ug','mg','g','kg')
   356)         unit_category(k) = 'mass'
   357)       case('C','Celcius')
   358)         unit_category(k) = 'temperature'
   359)       case('K','Kelvin')  
   360)         unit_category(k) = 'temperature'
   361)         error_msg = 'Kelvin temperature units are not supported. Use Celcius.' 
   362)         error = PETSC_TRUE
   363)       case('Pa','kPa','MPa','Bar')
   364)         unit_category(k) = 'pressure'
   365)       case('M','mM')
   366)         unit_category(k) = 'concentration'
   367)       case('N')
   368)         unit_category(k) = 'force'
   369)       case('unitless','1')
   370)         unit_category(k) = 'unitless'
   371)       case('not_assigned')
   372)         unit_category(k) = 'not_assigned'
   373)       case default
   374)         error_msg = 'The given units are unrecognized: ' // trim(unit(k))
   375)         error = PETSC_TRUE
   376)     end select
   377)     k = k + 1
   378)   enddo
   379)   
   380) end subroutine UnitsCategory
   381) 
   382) ! ************************************************************************** !
   383) 
   384) subroutine UnitsConvertToSI(unit,conversion_factor,error,error_msg)
   385)   ! 
   386)   ! Converts a unit to SI units.
   387)   ! 
   388)   ! Author: Jenn Frederick
   389)   ! Date: 01/21/2016
   390)   ! 
   391) 
   392)   use Option_module
   393)   
   394)   implicit none
   395)   
   396)   character(len=MAXWORDLENGTH) :: unit
   397)   PetscReal :: conversion_factor
   398)   PetscBool :: error
   399)   character(len=MAXSTRINGLENGTH) :: error_msg
   400) 
   401)   conversion_factor = 1.d0
   402)   error = PETSC_FALSE
   403) 
   404)   select case(trim(unit))
   405)   !---> VOLUME ---> (meter^3)
   406)     case('cm^3','ml','mL')
   407)       conversion_factor = 1.d-6
   408)     case('l','L','dm^3')
   409)       conversion_factor = 1.d-3
   410)     case('m^3')
   411)       conversion_factor = 1.d0
   412)     case('gal','gallon')
   413)       conversion_factor = 3.785411784d-3
   414)   !---> AREA ---> (meter^2)
   415)     case('cm^2')
   416)       conversion_factor = 1.d-4
   417)     case('dm^2')
   418)       conversion_factor = 1.d-2
   419)     case('m^2')
   420)       conversion_factor = 1.d0
   421)     case('km^2')
   422)       conversion_factor = 1.d6
   423)   ! ---> LENGTH ---> (meter)
   424)     case('km')
   425)       conversion_factor = 1000.d0
   426)     case('m','met','meter')
   427)       conversion_factor = 1.d0
   428)     case('dm')
   429)       conversion_factor = 1.d-1
   430)     case('cm')
   431)       conversion_factor = 1.d-2
   432)     case('mm')
   433)       conversion_factor = 1.d-3
   434)   ! ---> TIME ---> (second)
   435)     case('s','sec','second')
   436)       conversion_factor = 1.d0
   437)     case('min','minute')
   438)       conversion_factor = 60.d0
   439)     case('h','hr','hour')
   440)       conversion_factor = 3600.d0
   441)     case('d','day')
   442)       conversion_factor = 24.d0*3600.d0 
   443)     case('w','week')
   444)       conversion_factor = 7.d0*24.d0*3600.d0 
   445)     case('mo','month')
   446)       conversion_factor = 365.d0/12.d0*24.d0*3600.d0 
   447)     case('y','yr','year')
   448)       conversion_factor = 365.d0*24.d0*3600.d0
   449)   ! ---> ENERGY ---> (Joule)
   450)     case('J')   
   451)       conversion_factor = 1.d0
   452)     case('kJ')   
   453)       conversion_factor = 1.d3
   454)     case('MJ')   
   455)       conversion_factor = 1.d6
   456)   ! ---> ENERGY FLUX or POWER ---> (Watt)
   457)     case('W')   
   458)       conversion_factor = 1.d0
   459)     case('kW')   
   460)       conversion_factor = 1.d3
   461)     case('MW')   
   462)       conversion_factor = 1.d6
   463)   ! ---> MOLAR MASS ---> (kilogram, mole)
   464)     case('mol','mole','moles')
   465)       conversion_factor = 1.d0
   466)     case('kmol')
   467)       conversion_factor = 1.d3
   468)   ! ---> MASS ---> (kilogram, mole)
   469)     case('ug')
   470)       conversion_factor = 1.d-9
   471)     case('mg')
   472)       conversion_factor = 1.d-6
   473)     case('g')
   474)       conversion_factor = 1.d-3
   475)     case('kg')
   476)       conversion_factor = 1.d0
   477)   ! ---> TEMPERATURE ---> (C)
   478)     case('C','Celsius') 
   479)       conversion_factor = 1.d0
   480)   ! ---> PRESSURE ---> (Pascal)
   481)     case('Pa') 
   482)       conversion_factor = 1.d0
   483)     case('kPa')
   484)       conversion_factor = 1.d3
   485)     case('MPa')
   486)       conversion_factor = 1.d6
   487)     case('Bar')
   488)       conversion_factor = 1.d5
   489)   ! ---> CONCENTRATION ---> (M)
   490)     case('M') 
   491)       conversion_factor = 1.d0
   492)     case('mM') 
   493)       conversion_factor = 1.d-3
   494)   ! ---> FORCE ---> (Newton)
   495)     case('N') 
   496)       conversion_factor = 1.d0
   497)   ! ---> UNITLESS ---> (1)
   498)     case('unitless','1')
   499)       conversion_factor = 1.d0
   500)   ! ---> NOT_ASSIGNED ---> (error)
   501)     case('not_assigned','unknown')
   502)       error_msg = 'Unit not assigned or unknown. Please e-mail &
   503)                   &pflotran-dev@googlegroups.com (attn: jmfrede) &
   504)                   &with your input file and screen output.'
   505)       error = PETSC_TRUE
   506)     case default
   507)       error_msg = 'Unit [ ' // trim(unit) // ' ] not recognized when &
   508)                   &converting to SI units. If this is not a spelling error, &
   509)                   &then the unit is not supported.'
   510)       error = PETSC_TRUE
   511) 
   512)   end select
   513)   
   514) end subroutine UnitsConvertToSI
   515) 
   516) ! ************************************************************************** !
   517) 
   518) subroutine UnitsCategoryCheck(unit_user_cat,unit_internal_cat, &
   519)                               error,error_msg)
   520)   ! 
   521)   ! Checks if the unit categories of the given and internal units align.
   522)   ! 
   523)   ! Author: Jenn Frederick
   524)   ! Date: 02/15/2016
   525)   ! 
   526) 
   527)   use Option_module
   528)   
   529)   implicit none
   530)  
   531)   ! a maximum of 3 unit categories are allowed
   532)   character(len=MAXWORDLENGTH) :: unit_user_cat(3)
   533)   character(len=MAXWORDLENGTH) :: unit_internal_cat(3)
   534)   PetscBool :: error
   535)   character(len=MAXSTRINGLENGTH) :: error_msg
   536) 
   537)   PetscInt :: k, j
   538)   PetscBool :: category_assigned(3), successful
   539)   character(len=MAXWORDLENGTH) :: unit_cat
   540) 
   541)   category_assigned(:) = PETSC_FALSE
   542)   error = PETSC_FALSE
   543)   error_msg = ''
   544)   k = 1
   545) 
   546)   do while (k < 4)
   547)     successful = PETSC_FALSE
   548)     unit_cat = trim(unit_user_cat(k))
   549)     j = 1
   550)     do while (j < 4)
   551)       if ((trim(unit_internal_cat(j)) == unit_cat) .and. &
   552)           (.not.category_assigned(j))) then
   553)         category_assigned(j) = PETSC_TRUE
   554)         successful = PETSC_TRUE
   555)       endif
   556)       if (successful) exit ! after first successful assignment
   557)       j = j + 1
   558)     enddo
   559)     k = k + 1
   560)   enddo
   561) 
   562)   k = 1
   563)   do while (k < 4)
   564)     if (.not.category_assigned(k)) then
   565)       error_msg = 'Mismatch between the category of the given units &
   566)                    &and the expected, internal units. Units of ' &
   567)                    // trim(unit_internal_cat(k)) // ' were expected, but &
   568)                    &units of ' // trim(unit_user_cat(k)) // ' were given.'
   569)       error = PETSC_TRUE
   570)     endif
   571)     if (error) exit
   572)     k = k + 1
   573)   enddo
   574)   
   575) end subroutine UnitsCategoryCheck
   576) 
   577) ! ************************************************************************** !
   578) 
   579) function UnitsConvertToExternal(units,units_category,option)
   580)   ! 
   581)   ! UnitsConvert: Converts units to pflotran internal units
   582)   ! 
   583)   ! Author: Glenn Hammond
   584)   ! Date: 01/21/09
   585)   ! 
   586) 
   587)   use Option_module
   588) 
   589)   implicit none
   590)   
   591)   character(len=MAXSTRINGLENGTH) :: units
   592)   character(len=*) :: units_category
   593)   type(option_type) :: option
   594)   
   595)   PetscReal :: UnitsConvertToExternal
   596)   
   597)   UnitsConvertToExternal = 1.d0/UnitsConvertToInternal(units, &
   598)                                                        units_category,option)
   599) 
   600) end function UnitsConvertToExternal
   601) 
   602) end module Units_module

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