1
by hhiester
deleting initialisation as none of tools are used any longer. |
1 |
! Copyright (C) 2008 Imperial College London and others.
|
2 |
!
|
|
3 |
! Please see the AUTHORS file in the main source directory for a full list
|
|
4 |
! of copyright holders.
|
|
5 |
!
|
|
6 |
! Prof. C Pain
|
|
7 |
! Applied Modelling and Computation Group
|
|
8 |
! Department of Earth Science and Engineering
|
|
9 |
! Imperial College London
|
|
10 |
!
|
|
2392
by tmb1
Changing isntances of Chris' person email address to the group |
11 |
! amcgsoftware@imperial.ac.uk
|
1
by hhiester
deleting initialisation as none of tools are used any longer. |
12 |
!
|
13 |
! This library is free software; you can redistribute it and/or
|
|
14 |
! modify it under the terms of the GNU Lesser General Public
|
|
15 |
! License as published by the Free Software Foundation,
|
|
16 |
! version 2.1 of the License.
|
|
17 |
!
|
|
18 |
! This library is distributed in the hope that it will be useful,
|
|
19 |
! but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 |
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
21 |
! Lesser General Public License for more details.
|
|
22 |
!
|
|
23 |
! You should have received a copy of the GNU Lesser General Public
|
|
24 |
! License along with this library; if not, write to the Free Software
|
|
25 |
! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
26 |
! USA
|
|
27 |
#include "fdebug.h"
|
|
28 |
||
29 |
module upwind_stabilisation |
|
30 |
!!< This module provides routines for the upwind stabilisation of
|
|
31 |
!!< advection_diffusion equations.
|
|
32 |
||
33 |
use fields |
|
34 |
use metric_tools |
|
35 |
use spud |
|
3586
by Jon Hill
Fix to Upwind_Stabilisation for the wonderful intel compilers |
36 |
use shape_functions |
37 |
||
1
by hhiester
deleting initialisation as none of tools are used any longer. |
38 |
implicit none
|
39 |
||
40 |
private
|
|
41 |
||
3580.3.1
by david.ham at ac
Move the allocation of the supg test function outside the element loop. This is needed for OpenMP and actually ought to be faster for serial as well. |
42 |
public :: get_upwind_options, element_upwind_stabilisation,& |
43 |
& make_supg_shape, make_supg_element, supg_test_function |
|
1
by hhiester
deleting initialisation as none of tools are used any longer. |
44 |
|
45 |
integer, parameter, public :: NU_BAR_OPTIMAL = 1, & |
|
46 |
& NU_BAR_DOUBLY_ASYMPTOTIC = 2, NU_BAR_CRITICAL_RULE = 3, NU_BAR_UNITY = 4 |
|
47 |
||
48 |
real, parameter :: tolerance = 1.0e-10 |
|
49 |
! For Pe >= this, 1.0 / tanh(pe) differs from 1.0 by <= 1.0e-10
|
|
50 |
real, parameter :: tanh_tolerance = 11.859499013855018 |
|
51 |
||
52 |
contains
|
|
53 |
||
54 |
subroutine get_upwind_options(option_path, nu_bar_scheme, nu_bar_scale) |
|
55 |
character(len = *), intent(in) :: option_path |
|
56 |
integer, intent(out) :: nu_bar_scheme |
|
57 |
real, intent(out) :: nu_bar_scale |
|
58 |
||
59 |
if(have_option(trim(option_path) // "/nu_bar_optimal")) then |
|
60 |
ewrite(2, *) "nu_bar scheme: optimal" |
|
61 |
nu_bar_scheme = NU_BAR_OPTIMAL |
|
62 |
else if(have_option(trim(option_path) // "/nu_bar_doubly_asymptotic")) then |
|
63 |
ewrite(2, *) "nu_bar scheme: doubly asymptotic" |
|
64 |
nu_bar_scheme = NU_BAR_DOUBLY_ASYMPTOTIC |
|
65 |
else if(have_option(trim(option_path) // "/nu_bar_critical_rule")) then |
|
66 |
ewrite(2, *) "nu_bar scheme: critical rule" |
|
67 |
nu_bar_scheme = NU_BAR_CRITICAL_RULE |
|
68 |
else
|
|
69 |
assert(have_option(trim(option_path) // "/nu_bar_unity")) |
|
70 |
ewrite(2, *) "nu_bar scheme: unity (xi = sign(pe))" |
|
71 |
nu_bar_scheme = NU_BAR_UNITY |
|
72 |
end if
|
|
73 |
||
74 |
call get_option(trim(option_path) // "/nu_scale", nu_bar_scale) |
|
75 |
assert(nu_bar_scale >= 0.0) |
|
76 |
ewrite(2, *) "nu_bar scale factor = ", nu_bar_scale |
|
77 |
||
78 |
end subroutine get_upwind_options |
|
79 |
||
80 |
function element_upwind_stabilisation(t_shape, dshape, u_nl_q, j_mat, detwei, & |
|
81 |
& diff_q, nu_bar_scheme, nu_bar_scale) result (stab) |
|
82 |
!!< Calculate the upwind stabilisation on an individual element. This
|
|
83 |
!!< implements equation 2.52 in Donea & Huerta (2003):
|
|
84 |
!!<
|
|
85 |
!!< / nu
|
|
86 |
!!< | ----------- (U_nl\dot grad N_j)(U_nl\dot grad N_i)
|
|
87 |
!!< / ||U_nl||**2
|
|
88 |
!!<
|
|
89 |
!!< Where:
|
|
90 |
!!<
|
|
91 |
!!< nu = 0.5*U*dx/d\xi
|
|
92 |
!!<
|
|
93 |
type(element_type), intent(in) :: t_shape |
|
94 |
!! dshape is nloc x ngi x dim
|
|
95 |
real, dimension(t_shape%loc, t_shape%quadrature%ngi, t_shape%dim) :: dshape |
|
96 |
!! u_nl_q is dim x ngi
|
|
97 |
real, dimension(t_shape%dim, t_shape%quadrature%ngi), intent(in) :: u_nl_q |
|
98 |
!! j_mat is dim x dim x ngi
|
|
99 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), intent(in) :: j_mat |
|
100 |
real, dimension(size(u_nl_q, 2)), intent(in) :: detwei |
|
101 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), optional, intent(in) :: diff_q |
|
102 |
integer, optional, intent(in) :: nu_bar_scheme |
|
103 |
real, optional, intent(in) :: nu_bar_scale |
|
104 |
||
105 |
real, dimension(t_shape%loc, t_shape%loc) :: stab |
|
106 |
||
107 |
! Local Variables
|
|
108 |
||
109 |
!! This is the factor nu/||U_nl^^2||
|
|
110 |
real, dimension(size(detwei)) :: nu_scaled |
|
111 |
!! U_nl \dot dshape
|
|
112 |
real, dimension(t_shape%loc, size(detwei)) :: U_nl_dn |
|
113 |
||
114 |
integer :: i, j, loc, ngi |
|
115 |
||
116 |
loc = t_shape%loc |
|
117 |
ngi = size(u_nl_q, 2) |
|
118 |
||
119 |
nu_scaled = nu_bar_scaled_q(dshape, u_nl_q, j_mat, diff_q = diff_q, nu_bar_scheme = nu_bar_scheme, nu_bar_scale = nu_bar_scale) |
|
120 |
||
121 |
forall(i = 1:ngi, j = 1:loc) |
|
122 |
u_nl_dn(j, i) = dot_product(u_nl_q(:, i), dshape(j, i, :)) |
|
123 |
end forall
|
|
124 |
||
125 |
forall(i = 1:loc, j = 1:loc) |
|
126 |
stab(i, j) = dot_product(u_nl_dn(i, :) * detwei * nu_scaled, u_nl_dn(j, :)) |
|
127 |
end forall
|
|
128 |
||
129 |
end function element_upwind_stabilisation |
|
130 |
||
131 |
function xi_optimal(u_nl_q, j_mat, diff_q) result(xi_q) |
|
132 |
!!< Compute the directional xi factor as in equation 2.44b in Donea &
|
|
133 |
!!< Huerta (2003)
|
|
134 |
||
135 |
real, dimension(:), intent(in) :: U_nl_q |
|
136 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1)), intent(in) :: j_mat |
|
137 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1)), intent(in) :: diff_q |
|
138 |
||
139 |
real, dimension(size(u_nl_q, 1)) :: xi_q |
|
140 |
||
141 |
integer :: i |
|
142 |
real, dimension(size(u_nl_q, 1)) :: pe |
|
143 |
||
144 |
! Pe = u h_bar
|
|
145 |
! -------
|
|
146 |
! 2 kappa
|
|
147 |
pe = 0.5 * matmul(u_nl_q, matmul(j_mat, inverse(diff_q))) |
|
148 |
do i = 1, size(u_nl_q, 1) |
|
149 |
if(abs(pe(i)) < tolerance) then |
|
150 |
xi_q(i) = 0.0 |
|
151 |
else if(pe(i) > tanh_tolerance) then |
|
152 |
xi_q(i) = 1.0 - (1.0 / pe(i)) |
|
153 |
else if(pe(i) < -tanh_tolerance) then |
|
154 |
xi_q(i) = -1.0 - (1.0 / pe(i)) |
|
155 |
else
|
|
156 |
xi_q(i) = (1.0 / tanh(pe(i))) - (1.0 / pe(i)) |
|
157 |
end if
|
|
158 |
end do
|
|
159 |
|
|
160 |
end function xi_optimal |
|
161 |
||
162 |
function xi_doubly_asymptotic(u_nl_q, j_mat, diff_q) result(xi_q) |
|
163 |
!!< Compute the directional xi factor using the doubly asymptotic
|
|
164 |
!!< approximation as in equation 2.29 in Donea & Huerta (2003)
|
|
165 |
||
166 |
real, dimension(:), intent(in) :: U_nl_q |
|
167 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1)), intent(in) :: j_mat |
|
168 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1)), intent(in) :: diff_q |
|
169 |
||
170 |
real, dimension(size(u_nl_q, 1)) :: xi_q |
|
171 |
||
172 |
integer :: i |
|
173 |
real, dimension(size(u_nl_q, 1)) :: pe |
|
174 |
||
175 |
! Pe = u h_bar
|
|
176 |
! -------
|
|
177 |
! 2 kappa
|
|
178 |
pe = 0.5 * matmul(u_nl_q, matmul(j_mat, inverse(diff_q))) |
|
179 |
||
180 |
do i = 1, size(u_nl_q) |
|
181 |
if(abs(pe(i)) <= 3.0) then |
|
182 |
xi_q(i) = pe(i) / 3.0 |
|
183 |
else if(pe(i) > 0.0) then |
|
184 |
xi_q(i) = 1.0 |
|
185 |
else
|
|
186 |
xi_q(i) = -1.0 |
|
187 |
end if
|
|
188 |
end do
|
|
189 |
|
|
190 |
end function xi_doubly_asymptotic |
|
191 |
||
192 |
function xi_critical_rule(u_nl_q, j_mat, diff_q) result(xi_q) |
|
193 |
!!< Compute the directional xi factor using the critical rule
|
|
194 |
!!< approximation as in equation 3.3.2 of Brookes and Hughes, Computer
|
|
195 |
!!< Methods in Applied Mechanics and Engineering 32 (1982) 199-259.
|
|
196 |
||
197 |
real, dimension(:), intent(in) :: U_nl_q |
|
198 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1)), intent(in) :: j_mat |
|
199 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1)), intent(in) :: diff_q |
|
200 |
||
201 |
real, dimension(size(u_nl_q, 1)) :: xi_q |
|
202 |
||
203 |
integer :: i |
|
204 |
real, dimension(size(u_nl_q, 1)) :: pe |
|
205 |
||
206 |
! Pe = u h_bar
|
|
207 |
! -------
|
|
208 |
! 2 kappa
|
|
209 |
pe = 0.5 * matmul(u_nl_q, matmul(j_mat, inverse(diff_q))) |
|
210 |
||
211 |
do i = 1, size(u_nl_q) |
|
212 |
if(abs(pe(i)) <= 1.0) then |
|
213 |
xi_q(i) = 0.0 |
|
214 |
else if(pe(i) > 0.0) then |
|
215 |
xi_q(i) = 1.0 - 1.0 / pe(i) |
|
216 |
else
|
|
217 |
xi_q(i) = -1.0 - 1.0 / pe(i) |
|
218 |
end if
|
|
219 |
end do
|
|
220 |
|
|
221 |
end function xi_critical_rule |
|
222 |
||
223 |
function nu_bar_scaled_q(dshape, u_nl_q, j_mat, diff_q, nu_bar_scheme, nu_bar_scale) result(nu_bar_scaled) |
|
224 |
!!< Compute the diffusion parameter nu_bar, scaled by the norm of u
|
|
225 |
!!< nu_bar / ||u_nl^^2||
|
|
226 |
||
227 |
!! dshape is nloc x ngi x dim
|
|
228 |
real, dimension(:, :, :) :: dshape |
|
229 |
!! u_nl_q is dim x ngi
|
|
230 |
real, dimension(size(dshape, 3), size(dshape, 2)), intent(in) :: u_nl_q |
|
231 |
!! j_mat is dim x dim x ngi
|
|
232 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), intent(in) :: j_mat |
|
233 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), optional, intent(in) :: diff_q |
|
234 |
integer, optional, intent(in) :: nu_bar_scheme |
|
235 |
real, optional, intent(in) :: nu_bar_scale |
|
236 |
||
237 |
!! This is the factor nu/||u_nl^^2||
|
|
238 |
real, dimension(size(u_nl_q, 2)) :: nu_bar_scaled |
|
239 |
||
240 |
integer :: i, lnu_bar_scheme, ngi, loc |
|
241 |
real :: lnu_bar_scale, norm_u |
|
242 |
||
243 |
if(present(diff_q)) then |
|
244 |
if(present(nu_bar_scheme)) then |
|
245 |
lnu_bar_scheme = nu_bar_scheme |
|
246 |
else
|
|
247 |
lnu_bar_scheme = NU_BAR_OPTIMAL |
|
248 |
end if
|
|
249 |
else
|
|
250 |
! If we have no diffusivity then xi = sign(pe)
|
|
251 |
lnu_bar_scheme = NU_BAR_UNITY |
|
252 |
end if
|
|
253 |
if(present(nu_bar_scale)) then |
|
254 |
lnu_bar_scale = nu_bar_scale |
|
255 |
else
|
|
256 |
lnu_bar_scale = 0.5 |
|
257 |
end if
|
|
258 |
assert(lnu_bar_scale >= 0.0) |
|
259 |
||
260 |
loc = size(dshape, 1) |
|
261 |
ngi = size(u_nl_q, 2) |
|
262 |
||
263 |
select case(lnu_bar_scheme) |
|
264 |
case(NU_BAR_OPTIMAL) |
|
265 |
do i = 1, ngi |
|
266 |
norm_u = dot_product(u_nl_q(:, i), u_nl_q(:, i)) |
|
267 |
! Avoid divide by zeros or similar where u_nl is close to 0
|
|
268 |
if(norm_u < tolerance) then |
|
269 |
nu_bar_scaled(i) = 0.0 |
|
270 |
else
|
|
271 |
nu_bar_scaled(i) = dot_product(xi_optimal(u_nl_q(:, i), j_mat(:, :, i), diff_q(:, :, i)), matmul(u_nl_q(:, i), j_mat(:, :, i))) / norm_u |
|
272 |
end if
|
|
273 |
end do
|
|
274 |
case(NU_BAR_DOUBLY_ASYMPTOTIC) |
|
275 |
do i = 1, ngi |
|
276 |
norm_u = dot_product(u_nl_q(:, i), u_nl_q(:, i)) |
|
277 |
! Avoid divide by zeros or similar where u_nl is close to 0
|
|
278 |
if(norm_u < tolerance) then |
|
279 |
nu_bar_scaled(i) = 0.0 |
|
280 |
else
|
|
281 |
nu_bar_scaled(i) = dot_product(xi_doubly_asymptotic(u_nl_q(:, i), j_mat(:, :, i), diff_q(:, :, i)), matmul(u_nl_q(:, i), j_mat(:, :, i))) / norm_u |
|
282 |
end if
|
|
283 |
end do
|
|
284 |
case(NU_BAR_CRITICAL_RULE) |
|
285 |
do i = 1, ngi |
|
286 |
norm_u = dot_product(u_nl_q(:, i), u_nl_q(:, i)) |
|
287 |
! Avoid divide by zeros or similar where u_nl is close to 0
|
|
288 |
if(norm_u < tolerance) then |
|
289 |
nu_bar_scaled(i) = 0.0 |
|
290 |
else
|
|
291 |
nu_bar_scaled(i) = dot_product(xi_critical_rule(u_nl_q(:, i), j_mat(:, :, i), diff_q(:, :, i)), matmul(u_nl_q(:, i), j_mat(:, :, i))) / norm_u |
|
292 |
end if
|
|
293 |
end do
|
|
294 |
case(NU_BAR_UNITY) |
|
295 |
do i = 1, ngi |
|
296 |
norm_u = dot_product(u_nl_q(:, i), u_nl_q(:, i)) |
|
297 |
! Avoid divide by zeros or similar where u_nl is close to 0
|
|
298 |
if(norm_u < tolerance) then |
|
299 |
nu_bar_scaled(i) = 0.0 |
|
300 |
else
|
|
301 |
nu_bar_scaled(i) = sum(abs(matmul(u_nl_q(:, i), j_mat(:, :, i)))) / norm_u |
|
302 |
end if
|
|
303 |
end do
|
|
304 |
case default |
|
305 |
ewrite(-1, *) "For nu_bar scheme: ", lnu_bar_scheme |
|
306 |
FLAbort("Invalid nu_bar scheme") |
|
307 |
end select
|
|
308 |
|
|
309 |
nu_bar_scaled = nu_bar_scaled * lnu_bar_scale |
|
310 |
||
311 |
#ifdef DDEBUG
|
|
312 |
if(.not. all(nu_bar_scaled >= 0.0)) then |
|
313 |
ewrite(-1, *) "nu_bar_scaled = ", nu_bar_scaled |
|
314 |
FLAbort("Invalid nu_bar_scaled") |
|
315 |
end if
|
|
316 |
#endif
|
|
317 |
||
318 |
end function nu_bar_scaled_q |
|
319 |
||
320 |
function make_supg_shape(base_shape, dshape, u_nl_q, j_mat, & |
|
321 |
& diff_q, nu_bar_scheme, nu_bar_scale) result(test_function) |
|
322 |
!!< Construct the SUPG volume element test function. This implements
|
|
323 |
!!< equation 2.51 in Donea & Huerta (2003).
|
|
324 |
||
325 |
type(element_type), target, intent(in) :: base_shape |
|
326 |
!! dshape is nloc x ngi x dim
|
|
327 |
real, dimension(base_shape%loc, base_shape%quadrature%ngi, base_shape%dim) :: dshape |
|
328 |
!! u_nl_q is dim x ngi
|
|
329 |
real, dimension(base_shape%dim, base_shape%quadrature%ngi), intent(in) :: u_nl_q |
|
330 |
!! j_mat is dim x dim x ngi
|
|
331 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), intent(in) :: j_mat |
|
332 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), optional, intent(in) :: diff_q |
|
333 |
integer, optional, intent(in) :: nu_bar_scheme |
|
334 |
real, optional, intent(in) :: nu_bar_scale |
|
335 |
||
336 |
type(element_type) :: test_function |
|
337 |
||
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
338 |
integer :: coords, degree, dim, i, j, vertices, ngi |
1
by hhiester
deleting initialisation as none of tools are used any longer. |
339 |
!! This is the factor nu/||u_nl^^2||
|
340 |
real, dimension(size(u_nl_q, 2)) :: nu_bar_scaled |
|
341 |
!! u_nl \dot dshape
|
|
342 |
real, dimension(base_shape%loc, size(u_nl_q, 2)) :: u_nl_dn |
|
343 |
type(quadrature_type), pointer :: quad |
|
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
344 |
type(ele_numbering_type), pointer :: ele_num |
1
by hhiester
deleting initialisation as none of tools are used any longer. |
345 |
|
346 |
quad => base_shape%quadrature |
|
347 |
||
348 |
dim = base_shape%dim |
|
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
349 |
vertices = base_shape%numbering%vertices |
1
by hhiester
deleting initialisation as none of tools are used any longer. |
350 |
ngi = quad%ngi |
351 |
coords = local_coord_count(base_shape) |
|
352 |
degree = base_shape%degree |
|
353 |
||
354 |
! Step 1: Generate a new shape
|
|
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
355 |
ele_num => & |
3470.2.3
by Colin Cotter
Fixed some bugs with the new allocate_element interface. |
356 |
&find_element_numbering(& |
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
357 |
&vertices = vertices, dimension = dim, degree = degree) |
3470.2.3
by Colin Cotter
Fixed some bugs with the new allocate_element interface. |
358 |
call allocate(test_function, ele_num=ele_num,ngi=ngi) |
1
by hhiester
deleting initialisation as none of tools are used any longer. |
359 |
|
360 |
test_function%degree = degree |
|
361 |
test_function%quadrature = quad |
|
362 |
call incref(quad) |
|
363 |
||
364 |
test_function%dn = huge(0.0) |
|
365 |
assert(.not. associated(test_function%dn_s)) |
|
366 |
assert(.not. associated(test_function%n_s)) |
|
367 |
deallocate(test_function%spoly) |
|
368 |
nullify(test_function%spoly) |
|
369 |
deallocate(test_function%dspoly) |
|
370 |
nullify(test_function%dspoly) |
|
371 |
||
372 |
! Step 2: Calculate the scaled nu and u dot nabla
|
|
373 |
||
374 |
nu_bar_scaled = nu_bar_scaled_q(dshape, u_nl_q, j_mat, diff_q = diff_q, nu_bar_scheme = nu_bar_scheme, nu_bar_scale = nu_bar_scale) |
|
375 |
||
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
376 |
forall(i = 1:ngi, j = 1:base_shape%loc) |
1
by hhiester
deleting initialisation as none of tools are used any longer. |
377 |
u_nl_dn(j, i) = dot_product(u_nl_q(:, i), dshape(j, i, :)) |
378 |
end forall
|
|
379 |
||
380 |
! Step 3: Generate the test function
|
|
381 |
||
3470.2.8
by david.ham at ac
fix the SUPG shape function. All short tests now pass for me |
382 |
do i = 1, base_shape%loc |
1
by hhiester
deleting initialisation as none of tools are used any longer. |
383 |
test_function%n(i, :) = base_shape%n(i, :) + nu_bar_scaled * u_nl_dn(i, :) |
384 |
end do
|
|
385 |
|
|
386 |
end function make_supg_shape |
|
3580.3.1
by david.ham at ac
Move the allocation of the supg test function outside the element loop. This is needed for OpenMP and actually ought to be faster for serial as well. |
387 |
|
388 |
function make_supg_element(base_shape) result(test_function) |
|
389 |
!!< Construct the SUPG volume element object. This is to be constructed
|
|
390 |
!!< outside the element loop so the actual values are set later.
|
|
391 |
||
392 |
type(element_type), target, intent(in) :: base_shape |
|
393 |
type(element_type) :: test_function |
|
394 |
||
395 |
test_function=make_element_shape(base_shape) |
|
396 |
||
397 |
test_function%n = huge(0.0) |
|
398 |
test_function%dn = huge(0.0) |
|
399 |
assert(.not. associated(test_function%dn_s)) |
|
400 |
assert(.not. associated(test_function%n_s)) |
|
401 |
deallocate(test_function%spoly) |
|
402 |
nullify(test_function%spoly) |
|
403 |
deallocate(test_function%dspoly) |
|
404 |
nullify(test_function%dspoly) |
|
405 |
||
406 |
end function make_supg_element |
|
407 |
||
408 |
subroutine supg_test_function(test_function, base_shape, dshape, u_nl_q, j_mat, & |
|
409 |
& diff_q, nu_bar_scheme, nu_bar_scale) |
|
410 |
!!< Construct the SUPG volume element test function. This implements
|
|
411 |
!!< equation 2.51 in Donea & Huerta (2003).
|
|
412 |
type(element_type), intent(inout) :: test_function |
|
413 |
type(element_type), target, intent(in) :: base_shape |
|
414 |
!! dshape is nloc x ngi x dim
|
|
415 |
real, dimension(base_shape%loc, base_shape%quadrature%ngi, base_shape%dim) :: dshape |
|
416 |
!! u_nl_q is dim x ngi
|
|
417 |
real, dimension(base_shape%dim, base_shape%quadrature%ngi), intent(in) :: u_nl_q |
|
418 |
!! j_mat is dim x dim x ngi
|
|
419 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), intent(in) :: j_mat |
|
420 |
real, dimension(size(u_nl_q, 1), size(u_nl_q, 1), size(u_nl_q, 2)), optional, intent(in) :: diff_q |
|
421 |
integer, optional, intent(in) :: nu_bar_scheme |
|
422 |
real, optional, intent(in) :: nu_bar_scale |
|
423 |
||
424 |
integer :: i, j |
|
425 |
!! This is the factor nu/||u_nl^^2||
|
|
426 |
real, dimension(size(u_nl_q, 2)) :: nu_bar_scaled |
|
427 |
!! u_nl \dot dshape
|
|
428 |
real, dimension(base_shape%loc, size(u_nl_q, 2)) :: u_nl_dn |
|
429 |
||
430 |
! Step 1: Calculate the scaled nu and u dot nabla
|
|
431 |
||
432 |
nu_bar_scaled = nu_bar_scaled_q(dshape, u_nl_q, j_mat, diff_q = diff_q, nu_bar_scheme = nu_bar_scheme, nu_bar_scale = nu_bar_scale) |
|
433 |
||
434 |
forall(i = 1:base_shape%quadrature%ngi, j = 1:base_shape%loc) |
|
435 |
u_nl_dn(j, i) = dot_product(u_nl_q(:, i), dshape(j, i, :)) |
|
436 |
end forall
|
|
437 |
||
438 |
! Step 2: Generate the test function
|
|
439 |
||
440 |
do i = 1, base_shape%loc |
|
441 |
test_function%n(i, :) = base_shape%n(i, :) + nu_bar_scaled * u_nl_dn(i, :) |
|
442 |
end do
|
|
443 |
|
|
444 |
end subroutine supg_test_function |
|
1
by hhiester
deleting initialisation as none of tools are used any longer. |
445 |
|
446 |
end module upwind_stabilisation |