source: trunk/LMDZ.TITAN/libf/muphytitan/errors.F90 @ 3094

Last change on this file since 3094 was 3090, checked in by slebonnois, 15 months ago

BdeBatz? : Cleans microphysics and makes few corrections for physics

File size: 9.8 KB
Line 
1! Copyright (c) (2013-2015,2017,2022) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr).
2!
3! This file is part of SWIFT
4!
5! Permission is hereby granted, free of charge, to any person obtaining a copy of
6! this software and associated documentation files (the "Software"), to deal in
7! the Software without restriction, including without limitation the rights to
8! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9! the Software, and to permit persons to whom the Software is furnished to do so,
10! subject to the following conditions:
11!
12! The above copyright notice and this permission notice shall be included in all
13! copies or substantial portions of the Software.
14!
15! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22!! file: errors.F90
23!! summary: Errors handling source file.
24!! author: J. Burgalat
25!! date: 2013-2015,2017,2022
26
27#include "defined.h"
28
29MODULE ERRORS
30  !! Error handler module
31  !!
32  !! This module provides a single derived type, [[error(type)]] which is used in all
33  !! other parts of the library in order to handle errors.
34  USE, INTRINSIC :: ISO_C_BINDING
35  USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY : stdout=>OUTPUT_UNIT, stderr=>ERROR_UNIT
36
37  IMPLICIT NONE
38
39  PUBLIC
40
41  PRIVATE :: error_equals,error_equals_int,error_differs,error_differs_int, &
42             msg_length
43
44
45  INTEGER, PARAMETER :: msg_length = 250 !! Length of error message.
46
47  TYPE, PUBLIC :: error
48    !! Define an error
49    !!
50    !! The following derived type represents in the simplest way (I believe) an error which
51    !! stores:
52    !!
53    !! - An integer to numerically identify the error
54    !! - A string (250 chars max) with an appropriate error message
55    !! - A bounded procedure to get a string representation of the error (if bounded
56    !!   procedures are supported by the library).
57    !! - internal subroutines for derived type IO WRITE statement (if Derived IO
58    !!   subroutines are supported by the library).
59    !!
60    !! error type comes also with two operators ("==", "/=") to compare error type with
61    !! another one or an integer.
62    !! If an error is not initialized explicitly, then it is set to [[errors(module):noerror(variable)]].
63    CHARACTER(len=msg_length) :: msg = "No error"
64      !! Message associated to the error
65      !! @note
66      !! The message should be short (250 characters maximum) and explicit.
67    INTEGER :: id = 0
68      !! Numerical identifier of the error
69      !! @note
70      !! The error identifier is used to test the equality/inequality of two error objects.
71#if HAVE_FTNPROC
72    CONTAINS
73      PROCEDURE, PUBLIC :: to_string => error_to_string
74        !! Get a string representation of the error
75#endif
76  END TYPE error
77
78  INTERFACE
79    !! Clean subroutine interface
80    SUBROUTINE clean_callback(err)
81      !! A subroutine that may perform cleaning computation(s) before exit
82      IMPORT error
83      IMPLICIT NONE
84      TYPE(error), INTENT(in) :: err
85        !! An error object with the input error
86    END SUBROUTINE clean_callback
87  END INTERFACE
88
89  INTERFACE
90    subroutine abort_() bind(C, name="abort")
91    end subroutine
92  END INTERFACE
93
94  INTERFACE assert
95    !! _Raise_ an assertion.
96    !!
97    !! An assertion can be understood as a development error that should be raised in production mode.
98    MODULE PROCEDURE :: assert_r,assert_w
99  END INTERFACE assert
100
101  !> error equality operator
102  INTERFACE OPERATOR(==)
103    MODULE PROCEDURE error_equals, error_equals_int
104  END INTERFACE
105
106  !> error inequality operator
107  INTERFACE OPERATOR(/=)
108    MODULE PROCEDURE error_differs, error_differs_int
109  END INTERFACE
110
111  !> The no error error !
112  TYPE(error), PUBLIC, PARAMETER :: noerror = error("No error",0)
113
114  CONTAINS
115
116!===============================================================================
117! error TYPE RELATED METHODS
118!===============================================================================
119
120  FUNCTION error_equals(this, other) RESULT(res)
121    !! Check if two error objects are equivalent
122    TYPE(error), INTENT(in) :: this, & !! The first error object to compare
123                               other   !! The second error object to compare
124    LOGICAL :: res                     !! .true. if __this__ and __other__ identifiers are the same, .false. otherwise
125    res = (this%id == other%id)
126    RETURN
127  END FUNCTION error_equals
128
129  FUNCTION error_equals_int(this, id) RESULT(res)
130    !! Check if an error id is equal to a given integer
131    TYPE(error), INTENT(in) :: this !! An error object reference
132    INTEGER, INTENT(in)     :: id   !! An integer to compare to __this__ identifier
133    LOGICAL :: res                  !! .true. if __this__ identifier and __id__ have the same value, .false. otherwise
134    res = (this%id == id)
135    RETURN
136  END FUNCTION error_equals_int
137
138  FUNCTION error_differs(this, other) RESULT(res)
139    !! Check if two error objects are different
140    TYPE(error), INTENT(in) :: this, & !! The first error object to compare
141                               other   !! The second error object to compare
142    LOGICAL :: res                     !! .false. if __this__ and __other__ identifiers are the same, .true. otherwise
143    res = (this%id /= other%id)
144    RETURN
145  END FUNCTION error_differs
146
147  FUNCTION error_differs_int(this, id) RESULT(res)
148    !! Check if an error id is different from a given integer
149    TYPE(error), INTENT(in) :: this !! An error object reference
150    INTEGER, INTENT(in)     :: id   !! An integer to compare to __this__ identifier
151    LOGICAL :: res                  !! .false. if __this__ identifier and __id__ have the same value, .true. otherwise
152    res = (this%id /= id)
153    RETURN
154  END FUNCTION error_differs_int
155
156  FUNCTION error_to_string(this,progname,as_warning) RESULT(str)
157    !! (simple) String representation of the error
158    !!
159    !! The function returns a very simple formatted string with the error.
160    OBJECT(error), INTENT(in)              :: this
161      !! An error object reference
162    CHARACTER(len=*), INTENT(in), OPTIONAL :: progname
163      !! An optional string with the name of the program
164    LOGICAL, INTENT(in), OPTIONAL          :: as_warning
165      !! An optional boolean flag to print the message as warning rather than as error (default to .false.).
166    CHARACTER(len=:), ALLOCATABLE :: str
167      !! An allocatable string with the string representation of the error
168    CHARACTER(len=:), ALLOCATABLE :: pref
169    pref = "error: "
170    IF (PRESENT(as_warning)) THEN ; IF (as_warning) pref = "warning: " ; ENDIF
171    IF (PRESENT(progname)) THEN
172      IF (LEN_TRIM(progname) /=0) THEN
173        str = TRIM(progname)//': '//pref//TRIM(this%msg)
174      ELSE
175        str = pref//TRIM(this%msg)
176      ENDIF
177    ELSE
178      str = pref//TRIM(this%msg)
179    ENDIF
180    RETURN
181  END FUNCTION error_to_string
182
183  SUBROUTINE aborting(err)
184    !! Abort the program with specific exit code
185    !!
186    !! The method prints the message of the given error object and
187    !! stops the program using exit() subroutine.
188    TYPE(error), INTENT(in) :: err
189      !! An error object
190    IF (err /= 0) THEN
191      WRITE(*,'(a)') error_to_string(err)
192      CALL EXIT(err%id)
193    ENDIF
194  END SUBROUTINE aborting
195
196  SUBROUTINE assert_r(test,reason)
197    !! _Raise_ an assertion.
198    !!
199    !! The method raises an assertion and stops the execution if __test__ is .false.
200    !!
201    !! @note
202    !! If ISO_C_BINDING module is available, the method calls the method abort from the C standard library. Doing so,
203    !! developer is able to debug the source code by getting the backtrace of the execution.
204    !! In other situation, the method simply uses the Fortran STOP statement which makes its usage... useless.
205   LOGICAL, INTENT(in)          :: test
206     !! Expression to test.
207   CHARACTER(len=*), INTENT(in) :: reason
208     !! Optional assertion reason.
209   IF (.NOT.test) THEN
210     WRITE(stderr,'(a)') "assertion: "//reason
211     call abort_()
212   ENDIF
213  END SUBROUTINE assert_r
214
215  SUBROUTINE assert_w(test,where,reason)
216    !! _Raise_ an assertion.
217    !!
218    !! The method raises an assertion and stops the execution if __test__ is .false.
219    !!
220    !! See [[errors(module):assert_r(subroutine)]] remark.
221    LOGICAL, INTENT(in)         :: test
222     !! Expression to test.
223   CHARACTER(len=*), INTENT(in) :: where
224     !! Optional _location_ of the assertion.
225   CHARACTER(len=*), INTENT(in) :: reason
226     !! Optional assertion reason.
227   IF (.NOT.test) THEN
228     WRITE(stderr,'(a)') "assertion in "//where//": "//reason
229     call abort_()
230   ENDIF
231  END SUBROUTINE assert_w
232
233  FUNCTION free_lun() RESULT(lu)
234    !> Get the first free logical unit
235    !!
236    !! The function loops from 7 to 9999 and returns the first free logical unit.
237    !! @note
238    !! According to Fortran standard, the maximum value for a lun is processor
239    !! dependent. I just assume that [7,9999] is a valid range and I believe that
240    !! 9992 files to be opened is far enough for any program !
241    !! @note
242    !! If you intend to use loggers object from this library, you should keep in
243    !! mind that loggers open files with the first free logical unit. Consequently
244    !! if you need to perform I/O operations you should use this function to get a
245    !! free lun instead of just randomly set a lun !
246    INTEGER :: lu
247      !! First free logical unit in the range [7,9999]  or -1 if no lun is available
248    INTEGER, PARAMETER :: mxlu = 9999
249    LOGICAL :: notfree
250    lu = 6 ; notfree = .true.
251    DO WHILE(notfree.AND.lu<=mxlu)
252      lu=lu+1 ; INQUIRE(unit=lu,OPENED=notfree)
253    ENDDO
254    IF (lu >= mxlu) lu = -1
255  END FUNCTION free_lun
256
257
258
259END MODULE ERRORS
260
Note: See TracBrowser for help on using the repository browser.