4 use mom_eos,
only :
eos_type, extract_member_eos, eos_linear, eos_teos10, eos_wright
10 implicit none ;
private
12 public set_ndiff_aux_params
13 public mark_unstable_cells
14 public increment_interface
17 public search_other_column
18 public interpolate_for_nondim_position
19 public refine_nondim_position
20 public check_neutral_positions
31 logical :: force_brent = .false.
39 subroutine set_ndiff_aux_params( CS, deg, max_iter, drho_tol, xtol, ref_pres, force_brent, EOS, debug)
41 integer,
optional,
intent(in ) :: deg
42 integer,
optional,
intent(in ) :: max_iter
43 real,
optional,
intent(in ) :: drho_tol
44 real,
optional,
intent(in ) :: xtol
45 real,
optional,
intent(in ) :: ref_pres
46 logical,
optional,
intent(in ) :: force_brent
47 logical,
optional,
intent(in ) :: debug
48 type(
eos_type),
target,
optional,
intent(in ) :: eos
50 if (
present( deg )) cs%nterm = deg + 1
51 if (
present( max_iter )) cs%max_iter = max_iter
52 if (
present( drho_tol )) cs%drho_tol = drho_tol
53 if (
present( xtol )) cs%xtol = xtol
54 if (
present( ref_pres )) cs%ref_pres = ref_pres
55 if (
present( force_brent )) cs%force_brent = force_brent
56 if (
present( eos )) cs%EOS => eos
57 if (
present( debug )) cs%debug = debug
59 end subroutine set_ndiff_aux_params
63 subroutine mark_unstable_cells(nk, dRdT, dRdS,T, S, stable_cell, ns)
64 integer,
intent(in) :: nk
65 real,
dimension(nk,2),
intent(in) :: drdt
66 real,
dimension(nk,2),
intent(in) :: drds
67 real,
dimension(nk,2),
intent(in) :: t
68 real,
dimension(nk,2),
intent(in) :: s
69 logical,
dimension(nk),
intent( out) :: stable_cell
70 integer,
intent( out) :: ns
72 integer :: k, first_stable, prev_stable
79 delta_rho = (drdt(k,2) + drdt(k,1))*(t(k,2) - t(k,1)) + (drds(k,2) + drds(k,1))*(s(k,2) - s(k,1))
80 stable_cell(k) = delta_rho >= 0.
86 if (stable_cell(k))
then
91 prev_stable = first_stable
94 do k = prev_stable+1, nk
96 if (.not. stable_cell(k)) cycle
99 delta_rho = (drdt(k,1) + drdt(prev_stable,2))*(t(k,1) - t(prev_stable,2)) + &
100 (drds(k,1) + drds(prev_stable,2))*(s(k,1) - s(prev_stable,2))
101 stable_cell(k) = delta_rho >= 0.
103 if (stable_cell(k)) prev_stable = k
109 if (stable_cell(k)) ns = ns + 2
112 end subroutine mark_unstable_cells
115 subroutine increment_interface(nk, kl, ki, stable, reached_bottom, searching_this_column, searching_other_column)
116 integer,
intent(in ) :: nk
117 integer,
intent(inout) :: kl
118 integer,
intent(inout) :: ki
119 logical,
dimension(nk),
intent(in ) :: stable
120 logical,
intent(inout) :: reached_bottom
121 logical,
intent(inout) :: searching_this_column
122 logical,
intent(inout) :: searching_other_column
127 elseif ((ki == 2) .and. (kl < nk) )
then
136 reached_bottom = .true.
137 searching_this_column = .true.
138 searching_other_column = .false.
140 elseif ((kl == nk) .and. (ki==2))
then
141 reached_bottom = .true.
142 searching_this_column = .true.
143 searching_other_column = .false.
145 call mom_error(fatal,
"Unanticipated eventuality in increment_interface")
147 end subroutine increment_interface
150 real function calc_drho(T1, S1, dRdT1, dRdS1, T2, S2, dRdT2, dRdS2)
151 real,
intent(in ) :: t1
152 real,
intent(in ) :: s1
153 real,
intent(in ) :: drdt1
154 real,
intent(in ) :: drds1
155 real,
intent(in ) :: t2
156 real,
intent(in ) :: s2
157 real,
intent(in ) :: drdt2
158 real,
intent(in ) :: drds2
160 calc_drho = 0.5*( (drdt1+drdt2)*(t1-t2) + (drds1+drds2)*(s1-s2) )
161 end function calc_drho
165 subroutine drho_at_pos(CS, T_ref, S_ref, alpha_ref, beta_ref, P_top, P_bot, ppoly_T, ppoly_S, x0, &
166 delta_rho, P_out, T_out, S_out, alpha_avg_out, beta_avg_out, delta_T_out, delta_S_out)
168 real,
intent(in) :: t_ref
169 real,
intent(in) :: s_ref
170 real,
intent(in) :: alpha_ref
171 real,
intent(in) :: beta_ref
172 real,
intent(in) :: p_top
173 real,
intent(in) :: p_bot
174 real,
dimension(CS%nterm),
intent(in) :: ppoly_t
175 real,
dimension(CS%nterm),
intent(in) :: ppoly_s
176 real,
intent(in) :: x0
177 real,
intent(out) :: delta_rho
178 real,
optional,
intent(out) :: p_out
179 real,
optional,
intent(out) :: t_out
180 real,
optional,
intent(out) :: s_out
181 real,
optional,
intent(out) :: alpha_avg_out
182 real,
optional,
intent(out) :: beta_avg_out
183 real,
optional,
intent(out) :: delta_t_out
184 real,
optional,
intent(out) :: delta_s_out
186 real :: alpha, beta, alpha_avg, beta_avg, p_int, t, s, delta_t, delta_s
188 p_int = (1. - x0)*p_top + x0*p_bot
189 t = evaluation_polynomial( ppoly_t, cs%nterm, x0 )
190 s = evaluation_polynomial( ppoly_s, cs%nterm, x0 )
192 if (cs%ref_pres<0.)
then
200 alpha_avg = 0.5*( alpha + alpha_ref )
201 beta_avg = 0.5*( beta + beta_ref )
204 delta_rho = alpha_avg*delta_t + beta_avg*delta_s
207 if (
present(p_out)) p_out = p_int
208 if (
present(t_out)) t_out = t
209 if (
present(s_out)) s_out = s
210 if (
present(alpha_avg_out)) alpha_avg_out = alpha_avg
211 if (
present(beta_avg_out)) beta_avg_out = beta_avg
212 if (
present(delta_t_out)) delta_t_out = delta_t
213 if (
present(delta_s_out)) delta_s_out = delta_s
215 end subroutine drho_at_pos
218 subroutine search_other_column(dRhoTop, dRhoBot, Ptop, Pbot, lastP, lastK, kl, kl_0, ki, &
219 top_connected, bot_connected, out_P, out_K, search_layer)
220 real,
intent(in ) :: drhotop
221 real,
intent(in ) :: drhobot
222 real,
intent(in ) :: ptop
223 real,
intent(in ) :: pbot
224 real,
intent(in ) :: lastp
225 integer,
intent(in ) :: lastk
226 integer,
intent(in ) :: kl
227 integer,
intent(in ) :: kl_0
228 integer,
intent(in ) :: ki
229 logical,
dimension(:),
intent(inout) :: top_connected
230 logical,
dimension(:),
intent(inout) :: bot_connected
231 real,
intent( out) :: out_p
232 integer,
intent( out) :: out_k
233 logical,
intent( out) :: search_layer
235 search_layer = .false.
237 if (kl == lastk)
then
238 if (drhotop > 0.)
then
239 if (lastk == kl)
then
246 elseif ( drhotop == drhobot )
then
247 if (top_connected(kl))
then
248 out_p = 1. ; out_k = kl
250 out_p = max(0.,lastp) ; out_k = kl
252 elseif (drhotop >= drhobot)
then
253 out_p = 1. ; out_k = kl
254 elseif (drhotop < 0. .and. drhobot < 0.)
then
255 out_p = 1. ; out_k = kl
258 out_p = max(interpolate_for_nondim_position( drhotop, ptop, drhobot, pbot ),lastp)
259 search_layer = .true.
262 if (.not. bot_connected(kl-1) )
then
272 out_p = 0. ; out_k = kl
273 elseif (drhotop > 0.)
then
274 if (lastk == kl)
then
281 elseif ( drhotop == drhobot )
then
282 if (top_connected(kl))
then
283 out_p = 1. ; out_k = kl
285 out_p = max(0.,lastp) ; out_k = kl
287 elseif (drhotop >= drhobot)
then
288 out_p = 1. ; out_k = kl
289 elseif (drhotop < 0. .and. drhobot < 0.)
then
290 out_p = 1. ; out_k = kl
293 out_p = max(interpolate_for_nondim_position( drhotop, ptop, drhobot, pbot ),lastp)
294 search_layer = .true.
298 end subroutine search_other_column
303 real function interpolate_for_nondim_position(dRhoNeg, Pneg, dRhoPos, Ppos)
304 real,
intent(in) :: drhoneg
305 real,
intent(in) :: pneg
306 real,
intent(in) :: drhopos
307 real,
intent(in) :: ppos
310 stop
'interpolate_for_nondim_position: Houston, we have a problem! Ppos<Pneg'
311 elseif (drhoneg>drhopos)
then
312 write(0,*)
'dRhoNeg, Pneg, dRhoPos, Ppos=',drhoneg, pneg, drhopos, ppos
313 elseif (drhoneg>drhopos)
then
314 stop
'interpolate_for_nondim_position: Houston, we have a problem! dRhoNeg>dRhoPos'
317 interpolate_for_nondim_position = 0.5
318 elseif ( drhopos - drhoneg > 0. )
then
319 interpolate_for_nondim_position = min( 1., max( 0., -drhoneg / ( drhopos - drhoneg ) ) )
320 elseif ( drhopos - drhoneg == 0)
then
322 interpolate_for_nondim_position = 0.
323 elseif (drhoneg<0.)
then
324 interpolate_for_nondim_position = 1.
326 interpolate_for_nondim_position = 0.5
329 interpolate_for_nondim_position = 0.5
331 if ( interpolate_for_nondim_position < 0. ) &
332 stop
'interpolate_for_nondim_position: Houston, we have a problem! Pint < Pneg'
333 if ( interpolate_for_nondim_position > 1. ) &
334 stop
'interpolate_for_nondim_position: Houston, we have a problem! Pint > Ppos'
335 end function interpolate_for_nondim_position
344 real function refine_nondim_position(CS, T_ref, S_ref, alpha_ref, beta_ref, P_top, P_bot, &
345 ppoly_T, ppoly_S, drho_top, drho_bot, min_bound)
347 real,
intent(in) :: t_ref
348 real,
intent(in) :: s_ref
349 real,
intent(in) :: alpha_ref
350 real,
intent(in) :: beta_ref
351 real,
intent(in) :: p_top
352 real,
intent(in) :: p_bot
353 real,
dimension(:),
intent(in) :: ppoly_t
355 real,
dimension(:),
intent(in) :: ppoly_s
357 real,
intent(in) :: drho_top
358 real,
intent(in) :: drho_bot
359 real,
intent(in) :: min_bound
362 integer :: form_of_eos
364 logical :: do_newton, do_brent
366 real :: delta_rho, d_delta_rho_dp
367 real :: p_int, p_min, p_ref
368 real :: delta_rho_init, delta_rho_final
369 real :: neg_x, neg_fun
370 real :: t, s, alpha, beta, alpha_avg, beta_avg
372 real :: dt_dp, ds_dp, delta_t, delta_s, delta_p
373 real :: dbeta_ds, dbeta_dt, dalpha_dt, dalpha_ds, dbeta_dp, dalpha_dp
374 real :: a, b, c, b_last
376 real :: d, e, f, fa, fb, fc, m, p, q, r, s0, sa, sb, tol, machep
380 machep = epsilon(machep)
381 if (cs%ref_pres>=0.) p_ref = cs%ref_pres
382 delta_p = p_bot-p_top
383 refine_nondim_position = min_bound
385 call extract_member_eos(cs%EOS, form_of_eos = form_of_eos)
386 do_newton = (form_of_eos == eos_linear) .or. (form_of_eos == eos_teos10) .or. (form_of_eos == eos_wright)
387 do_brent = .not. do_newton
388 if (cs%force_brent)
then
389 do_newton = .not. cs%force_brent
390 do_brent = cs%force_brent
394 call drho_at_pos(cs, t_ref, s_ref, alpha_ref, beta_ref, p_top, p_bot, ppoly_t, ppoly_s, min_bound, &
395 delta_rho, p_int, t, s, alpha_avg, beta_avg, delta_t, delta_s)
396 delta_rho_init = delta_rho
397 if ( abs(delta_rho_init) <= cs%drho_tol )
then
398 refine_nondim_position = min_bound
401 if (abs(drho_bot) <= cs%drho_tol)
then
402 refine_nondim_position = 1.
412 write (*,*)
"Starting x0, delta_rho: ", min_bound, delta_rho
418 refine_nondim_position = min_bound
420 p_min = p_top*(1.-min_bound) + p_bot*(min_bound)
421 fa = delta_rho_init ; a = min_bound
422 fb = delta_rho_init ; b = min_bound
423 fc = drho_bot ; c = 1.
425 do iter = 1, cs%max_iter
426 p_int = p_top*(1. - b) + p_bot*b
428 if (cs%ref_pres<0.) p_ref = p_int
431 if (cs%ref_pres>=0.)
then
432 dalpha_dp = 0. ; dbeta_dp = 0.
436 dt_dp = first_derivative_polynomial( ppoly_t, cs%nterm, b ) / delta_p
437 ds_dp = first_derivative_polynomial( ppoly_s, cs%nterm, b ) / delta_p
439 d_delta_rho_dp = 0.5*( delta_s*(ds_dp*dbeta_ds + dt_dp*dbeta_dt + dbeta_dp) + &
440 ( delta_t*(ds_dp*dalpha_ds + dt_dp*dalpha_dt + dalpha_dp))) + &
441 ds_dp*beta_avg + dt_dp*alpha_avg
443 if (d_delta_rho_dp == 0.)
then
447 p_int = p_int - (fb / d_delta_rho_dp)
451 b = (p_int-p_top)/delta_p
453 if (b < a .or. b > c)
then
457 call drho_at_pos(cs, t_ref, s_ref, alpha_ref, beta_ref, p_top, p_bot, ppoly_t, ppoly_s, &
458 b, fb, p_int, t, s, alpha_avg, beta_avg, delta_t, delta_s)
459 if (cs%debug)
write(*,
'(A,I3.3,X,ES23.15,X,ES23.15)')
"Iteration, b, fb: ", iter, b, fb
461 if (fb < 0. .and. fb > neg_fun)
then
468 if ((fb <= 0.) .and. (fb >= -cs%drho_tol))
then
469 refine_nondim_position = b
473 if ( abs(b-b_last)<=cs%xtol )
then
474 refine_nondim_position = b
479 if (sign(1.,fa)*sign(1.,fb)<0.)
then
487 refine_nondim_position = b
490 if (delta_rho > 0.)
then
491 refine_nondim_position = neg_x
496 sa = max(refine_nondim_position,min_bound) ; fa = delta_rho
497 sb = 1. ; fb = drho_bot
498 c = sa ; fc = fa ; e = sb - sa; d = e
502 do iter = 1,cs%max_iter
503 if ( abs( fc ) < abs( fb ) )
then
511 tol = 2. * machep * abs( sb ) + cs%xtol
513 if ( abs( m ) <= tol .or. fb == 0. )
then
516 if ( abs( e ) < tol .or. abs( fa ) <= abs( fb ) )
then
527 p = s0 * ( 2. * m * q * ( q - r ) - ( sb - sa ) * ( r - 1. ) )
528 q = ( q - 1. ) * ( r - 1. ) * ( s0 - 1. )
537 if ( 2. * p < 3. * m * q - abs( tol * q ) .and. &
538 p < abs( 0.5 * s0 * q ) )
then
547 if ( tol < abs( d ) )
then
549 elseif ( 0. < m )
then
554 call drho_at_pos(cs, t_ref, s_ref, alpha_ref, beta_ref, p_top, p_bot, ppoly_t, ppoly_s, &
556 if ( ( 0. < fb .and. 0. < fc ) .or. &
557 ( fb <= 0. .and. fc <= 0. ) )
then
565 fa = abs(fa) ; fb = abs(fb) ; fc = abs(fc)
566 delta_rho = min(fa, fb, fc)
568 if (fb==delta_rho)
then
569 refine_nondim_position = max(sb,min_bound)
570 elseif (fa==delta_rho)
then
571 refine_nondim_position = max(sa,min_bound)
572 elseif (fc==delta_rho)
then
573 refine_nondim_position = max(c, min_bound)
578 if (refine_nondim_position>1.)
then
580 write (*,*)
"T, T Poly Coeffs: ", t, ppoly_t
581 write (*,*)
"S, S Poly Coeffs: ", s, ppoly_s
582 write (*,*)
"T_ref, alpha_ref: ", t_ref, alpha_ref
583 write (*,*)
"S_ref, beta_ref : ", s_ref, beta_ref
584 write (*,*)
"x0: ", min_bound
585 write (*,*)
"refine_nondim_position: ", refine_nondim_position
587 call mom_error(warning,
"refine_nondim_position>1.")
588 refine_nondim_position = 1.
591 if (refine_nondim_position<min_bound)
then
593 write (*,*)
"T, T Poly Coeffs: ", t, ppoly_t
594 write (*,*)
"S, S Poly Coeffs: ", s, ppoly_s
595 write (*,*)
"T_ref, alpha_ref: ", t_ref, alpha_ref
596 write (*,*)
"S_ref, beta_ref : ", s_ref, beta_ref
597 write (*,*)
"x0: ", min_bound
598 write (*,*)
"refine_nondim_position: ", refine_nondim_position
600 call mom_error(warning,
"refine_nondim_position<min_bound.")
601 refine_nondim_position = min_bound
605 call drho_at_pos(cs, t_ref, s_ref, alpha_ref, beta_ref, p_top, p_bot, ppoly_t, ppoly_s, &
606 refine_nondim_position, delta_rho)
607 write (*,*)
"End delta_rho: ", delta_rho
608 write (*,*)
"x0, delta_x: ", min_bound, refine_nondim_position-min_bound
609 write (*,*)
"refine_nondim_position: ", refine_nondim_position
610 write (*,*)
"Iterations: ", iter
611 write (*,*)
"T_poly_coeffs: ", ppoly_t
612 write (*,*)
"S_poly_coeffs: ", ppoly_s
616 end function refine_nondim_position
618 subroutine check_neutral_positions(CS, Ptop_l, Pbot_l, Ptop_r, Pbot_r, PoL, PoR, Tl_coeffs, Tr_coeffs, &
619 Sl_coeffs, Sr_coeffs)
621 real,
intent(in) :: ptop_l
622 real,
intent(in) :: pbot_l
623 real,
intent(in) :: ptop_r
624 real,
intent(in) :: pbot_r
625 real,
intent(in) :: pol
626 real,
intent(in) :: por
627 real,
dimension(CS%nterm),
intent(in) :: tl_coeffs
628 real,
dimension(CS%nterm),
intent(in) :: tr_coeffs
629 real,
dimension(CS%nterm),
intent(in) :: sl_coeffs
630 real,
dimension(CS%nterm),
intent(in) :: sr_coeffs
632 real :: pl, pr, tl, tr, sl, sr
633 real :: alpha_l, alpha_r, beta_l, beta_r
636 pl = (1. - pol)*ptop_l + pol*pbot_l
637 pr = (1. - por)*ptop_r + por*pbot_r
638 tl = evaluation_polynomial( tl_coeffs, cs%nterm, pol )
639 sl = evaluation_polynomial( sl_coeffs, cs%nterm, pol )
640 tr = evaluation_polynomial( tr_coeffs, cs%nterm, por )
641 sr = evaluation_polynomial( sr_coeffs, cs%nterm, por )
643 if (cs%ref_pres<0.)
then
651 delta_rho = 0.5*( (alpha_l + alpha_r)*(tl - tr) + (beta_l + beta_r)*(sl - sr) )
652 write(*,
'(A,ES23.15)')
"Delta-rho: ", delta_rho
654 end subroutine check_neutral_positions
657 subroutine kahan_sum(sum, summand, c)
658 real,
intent(inout) :: sum
659 real,
intent(in ) :: summand
660 real ,
intent(inout) :: c
667 end subroutine kahan_sum