|
| 1 | +#:if DEBUG > 0 |
| 2 | +print *, "Some debug information" |
| 3 | +#:endif |
| 4 | + |
| 5 | +#:set LOGLEVEL = 2 |
| 6 | +print *, "LOGLEVEL: ${LOGLEVEL}$" |
| 7 | + |
| 8 | +#:del LOGLEVEL |
| 9 | + |
| 10 | +#:def assertTrue(cond) |
| 11 | +#:if DEBUG > 0 |
| 12 | +if (.not. ${cond}$) then |
| 13 | + print *, "Assert failed in file ${_FILE_}$, line ${_LINE_}$" |
| 14 | + error stop |
| 15 | +end if |
| 16 | +#:endif |
| 17 | +#:enddef assertTrue |
| 18 | + |
| 19 | +! Invoked via direct call (argument needs no quotation) |
| 20 | +@:assertTrue(size(myArray) > 0) |
| 21 | + |
| 22 | +! Invoked as Python expression (argument needs quotation) |
| 23 | +$:assertTrue('size(myArray) > 0') |
| 24 | + |
| 25 | +program test |
| 26 | +#:if defined('WITH_MPI') |
| 27 | + use mpi |
| 28 | +#:elif defined('WITH_OPENMP') |
| 29 | + use openmp |
| 30 | +#:else |
| 31 | + use serial |
| 32 | +#:endif |
| 33 | +end program |
| 34 | + |
| 35 | +interface myfunc |
| 36 | +#:for dtype in ['real', 'dreal', 'complex', 'dcomplex'] |
| 37 | + module procedure myfunc_${dtype}$ |
| 38 | +#:endfor |
| 39 | +end interface myfunc |
| 40 | + |
| 41 | +logical, parameter :: hasMpi = #{if defined('MPI')}# .true. #{else}# .false. #{endif}# |
| 42 | + |
| 43 | +character(*), parameter :: comp_date = "${time.strftime('%Y-%m-%d')}$" |
| 44 | + |
| 45 | +#:include "macrodefs.fypp" |
| 46 | + |
| 47 | +#:if var1 > var2 & |
| 48 | + & or var2> var4 |
| 49 | +print *, "Doing something here" |
| 50 | +#:endif |
| 51 | + |
| 52 | +#! Callable needs only string argument |
| 53 | +#:def debug_code(code) |
| 54 | + #:if DEBUG > 0 |
| 55 | + $:code |
| 56 | + #:endif |
| 57 | +#:enddef debug_code |
| 58 | + |
| 59 | +#! Pass code block as first positional argument |
| 60 | +#:call debug_code |
| 61 | +if (size(array) > 100) then |
| 62 | + print *, "DEBUG: spuriously large array" |
| 63 | +end if |
| 64 | +#:endcall debug_code |
| 65 | + |
| 66 | +#! Callable needs also non-string argument types |
| 67 | +#:def repeat_code(code, repeat) |
| 68 | + #:for ind in range(repeat) |
| 69 | + $:code |
| 70 | + #:endfor |
| 71 | +#:enddef repeat_code |
| 72 | + |
| 73 | +#! Pass code block as positional argument and 3 as keyword argument "repeat" |
| 74 | +#:call repeat_code(repeat=3) |
| 75 | +this will be repeated 3 times |
| 76 | +#:endcall repeat_code |
| 77 | + |
| 78 | +#! This will not show up in the output |
| 79 | +#! Also the newline characters at the end of the lines will be suppressed |
| 80 | + |
| 81 | +#! Definitions are read, but no output (e.g. newlines) will be produced |
| 82 | +#:mute |
| 83 | +#:include "macrodefs.fypp" |
| 84 | +#:endmute |
| 85 | + |
| 86 | +#:if DEBUGLEVEL < 0 |
| 87 | + #:stop 'Negative debug level not allowed!' |
| 88 | +#:endif |
| 89 | + |
| 90 | +#:def mymacro(RANK) |
| 91 | + #! Macro only works for RANK 1 and above |
| 92 | + #:assert RANK > 0 |
| 93 | +#:enddef mymacro |
| 94 | + |
| 95 | +program test |
| 96 | +#:if defined('MPI') |
| 97 | + use mpi |
| 98 | +#:endif |
| 99 | +end program |
| 100 | + |
| 101 | +#{if 1 > 2}#Some code#{endif}# |
| 102 | + |
| 103 | +@:mymacro(a<b) |
| 104 | + |
| 105 | +print *, @{mymacro(a <b)}@ |
| 106 | + |
| 107 | +#:if defined('DEBUG') #! The Python function defined() expects a string argument |
| 108 | +#:for dtype in ['real(dp)', 'integer', 'logical'] #! dtype runs over strings |
| 109 | + |
| 110 | +print *, "This is line nr. ${_LINE_}$ in file '${_FILE_}$'" |
| 111 | + |
| 112 | +print *, "Rendering started ${_DATE_}$ ${_TIME_}$" |
| 113 | + |
| 114 | +$:setvar('i', 1, 'j', 2) |
| 115 | +print *, "VAR I: ${i}$, VAR J: ${j}$" |
| 116 | + |
| 117 | +$:delvar('i', 'j') |
| 118 | + |
| 119 | +#{set X = 2}#print *, ${X}$ |
| 120 | + |
| 121 | +#:set real_kinds = ['sp', 'dp'] |
| 122 | + |
| 123 | +interface sin2 |
| 124 | +#:for rkind in real_kinds |
| 125 | + module procedure sin2_${rkind}$ |
| 126 | +#:endfor |
| 127 | +end interface sin2 |
| 128 | + |
| 129 | +#:for rkind in real_kinds |
| 130 | +function sin2_${rkind}$ (xx) result(res) |
| 131 | + real(${rkind}$), intent(in) :: xx |
| 132 | + real(${rkind}$) :: res |
| 133 | + |
| 134 | + res = sin(xx)*sin(xx) |
| 135 | + |
| 136 | +end function sin2_${rkind}$ |
| 137 | +#:endfor |
| 138 | + |
| 139 | +#:set kinds = ['sp', 'dp'] |
| 140 | +#:set names = ['real', 'dreal'] |
| 141 | +#! create kinds_names as [('sp', 'real'), ('dp', 'dreal')] |
| 142 | +#:set kinds_names = list(zip(kinds, names)) |
| 143 | + |
| 144 | +#! Acces by indexing |
| 145 | +interface sin2 |
| 146 | +#:for kind_name in kinds_names |
| 147 | + module procedure sin2_${kind_name[1]}$ |
| 148 | +#:endfor |
| 149 | +end interface sin2 |
| 150 | + |
| 151 | +#! Unpacking in the loop header |
| 152 | +#:for kind, name in kinds_names |
| 153 | +function sin2_${name}$ (xx) result(res) |
| 154 | + real(${kind}$), intent(in) :: xx |
| 155 | + real(${kind}$) :: res |
| 156 | + |
| 157 | + res = sin(xx)*sin(xx) |
| 158 | + |
| 159 | +end function sin2_${name}$ |
| 160 | +#:endfor |
| 161 | + |
| 162 | +#:def assertTrue(cond) |
| 163 | +#:if DEBUG > 0 |
| 164 | +if (.not. (${cond}$)) then |
| 165 | + print *, "Assert failed!" |
| 166 | + error stop |
| 167 | +end if |
| 168 | +#:endif |
| 169 | +#:enddef |
| 170 | + |
| 171 | +#:def macro(X, *VARARGS) |
| 172 | +X = ${X}$, VARARGS = #{for ARG in VARARGS}#${ARG}$#{endfor}# |
| 173 | +#:enddef macro |
| 174 | + |
| 175 | +$:macro(1,2, 3) #! Returns "X=1, VARARGS=23" |
| 176 | + |
| 177 | +! Rather ugly |
| 178 | +print *, #{call choose_code}# a(:) #{nextarg}# size(a) #{endcall}# |
| 179 | + |
| 180 | +! This form is more readable |
| 181 | +print *, ${choose_code('a(:)', 'size(a)')}$ |
| 182 | + |
| 183 | +! Alternatively, you may use a direct call (see next section) |
| 184 | +print *, @{choose_code(a(:), size(a))}@ |
| 185 | + |
| 186 | +@:assertEqual(size(coords, dim=2), & |
| 187 | + & size( atomtypes)) |
| 188 | + |
| 189 | +#! Using choose_code() macro defined in previous section |
| 190 | +print *, @{choose_code(a(:),size(a))}@ |
| 191 | + |
| 192 | +#:if a > b & |
| 193 | + & or b > c & |
| 194 | + & or c>d |
| 195 | +$:somePythonFunction( param1, & |
| 196 | + ¶m2) |
| 197 | + |
| 198 | +#:mute |
| 199 | + |
| 200 | +#! Enable debug feature if the preprocessor variable DEBUG has been defined |
| 201 | +#:set DEBUG = defined('DEBUG') |
| 202 | + |
| 203 | +#! Stops the code, if the condition passed to it is not fulfilled |
| 204 | +#! Only included in debug mode. |
| 205 | +#:def ensure(cond, msg=None) |
| 206 | + #:if DEBUG |
| 207 | +if (.not. (${cond}$)) then |
| 208 | + write (*, *) 'Run-time check failed' |
| 209 | + write (*, *) 'Condition: ${cond.replace("'", "''")}$' |
| 210 | + #:if msg is not None |
| 211 | + write (*, *) 'Message: ', ${msg}$ |
| 212 | + #:endif |
| 213 | + write (*, *) 'File: ${_FILE_}$' |
| 214 | + write (*, *) 'Line: ', ${_LINE_}$ |
| 215 | + stop |
| 216 | +end if |
| 217 | + #:endif |
| 218 | +#:enddef ensure |
| 219 | +
|
| 220 | +#! Includes code if in debug mode. |
| 221 | +#:def debug_code(code) |
| 222 | + #:if DEBUG |
| 223 | +$:code |
| 224 | + #:endif |
| 225 | +#:enddef debug_code |
| 226 | +
|
| 227 | +#:endmute |
| 228 | +
|
| 229 | +#:include 'checks.fypp' |
| 230 | +
|
| 231 | +module testmod |
| 232 | + implicit none |
| 233 | +
|
| 234 | +contains |
| 235 | +
|
| 236 | + subroutine someFunction(ind, uplo) |
| 237 | + integer, intent(in) :: ind |
| 238 | + character, intent(in) :: uplo |
| 239 | +
|
| 240 | + @:ensure(ind > 0, msg="Index must be positive") |
| 241 | + @:ensure(uplo == 'U' .or. uplo == 'L') |
| 242 | +
|
| 243 | + ! Do something useful here |
| 244 | +
|
| 245 | + #:call debug_code |
| 246 | + print *, 'We are in debug mode' |
| 247 | + print *, 'The value of ind is', ind |
| 248 | + #:endcall debug_code |
| 249 | +
|
| 250 | + end subroutine someFunction |
| 251 | +
|
| 252 | +end module testmod |
| 253 | +
|
| 254 | +#:def ranksuffix(RANK) |
| 255 | +$:'' if RANK == 0 else '(' + ':' + ',:' * (RANK - 1) + ')' |
| 256 | +#:enddef ranksuffix |
| 257 | +
|
| 258 | +#:set PRECISIONS = ['sp', 'dp'] |
| 259 | +#:set RANKS = range(0, 8) |
| 260 | +
|
| 261 | +module errorcalc |
| 262 | + implicit none |
| 263 | +
|
| 264 | + integer, parameter :: sp = kind(1.0) |
| 265 | + integer, parameter :: dp = kind(1.0d0) |
| 266 | +
|
| 267 | + interface maxRelError |
| 268 | + #:for PREC in PRECISIONS |
| 269 | + #:for RANK in RANKS |
| 270 | + module procedure maxRelError_${RANK}$_${PREC}$ |
| 271 | + #:endfor |
| 272 | + #:endfor |
| 273 | + end interface maxRelError |
| 274 | +
|
| 275 | +contains |
| 276 | +
|
| 277 | +#:for PREC in PRECISIONS |
| 278 | + #:for RANK in RANKS |
| 279 | +
|
| 280 | + function maxRelError_${RANK}$_${PREC}$ (obtained, reference) result(res) |
| 281 | + real(${PREC}$), intent(in) :: obtained${ranksuffix(RANK)}$ |
| 282 | + real(${PREC}$), intent(in) :: reference${ranksuffix(RANK)}$ |
| 283 | + real(${PREC}$) :: res |
| 284 | +
|
| 285 | + #:if RANK == 0 |
| 286 | + res = abs((obtained - reference)/reference) |
| 287 | + #:else |
| 288 | + res = maxval(abs((obtained - reference)/reference)) |
| 289 | + #:endif |
| 290 | +
|
| 291 | + end function maxRelError_${RANK}$_${PREC}$ |
| 292 | +
|
| 293 | + #:endfor |
| 294 | +#:endfor |
| 295 | +
|
| 296 | +end module errorcalc |
| 297 | +
|
| 298 | +#:def maxRelError_template(RANK, PREC) |
| 299 | +function maxRelError_${RANK}$_${PREC}$ (obtained, reference) result(res) |
| 300 | + real(${PREC}$), intent(in) :: obtained${ranksuffix(RANK)}$ |
| 301 | + real(${PREC}$), intent(in) :: reference${ranksuffix(RANK)}$ |
| 302 | + real(${PREC}$) :: res |
| 303 | +
|
| 304 | + #:if RANK == 0 |
| 305 | + res = abs((obtained - reference)/reference) |
| 306 | + #:else |
| 307 | + res = maxval(abs((obtained - reference)/reference)) |
| 308 | + #:endif |
| 309 | +
|
| 310 | +end function maxRelError_${RANK}$_${PREC}$ |
| 311 | +#:enddef maxRelError_template |
| 312 | +
|
| 313 | +#:for PREC in PRECISIONS |
| 314 | + #:for RANK in RANKS |
| 315 | + $:maxRelError_template(RANK, PREC) |
| 316 | + #:endfor |
| 317 | +#:endfor |
| 318 | +
|
| 319 | +end module errorcalc |
| 320 | +
|
0 commit comments