3103
3121
type(state_type), intent(in) :: state
3104
3122
type(vector_field), intent(inout) :: bed_shear_stress
3105
type(vector_field), pointer :: U
3106
integer, dimension(:), allocatable:: faceglobalnodes
3107
integer :: j,snloc,ele,sele,globnod
3123
type(scalar_field) :: masslump
3124
type(vector_field), pointer :: U, X, bed_shear_stress_surface
3125
type(tensor_field), pointer :: visc
3126
integer, dimension(:), allocatable :: faceglobalnodes
3127
integer :: i,j,snloc,ele,sele,globnod,face
3108
3128
real :: speed,density,drag_coefficient
3129
real, dimension(mesh_dim(bed_shear_stress)) :: invmass
3130
type(mesh_type) :: surface_mesh
3131
integer, dimension(:), pointer :: surface_node_list
3134
! assumes constant density
3110
3135
call get_option(trim(bed_shear_stress%option_path)//"/diagnostic/density", density)
3111
call get_option(trim(bed_shear_stress%option_path)//"/diagnostic/drag_coefficient", drag_coefficient)
3113
call zero(bed_shear_stress)
3114
U => extract_vector_field(state, "Velocity")
3115
snloc = face_loc(U, 1)
3116
allocate( faceglobalnodes(1:snloc) )
3117
do sele=1,surface_element_count(U)
3118
ele = face_ele(U, sele)
3119
faceglobalnodes = face_global_nodes(U, sele)
3121
globnod = faceglobalnodes(j)
3122
speed = norm2(node_val(U, globnod))
3123
call set(bed_shear_stress, globnod, density*drag_coefficient*speed * node_val(U, globnod))
3126
deallocate( faceglobalnodes )
3137
! calculate using drag coefficient
3138
if (have_option(trim(bed_shear_stress%option_path)//&
3139
&"/diagnostic/calculation_method/drag_coefficient")) then
3141
call zero(bed_shear_stress)
3143
call get_option(trim(bed_shear_stress%option_path)//&
3144
& "/diagnostic/calculation_method/drag_coefficient",&
3147
U => extract_vector_field(state, "Velocity")
3148
snloc = face_loc(U, 1)
3149
allocate( faceglobalnodes(1:snloc) )
3150
do sele=1,surface_element_count(U)
3151
ele = face_ele(U, sele)
3152
faceglobalnodes = face_global_nodes(U, sele)
3154
globnod = faceglobalnodes(j)
3155
speed = norm2(node_val(U, globnod))
3156
call set(bed_shear_stress, globnod, density*drag_coefficient*speed * node_val(U, globnod))
3159
deallocate( faceglobalnodes )
3161
! calculate using velocity gradient
3162
else if (have_option(trim(bed_shear_stress%option_path)//&
3163
&"/diagnostic/calculation_method/wall_treatment")) then
3165
! not handled here - handled in Weak_BCs
3167
! calculate using velocity gradient
3168
else if (have_option(trim(bed_shear_stress%option_path)//&
3169
&"/diagnostic/calculation_method/velocity_gradient")) then
3171
call zero(bed_shear_stress)
3173
visc => extract_tensor_field(state, "Viscosity")
3174
U => extract_vector_field(state, "Velocity")
3175
X => extract_vector_field(state, "Coordinate")
3177
! In the CG case we need to calculate a global lumped mass
3178
if(continuity(bed_shear_stress)>=0) then
3179
call allocate(masslump, bed_shear_stress%mesh, 'Masslump')
3183
do face = 1, surface_element_count(bed_shear_stress)
3184
call calculate_bed_shear_stress_ele(bed_shear_stress, masslump, face, X, U,&
3188
! In the CG case we globally apply inverse mass
3189
if(continuity(bed_shear_stress)>=0) then
3190
where (masslump%val/=0.0)
3191
masslump%val=1./masslump%val
3193
call scale(bed_shear_stress, masslump)
3194
call deallocate(masslump)
3198
FLAbort('Unknown bed shear stress calculation method')
3127
3201
end subroutine calculate_bed_shear_stress
3203
subroutine calculate_bed_shear_stress_ele(bed_shear_stress, masslump, face, X, U, visc&
3206
type(vector_field), intent(inout) :: bed_shear_stress
3207
type(scalar_field), intent(inout) :: masslump
3208
type(vector_field), intent(in), pointer :: X, U
3209
type(tensor_field), intent(in), pointer :: visc
3210
integer, intent(in) :: face
3211
real, intent(in) :: density
3213
integer :: i, j, i_gi, ele, dim
3214
type(element_type) :: augmented_shape
3215
type(element_type), pointer :: f_shape, shape, X_f_shape, X_shape
3216
real, dimension(X%dim, X%dim, ele_ngi(X, face_ele(X, face))) :: invJ
3217
real, dimension(X%dim, X%dim, face_ngi(X, face)) :: f_invJ
3218
real, dimension(face_ngi(X, face)) :: detwei
3219
real, dimension(X%dim, face_ngi(X, face)) :: normal, normal_shear_at_quad, X_ele
3220
real, dimension(X%dim) :: abs_normal
3221
real, dimension(ele_loc(X, face_ele(X, face)), face_ngi(X, face), X%dim) :: ele_dshape_at_face_quad
3222
real, dimension(X%dim, X%dim, face_ngi(X, face)) :: grad_U_at_quad, visc_at_quad, shear_at_quad
3223
real, dimension(X%dim, face_loc(U, face)) :: normal_shear_at_loc
3224
real, dimension(face_loc(X, face), face_loc(U, face)) :: mass
3226
ele = face_ele(X, face) ! ele number for volume mesh
3227
dim = mesh_dim(bed_shear_stress) ! field dimension
3229
! get shape functions
3230
f_shape => face_shape(U, face)
3231
shape => ele_shape(U, ele)
3233
! generate shape functions that include quadrature points on the face required
3234
! check that the shape does not already have these first
3235
assert(shape%degree == 1)
3236
if(associated(shape%dn_s)) then
3237
augmented_shape = shape
3238
call incref(augmented_shape)
3240
augmented_shape = make_element_shape(shape%loc, shape%dim, shape%degree, &
3241
& shape%quadrature, quad_s = f_shape%quadrature)
3244
! assumes that the jacobian is the same for all quadrature points
3245
! this is not valid for spheres!
3246
call compute_inverse_jacobian(ele_val(X, ele), ele_shape(X, ele), invj = invJ)
3247
assert(ele_numbering_family(shape) == FAMILY_SIMPLEX)
3248
f_invJ = spread(invJ(:, :, 1), 3, size(f_invJ, 3))
3250
call transform_facet_to_physical(X, face, detwei_f = detwei, normal = normal)
3252
! Evaluate the volume element shape function derivatives at the surface
3253
! element quadrature points
3254
ele_dshape_at_face_quad = eval_volume_dshape_at_face_quad(augmented_shape, &
3255
& local_face_number(X, face), f_invJ)
3257
! Calculate grad of U at the surface element quadrature points
3260
grad_U_at_quad(i, j, :) = &
3261
& matmul(ele_val(U, j, ele), ele_dshape_at_face_quad(:,:,i))
3265
visc_at_quad = face_val_at_quad(visc, face)
3266
X_ele = face_val_at_quad(X, face)
3267
do i_gi = 1, face_ngi(X, face)
3268
! Multiply by visosity
3269
shear_at_quad(:,:,i_gi) = matmul(grad_U_at_quad(:,:,i_gi), visc_at_quad(:,:,i_gi))
3271
! Get absolute of normal vector
3273
abs_normal(i) = abs(normal(i,i_gi))
3276
! Multiply by surface normal (dim,sgi) to obtain shear in direction normal
3277
! to surface - transpose (because fluidity stores data in row-major order??)
3278
normal_shear_at_quad(:,i_gi) = matmul(transpose(shear_at_quad(:,:,i_gi)),&
3282
normal_shear_at_loc = shape_vector_rhs(f_shape, normal_shear_at_quad, density *&
3285
mass = shape_shape(f_shape, f_shape, detwei)
3286
! In the CG case we need to calculate a global lumped mass
3287
if(continuity(bed_shear_stress)>=0) then
3288
call addto(masslump, face_global_nodes(bed_shear_stress,face), sum(mass,1))
3289
else ! In the DG case we will apply the inverse mass locally.
3291
normal_shear_at_loc(i,:) = matmul(inverse(mass), normal_shear_at_loc(i,:))
3295
! add to bed_shear_stress field
3296
call addto(bed_shear_stress, face_global_nodes(bed_shear_stress,face), normal_shear_at_loc)
3298
call deallocate(augmented_shape)
3300
end subroutine calculate_bed_shear_stress_ele
3129
3302
subroutine calculate_max_bed_shear_stress(state, max_bed_shear_stress)
3131
3304
type(state_type), intent(in) :: state