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