~reducedmodelling/fluidity/ROM_Non-intrusive-ann

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