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 
12 module 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 
60 contains
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 *, operator"DCUnitsBuild: syntax error, (**) 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
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 
482 end module dc_units
integer, parameter, public s_exponent
Definition: dcunits_com.f90:34
subroutine ustack_clear
Definition: dc_units.f90:446
integer, parameter, public s_eof
Definition: dcunits_com.f90:29
integer, parameter, public s_openpar
Definition: dcunits_com.f90:35
integer, parameter, public token
単語やキーワードを保持する文字型変数の種別型パラメタ
Definition: dc_types.f90:109
type(units) function dcunitsadd(u1, u2)
Definition: dc_units.f90:152
subroutine error
Definition: dc_units.f90:415
subroutine dcunitstostring(string, u)
Definition: dc_units.f90:212
subroutine dcunitsbuild(u, cunits)
Definition: dc_units.f90:260
integer, parameter, public s_shift
Definition: dcunits_com.f90:30
integer, parameter, public s_real
Definition: dcunits_com.f90:37
type(units) function dcunitsdiv(u1, u2)
Definition: dc_units.f90:118
subroutine ustack_grow
Definition: dc_units.f90:451
subroutine cancel_exp
Definition: dc_units.f90:411
subroutine factor_next
Definition: dc_units.f90:426
subroutine dcunitsdeallocate(u)
Definition: dc_units.f90:203
integer, parameter, public dp
倍精度実数型変数
Definition: dc_types.f90:83
integer, parameter, public s_divide
Definition: dcunits_com.f90:33
subroutine, private units_simplify(u, name, power)
Definition: dc_units.f90:63
subroutine dcunitsclear(u)
Definition: dc_units.f90:194
subroutine power_next
Definition: dc_units.f90:420
logical function, public add_okay(u1, u2)
Definition: dc_units.f90:175
subroutine pstack_pop
Definition: dc_units.f90:475
種別型パラメタを提供します。
Definition: dc_types.f90:49
integer, parameter, public s_multiply
Definition: dcunits_com.f90:32
integer, parameter, public s_closepar
Definition: dcunits_com.f90:36
type(units) function dcunitsmul(u1, u2)
Definition: dc_units.f90:98
integer, parameter, public s_text
Definition: dcunits_com.f90:31
subroutine, public dcunitsgettoken(tokentype, ivalue, dvalue, cvalue)
Definition: dcunits_com.f90:54
subroutine, public dcunitssetline(line)
Definition: dcunits_com.f90:47
integer, parameter, public s_integer
Definition: dcunits_com.f90:38
subroutine pstack_push
Definition: dc_units.f90:464
subroutine units_finalize
Definition: dc_units.f90:442
subroutine pstack_clear
Definition: dc_units.f90:459
integer, parameter, public string
文字列を保持する 文字型変数の種別型パラメタ
Definition: dc_types.f90:118