25 public::
assignment(=),
operator(*),
operator(/),
operator(+)
26 private:: units_simplify
31 character(TOKEN),
pointer:: name(:)
32 character(TOKEN):: offset
33 real(
dp),
pointer:: power(:)
37 module procedure dcunitsclear
41 module procedure dcunitsdeallocate
44 interface assignment(=)
45 module procedure dcunitsbuild, dcunitstostring
49 module procedure dcunitsmul
53 module procedure dcunitsdiv
57 module procedure dcunitsadd
62 subroutine units_simplify(u, name, power)
63 type(UNITS),
intent(inout):: u
64 character(*),
intent(in):: name(u%nelems)
65 real(DP),
intent(in):: power(u%nelems)
66 integer:: i, n, j, onazi
67 integer:: table(u%nelems)
69 if (u%nelems < 1)
return
73 if (name(i) ==
'') cycle
76 if (name(j) == name(i))
then
81 table(i) = table(onazi)
87 allocate(u%name(n), u%power(n))
90 if (table(i) == 0) cycle
91 u%name(table(i)) = name(i)
92 u%power(table(i)) = u%power(table(i)) + power(i)
95 end subroutine units_simplify
97 type(
units) function dcunitsmul(u1, u2) result(result)
98 type(
units),
intent(in):: u1, u2
100 character(TOKEN),
allocatable:: name(:)
101 real(
dp),
allocatable:: power(:)
102 result%factor = u1%factor * u2%factor
103 result%nelems = u1%nelems + u2%nelems
107 nullify(result%name, result%power)
110 allocate(name(n), power(n))
111 name = (/u1%name, u2%name/)
112 power = (/u1%power, u2%power/)
113 call units_simplify(result, name, power)
114 deallocate(name, power)
115 end function dcunitsmul
117 type(
units) function dcunitsdiv(u1, u2) result(result)
118 type(
units),
intent(in):: u1, u2
120 character(TOKEN),
allocatable:: name(:)
121 real(dp),
allocatable:: power(:)
122 if (abs(u2%factor) < tiny(u2%factor))
then
123 result%factor = sign(u1%factor, 1.0_dp) * &
124 & sign(u2%factor, 1.0_dp) * &
127 result%factor = u1%factor / u2%factor
129 result%nelems = u1%nelems + u2%nelems
133 nullify(result%name, result%power)
136 allocate(name(n), power(n))
139 name(1:n1) = u1%name(1:n1)
140 power(1:n1) = u1%power(1:n1)
144 name(n1:n) = u2%name(1:u2%nelems)
145 power(n1:n) = -u2%power(1:u2%nelems)
147 call units_simplify(result, name, power)
148 deallocate(name, power)
149 end function dcunitsdiv
151 type(
units) function dcunitsadd(u1, u2) result(result)
152 type(
units),
intent(in):: u1, u2
154 result%offset = u1%offset
155 result%nelems = u1%nelems
156 result%factor = u1%factor + u2%factor
158 if (x%nelems == 0)
then
159 nullify(result%name, result%power)
162 if (all(abs(x%power(1:result%nelems)) < tiny(0.0_dp)))
then
163 allocate(result%name(result%nelems), result%power(result%nelems))
164 result%name = u1%name
165 result%power = u1%power
170 result%offset =
"MISMATCH"
171 nullify(result%name, result%power)
172 end function dcunitsadd
175 type(
units),
intent(in):: u1, u2
177 character(STRING):: debug
183 if (x%nelems == 0)
then
185 else if (all(abs(x%power(1:x%nelems)) < tiny(0.0_dp)))
then
193 subroutine dcunitsclear(u)
194 type(
units),
intent(inout):: u
200 end subroutine dcunitsclear
202 subroutine dcunitsdeallocate(u)
203 type(
units),
intent(inout):: u
204 if (
associated(u%name))
deallocate(u%name)
205 if (
associated(u%power))
deallocate(u%power)
209 end subroutine dcunitsdeallocate
211 subroutine dcunitstostring(string, u)
215 character(*),
intent(out):: string
216 type(
units),
intent(in):: u
217 integer:: i, ip, npower
218 character(TOKEN):: buffer
219 character:: mul =
'.'
220 real(DP),
parameter:: allowed = epsilon(1.0_dp) * 16.0
222 if (u%nelems < 0)
then
223 string =
'error from ' // u%offset
227 write(buffer,
"(1pg20.12)") u%factor
229 if (u%nelems < 1)
return
231 if (abs(u%factor - 1.0) < allowed)
then
233 else if (abs(u%factor + 1.0) < allowed)
then
237 ip = len_trim(string) + 1
239 npower = nint(u%power(i))
240 if (abs(1.0 - u%power(i)) < allowed)
then
242 else if (abs(npower - u%power(i)) < allowed)
then
243 write(buffer,
"(i10)") npower
244 buffer = adjustl(buffer)
246 write(buffer,
"(1pg10.3)") u%power(i)
247 buffer = adjustl(buffer)
249 if (buffer ==
'0') cycle
250 string = trim(string) // mul // trim(u%name(i)) // trim(buffer)
252 if (ip <= len(string)) string(ip:ip) =
' '
253 if (string(1:1) ==
" ") string = adjustl(string)
254 if (u%offset /=
"")
then
255 string = trim(string) //
'@' // trim(u%offset)
257 end subroutine dcunitstostring
259 subroutine dcunitsbuild(u, cunits)
264 type(
units),
intent(out):: u
265 character(*),
intent(in):: cunits
270 character(TOKEN):: name
271 real(DP):: power, factor
273 type(elem_units),
target:: ustack(100)
284 type(paren_t):: pstack(50)
288 integer,
parameter:: Y_INIT = 1, y_number = 2, y_name = 3, &
289 & y_nx = 4, y_ni = 5, y_mul = 6, y_shift = 7
290 integer:: yparse_status = y_init
296 character(TOKEN):: cvalue
302 if (
associated(u%name))
deallocate(u%name)
303 if (
associated(u%power))
deallocate(u%power)
307 if (cunits ==
"")
return
311 yparse_status = y_init
317 select case(yparse_status)
319 pstack(pi)%factor = pstack(pi)%factor * ivalue(1)
320 yparse_status = y_number
322 i = pstack(pi)%power_exp
323 ustack(i:ui)%power = ustack(i:ui)%power * ivalue(1)
332 select case(yparse_status)
334 pstack(pi)%factor = pstack(pi)%factor * dvalue
335 yparse_status = y_number
337 i = pstack(pi)%power_exp
338 ustack(i:ui)%power = ustack(i:ui)%power * dvalue
347 select case(yparse_status)
348 case (y_init, y_number, y_mul)
349 ustack(ui)%name = cvalue
350 yparse_status = y_name
354 ustack(ui)%name = cvalue
355 yparse_status = y_name
362 select case(yparse_status)
369 select case(yparse_status)
370 case (y_number, y_name)
372 yparse_status = y_mul
377 select case(yparse_status)
378 case (y_number, y_name)
380 pstack(pi)%factor_inv = .true.
381 yparse_status = y_mul
388 yparse_status = y_shift
405 u%factor = product(ustack(1:ui)%factor)
406 call units_simplify(u, ustack(1:ui)%name, ustack(1:ui)%power)
411 print *,
"DCUnitsBuild: syntax error, operator(**) ignored"
415 print *,
"DCUnitsBuild: unexpected token <", &
416 & trim(cvalue),
"> ignored"
419 subroutine power_next
422 pstack(pi)%power_exp = ui
423 end subroutine power_next
425 subroutine factor_next
428 i = pstack(pi)%factor_exp
429 factor = product(ustack(i:ui)%factor) * pstack(pi)%factor
430 if (pstack(pi)%factor_inv)
then
431 ustack(i:ui)%power = -ustack(i:ui)%power
432 factor = 1.0_dp / factor
434 ustack(i)%factor = factor
435 ustack(i+1:ui)%factor = 1.0_dp
437 pstack(pi)%factor = 1.0_dp
438 pstack(pi)%factor_exp = ui
439 end subroutine factor_next
441 subroutine units_finalize
443 end subroutine units_finalize
445 subroutine ustack_clear
448 end subroutine ustack_clear
450 subroutine ustack_grow
451 if (ui >=
size(ustack)) stop
'DCUnitsBuild: too many elements'
454 ustack(ui)%factor = 1.0_dp
455 ustack(ui)%power = 1.0_dp
456 end subroutine ustack_grow
458 subroutine pstack_clear
461 end subroutine pstack_clear
463 subroutine pstack_push
464 if (pi >=
size(pstack)) stop
'DCUnitsBuild: too many parens'
467 pstack(pi)%factor_exp = ui
468 pstack(pi)%factor = 1.0_dp
469 pstack(pi)%factor_inv = .false.
470 pstack(pi)%power_exp = ui
471 pstack(pi)%paren_exp = ui
472 end subroutine pstack_push
474 subroutine pstack_pop
478 end subroutine pstack_pop
480 end subroutine dcunitsbuild
Provides kind type parameter values.
integer, parameter, public token
Character length for word, token
integer, parameter, public string
Character length for string
integer, parameter, public dp
Double Precision Real number
logical function, public add_okay(u1, u2)
integer, parameter, public s_real
integer, parameter, public s_closepar
integer, parameter, public s_text
integer, parameter, public s_multiply
integer, parameter, public s_openpar
integer, parameter, public s_shift
integer, parameter, public s_integer
integer, parameter, public s_eof
subroutine, public dcunitsgettoken(tokentype, ivalue, dvalue, cvalue)
subroutine, public dcunitssetline(line)
integer, parameter, public s_exponent
integer, parameter, public s_divide