Loading...
Searching...
No Matches
dc_units.f90
Go to the documentation of this file.
1!== dc_units.f90 - 単位系処理用モジュール
2!
3! Authors:: Eizi TOYODA, Yasuhiro MORIKAWA
4! Version:: $Id: dc_units.f90,v 1.1 2009-03-20 09:09:52 morikawa Exp $
5! Tag Name:: $Name: $
6! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
7! License:: See COPYRIGHT[link:../../COPYRIGHT]
8!
9! This file provides dc_units
10!
11
12module dc_units !:nodoc:
13 !
14 !== Overview
15 !
16 ! このモジュールは単位系処理のためのプログラム群を提供します。
17 !
18
19 use dc_types, only: dp, token, string
20 implicit none
21
22 private
23 public:: units
24 public:: clear, deallocate, add_okay
25 public:: assignment(=), operator(*), operator(/), operator(+)
26 private:: units_simplify
27
28 type units
29 real(dp):: factor
30 integer:: nelems
31 character(TOKEN), pointer:: name(:)
32 character(TOKEN):: offset
33 real(dp), pointer:: power(:)
34 end type units
35
36 interface clear
37 module procedure dcunitsclear
38 end interface
39
40 interface deallocate
41 module procedure dcunitsdeallocate
42 end interface
43
44 interface assignment(=)
45 module procedure dcunitsbuild, dcunitstostring
46 end interface
47
48 interface operator(*)
49 module procedure dcunitsmul
50 end interface
51
52 interface operator(/)
53 module procedure dcunitsdiv
54 end interface
55
56 interface operator(+)
57 module procedure dcunitsadd
58 end interface
59
60contains
61
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)
68
69 if (u%nelems < 1) return
70 table(:) = 0
71 n = 0
72 do, i = 1, u%nelems
73 if (name(i) == '') cycle
74 onazi = 0
75 do, j = 1, i - 1
76 if (name(j) == name(i)) then
77 onazi = j
78 endif
79 enddo
80 if (onazi > 0) then
81 table(i) = table(onazi)
82 else
83 n = n + 1
84 table(i) = n
85 endif
86 enddo
87 allocate(u%name(n), u%power(n))
88 u%power = 0.0_dp
89 do, i = 1, u%nelems
90 if (table(i) == 0) cycle
91 u%name(table(i)) = name(i)
92 u%power(table(i)) = u%power(table(i)) + power(i)
93 enddo
94 u%nelems = n
95 end subroutine units_simplify
96
97 type(units) function dcunitsmul(u1, u2) result(result)
98 type(units), intent(in):: u1, u2
99 integer:: n
100 character(TOKEN), allocatable:: name(:)
101 real(dp), allocatable:: power(:)
102 result%factor = u1%factor * u2%factor
103 result%nelems = u1%nelems + u2%nelems
104 result%offset = ""
105 n = result%nelems
106 if (n == 0) then
107 nullify(result%name, result%power)
108 return
109 endif
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
116
117 type(units) function dcunitsdiv(u1, u2) result(result)
118 type(units), intent(in):: u1, u2
119 integer:: n, n1
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) * &
125 & huge(1.0_dp)
126 else
127 result%factor = u1%factor / u2%factor
128 endif
129 result%nelems = u1%nelems + u2%nelems
130 result%offset = ""
131 n = result%nelems
132 if (n == 0) then
133 nullify(result%name, result%power)
134 return
135 endif
136 allocate(name(n), power(n))
137 n1 = u1%nelems
138 if (n1 >= 1) then
139 name(1:n1) = u1%name(1:n1)
140 power(1:n1) = u1%power(1:n1)
141 endif
142 n1 = n1 + 1
143 if (n >= n1) then
144 name(n1:n) = u2%name(1:u2%nelems)
145 power(n1:n) = -u2%power(1:u2%nelems)
146 endif
147 call units_simplify(result, name, power)
148 deallocate(name, power)
149 end function dcunitsdiv
150
151 type(units) function dcunitsadd(u1, u2) result(result)
152 type(units), intent(in):: u1, u2
153 type(units):: x
154 result%offset = u1%offset
155 result%nelems = u1%nelems
156 result%factor = u1%factor + u2%factor
157 x = u1 / u2
158 if (x%nelems == 0) then
159 nullify(result%name, result%power)
160 return
161 endif
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
166 return
167 endif
168 result%factor = 0.0
169 result%nelems = -1
170 result%offset = "MISMATCH"
171 nullify(result%name, result%power)
172 end function dcunitsadd
173
174 logical function add_okay(u1, u2) result(result)
175 type(units), intent(in):: u1, u2
176 type(units):: x
177 character(STRING):: debug
178 call clear(x)
179 x = u1 / u2
180 debug = u1
181 debug = u2
182 debug = x
183 if (x%nelems == 0) then
184 result = .true.
185 else if (all(abs(x%power(1:x%nelems)) < tiny(0.0_dp))) then
186 result = .true.
187 else
188 result = .false.
189 endif
190 call deallocate(x)
191 end function add_okay
192
193 subroutine dcunitsclear(u)
194 type(units), intent(inout):: u
195 nullify(u%name)
196 nullify(u%power)
197 u%factor = 1.0_dp
198 u%offset = ""
199 u%nelems = 0
200 end subroutine dcunitsclear
201
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)
206 u%factor = 1.0_dp
207 u%offset = ""
208 u%nelems = 0
209 end subroutine dcunitsdeallocate
210
211 subroutine dcunitstostring(string, u)
212 !
213 ! UNITS 型変数から文字型変数を生成します。
214 !
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
221
222 if (u%nelems < 0) then
223 string = 'error from ' // u%offset
224 return
225 endif
226
227 write(buffer, "(1pg20.12)") u%factor
228 string = buffer
229 if (u%nelems < 1) return
230
231 if (abs(u%factor - 1.0) < allowed) then
232 string = ""
233 else if (abs(u%factor + 1.0) < allowed) then
234 string = "-"
235 endif
236
237 ip = len_trim(string) + 1
238 do, i = 1, u%nelems
239 npower = nint(u%power(i))
240 if (abs(1.0 - u%power(i)) < allowed) then
241 buffer = " "
242 else if (abs(npower - u%power(i)) < allowed) then
243 write(buffer, "(i10)") npower
244 buffer = adjustl(buffer)
245 else
246 write(buffer, "(1pg10.3)") u%power(i)
247 buffer = adjustl(buffer)
248 endif
249 if (buffer == '0') cycle
250 string = trim(string) // mul // trim(u%name(i)) // trim(buffer)
251 enddo
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)
256 endif
257 end subroutine dcunitstostring
258
259 subroutine dcunitsbuild(u, cunits)
260 !
261 ! 文字型変数から UNITS 型変数を生成します (constructor)。
262 !
263 use dcunits_com
264 type(units), intent(out):: u
265 character(*), intent(in):: cunits
266
267 ! 構築中の情報、乗算対象の列として保持する。
268 ! これは shift オペレータ付き単位を乗算できないことを示す。
269 type elem_units
270 character(TOKEN):: name
271 real(DP):: power, factor
272 end type elem_units
273 type(elem_units), target:: ustack(100)
274 integer:: ui = 1
275
276 ! 構文単位が占める乗算対象の stack における最初の添字
277 type paren_t
278 real(DP):: factor
279 integer:: factor_exp
280 logical:: factor_inv
281 integer:: power_exp
282 integer:: paren_exp
283 end type paren_t
284 type(paren_t):: pstack(50)
285 integer:: pi = 1
286
287 ! パーサの状態遷移
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
291
292 ! 字句
293 integer:: ltype
294 integer:: ivalue(5)
295 real(DP):: dvalue
296 character(TOKEN):: cvalue
297 ! その他
298 integer:: i
299
300 ! --- 実行部 ---
301 ! 初期化
302 if (associated(u%name)) deallocate(u%name)
303 if (associated(u%power)) deallocate(u%power)
304 u%nelems = 0
305 u%offset = ""
306 u%factor = 1.0_dp
307 if (cunits == "") return
308 call dcunitssetline(cunits)
309 call ustack_clear
310 call pstack_clear
311 yparse_status = y_init
312
313 do
314 call dcunitsgettoken(ltype, ivalue, dvalue, cvalue)
315 select case(ltype)
316 case (s_integer)
317 select case(yparse_status)
318 case (y_init, y_mul)
319 pstack(pi)%factor = pstack(pi)%factor * ivalue(1)
320 yparse_status = y_number
321 case (y_name, y_nx)
322 i = pstack(pi)%power_exp
323 ustack(i:ui)%power = ustack(i:ui)%power * ivalue(1)
324 call power_next
325 yparse_status = y_ni
326 case (y_shift)
327 u%offset = cvalue
328 case default
329 call error
330 end select
331 case (s_real)
332 select case(yparse_status)
333 case (y_init, y_mul)
334 pstack(pi)%factor = pstack(pi)%factor * dvalue
335 yparse_status = y_number
336 case (y_name, y_nx)
337 i = pstack(pi)%power_exp
338 ustack(i:ui)%power = ustack(i:ui)%power * dvalue
339 call power_next
340 yparse_status = y_ni
341 case (y_shift)
342 u%offset = cvalue
343 case default
344 call error
345 end select
346 case (s_text)
347 select case(yparse_status)
348 case (y_init, y_number, y_mul)
349 ustack(ui)%name = cvalue
350 yparse_status = y_name
351 case (y_name, y_ni)
352 call ustack_grow
353 call power_next
354 ustack(ui)%name = cvalue
355 yparse_status = y_name
356 case (y_shift)
357 u%offset = cvalue
358 case default
359 call error
360 end select
361 case (s_exponent)
362 select case(yparse_status)
363 case (y_name)
364 yparse_status = y_nx
365 case default
366 call error
367 end select
368 case (s_multiply)
369 select case(yparse_status)
370 case (y_number, y_name)
371 call factor_next
372 yparse_status = y_mul
373 case default
374 call error
375 end select
376 case (s_divide)
377 select case(yparse_status)
378 case (y_number, y_name)
379 call factor_next
380 pstack(pi)%factor_inv = .true.
381 yparse_status = y_mul
382 case default
383 call error
384 end select
385 case (s_shift)
386 if (yparse_status == y_nx) call cancel_exp
387 call units_finalize
388 yparse_status = y_shift
389 case (s_openpar)
390 if (yparse_status == y_nx) call cancel_exp
391 call pstack_push
392 case (s_closepar)
393 call units_finalize
394 call pstack_pop
395 case (s_eof)
396 exit
397 case default
398 call error
399 end select
400 enddo
401 if (yparse_status == y_nx) call cancel_exp
402 call units_finalize
403
404 u%nelems = ui
405 u%factor = product(ustack(1:ui)%factor)
406 call units_simplify(u, ustack(1:ui)%name, ustack(1:ui)%power)
407
408 contains
409
410 subroutine cancel_exp
411 print *, "DCUnitsBuild: syntax error, operator(**) ignored"
412 end subroutine cancel_exp
413
414 subroutine error
415 print *, "DCUnitsBuild: unexpected token <", &
416 & trim(cvalue), "> ignored"
417 end subroutine error
418
419 subroutine power_next
420 ! power_exp の終了処理
421 call ustack_grow
422 pstack(pi)%power_exp = ui
423 end subroutine power_next
424
425 subroutine factor_next
426 ! factor_exp の終了処理
427 real(DP):: factor
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
433 endif
434 ustack(i)%factor = factor
435 ustack(i+1:ui)%factor = 1.0_dp
436 call power_next
437 pstack(pi)%factor = 1.0_dp
438 pstack(pi)%factor_exp = ui
439 end subroutine factor_next
440
441 subroutine units_finalize
442 call factor_next
443 end subroutine units_finalize
444
445 subroutine ustack_clear
446 ui = 0
447 call ustack_grow
448 end subroutine ustack_clear
449
450 subroutine ustack_grow
451 if (ui >= size(ustack)) stop 'DCUnitsBuild: too many elements'
452 ui = ui + 1
453 ustack(ui)%name = ""
454 ustack(ui)%factor = 1.0_dp
455 ustack(ui)%power = 1.0_dp
456 end subroutine ustack_grow
457
458 subroutine pstack_clear
459 pi = 0
460 call pstack_push
461 end subroutine pstack_clear
462
463 subroutine pstack_push
464 if (pi >= size(pstack)) stop 'DCUnitsBuild: too many parens'
465 pi = pi + 1
466 call ustack_grow
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
473
474 subroutine pstack_pop
475 ! factor_exp の終了処理
476 call power_next
477 pi = pi - 1
478 end subroutine pstack_pop
479
480 end subroutine dcunitsbuild
481
482end module dc_units
subroutine cancel_exp
Definition dc_units.f90:411
Provides kind type parameter values.
Definition dc_types.f90:49
integer, parameter, public token
Character length for word, token
Definition dc_types.f90:109
integer, parameter, public string
Character length for string
Definition dc_types.f90:118
integer, parameter, public dp
Double Precision Real number
Definition dc_types.f90:83
logical function, public add_okay(u1, u2)
Definition dc_units.f90:175
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