gtool5 Fortran 90/95 Library 1.0.0-rc5
日本語
Loading...
Searching...
No Matches
dc_trace.f90
Go to the documentation of this file.
1! -*- mode: f90; coding: utf-8 -*-
2!-----------------------------------------------------------------------
3! Copyright (c) 2000-2026 Gtool Development Group. All rights reserved.
4!-----------------------------------------------------------------------
5!>
6!> @author Yasuhiro MORIKAWA, Eizi TOYODA
7!> @copyright Copyright (C) GFD Dennou Club, 2000-2026. All rights reserved. <br/>
8!> License is BSD-2-Clause. see [COPYRIGHT](@ref COPYRIGHT) in detail
9!>
10!> @en
11!> @brief Debug tracing module
12!> @details
13!> dc_trace is a module that provides subroutines to assist in tracing
14!> causes during debugging. By using this module, you can output debug
15!> messages that show the hierarchical structure of subroutines as follows:
16!>
17!> @code
18!> :
19!> #call HistoryPut0
20!> #| call HistoryPutEx : time
21!> #| | call TimeGoAhead : varname=time head=1.
22!> #| | | call lookup_dimension
23!> #| | | | call gtvarinquire : var.mapid=1
24!> #| | | | | call gdncvarinqurie : var.id=1
25!> #| | | | | end gdncvarinqurie : ok
26!> #| | | | |-name=time
27!> #| | | | end gtvarinquire
28!> #| | | end lookup_dimension : ord=1
29!> #| | end TimeGoAhead
30!> #| end HistoryPutEx
31!> #end HistoryPut0
32!> :
33!> @endcode
34!>
35!> @section dc_trace_procedures Procedures List
36!>
37!> | Procedure | Description |
38!> |-------------|------------------------------------------|
39!> | SetDebug | Turn debug mode on/off |
40!> | BeginSub | Output subprogram start message |
41!> | EndSub | Output subprogram end message |
42!> | DbgMessage | Output debug message |
43!> | DataDump | Output multi-dimensional data |
44!>
45!> @section dc_trace_usage Usage
46!>
47!> Use BeginSub and EndSub at the beginning and end of subprogram execution:
48!>
49!> @code{.f90}
50!> subroutine TestRoutine(file, var, times, url)
51!> use dc_types, only: STRING
52!> use dc_trace, only: BeginSub, EndSub
53!> character(*), intent(in) :: file, var
54!> integer, intent(in) :: times
55!> character(*), intent(out):: url
56!> character(STRING), parameter:: subname = "TestRoutine"
57!> continue
58!> call BeginSub(subname, 'file=%c, var=%c, times=%d', &
59!> & c1=trim(file), c2=trim(var), i=(/times/) )
60!> url = trim(file) // trim(var)
61!> call EndSub(subname, 'url=%c', c1=trim(url) )
62!> end subroutine TestRoutine
63!> @endcode
64!>
65!> Call SetDebug at the beginning of the main program:
66!>
67!> @code{.f90}
68!> program main
69!> use dc_trace, only: SetDebug
70!> continue
71!> call SetDebug
72!> call TestRoutine(...)
73!> end program main
74!> @endcode
75!>
76!> @enden
77!>
78!> @ja
79!> @brief デバッグ時の追跡用モジュール
80!> @details
81!> dc_trace はデバッグ時の原因の追跡を補助するためのサブルーチン群
82!> を持つモジュールです。このモジュールを利用する事で、
83!> 以下のようにサブルーチンの階層構造がそのまま分かるような
84!> デバッグメッセージを出力する事が可能です。
85!>
86!> @code
87!> :
88!> #call HistoryPut0
89!> #| call HistoryPutEx : time
90!> #| | call TimeGoAhead : varname=time head=1.
91!> #| | | call lookup_dimension
92!> #| | | | call gtvarinquire : var.mapid=1
93!> #| | | | | call gdncvarinqurie : var.id=1
94!> #| | | | | end gdncvarinqurie : ok
95!> #| | | | |-name=time
96!> #| | | | end gtvarinquire
97!> #| | | end lookup_dimension : ord=1
98!> #| | end TimeGoAhead
99!> #| end HistoryPutEx
100!> #end HistoryPut0
101!> :
102!> @endcode
103!>
104!> @section dc_trace_procedures_ja 手続一覧
105!>
106!> | 手続名 | 説明 |
107!> |-------------|------------------------------------------|
108!> | SetDebug | デバッグモードをオンオフ |
109!> | BeginSub | 副プログラム開始のメッセージ出力 |
110!> | EndSub | 副プログラム終了のメッセージ出力 |
111!> | DbgMessage | デバッグ用メッセージ出力 |
112!> | DataDump | 多次元データ出力 |
113!>
114!> @section dc_trace_usage_ja 使用方法
115!>
116!> 副プログラムの実行文の先頭と最後で BeginSub と EndSub を使用します。
117!>
118!> @code{.f90}
119!> subroutine TestRoutine(file, var, times, url)
120!> use dc_types, only: STRING
121!> use dc_trace, only: BeginSub, EndSub
122!> character(*), intent(in) :: file, var
123!> integer, intent(in) :: times
124!> character(*), intent(out):: url
125!> character(STRING), parameter:: subname = "TestRoutine"
126!> continue
127!> call BeginSub(subname, 'file=%c, var=%c, times=%d', &
128!> & c1=trim(file), c2=trim(var), i=(/times/) )
129!> url = trim(file) // trim(var)
130!> call EndSub(subname, 'url=%c', c1=trim(url) )
131!> end subroutine TestRoutine
132!> @endcode
133!>
134!> 主プログラムの実行文の先頭で SetDebug を使用します。
135!>
136!> @code{.f90}
137!> program main
138!> use dc_trace, only: SetDebug
139!> continue
140!> call SetDebug
141!> call TestRoutine(...)
142!> end program main
143!> @endcode
144!>
145!> @note BeginSub よりも前に SetDebug が呼ばれている必要があります。
146!> @note BeginSub と同じ回数だけ EndSub が呼ばれていなければなりません。
147!>
148!> @endja
149!>
151 use dc_types, only: token, string
152 implicit none
153 private
154 logical, save :: lfirst = .true.
155 ! 初回フラグ
156 integer, save, public :: dbg = -1 ! SetDebug で設定された
157 ! デバッグメッセージの
158 ! 出力される装置番号です。
159 integer, save :: level = 0 ! サブルーチンレベル
160 integer, parameter :: trace_stack_size = 128
161 ! 最大階層数
162 character(TOKEN), save:: table(trace_stack_size)
163 ! 階層⇔プログラム名
164 character(STRING), save, allocatable:: called_subname(:), &
165 & called_subname_tmp(:)
166 ! 既に一度呼ばれており,
167 ! *version* 引数を指定している
168 ! 副プログラム名を格納する配列
169 character(1), parameter:: head = '#' ! 行頭文字
170 character(2), parameter :: indent = '| ' ! 字下げ文字
171 character(2), parameter :: meshead = '|-' ! DbgMessage 用行頭文字
173 public:: sublevel, datadump
174 interface debug
175 module procedure dctracedebug
176 end interface
177 interface datadump
178 module procedure datad1dump, datad2dump, datad3dump
179 end interface
180contains
181 !> @en
182 !> @brief Return the hierarchical level of subprograms
183 !> @details
184 !> Returns the hierarchical level of subprograms. The default level is 0.
185 !> The level increases by 1 with BeginSub and decreases by 1 with EndSub.
186 !>
187 !> @return Hierarchical level of subprograms
188 !> @enden
189 !>
190 !> @ja
191 !> @brief 副プログラムの階層レベルを返す
192 !> @details
193 !> 副プログラムの階層レベルを返します。レベルのデフォルトは 0 で、
194 !> BeginSub によりレベルは 1 増え、EndSub によりレベルは 1 減ります。
195 !>
196 !> @return 副プログラムの階層レベル
197 !> @endja
198 integer function sublevel() result(result)
199 result = level
200 end function sublevel
201 !> @en
202 !> @brief Erase debug messages
203 !> @details
204 !> **Operation has not been confirmed. Please use with caution.**
205 !>
206 !> By giving .true. to the logical variable `on`, subsequent debug messages
207 !> can be erased.
208 !>
209 !> By giving .false. to the logical variable `on`, messages since the
210 !> previous Dbg_Scratch call will be output as debug messages again,
211 !> and subsequent debug messages will also be output.
212 !>
213 !> @param[in] on If .true., erase subsequent debug messages.
214 !> If .false., output erased messages and resume normal output.
215 !> @enden
216 !>
217 !> @ja
218 !> @brief デバッグメッセージの抹消
219 !> @details
220 !> **動作未確認ですので利用の際にはご注意下さい。**
221 !>
222 !> 論理型変数 `on` に .true. を与える事で、
223 !> 以降のデバッグメッセージを抹消する事が出来ます。
224 !>
225 !> なお、論理型変数 `on` に .false. を与える事で、
226 !> 直前に呼んだ Dbg_Scratch 以降のメッセージを
227 !> デバッグメッセージとして再び出力し、
228 !> 以降のデバッグメッセージも出力されるようにします。
229 !>
230 !> @param[in] on .true. の場合、以降のデバッグメッセージを抹消する。
231 !> .false. の場合、抹消されたメッセージを出力し、通常出力を再開する。
232 !> @endja
233 subroutine dbg_scratch(on)
234 logical, intent(in):: on
235 integer, save:: saved_dbg = -1
236 logical:: x, p
237 character(80):: line
238 integer:: ios
239 continue
240 if (on) then
241 if (dbg < 0) return
242 saved_dbg = dbg
243 ! 有効な 1 〜 99 の装置番号の内の大きめの値を設定 (?)
244 dbg = 98
245 do
246 inquire(unit=dbg, exist=x, opened=p)
247 ! 装置番号 dbg が接続可能で、かつ未接続の場合
248 if (x .and. .not. p) then
249 ! 装置番号 deg をスクラッチファイルとして開く。
250 ! ※ スクラッチファイルとは、特殊な外部ファイルである。
251 ! これは名前なしの一時ファイルであり、開いている
252 ! 間だけ存在する。つまり、プログラムが終了すると
253 ! 存在しなくなる。
254 open(unit=dbg, status='SCRATCH')
255 ! 開く事が出来ればそれで終了。
256 return
257 endif
258 ! 装置番号 dbg が利用不可、または利用済の場合は 0 以下に
259 ! なるまで dbg - 1 して繰り返す。
260 dbg = dbg - 1
261 if (dbg < 0) exit
262 enddo
263 ! 装置番号 dbg が開けない場合、dbg と saved_dbg を初期化
264 dbg = saved_dbg
265 saved_dbg = -1
266 else
267 ! 以前に装置番号 dbg = 98〜0 でスクラッチファイルを開けてい
268 ! なければそれで終了
269 if (saved_dbg < 0) return
270 ! 装置番号 dbg に接続されたスクラッチファイルをその開始位置
271 ! に位置付ける。エラーが生じたら「100 continue」へ
272 rewind(dbg, err=100)
273 do
274 ! 装置番号 dbg に接続されたスクラッチファイルの一行を
275 ! line へ
276 read(dbg, '(A)', iostat=ios) line
277 if (ios /= 0) exit
278 ! line を装置番号 saved_dbg へ書き出す。
279 write(saved_dbg, '(A)', iostat=ios) trim(line)
280 if (ios /= 0) exit
281 enddo
282 100 continue
283 close(dbg, iostat=ios)
284 ! 最後に dbg と saved_dbg を初期化
285 dbg = saved_dbg
286 saved_dbg = -1
287 endif
288 end subroutine dbg_scratch
289 !> @en
290 !> @brief Turn debug mode on/off
291 !> @details
292 !> Call this subroutine when you want to output debug messages.
293 !>
294 !> If the integer variable `debug` is given, debug messages from subsequent
295 !> subroutines will be output to that unit number.
296 !> If `debug` is not given, debug messages will be output to unit number 0
297 !> (standard error output). If output to unit number 0 fails, debug messages
298 !> will be output to unit number 6 (standard output) instead.
299 !>
300 !> If a negative integer is given to `debug`, debug mode is disabled and
301 !> no debug messages will be output.
302 !>
303 !> When SetDebug is called, the following message is displayed:
304 !>
305 !> #SetDebug: dbg = debug
306 !>
307 !> @param[in] debug Unit number for debug message output (optional).
308 !> If not given, standard error output is used.
309 !> If negative, debug mode is disabled.
310 !> @enden
311 !>
312 !> @ja
313 !> @brief デバッグモードをオンオフ
314 !> @details
315 !> デバッグメッセージを出力したい時にこのサブルーチンを呼びます。
316 !>
317 !> 整数型変数 `debug` が与えられる場合は、その装置番号 debug に、
318 !> 以降のサブルーチンによるデバッグメッセージを出力するようにします。
319 !> `debug` が与えられない場合、装置番号 0 (標準エラー出力)
320 !> にデバッグメッセージが出力されるようになります。
321 !> 装置番号 0 への出力が成功しない場合は代わりに
322 !> 装置番号 6 (標準出力) にデバッグメッセージが出力されるようになります。
323 !>
324 !> `debug` に負の整数を与える場合、デバッグモードが解除され、
325 !> 以降デバッグメッセージは出力されません。
326 !>
327 !> なお、この SetDebug を呼んだ際にも、装置番号 debug
328 !> に以下のメッセージが表示されます。
329 !>
330 !> #SetDebug: dbg = debug
331 !>
332 !> @param[in] debug デバッグメッセージ出力用の装置番号 (省略可)。
333 !> 省略時は標準エラー出力を使用。負の値を与えるとデバッグモード解除。
334 !> @endja
335 subroutine setdebug(debug)
336 use dc_types, only: stdout, stderr
337 implicit none
338 integer, intent(in), optional:: debug
339 integer:: ios
340 continue
341 if (present(debug)) then
342 ! debug が与えられる時は装置番号として deg を用いる。
343 dbg = debug
344 write(dbg, "(A, 'SetDebug: dbg =', i4)", iostat=ios) &
345 & trim(head), dbg
346 if (ios == 0) return
347 else
348 ! debug が与えられ無い時は装置番号 0 (標準エラー出力)
349 dbg = stderr
350 write(dbg, "(A, 'SetDebug: dbg = ', I0)", iostat=ios) trim(head), dbg
351 if (ios == 0) return
352 ! 装置番号 0 への出力が失敗したら装置番号 6 (標準出力)
353 dbg = stdout
354 write(dbg, "(A, 'SetDebug: dbg = ', I0)", iostat=ios) trim(head), dbg
355 if (ios == 0) return
356 endif
357 ! 例外処理として dbg の初期化
358 dbg = -1
359 end subroutine setdebug
360 !> @en
361 !> @brief Check if debug mode is enabled
362 !> @details
363 !> Returns .true. if debug mode is enabled by SetDebug,
364 !> .false. if debug mode is not enabled.
365 !>
366 !> @param[out] dbg_mode .true. if debug mode is enabled, .false. otherwise
367 !> @enden
368 !>
369 !> @ja
370 !> @brief デバックモードかどうかの診断
371 !> @details
372 !> SetDebug でデバッグモードになっている場合には .true. が、
373 !> デバッグモードでない場合には .false. が返ります。
374 !>
375 !> @param[out] dbg_mode デバッグモードの場合 .true.、そうでなければ .false.
376 !> @endja
377 subroutine dctracedebug(dbg_mode)
378 logical, intent(out):: dbg_mode
379 dbg_mode = dbg >= 0
380 end subroutine dctracedebug
381 !> @brief Initialize internal variables
382 subroutine initialize
383 table(:) = ' '
384 lfirst = .false.
385 end subroutine initialize
386 !> @en
387 !> @brief Output subprogram start message
388 !> @details
389 !> Outputs the subprogram name given to `name` as follows:
390 !>
391 !> # call name
392 !>
393 !> By calling multiple times, messages are output showing the hierarchical
394 !> structure (see dc_trace Overview). Make sure to call EndSub the same
395 !> number of times as BeginSub.
396 !>
397 !> Additional messages can be output by providing `fmt` and subsequent arguments:
398 !>
399 !> # call name : fmt
400 !>
401 !> See dc_string::CPrintf for format specification.
402 !>
403 !> The `version` argument specifies the version number of the subprogram.
404 !> The version string is displayed only on the first call of a subprogram.
405 !>
406 !> @param[in] name Subprogram name
407 !> @param[in] fmt Format string for additional message (optional)
408 !> @param[in] i Integer array for formatting
409 !> @param[in] r Real array for formatting
410 !> @param[in] d Double precision array for formatting
411 !> @param[in] L Logical array for formatting
412 !> @param[in] n Integer array for formatting
413 !> @param[in] c1 Character string 1 for formatting
414 !> @param[in] c2 Character string 2 for formatting
415 !> @param[in] c3 Character string 3 for formatting
416 !> @param[in] ca Character array for formatting
417 !> @param[in] version Version number of the subprogram (optional)
418 !> @enden
419 !>
420 !> @ja
421 !> @brief 副プログラム開始のメッセージ出力
422 !> @details
423 !> 文字型変数 `name` に与えた副プログラム名を以下のように出力します。
424 !>
425 !> # call name
426 !>
427 !> 複数回呼ぶ事で階層構造が分かるメッセージが出力されます
428 !> (dc_trace の Overview 参照)。
429 !> 必ず BeginSub と同様な数だけ EndSub を呼ぶようにしてください。
430 !>
431 !> `fmt` およびそれ以降の引数を与える事で、付加メッセージも出力可能です:
432 !>
433 !> # call name : fmt
434 !>
435 !> 書式は dc_string::CPrintf を参照して下さい。
436 !>
437 !> `version` には副プログラムのバージョンナンバーを与えます。
438 !> version に与えられた文字列は、初回に呼び出された時のみ表示されます。
439 !>
440 !> @note このサブルーチンにより内部変数 level の値が 1 増えます。
441 !>
442 !> @param[in] name 副プログラム名
443 !> @param[in] fmt 付加メッセージ用フォーマット文字列 (省略可)
444 !> @param[in] i フォーマット用整数配列
445 !> @param[in] r フォーマット用実数配列
446 !> @param[in] d フォーマット用倍精度実数配列
447 !> @param[in] L フォーマット用論理配列
448 !> @param[in] n フォーマット用整数配列
449 !> @param[in] c1 フォーマット用文字列1
450 !> @param[in] c2 フォーマット用文字列2
451 !> @param[in] c3 フォーマット用文字列3
452 !> @param[in] ca フォーマット用文字列配列
453 !> @param[in] version 副プログラムのバージョンナンバー (省略可)
454 !> @endja
455 subroutine beginsub(name, fmt, i, r, d, L, n, c1, c2, c3, ca, &
456 & version)
457 use dc_types, only: string, dp
458 use dc_string, only: cprintf, strinclude
459 character(*), intent(in) :: name
460 character(*), intent(in), optional:: fmt
461 integer, intent(in), optional:: i(:), n(:)
462 real, intent(in), optional:: r(:)
463 real(dp), intent(in), optional:: d(:)
464 logical, intent(in), optional:: l(:)
465 character(*), intent(in), optional:: c1, c2, c3
466 character(*), intent(in), optional:: ca(:)
467 character(*), intent(in), optional:: version
468 character(STRING) :: cbuf
469 character(STRING) :: name_ver
470 logical :: dbg_mode, print_version
471 integer :: alloc_size
472 continue
473 if ( dbg < 0 ) return
474 if (lfirst) call initialize
475 call debug( dbg_mode )
476 if ( dbg_mode ) then
477 name_ver = name
478 print_version = .false.
479 !---------------------------------
480 ! Print Version check
481 if (present(version)) then
482 if (.not. allocated(called_subname)) then
483 allocate(called_subname(1))
484 called_subname(1) = name
485 print_version = .true.
486 else
487 if (.not. strinclude(called_subname, trim(name))) then
488 alloc_size = size(called_subname)
489 allocate(called_subname_tmp(alloc_size))
490 called_subname_tmp = called_subname
491 deallocate(called_subname)
492 allocate(called_subname(alloc_size + 1))
493 called_subname(1:alloc_size) = called_subname_tmp
494 deallocate(called_subname_tmp)
495 called_subname(alloc_size + 1) = name
496 print_version = .true.
497 end if
498 end if
499 if (print_version) then
500 name_ver = cprintf('%c version=<%c>', &
501 & c1=trim(name), c2=trim(version))
502 end if
503 end if
504 !---------------------------------
505 ! Print Debug message
506 if (present(fmt)) then
507 cbuf = cprintf(fmt, i, r, d, l, n, c1, c2, c3, ca)
508 write(dbg, "(A, A, 'call ', A, ' : ', A)") trim(head), &
509 & repeat(indent, level), trim(name_ver), trim(cbuf)
510 else
511 write(dbg, "(A, A, 'call ',A)") trim(head), &
512 & repeat(indent, level), trim(name_ver)
513 endif
514 endif
515 ! call errtra ! --- for Fujitsu debug
516 if (level > size(table)) return
517 level = level + 1
518 table(level) = name
519 end subroutine beginsub
520 !> @en
521 !> @brief Output subprogram end message
522 !> @details
523 !> Outputs the subprogram name given to `name` as follows:
524 !>
525 !> # end name
526 !>
527 !> This corresponds one-to-one with BeginSub, so give the same `name`
528 !> as the corresponding BeginSub argument.
529 !>
530 !> Additional messages can be output by providing `fmt` and subsequent arguments:
531 !>
532 !> # end name fmt
533 !>
534 !> See dc_string::CPrintf for format specification.
535 !>
536 !> @param[in] name Subprogram name
537 !> @param[in] fmt Format string for additional message (optional)
538 !> @param[in] i Integer array for formatting
539 !> @param[in] r Real array for formatting
540 !> @param[in] d Double precision array for formatting
541 !> @param[in] L Logical array for formatting
542 !> @param[in] n Integer array for formatting
543 !> @param[in] c1 Character string 1 for formatting
544 !> @param[in] c2 Character string 2 for formatting
545 !> @param[in] c3 Character string 3 for formatting
546 !> @param[in] ca Character array for formatting
547 !> @enden
548 !>
549 !> @ja
550 !> @brief 副プログラム終了のメッセージ出力
551 !> @details
552 !> 文字型変数 `name` に与えた副プログラム名を以下のように出力します。
553 !>
554 !> # end name
555 !>
556 !> BeginSub に対して一対一対応していますので、name には対応する
557 !> BeginSub の引数 name と同じものを与えて下さい。
558 !>
559 !> `fmt` およびそれ以降の引数を与える事で、付加メッセージも出力可能です:
560 !>
561 !> # end name fmt
562 !>
563 !> 書式は dc_string::CPrintf を参照して下さい。
564 !>
565 !> @note このサブルーチンにより内部変数 level の値が 1 減ります。
566 !>
567 !> @param[in] name 副プログラム名
568 !> @param[in] fmt 付加メッセージ用フォーマット文字列 (省略可)
569 !> @param[in] i フォーマット用整数配列
570 !> @param[in] r フォーマット用実数配列
571 !> @param[in] d フォーマット用倍精度実数配列
572 !> @param[in] L フォーマット用論理配列
573 !> @param[in] n フォーマット用整数配列
574 !> @param[in] c1 フォーマット用文字列1
575 !> @param[in] c2 フォーマット用文字列2
576 !> @param[in] c3 フォーマット用文字列3
577 !> @param[in] ca フォーマット用文字列配列
578 !> @endja
579 subroutine endsub(name, fmt, i, r, d, L, n, c1, c2, c3, ca)
580 use dc_types, only: dp
581 use dc_string, only: cprintf
582 character(*), intent(in) :: name
583 character(*), intent(in), optional:: fmt
584 integer, intent(in), optional:: i(:), n(:)
585 real, intent(in), optional:: r(:)
586 real(dp), intent(in), optional:: d(:)
587 logical, intent(in), optional:: l(:)
588 character(*), intent(in), optional:: c1, c2, c3
589 character(*), intent(in), optional:: ca(:)
590 character(STRING):: cbuf
591 logical:: debug_mode
592 continue
593 if ( dbg < 0 ) return
594 if (lfirst) call initialize
595 ! call errtra ! --- for Fujitsu debug
596 if (level <= 0) then
597 write(*, "(A, 'Warning EndSub[',A,'] without BeginSub')") &
598 & trim(head), trim(name)
599 else if (name /= table(level)) then
600 write(*, "(A, 'Warning EndSub[',A,'] but tos[',A,']')") &
601 & trim(head), trim(name), trim(table(level))
602 else
603 level = level - 1
604 endif
605 call debug( debug_mode )
606 if ( debug_mode ) then
607 if (present(fmt)) then
608 cbuf = cprintf(fmt, i, r, d, l, n, c1, c2, c3, ca)
609 write(dbg, "(A, A, 'end ', A, ' : ', A)") trim(head), &
610 & repeat(indent, level), trim(name), trim(cbuf)
611 else
612 write(dbg, "(A, A, 'end ', A)") trim(head), &
613 & repeat(indent, level), trim(name)
614 endif
615 endif
616 end subroutine endsub
617 !> @en
618 !> @brief Output debug message
619 !> @details
620 !> Outputs debug messages according to the format string `fmt`.
621 !> See dc_string::CPrintf for format specification.
622 !>
623 !> See dc_trace Example for usage examples.
624 !>
625 !> @note This subroutine does not change the internal variable `level`.
626 !>
627 !> @param[in] fmt Format string
628 !> @param[in] i Integer array for formatting
629 !> @param[in] r Real array for formatting
630 !> @param[in] d Double precision array for formatting
631 !> @param[in] L Logical array for formatting
632 !> @param[in] n Integer array for formatting
633 !> @param[in] c1 Character string 1 for formatting
634 !> @param[in] c2 Character string 2 for formatting
635 !> @param[in] c3 Character string 3 for formatting
636 !> @param[in] ca Character array for formatting
637 !> @enden
638 !>
639 !> @ja
640 !> @brief デバッグ用メッセージ出力
641 !> @details
642 !> フォーマット文字列 `fmt` に従ってデバッグメッセージを出力します。
643 !> 書式は dc_string::CPrintf を参照して下さい。
644 !>
645 !> 利用例に関しては dc_trace の Example を参照して下さい。
646 !>
647 !> @note このサブルーチンを用いても内部変数 level の値は変化しません。
648 !>
649 !> @param[in] fmt フォーマット文字列
650 !> @param[in] i フォーマット用整数配列
651 !> @param[in] r フォーマット用実数配列
652 !> @param[in] d フォーマット用倍精度実数配列
653 !> @param[in] L フォーマット用論理配列
654 !> @param[in] n フォーマット用整数配列
655 !> @param[in] c1 フォーマット用文字列1
656 !> @param[in] c2 フォーマット用文字列2
657 !> @param[in] c3 フォーマット用文字列3
658 !> @param[in] ca フォーマット用文字列配列
659 !> @endja
660 subroutine dbgmessage(fmt, i, r, d, L, n, c1, c2, c3, ca)
661 use dc_types, only: string, dp
662 use dc_string, only: cprintf, tochar
663 character(*), intent(in) :: fmt
664 integer, intent(in), optional:: i(:), n(:)
665 real, intent(in), optional:: r(:)
666 real(dp), intent(in), optional:: d(:)
667 logical, intent(in), optional:: l(:)
668 character(*), intent(in), optional:: c1, c2, c3
669 character(*), intent(in), optional:: ca(:)
670 character(STRING):: cbuf
671 character(STRING):: meshead_tmp
672 integer :: meshead_len
673 continue
674 if ( dbg < 0 ) return
675 cbuf = cprintf(fmt, i, r, d, l, n, c1, c2, c3, ca)
676 if (level < 1) then
677 meshead_tmp = ''
678 meshead_len = 0
679 else
680 meshead_tmp = meshead
681 meshead_len = len(meshead)
682 endif
683 write(dbg, "(A, A, A, A)") &
684 & trim(head), repeat( indent, max(level-1, 0) ), &
685 & meshead_tmp(1:meshead_len), trim(cbuf)
686 end subroutine dbgmessage
687 !> @en
688 !> @brief Output 1-dimensional data
689 !> @details
690 !> Outputs multi-dimensional data `d` (double precision real) as debug messages.
691 !> The character variable `header` is used as a prefix for output.
692 !> By providing `strlen`, you can specify the number of characters per line
693 !> (default is dc_types::STRING).
694 !> By providing `multi(:)`, you can add dimension subscripts after the header.
695 !>
696 !> See dc_trace Example for usage examples.
697 !>
698 !> @note This subroutine does not change the internal variable `level`.
699 !>
700 !> @param[in] header Data name (prefix for output)
701 !> @param[in] d 1-dimensional double precision real data
702 !> @param[in] strlen Number of characters per line (optional)
703 !> @param[in] multi Higher dimension subscripts (optional)
704 !> @enden
705 !>
706 !> @ja
707 !> @brief 1 次元データ出力
708 !> @details
709 !> デバッグメッセージとして、多次元データ `d` (倍精度実数型) を出力します。
710 !> 文字型変数 `header` は出力時の頭文字として利用されます。
711 !> `strlen` を与える事で、一行の文字数を指定できます
712 !> (デフォルトは dc_types::STRING)。
713 !> `multi(:)` を与えることで、header の後ろに次元添字をつける事が可能です。
714 !>
715 !> 利用例に関しては dc_trace の Example を参照して下さい。
716 !>
717 !> @note このサブルーチンを用いても内部変数 level の値は変化しません。
718 !>
719 !> @param[in] header データの名称 (出力時の接頭辞)
720 !> @param[in] d 倍精度実数1次元データ
721 !> @param[in] strlen 一行の文字数 (省略可)
722 !> @param[in] multi 上位の次元添字 (省略可)
723 !> @endja
724 subroutine datad1dump(header, d, strlen, multi)
725 use dc_types, only: string, dp
726 use dc_string, only: tochar
727 character(*), intent(in) :: header
728 real(DP), intent(in) :: d(:)
729 integer, intent(in), optional:: strlen
730 integer, intent(in), optional:: multi(:)
731 integer :: i, j
732 character(STRING):: unit ! データ文字列
733 character(STRING):: unitbuf ! データ文字列バッファ
734 integer :: ucur ! unit に書かれた文字数
735 character(STRING):: cbuf ! read/write 文のバッファ
736 integer :: stat ! ステータス
737 logical :: first ! 1つ目のデータかどうか
738 integer :: begini ! 1つ目のデータの添字
739 integer :: endi ! 最後のデータの添字
740 character(STRING):: cmulti ! 次元添字用文字列
741 character(STRING):: cout ! 出力する文字列
742 character(STRING):: meshead_tmp
743 integer :: meshead_len
744 continue
745 if ( dbg < 0 ) return
746 ! 初期化
747 unit = ''
748 unitbuf = ''
749 ucur = 0
750 stat = 0
751 first = .true.
752 cmulti = ''
753 ! デバッグメッセージヘッダの作成。
754 if (level < 1) then
755 meshead_tmp = ''
756 meshead_len = 0
757 else
758 meshead_tmp = meshead
759 meshead_len = len(meshead)
760 endif
761 ! 次元添字用文字列を作成
762 if (present(multi)) then
763 do j = 1, size(multi)
764 cmulti = trim(cmulti) // ', ' // trim( tochar( multi(j) ) )
765 enddo
766 endif
767 i = 1
768 dim_1_loop : do
769 if (first) begini = i
770 endi = i
771 write(cbuf, "(g40.20)") d(i)
772 if (.not. first) cbuf = ', ' // adjustl(cbuf(1:254))
773 unitbuf = unit
774 call append(unit, ucur, trim(adjustl(cbuf)), stat, strlen)
775 if ( stat /= 0 .or. i == size( d(:) ) ) then
776 ! 一回目は、文字数オーバーでもそのまま出力。
777 if (first) then
778 cout = header // '(' &
779 & // trim(tochar(begini)) &
780 & // trim(cmulti) &
781 & // ')=' // trim(unit)
782 ! 二回目以降は、オーバーしたものは次回へ
783 elseif (stat /= 0 .and. begini == endi-1) then
784 cout = header // '(' &
785 & // trim(tochar(begini)) &
786 & // trim(cmulti) &
787 & // ')='// trim(unitbuf)
788 ! 1つ巻戻す
789 i = i - 1
790 elseif (stat /= 0 .and. begini /= endi-1) then
791 cout = header // '(' &
792 & // trim(tochar(begini)) // '-' &
793 & // trim(tochar(endi-1)) &
794 & // trim(cmulti) &
795 & // ')=' // trim(unitbuf)
796 ! 1つ巻戻す
797 i = i - 1
798 ! i が size(d) まで到達した場合もそのまま出力。
799 elseif ( i == size( d(:) ) ) then
800 cout = header // '(' &
801 & // trim(tochar(begini)) // '-' &
802 & // trim(tochar(endi)) &
803 & // trim(cmulti) &
804 & // ')='// trim(unit)
805 endif
806 write(dbg, "(A, A, A, A)") &
807 & trim(head), repeat( indent, max(level-1, 0) ), &
808 & meshead_tmp(1:meshead_len), trim(cout)
809 ! unit, unitbuf をクリア
810 unit = ''
811 unitbuf = ''
812 ucur = 0
813 first = .true.
814 else
815 first = .false.
816 endif
817 if (i == size( d(:) ) ) exit dim_1_loop
818 i = i + 1
819 enddo dim_1_loop
820 end subroutine datad1dump
821 !> @en
822 !> @brief Output 2-dimensional data
823 !> @details
824 !> See DataDump or DataD1Dump for details.
825 !>
826 !> @param[in] header Data name (prefix for output)
827 !> @param[in] d 2-dimensional double precision real data
828 !> @param[in] strlen Number of characters per line (optional)
829 !> @param[in] multi Higher dimension subscripts (optional)
830 !> @enden
831 !>
832 !> @ja
833 !> @brief 2 次元データ出力
834 !> @details
835 !> 詳しくは DataDump または DataD1Dump を参照ください。
836 !>
837 !> @param[in] header データの名称
838 !> @param[in] d 倍精度実数2次元データ
839 !> @param[in] strlen 一行の文字数 (省略可)
840 !> @param[in] multi 上位の次元添字 (省略可)
841 !> @endja
842 subroutine datad2dump(header, d, strlen, multi)
843 use dc_types, only: dp
844 character(*), intent(in) :: header
845 real(DP), intent(in) :: d(:,:)
846 integer, intent(in), optional:: strlen
847 integer, intent(in), optional:: multi(:)
848 integer, allocatable :: total(:)
849 integer :: j
850 continue
851 if ( dbg < 0 ) return
852 if (present(multi)) then
853 allocate( total(size(multi)+1) )
854 total(2:size(multi)+1) = multi(:)
855 else
856 allocate( total(1) )
857 endif
858 do j = 1, size( d(:,:), 2 )
859 total(1) = j
860 call datadump(header, d(:,j), strlen=strlen, multi=total(:))
861 enddo
862 deallocate( total )
863 end subroutine datad2dump
864 !> @en
865 !> @brief Output 3-dimensional data
866 !> @details
867 !> See DataDump or DataD1Dump for details.
868 !>
869 !> @param[in] header Data name (prefix for output)
870 !> @param[in] d 3-dimensional double precision real data
871 !> @param[in] strlen Number of characters per line (optional)
872 !> @param[in] multi Higher dimension subscripts (optional)
873 !> @enden
874 !>
875 !> @ja
876 !> @brief 3 次元データ出力
877 !> @details
878 !> 詳しくは DataDump または DataD1Dump を参照ください。
879 !>
880 !> @param[in] header データの名称
881 !> @param[in] d 倍精度実数3次元データ
882 !> @param[in] strlen 一行の文字数 (省略可)
883 !> @param[in] multi 上位の次元添字 (省略可)
884 !> @endja
885 subroutine datad3dump(header, d, strlen, multi)
886 use dc_types, only: dp
887 character(*), intent(in) :: header
888 real(DP), intent(in) :: d(:,:,:)
889 integer, intent(in), optional:: strlen
890 integer, intent(in), optional:: multi(:)
891 integer, allocatable :: total(:)
892 integer :: k
893 continue
894 if ( dbg < 0 ) return
895 if (present(multi)) then
896 allocate( total(size(multi)+1) )
897 total(2:size(multi)+1) = multi(:)
898 else
899 allocate( total(1) )
900 endif
901 do k = 1, size( d(:,:,:), 3 )
902 total(1) = k
903 call datadump(header, d(:,:,k), strlen=strlen, multi=total(:))
904 enddo
905 deallocate( total )
906 end subroutine datad3dump
907 !> @en
908 !> @brief Internal function for DataD1Dump
909 !> @details
910 !> Appends `val` to `unit`. If `unit` exceeds its maximum string length,
911 !> returns stat = 2.
912 !>
913 !> @param[in,out] unit Final string to be returned
914 !> @param[in,out] ucur Number of characters in unit
915 !> @param[in] val String to be appended to unit
916 !> @param[out] stat Status (0: success, 1: truncated, 2: overflow)
917 !> @param[in] strlen Manual specification of character count (optional)
918 !> @enden
919 !>
920 !> @ja
921 !> @brief DataD1Dump の内部関数
922 !> @details
923 !> unit に val を付加。その際、unit がその最大文字列長を越えた場合
924 !> には stat = 2 を返す。
925 !>
926 !> @param[in,out] unit 最終的に返される文字列
927 !> @param[in,out] ucur unit の文字数
928 !> @param[in] val unit に付加される文字列
929 !> @param[out] stat ステータス (0: 成功, 1: 切り捨て, 2: オーバーフロー)
930 !> @param[in] strlen 文字数の手動指定 (省略可)
931 !> @endja
932 subroutine append(unit, ucur, val, stat, strlen)
933 character(*), intent(inout):: unit
934 integer, intent(inout):: ucur
935 character(*), intent(in) :: val
936 integer, intent(out) :: stat
937 integer, intent(in), &
938 & optional :: strlen
939 integer :: wrsz ! val の文字列
940 continue
941 ! unit の最大長を越えた場合には stat = 2 を返す。
942 if (present(strlen)) then
943 if (ucur >= strlen) then
944 stat = 2
945 return
946 endif
947 else
948 if (ucur >= len(unit)) then
949 stat = 2
950 return
951 endif
952 endif
953 ! 正常時の処理。
954 ! unit の長さを越えた場合も考慮して unit に val を付加する。
955 wrsz = min(len(val), len(unit) - ucur)
956 unit(1+ucur: wrsz+ucur) = val(1: wrsz)
957 ucur = ucur + wrsz
958 stat = 0
959 if (wrsz < len(val)) stat = 1
960 end subroutine append
961 !> @namespace dc_trace
962end module dc_trace
Handling character types.
Definition dc_string.f90:83
Debug tracing module.
Definition dc_trace.f90:150
integer function, public sublevel()
Definition dc_trace.f90:199
subroutine, public setdebug(debug)
Definition dc_trace.f90:336
subroutine, public dbgmessage(fmt, i, r, d, l, n, c1, c2, c3, ca)
Definition dc_trace.f90:661
subroutine, public beginsub(name, fmt, i, r, d, l, n, c1, c2, c3, ca, version)
Definition dc_trace.f90:457
subroutine, public dbg_scratch(on)
Definition dc_trace.f90:234
integer, save, public dbg
Definition dc_trace.f90:156
subroutine, public endsub(name, fmt, i, r, d, l, n, c1, c2, c3, ca)
Definition dc_trace.f90:580
Provides kind type parameter values.
Definition dc_types.f90:55
integer, parameter, public token
Character length for word, token
Definition dc_types.f90:128
integer, parameter, public string
Character length for string
Definition dc_types.f90:137
integer, parameter, public stdout
Unit number for Standard OUTPUT
Definition dc_types.f90:117
integer, parameter, public dp
Double Precision Real number
Definition dc_types.f90:92
integer, parameter, public stderr
Unit number for Standard ERROR
Definition dc_types.f90:122