415
413
smagorinsky_coefficient)
417
415
if(dynamic_les) then
418
! Are we using the Lilly (1991) modification?
419
have_lilly = have_option(trim(les_option_path)//"/dynamic_les/enable_lilly")
421
! Whether or not to allow backscatter (negative eddy viscosity)
422
backscatter = have_option(trim(les_option_path)//"/dynamic_les/enable_backscatter")
416
! Scalar or tensor filter width
417
call get_option(trim(les_option_path)//"/dynamic_les/length_scale_type", length_scale_type)
424
418
! Initialise optional diagnostic fields
425
419
have_eddy_visc = have_option(trim(les_option_path)//"/dynamic_les/tensor_field::EddyViscosity")
426
have_strain = have_option(trim(les_option_path)//"/dynamic_les/tensor_field::StrainRate")
427
have_filtered_strain = have_option(trim(les_option_path)//"/dynamic_les/tensor_field::FilteredStrainRate")
428
420
have_filter_width = have_option(trim(les_option_path)//"/dynamic_les/tensor_field::FilterWidth")
429
call les_init_diagnostic_fields(state, have_eddy_visc, have_strain, have_filtered_strain, have_filter_width)
421
have_coeff = have_option(trim(les_option_path)//"/dynamic_les/scalar_field::SmagorinskyCoefficient")
422
call les_init_diagnostic_fields(state, have_eddy_visc, have_filter_width, have_coeff)
431
424
! Initialise necessary local fields.
432
425
ewrite(2,*) "Initialising compulsory dynamic LES fields"
433
if(have_option(trim(les_option_path)//"/dynamic_les/vector_field::FilteredVelocity")) then
434
tnu => extract_vector_field(state, "FilteredVelocity")
426
if(have_option(trim(les_option_path)//"/dynamic_les/vector_field::FirstFilteredVelocity")) then
427
fnu => extract_vector_field(state, "FirstFilteredVelocity")
430
call allocate(fnu, u%dim, u%mesh, "FirstFilteredVelocity")
433
if(have_option(trim(les_option_path)//"/dynamic_les/vector_field::TestFilteredVelocity")) then
434
tnu => extract_vector_field(state, "TestFilteredVelocity")
437
call allocate(tnu, u%dim, u%mesh, "FilteredVelocity")
437
call allocate(tnu, u%dim, u%mesh, "TestFilteredVelocity")
440
440
allocate(leonard)
441
441
call allocate(leonard, u%mesh, "LeonardTensor")
442
442
call zero(leonard)
444
call allocate(strainprod, u%mesh, "StrainProduct")
445
call zero(strainprod)
444
! Get (test filter)/(mesh filter) size ratio alpha. Default value is 2.
447
! Get (first filter)/(mesh size) ratio alpha. Default value is 2.
445
448
call get_option(trim(les_option_path)//"/dynamic_les/alpha", alpha, default=2.0)
449
! Get (test filter)/(first filter) size ratio alpha. Default value is 2.
450
call get_option(trim(les_option_path)//"/dynamic_les/gama", gamma, default=2.0)
447
452
! Calculate test-filtered velocity field and Leonard tensor field.
448
453
ewrite(2,*) "Calculating test-filtered velocity and Leonard tensor"
449
call leonard_tensor(nu, x, tnu, leonard, alpha, les_option_path)
454
call leonard_tensor(nu, x, fnu, tnu, leonard, strainprod, alpha, gamma, les_option_path)
451
456
ewrite_minmax(leonard)
457
ewrite_minmax(strainprod)
453
460
tnu => dummyvector
454
461
leonard => dummytensor
462
strainprod => dummytensor
457
465
les_second_order=.false.; les_fourth_order=.false.; wale=.false.; dynamic_les=.false.
458
tnu => dummyvector; leonard => dummytensor
466
fnu => dummyvector; tnu => dummyvector; leonard => dummytensor; strainprod => dummytensor
1982
1994
type(tensor_field), intent(in) :: grad_u
1984
1996
! Fields for Germano Dynamic LES Model
1985
type(vector_field), intent(in) :: tnu
1986
type(tensor_field), intent(in) :: leonard
1987
real, intent(in) :: alpha
1997
type(vector_field), intent(in) :: fnu, tnu
1998
type(tensor_field), intent(in) :: leonard, strainprod
1999
real, intent(in) :: alpha, gamma
1989
2001
! Local quantities specific to Germano Dynamic LES Model
1990
real :: numerator, denominator
1991
real, dimension(x%dim, x%dim, ele_ngi(u,ele)) :: strain_gi, t_strain_gi
2002
real, dimension(x%dim, x%dim, ele_ngi(u,ele)) :: strain_gi, t_strain_gi, strainprod_gi
1992
2003
real, dimension(x%dim, x%dim, ele_ngi(u,ele)) :: mesh_size_gi, leonard_gi
2004
real, dimension(x%dim, x%dim, ele_ngi(u,ele)) :: f_tensor, t_tensor
2005
real, dimension(x%dim, x%dim) :: mij
1993
2006
real, dimension(ele_ngi(u, ele)) :: strain_mod, t_strain_mod
2007
real, dimension(ele_ngi(u, ele)) :: f_scalar, t_scalar
1994
2008
type(element_type) :: shape_nu
1995
2009
integer, dimension(:), pointer :: nodes_nu
2112
2126
nodes_nu => ele_nodes(nu, ele)
2113
2127
les_tensor_gi=0.0
2115
! Get strain S1 for unfiltered velocity (dim,dim,ngi)
2116
strain_gi = les_strain_rate(du_t, ele_val(nu, ele))
2117
! Get strain S2 for test-filtered velocity (dim,dim,ngi)
2129
! Get strain S1 for first-filtered velocity
2130
strain_gi = les_strain_rate(du_t, ele_val(fnu, ele))
2131
! Get strain S2 for test-filtered velocity
2118
2132
t_strain_gi = les_strain_rate(du_t, ele_val(tnu, ele))
2119
! Filter width G1 associated with mesh size (units length^2)
2133
! Mesh size (units length^2)
2120
2134
mesh_size_gi = length_scale_tensor(du_t, ele_shape(u, ele))
2121
! Leonard tensor L at gi
2135
! Leonard tensor and strain product at Gauss points
2122
2136
leonard_gi = ele_val_at_quad(leonard, ele)
2137
strainprod_gi = ele_val_at_quad(strainprod, ele)
2124
2139
do gi=1, ele_ngi(nu, ele)
2125
! Get strain modulus |S1| for unfiltered velocity (ngi)
2126
strain_mod(gi) = sqrt( 2*sum(strain_gi(:,:,gi)*strain_gi(:,:,gi) ) )
2127
! Get strain modulus |S2| for test-filtered velocity (ngi)
2128
t_strain_mod(gi) = sqrt( 2*sum(t_strain_gi(:,:,gi)*t_strain_gi(:,:,gi) ) )
2140
! Get strain modulus |S1| for first-filtered velocity
2141
strain_mod(gi) = sqrt( 2*sum(strain_gi(:,:,gi)*strain_gi(:,:,gi) ) )
2142
! Get strain modulus |S2| for test-filtered velocity
2143
t_strain_mod(gi) = sqrt( 2*sum(t_strain_gi(:,:,gi)*t_strain_gi(:,:,gi) ) )
2131
! If sum of strain components = 0, don't use dynamic LES model
2132
if(abs(sum(strain_gi(:,:,:))) < epsilon(0.0)) then
2136
! Choose original Germano model or Lilly's (1991) modification from options
2137
if(.not. have_lilly) then
2138
do gi=1, ele_ngi(nu, ele)
2140
numerator = sum( leonard_gi(:,:,gi)*strain_gi(:,:,gi) )*strain_mod(gi)
2142
! alpha^2*|S2|*S2.S1
2143
! This term is WRONG until I find a way of filtering the strain rate product. The difference may be quite small though.
2144
denominator = -alpha**2*t_strain_mod(gi)*sum(t_strain_gi(:,:,gi)*strain_gi(:,:,gi))
2146
! Dynamic eddy viscosity m_ij = C*S1
2147
les_tensor_gi(:,:,gi) = numerator/denominator
2149
! Whether or not to allow negative eddy viscosity (backscattering)
2150
! but do not allow (viscosity+eddy_viscosity) < 0.
2151
if(any(les_tensor_gi(:,:,gi) < 0.0)) then
2152
if(backscatter) then
2153
les_tensor_gi(:,:,gi) = max(les_tensor_gi(:,:,gi), epsilon(0.0) - viscosity_gi(:,:,gi))
2155
les_tensor_gi(:,:,gi) = max(les_tensor_gi(:,:,gi),0.0)
2159
else if(have_lilly) then
2160
do gi=1, ele_ngi(nu, ele)
2162
numerator = sum(leonard_gi(:,:,gi)*t_strain_gi(:,:,gi))*strain_mod(gi)
2163
! alpha^2*|S2|^2*S2.S2
2164
! This term is WRONG until I find a way of filtering the strain rate product. The difference may be quite small though.
2165
denominator = -alpha**2*(t_strain_mod(gi))**2*sum(t_strain_gi(:,:,gi)*t_strain_gi(:,:,gi))
2166
! Dynamic eddy viscosity m_ij
2167
les_tensor_gi(:,:,gi) = numerator/denominator
2169
! Whether or not to allow negative eddy viscosity (backscattering)
2170
! but do not allow (viscosity+eddy_viscosity) < 0.
2171
if(any(les_tensor_gi(:,:,gi) < 0.0)) then
2172
if(backscatter) then
2173
les_tensor_gi(:,:,gi) = max(les_tensor_gi(:,:,gi), epsilon(0.0) - viscosity_gi(:,:,gi))
2175
les_tensor_gi(:,:,gi) = max(les_tensor_gi(:,:,gi),0.0)
2146
select case(length_scale_type)
2148
! Scalar first filter width G1 = alpha^2*meshsize (units length^2)
2149
f_scalar = alpha**2*length_scale_scalar(x, ele)
2150
! Combined width G2 = (1+gamma^2)*G1
2151
t_scalar = (1.0+gamma**2)*f_scalar
2152
do gi=1, ele_ngi(nu, ele)
2153
! Tensor M_ij = (|S2|*S2)G2 - ((|S1|S1)^f2)G1
2154
mij = t_strain_mod(gi)*t_strain_gi(:,:,gi)*t_scalar(gi) - strainprod_gi(:,:,gi)*f_scalar(gi)
2155
! Model coeff C_S = -(L_ij M_ij) / 2(M_ij M_ij)
2156
les_coef_gi(gi) = -0.5*sum(leonard_gi(:,:,gi)*mij) / sum(mij*mij)
2157
! Constrain C_S to be between 0 and 0.04.
2158
les_coef_gi(gi) = min(max(les_coef_gi(gi),0.0), 0.04)
2159
! Isotropic tensor dynamic eddy viscosity = -2C_S|S1|.alpha^2.G1
2160
les_tensor_gi(:,:,gi) = 2*alpha**2*les_coef_gi(gi)*strain_mod(gi)*f_scalar(gi)
2163
! First filter width G1 = alpha^2*mesh size (units length^2)
2164
f_tensor = alpha**2*mesh_size_gi
2165
! Combined width G2 = (1+gamma^2)*G1
2166
t_tensor = (1.0+gamma**2)*f_tensor
2167
do gi=1, ele_ngi(nu, ele)
2168
! Tensor M_ij = (|S2|*S2).G2 - ((|S1|S1)^f2).G1
2169
mij = t_strain_mod(gi)*t_strain_gi(:,:,gi)*t_tensor(:,:,gi) - strainprod_gi(:,:,gi)*f_tensor(:,:,gi)
2170
! Model coeff C_S = -(L_ij M_ij) / 2(M_ij M_ij)
2171
les_coef_gi(gi) = -0.5*sum(leonard_gi(:,:,gi)*mij) / sum(mij*mij)
2172
! Constrain C_S to be between 0 and 0.04.
2173
les_coef_gi(gi) = min(max(les_coef_gi(gi),0.0), 0.04)
2174
! Anisotropic tensor dynamic eddy viscosity m_ij = -2C_S|S1|.alpha^2.G1
2175
les_tensor_gi(:,:,gi) = 2*alpha**2*les_coef_gi(gi)*strain_mod(gi)*f_tensor(:,:,gi)
2182
2179
! Assemble diagnostic fields
2183
2180
call les_assemble_diagnostic_fields(state, nu, ele, detwei, &
2184
mesh_size_gi, strain_gi, t_strain_gi, les_tensor_gi, &
2185
have_eddy_visc, have_strain, have_filtered_strain, have_filter_width)
2181
mesh_size_gi, les_tensor_gi, les_coef_gi, &
2182
have_eddy_visc, have_filter_width, have_coeff)
2188
2185
FLAbort("Unknown LES model")