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