forked from ESCOMP/CLUBB_CESM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclip_semi_implicit.F90
659 lines (551 loc) · 24.9 KB
/
clip_semi_implicit.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
!-----------------------------------------------------------------------
! $Id$
!===============================================================================
module clip_semi_implicit
! Description of the semi-implicit clipping code:
! The semi-implicit clipping code is based on an upper threshold and/or a
! lower threshold value for variable f.
!
! The semi-implicit clipping code is used when the value of variable f should
! not exceed the designated threshold(s) when it is advanced to timestep
! index (t+1).
!
!
! Clipping at an Upper Threshold:
!
! When there is an upper threshold to be applied, the equation for the clipped
! value of the variable f, f_clipped, is:
!
! f_clipped(t+1) = MIN( f_unclipped(t+1), upper_threshold )
! = ( f_unclipped(t+1) - upper_threshold )
! * H(upper_threshold-f_unclipped(t+1))
! + upper_threshold;
!
! where f_unclipped is the value of the variable f without clipping, and
! H(upper_threshold-f_unclipped(t+1)) is the Heaviside Step function. The
! clipping term is turned into a time tendency term, such that:
!
! (df/dt)_clipping = (1/dt_clip)
! * ( f_clipped(t+1) - f_unclipped(t+1) );
!
! where dt_clip is the time scale for the clipping term. The difference
! between the threshold value and f_unclipped is defined as f_diff:
!
! f_diff = upper_threshold - f_unclipped.
!
! The clipping time tendency is now simplified as:
!
! (df/dt)_clipping = + (1/dt_clip)
! * { f_diff(t+1) * [ 1 - H(f_diff(t+1)) ] }.
!
! Function R(f_diff) is defined as:
!
! R(f_diff) = { f_diff * [ 1 - H(f_diff) ] }.
!
! The clipping time tendency is now written as:
!
! (df/dt)_clipping = + (1/dt_clip) * R(f_diff(t+1)).
!
! In order to solve for f_unclipped (and f_diff) at timestep index (t+1), the
! clipping term must be linearized. A Taylor Series expansion (truncated
! after the first derivative term) of R(f_diff) around f_diff = f_diff(t) is
! used to linearize the term. However, the Heaviside Step function,
! H(f_diff), is not differentiable when f_diff(t) = 0, as the function jumps
! at that point. Likewise, the function R(f_diff) is not differentiable when
! f_diff(t) = 0, as the function has a corner at that point. Therefore, a new
! function, F_R(f_diff) is used as an approximation of R(f_diff). Function
! F_R(f_diff) is a three-piece function that has the exact same value as
! R(f_diff) when f_diff <= -sigma or f_diff >= sigma (sigma is an arbitrarily
! declared value). However, when -sigma < f_diff < sigma, a parabolic
! function is used to approximate the corner found in R(f_diff). The
! parabolic function needs to have the same values at f_diff = -sigma and
! f_diff = sigma as does R(f_diff). Furthermore, the derivative of the
! parabolic function (with respect to f_diff) needs to have the same values at
! f_diff = -sigma and f_diff = sigma as does d(R)/d(f_diff). The parabolic
! function that satisfies these properities is:
! f_diff - (sigma/4) * [ 1 + (f_diff/sigma) ]^2.
! Therefore:
!
! | f_diff; where f_diff <= -sigma
! |
! F_R(f_diff) = | f_diff - (sigma/4) * [ 1 + (f_diff/sigma) ]^2;
! | where -sigma < f_diff < sigma
! |
! | 0; where f_diff >= sigma; and
!
! | 1; where f_diff <= -sigma
! |
! ( d F_R / d f_diff ) = | 1 - (1/2) * [ 1 + (f_diff/sigma) ];
! | where -sigma < f_diff < sigma
! |
! | 0; where f_diff >= sigma.
!
! Since, R(f_diff(t+1)) approx.= F_R(f_diff(t+1)), the Taylor Series expansion
! is done for F_R(f_diff) around f_diff = f_diff(t) in order to linearize the
! term:
!
! F_R(f_diff(t+1)) approx.=
! A_fnc + B_fnc * ( f_diff(t+1) - f_diff(t) );
!
! where A_fnc is defined as F_R(f_diff(t)) and B_fnc is defined as
! ( d F_R / d f_diff )|_(f_diff=f_diff(t)).
!
! The approximation is substituted into the (df/dt)_clipping equation. The
! rate of change of variable f due to clipping with the upper threshold is:
!
! (df/dt)_clipping
! = + (1/dt_clip)
! * { A_fnc - B_fnc * f_diff(t)
! + B_fnc * upper_threshold - B_fnc * f_unclipped(t+1) }.
!
! The implicit (LHS) portion of the equation for clipping with the upper
! threshold is:
!
! - (1/dt_clip) * B_fnc * f_unclipped(t+1).
!
! Note: When the term is brought over to the left-hand side, the sign
! is reversed and the leading "-" in front of the term is changed
! to a "+".
!
! The explicit (RHS) portion of the equation for clipping with the upper
! threshold is:
!
! + (1/dt_clip)
! * { A_fnc - B_fnc * f_diff(t) + B_fnc * upper_threshold }.
!
! Timestep index (t) stands for the index of the current timestep, while
! timestep index (t+1) stands for the index of the next timestep, which is
! being advanced to in solving the d(f)/dt equation.
!
!
! Clipping at a Lower Threshold:
!
! When there is a lower threshold to be applied, the equation for the clipped
! value of the variable f, f_clipped, is:
!
! f_clipped(t+1) = MAX( f_unclipped(t+1), lower_threshold )
! = ( f_unclipped(t+1) - lower_threshold )
! * H(f_unclipped(t+1)-lower_threshold)
! + lower_threshold;
!
! where f_unclipped is the value of the variable f without clipping, and
! H(f_unclipped(t+1)-lower_threshold) is the Heaviside Step function. The
! clipping term is turned into a time tendency term, such that:
!
! (df/dt)_clipping = (1/dt_clip)
! * ( f_clipped(t+1) - f_unclipped(t+1) );
!
! where dt_clip is the time scale for the clipping term. The difference
! between f_unclipped and the threshold value is defined as f_diff:
!
! f_diff = f_unclipped - lower_threshold.
!
! The clipping time tendency is now simplified as:
!
! (df/dt)_clipping = - (1/dt_clip)
! * { f_diff(t+1) * [ 1 - H(f_diff(t+1)) ] }.
!
! Function R(f_diff) is defined as:
!
! R(f_diff) = { f_diff * [ 1 - H(f_diff) ] }.
!
! The clipping time tendency is now written as:
!
! (df/dt)_clipping = - (1/dt_clip) * R(f_diff(t+1)).
!
! The linearization process is the same for the lower threshold as it is for
! the upper threshold. The formulas for A_fnc and B_fnc are the same, but the
! values (based on a different f_diff) are different. The rate of change of
! variable f due to clipping with the lower threshold is:
!
! (df/dt)_clipping
! = - (1/dt_clip)
! * { A_fnc - B_fnc * f_diff(t)
! - B_fnc * lower_threshold + B_fnc * f_unclipped(t+1) }.
!
! The implicit (LHS) portion of the equation for clipping with the lower
! threshold is:
!
! - (1/dt_clip) * B_fnc * f_unclipped(t+1).
!
! Note: When the term is brought over to the left-hand side, the sign
! is reversed and the leading "-" in front of the term is changed
! to a "+".
!
! The explicit (RHS) portion of the equation for clipping with the lower
! threshold is:
!
! - (1/dt_clip)
! * { A_fnc - B_fnc * f_diff(t) - B_fnc * lower_threshold }.
!
! All variables in these equations are on the same vertical levels as the
! variable f.
!
!
! Adjustable parameters:
!
! sigma: sigma is the amount on either side of the threshold value to which
! the parabolic function portion of F_R(f_diff) is applied. The value
! of sigma must be greater than 0. A proportionally larger value of
! sigma can be used to effect values of f that are near the threshold,
! but not to it or over it. The close-to-threshold values will be
! nudged away from the threshold.
!
! dt_clip: dt_clip is the clipping time scale. It can be set equal to the
! model timestep, dt, but it doesn't have to be. Smaller values of
! dt_clip produce a greater effect on the clipping term.
! References:
!-----------------------------------------------------------------------
use clubb_precision, only: &
core_rknd ! Variable(s)
implicit none
private
public :: clip_semi_imp_lhs, &
clip_semi_imp_rhs
private :: compute_clip_lhs, &
compute_fncts_A_B
! Constant parameters.
! sigma coefficient: A coefficient with dimensionless units that must have a
! value greater than 0. The value should be kept below 1.
! The larger the value of sigma_coef, the larger the value
! of sigma, and the larger the range of close-to-threshold
! values that will be effected (nudged away from the
! threshold) by the semi-implicit clipping.
real( kind = core_rknd ), parameter :: sigma_coef = 0.15_core_rknd
! dt_clip coefficient: A coefficient with dimensionless units that must have
! a value greater than 0. A value of 1 will set the
! clipping time scale, dt_clip, equal to the model
! timestep, dt. The smaller the value of dt_clip_coef,
! the smaller the value of dt_clip, and the larger the
! magnitude of (df/dt)_clipping.
real(kind=core_rknd), parameter :: dt_clip_coef = 1.0_core_rknd
contains
!=============================================================================
function clip_semi_imp_lhs( dt, f_unclipped, &
l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold ) &
result( lhs )
! Description:
! The implicit portion of the semi-implicit clipping code.
!
! The implicit (LHS) portion of the equation for clipping with the upper
! threshold is:
!
! - (1/dt_clip) * B_fnc * f_unclipped(t+1).
!
! The implicit (LHS) portion of the equation for clipping with the lower
! threshold is:
!
! - (1/dt_clip) * B_fnc * f_unclipped(t+1).
!
! Note: When either term is brought over to the left-hand side, the sign
! is reversed and the leading "-" in front of either term is changed
! to a "+".
!
! The timestep index (t+1) means that the value of f being used is from the
! next timestep, which is being advanced to in solving the d(f)/dt equation.
!
! While the formulas are the same for both the upper threshold and the lower
! threshold, the values of A_fnc, B_fnc, and f_diff will differ between the
! two thresholds.
!
! The overall implicit (LHS) portion for the clipping term is the sum of the
! implicit portion from the upper threshold and the implicit portion from
! the lower threshold.
! References:
!-----------------------------------------------------------------------
use clubb_precision, only: &
core_rknd ! Variable(s)implicit none
implicit none
! Input Variables
real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep. [s]
real( kind = core_rknd ), intent(in) :: &
f_unclipped, & ! The unclipped value of variable f at timestep (t). [f units]
upper_threshold, & ! Greatest allowable value of variable f. [f units]
lower_threshold ! Smallest allowable value of variable f. [f units]
logical, intent(in) :: &
l_upper_thresh, & ! Flag for having an upper threshold value.
l_lower_thresh ! Flag for having a lower threshold value.
! Return Variable
real( kind = core_rknd ) :: lhs
! Local Variables
real( kind = core_rknd ) :: &
dt_clip ! Time scale for semi-implicit clipping term. [s]
real( kind = core_rknd ) :: &
f_diff, & ! Difference between the threshold value and f_unclipped. [f units]
A_fnc, & ! Function that approximates { f_diff * [ 1 - H(f_diff) ] }. [f units]
B_fnc, & ! Derivative w/ respect to f_diff of function A_fnc. []
lhs_upper, & ! Contribution of upper threshold to implicit portion (LHS). [s^-1]
lhs_lower ! Contribution of lower threshold to implicit portion (LHS). [s^-1]
! Compute the clipping time scale, dt_clip.
dt_clip = dt_clip_coef * dt
! Upper Threshold
if ( l_upper_thresh ) then
! f_diff is the difference between the threshold value and f_unclipped.
! In regards to the upper threshold, it is defined as
! upper_threshold - f_unclipped.
f_diff = upper_threshold - f_unclipped
! Compute the values of functions A_fnc and B_fnc evaluated at f_diff(t)
! for the upper threshold.
call compute_fncts_A_B( l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold, &
f_diff, A_fnc, B_fnc )
! Compute the implicit (LHS) contribution from clipping for the upper
! threshold.
lhs_upper = compute_clip_lhs( dt_clip, B_fnc )
else
lhs_upper = 0.0_core_rknd
endif
! Lower Threshold
if ( l_lower_thresh ) then
! f_diff is the difference between the threshold value and f_unclipped.
! In regards to the lower threshold, it is defined as
! f_unclipped - lower_threshold.
f_diff = f_unclipped - lower_threshold
! Compute the values of functions A_fnc and B_fnc evaluated at f_diff(t)
! for the lower threshold.
call compute_fncts_A_B( l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold, &
f_diff, A_fnc, B_fnc )
! Compute the implicit (LHS) contribution from clipping for the lower
! threshold.
lhs_lower = compute_clip_lhs( dt_clip, B_fnc )
else
lhs_lower = 0.0_core_rknd
endif
! Total implicit (LHS) contribution to clipping.
! Main diagonal: [ x f_unclipped(k,<t+1>) ]
lhs = lhs_upper + lhs_lower
end function clip_semi_imp_lhs
!=============================================================================
pure function compute_clip_lhs( dt_clip, B_fnc ) &
result( lhs_contribution )
! Description:
! Calculation of the implicit portion of the semi-implicit clipping term.
!
! The implicit portion of the semi-implicit clipping term is:
!
! - (1/dt_clip) * B_fnc * f_unclipped(t+1).
!
! Note: When the term is brought over to the left-hand side, the sign
! is reversed and the leading "-" in front of the term is changed
! to a "+".
!
! The timestep index (t+1) means that the value of f being used is from the
! next timestep, which is being advanced to in solving the d(f)/dt equation.
! References:
!-----------------------------------------------------------------------
use clubb_precision, only: &
core_rknd ! Variable(s)
implicit none
! Input Variables
real( kind = core_rknd), intent(in) :: &
dt_clip ! Time scale for semi-implicit clipping term. [s]
real( kind = core_rknd ), intent(in) :: &
B_fnc ! Derivative w/ respect to f_diff of function A_fnc. []
! Return Variable
real( kind = core_rknd ) :: lhs_contribution
! Main diagonal: [ x f_unclipped(k,<t+1>) ]
lhs_contribution &
= + (1.0_core_rknd/dt_clip * B_fnc )
end function compute_clip_lhs
!=============================================================================
function clip_semi_imp_rhs( dt, f_unclipped, &
l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold ) &
result( rhs )
! Description:
! The explicit portion of the semi-implicit clipping code.
!
! The explicit (RHS) portion of the equation for clipping with the upper
! threshold is:
!
! + (1/dt_clip)
! * { A_fnc - B_fnc * f_diff(t) + B_fnc * upper_threshold }.
!
! The explicit (RHS) portion of the equation for clipping with the lower
! threshold is:
!
! - (1/dt_clip)
! * { A_fnc - B_fnc * f_diff(t) - B_fnc * lower_threshold }.
!
! Timestep index (t) stands for the index of the current timestep.
!
! The values of A_fnc, B_fnc, and f_diff will differ between the two
! thresholds.
!
! The overall explicit (RHS) portion for the clipping term is the sum of the
! explicit portion from the upper threshold and the explicit portion from
! the lower threshold.
! References:
!-----------------------------------------------------------------------
use clubb_precision, only: &
core_rknd ! Variable(s)
implicit none
! Input Variables
real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep. [s]
real( kind = core_rknd ), intent(in) :: &
f_unclipped, & ! The unclipped value of variable f at timestep (t). [f units]
upper_threshold, & ! Greatest allowable value of variable f. [f units]
lower_threshold ! Smallest allowable value of variable f. [f units]
logical, intent(in) :: &
l_upper_thresh, & ! Flag for having an upper threshold value.
l_lower_thresh ! Flag for having a lower threshold value.
! Return Variable
real( kind = core_rknd ) :: rhs
! Local Variables
real( kind = core_rknd) :: &
dt_clip ! Time scale for semi-implicit clipping term. [s]
real( kind = core_rknd ) :: &
f_diff, & ! Difference between the threshold value and f_unclipped. [f units]
A_fnc, & ! Function that approximates { f_diff * [ 1 - H(f_diff) ] }. [f units]
B_fnc, & ! Derivative w/ respect to f_diff of function A_fnc. []
rhs_upper, & ! Contribution of upper threshold to explicit portion (RHS). [s^-1]
rhs_lower ! Contribution of lower threshold to explicit portion (RHS). [s^-1]
! Compute the clipping time scale, dt_clip.
dt_clip = dt_clip_coef * dt
! Upper Threshold
if ( l_upper_thresh ) then
! f_diff is the difference between the threshold value and f_unclipped.
! In regards to the upper threshold, it is defined as
! upper_threshold - f_unclipped.
f_diff = upper_threshold - f_unclipped
! Compute the values of functions A_fnc and B_fnc evaluated at f_diff(t)
! for the upper threshold.
call compute_fncts_A_B( l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold, &
f_diff, A_fnc, B_fnc )
! Compute the explicit (RHS) contribution from clipping for the upper
! threshold.
rhs_upper &
= + (1.0_core_rknd/dt_clip &
* ( A_fnc - B_fnc * f_diff + B_fnc * upper_threshold ) )
else
rhs_upper = 0.0_core_rknd
endif
! Lower Threshold
if ( l_lower_thresh ) then
! f_diff is the difference between the threshold value and f_unclipped.
! In regards to the lower threshold, it is defined as
! f_unclipped - lower_threshold.
f_diff = f_unclipped - lower_threshold
! Compute the values of functions A_fnc and B_fnc evaluated at f_diff(t)
! for the lower threshold.
call compute_fncts_A_B( l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold, &
f_diff, A_fnc, B_fnc )
! Compute the explicit (RHS) contribution from clipping for the lower
! threshold.
rhs_lower &
= - (1.0_core_rknd/ dt_clip) &
* ( A_fnc - B_fnc * f_diff - B_fnc * lower_threshold )
else
rhs_lower = 0.0_core_rknd
endif
! Total explicit (RHS) contribution to clipping.
rhs = rhs_upper + rhs_lower
end function clip_semi_imp_rhs
!=============================================================================
subroutine compute_fncts_A_B( l_upper_thresh, upper_threshold, &
l_lower_thresh, lower_threshold, &
f_diff, A_fnc, B_fnc )
! Description:
! This subroutine computes the values of two functions used in semi-implicit
! clipping. Both of the functions are based on the values of f_diff(t) and
! the parameter sigma. One function is A_fnc, which is F_R(f_diff)
! evaluated at f_diff = f_diff(t). F_R(f_diff) is a three-piece function
! that is used to approximate function R(f_diff). The other function is
! B_fnc, the derivative with respect to f_diff of function A_fnc. In other
! words, B_fnc is ( d F_R / d f_diff ) evaluated at f_diff = f_diff(t).
!
! The equation for A_fnc is:
!
! | f_diff(t); where f_diff(t) <= -sigma
! |
! A_fnc = | f_diff(t) - (sigma/4) * [ 1 + (f_diff(t)/sigma) ]^2;
! | where -sigma < f_diff(t) < sigma
! |
! | 0; where f_diff(t) >= sigma;
!
! while the equation for B_fnc is:
!
! | 1; where f_diff(t) <= -sigma
! |
! B_fnc = | 1 - (1/2) * [ 1 + (f_diff(t)/sigma) ];
! | where -sigma < f_diff(t) < sigma
! |
! | 0; where f_diff(t) >= sigma;
!
! where timestep index (t) stands for the index of the current timestep.
! References:
!-----------------------------------------------------------------------
use constants_clubb, only: eps ! Variable(s)
use clubb_precision, only: &
core_rknd ! Variable(s)
implicit none
! Input Variable
real( kind = core_rknd ), intent(in) :: &
f_diff, & ! Difference between the threshold value and f_unclipped. [f units]
upper_threshold, & ! Greatest allowable value of variable f. [f units]
lower_threshold ! Smallest allowable value of variable f. [f units]
logical, intent(in) :: &
l_upper_thresh, & ! Flag for having an upper threshold value.
l_lower_thresh ! Flag for having a lower threshold value.
! Output Variables
real( kind = core_rknd ), intent(out) :: &
A_fnc, & ! Function that approximates { f_diff * [ 1 - H(f_diff) ] }. [f units]
B_fnc ! Derivative w/ respect to f_diff of function A_fnc. []
! Local Variables
real( kind = core_rknd ) :: sigma_val, & ! Value of parameter sigma. [f units]
thresh_avg_mag ! Average magnitude of threshold(s). [f units]
thresh_avg_mag = 0.0_core_rknd ! Default Initialization
! Find the average magnitude of the threshold.
! In cases where only one threshold applies, the average magnitude of the
! threshold must be greater than 0.
! Note: The constant eps is there in case only one threshold applies, and
! it has a value of 0 (or very close to 0). However, eps is a very
! small number, and therefore it will not start curbing values until
! they get extremely close to the threshold. A larger constant value
! may work better.
if ( l_upper_thresh .and. l_lower_thresh ) then
! Both thresholds apply.
thresh_avg_mag = 0.5_core_rknd * ( abs(upper_threshold) &
+ abs(lower_threshold) )
elseif ( l_upper_thresh ) then
! Only the upper threshold applies.
thresh_avg_mag = max( abs(upper_threshold), eps )
elseif ( l_lower_thresh ) then
! Only the lower threshold applies.
thresh_avg_mag = max( abs(lower_threshold), eps )
endif
! Compute the value of sigma based on the magnitude of the threshold(s) for
! variable f and the sigma coefficient. The value of sigma must always be
! positive.
sigma_val = sigma_coef * thresh_avg_mag
! A_fnc is a three-piece function that approximates function
! R(f_diff(t)) = { f_diff(t) * [ 1 - H(f_diff(t)) ] }. This is needed
! because the R(f_diff(t)) is not differentiable at point f_diff(t) = 0, as
! the function has a corner at that point. Function A_fnc is differentiable
! at all points. It is evaluated for f_diff at timestep index (t).
if ( f_diff <= -sigma_val ) then
A_fnc = f_diff
elseif ( f_diff >= sigma_val ) then
A_fnc = 0.0_core_rknd
else ! -sigma_val < f_diff < sigma_val
A_fnc = f_diff - ( (sigma_val/4.0_core_rknd) &
* ( 1.0_core_rknd + f_diff/sigma_val )**2 )
endif
! B_fnc is the derivative with respect to f_diff of function A_fnc. It is
! evaluated for f_diff at timestep index (t).
if ( f_diff <= -sigma_val ) then
B_fnc = 1.0_core_rknd
elseif ( f_diff >= sigma_val ) then
B_fnc = 0.0_core_rknd
else ! -sigma_val < f_diff < sigma_val
B_fnc = 1.0_core_rknd - (1.0_core_rknd/2.0_core_rknd)*( 1.0_core_rknd + f_diff/sigma_val )
endif
end subroutine compute_fncts_A_B
!===============================================================================
end module clip_semi_implicit