51
!Variables belonging to the Newton solver
52
logical, private :: newton_initialised = .false.
53
!Cached Newton solver matrices
54
type(csr_matrix), private :: Newton_lambda_mat
55
type(block_csr_matrix), private :: Newton_continuity_mat
56
type(real_matrix), pointer, dimension(:), private &
57
&:: Newton_local_solver_cache=>null()
58
type(real_matrix), pointer, dimension(:), private &
59
&:: Newton_local_solver_rhs_cache=>null()
63
subroutine solve_hybridised_timestep_residual(state,newU,newD,&
66
! Subroutine to apply one Newton iteration to hybridised shallow
68
! Written to cache all required matrices
70
type(state_type), intent(inout) :: state
71
type(vector_field), intent(inout) :: newU !U at next timestep
72
type(scalar_field), intent(inout) :: newD !D at next timestep
73
type(vector_field), intent(in), optional :: UResidual
74
type(scalar_field), intent(in), optional :: DResidual
76
type(vector_field), pointer :: X, U, down, U_cart, U_old
77
type(scalar_field), pointer :: D,f, D_old
78
type(scalar_field) :: lambda, D_res, D_res2
79
type(vector_field) :: U_res, U_res2
80
type(scalar_field), target :: lambda_rhs, u_cpt
81
type(csr_sparsity) :: lambda_sparsity, continuity_sparsity
82
type(csr_matrix) :: continuity_block_mat
83
type(mesh_type), pointer :: lambda_mesh
84
real :: D0, dt, g, theta, tolerance
85
integer :: ele,i1, stat, dim1, dloc, uloc,mdim,n_constraints
86
logical :: have_constraint
87
character(len=OPTION_PATH_LEN) :: constraint_option_string
89
ewrite(1,*) 'solve_hybridised_timestep_residual(state)'
91
ewrite(1,*) 'TIMESTEPPING LAMBDA'
94
call get_option("/physical_parameters/gravity/magnitude", g)
95
call get_option("/timestepping/theta",theta)
96
call get_option("/material_phase::Fluid/scalar_field::LayerThickness/&
97
&prognostic/mean_layer_thickness",D0)
98
call get_option("/timestepping/timestep", dt)
100
!Pull the fields out of state
101
D=>extract_scalar_field(state, "LayerThickness")
102
f=>extract_scalar_field(state, "Coriolis")
103
U=>extract_vector_field(state, "LocalVelocity")
104
X=>extract_vector_field(state, "Coordinate")
105
down=>extract_vector_field(state, "GravityDirection")
106
U_cart => extract_vector_field(state, "Velocity")
107
U_old => extract_vector_field(state, "OldLocalVelocity")
108
D_old => extract_scalar_field(state, "OldLayerThickness")
110
!Allocate local field variables
111
lambda_mesh=>extract_mesh(state, "VelocityMeshTrace")
112
call allocate(lambda,lambda_mesh,name="LagrangeMultiplier")
113
call allocate(lambda_rhs,lambda%mesh,"LambdaRHS")
114
call zero(lambda_rhs)
115
call allocate(U_res,U%dim,U%mesh,"VelocityResidual")
116
call allocate(D_res,D%mesh,"LayerThicknessResidual")
117
call allocate(U_res2,U%dim,U%mesh,"VelocityResidual2")
118
call allocate(D_res2,D%mesh,"LayerThicknessResidual2")
120
if(.not.newton_initialised) then
121
!construct/extract sparsities
122
lambda_sparsity=get_csr_sparsity_firstorder(&
123
&state, lambda%mesh, lambda&
125
continuity_sparsity=get_csr_sparsity_firstorder(state, u%mesh,&
129
call allocate(Newton_lambda_mat,lambda_sparsity)
130
call zero(Newton_lambda_mat)
131
call allocate(Newton_continuity_mat,continuity_sparsity,(/U%dim,1/))
132
call zero(Newton_continuity_mat)
136
&have_option(trim(U%mesh%option_path)//"/from_mesh/constraint_type")
138
allocate(newton_local_solver_cache(ele_count(U)))
139
allocate(newton_local_solver_rhs_cache(ele_count(U)))
140
do ele = 1, ele_count(D)
141
uloc = ele_loc(U,ele)
142
dloc = ele_loc(d,ele)
144
if(have_constraint) then
145
n_constraints = ele_n_constraints(U,ele)
146
allocate(newton_local_solver_cache(ele)%ptr(&
147
mdim*uloc+dloc+n_constraints,&
148
mdim*uloc+dloc+n_constraints))
149
allocate(newton_local_solver_rhs_cache(ele)%ptr(&
150
mdim*uloc+dloc,mdim*uloc+dloc))
155
do ele = 1, ele_count(D)
156
call assemble_newton_solver_ele(D,f,U,X,down,lambda_rhs,ele, &
158
&lambda_mat=Newton_lambda_mat,&
159
&continuity_mat=Newton_continuity_mat,&
160
&Local_solver_matrix=Newton_local_solver_cache(ele)%ptr,&
161
&Local_solver_rhs=Newton_local_solver_rhs_cache(ele)%ptr)
163
newton_initialised = .true.
166
if(present(DResidual).and.present(UResidual).and..not.&
167
have_option('/material_phase::Fluid/vector_field::Velocity/prognostic/wave_equation/fully_coupled/linear_debug')) then
168
!Set residuals from nonlinear input
169
call set(U_res,UResidual)
170
call set(D_res,DResidual)
172
!Compute residuals for linear equation
173
do ele = 1, ele_count(D)
174
call get_linear_residuals_ele(U_res,D_res,&
175
U_old,D_old,newU,newD,&
176
newton_local_solver_cache(ele)%ptr,&
177
newton_local_solver_rhs_cache(ele)%ptr,ele)
179
ewrite(2,*) 'cjc U_res calc', sum(newU%val), maxval(abs(U_res%val))
180
ewrite(2,*) 'cjc D_res calc', sum(newD%val), maxval(abs(D_res%val))
183
do ele = 1, ele_count(D)
184
call local_solve_residuals_ele(U_res,D_res,&
185
newton_local_solver_cache(ele)%ptr,ele)
188
call mult_t(lambda_rhs,Newton_continuity_mat,U_res)
189
call scale(lambda_rhs,-1.0)
190
ewrite(2,*) 'LAMBDARHS', maxval(abs(lambda_rhs%val))
194
call petsc_solve(lambda,newton_lambda_mat,lambda_rhs,&
195
option_path=trim(U_cart%mesh%option_path)//&
196
&"/from_mesh/constraint_type")
197
ewrite(2,*) 'LAMBDA', maxval(abs(lambda%val))
199
!Update new U and new D from lambda
201
if(present(DResidual).and.present(UResidual).and..not.&
202
have_option('/material_phase::Fluid/vector_field::Velocity/prognostic/wave_equation/fully_coupled/linear_debug')) then
203
call set(U_res,UResidual)
204
call set(D_res,DResidual)
206
do ele = 1, ele_count(D)
207
call get_linear_residuals_ele(U_res,D_res,&
208
U_old,D_old,newU,newD,&
209
newton_local_solver_cache(ele)%ptr,&
210
newton_local_solver_rhs_cache(ele)%ptr,ele)
213
ewrite(2,*) 'cjc U_res recalc', sum(newU%val), maxval(abs(U_res%val))
214
ewrite(2,*) 'cjc D_res recalc', sum(newD%val), maxval(abs(D_res%val))
216
call mult(U_res2,Newton_continuity_mat,lambda)
217
call addto(U_res,U_res2)
218
do ele = 1, ele_count(U)
219
call local_solve_residuals_ele(U_res,D_res,&
220
newton_local_solver_cache(ele)%ptr,ele)
223
!Negative scaling occurs here.
224
call scale(U_res,-1.0)
225
call scale(D_res,-1.0)
227
ewrite(2,*) 'Delta U', maxval(abs(U_res%val))
228
ewrite(2,*) 'Delta D', maxval(abs(D_res%val))
230
call addto(newU,U_res)
231
call addto(newD,D_res)
233
!Deallocate local variables
234
call deallocate(lambda_rhs)
235
call deallocate(lambda)
236
call deallocate(U_res)
237
call deallocate(D_res)
238
call deallocate(U_res2)
239
call deallocate(D_res2)
241
ewrite(1,*) 'END solve_hybridised_timestep_residual(state)'
243
end subroutine solve_hybridised_timestep_residual
53
245
subroutine solve_hybridized_helmholtz(state,D_rhs,U_Rhs,&
275
467
ewrite(1,*) 'END subroutine solve_hybridized_helmholtz'
277
469
end subroutine solve_hybridized_helmholtz
471
subroutine get_linear_residuals_ele(U_res,D_res,U,D,&
472
newU,newD,local_solver,local_solver_rhs,ele)
474
type(vector_field), intent(inout) :: U_res,U,newU
475
type(scalar_field), intent(inout) :: D_res,D,newD
476
real, dimension(:,:), intent(in) :: local_solver, local_solver_rhs
477
integer, intent(in) :: ele
479
integer :: uloc, dloc, dim1, d_start, d_end, mdim
480
integer, dimension(mesh_dim(U)) :: U_start, U_end
481
real, dimension(mesh_dim(U)*ele_loc(U,ele)+ele_loc(D,ele))&
483
real, dimension(mesh_dim(U),ele_loc(U,ele)) :: U_val
485
!Calculate indices in a vector containing all the U and D dofs in
486
!element ele, First the u1 components, then the u2 components, then the
487
!D components are stored.
488
uloc = ele_loc(U_res,ele)
489
dloc = ele_loc(D_res,ele)
490
d_end = mesh_dim(U_res)*uloc+dloc
493
u_start(dim1) = uloc*(dim1-1)+1
494
u_end(dim1) = uloc*dim1
496
d_start = uloc*mdim + 1
497
d_end = uloc*mdim+dloc
499
U_val = ele_val(U,ele)
500
do dim1 = 1, mesh_dim(U)
501
rhs_loc1(u_start(dim1):u_end(dim1)) = u_val(dim1,:)
503
rhs_loc1(d_start:d_end) = ele_val(D,ele)
504
rhs_loc1 = matmul(local_solver_rhs,rhs_loc1)
505
U_val = ele_val(newU,ele)
506
do dim1 = 1, mesh_dim(U)
507
rhs_loc2(u_start(dim1):u_end(dim1)) = u_val(dim1,:)
509
rhs_loc2(d_start:d_end) = ele_val(newD,ele)
510
rhs_loc2 = matmul(local_solver(1:d_end,1:d_end),rhs_loc2)
511
rhs_loc2 = rhs_loc2-rhs_loc1
512
do dim1 = 1, mesh_dim(U)
513
call set(U_res,dim1,ele_nodes(U,ele),&
514
rhs_loc2(u_start(dim1):u_end(dim1)))
516
call set(D_res,ele_nodes(D,ele),&
517
rhs_loc2(d_start:d_end))
518
end subroutine get_linear_residuals_ele
520
subroutine local_solve_residuals_ele(U_res,D_res,&
521
local_solver_matrix,ele)
522
type(vector_field), intent(inout) :: U_res
523
type(scalar_field), intent(inout) :: D_res
524
real, dimension(:,:), intent(in) :: local_solver_matrix
525
integer, intent(in) :: ele
527
real, dimension(mesh_dim(U_res)*ele_loc(U_res,ele)+ele_loc(D_res,ele)+&
528
&ele_n_constraints(U_res,ele)) :: rhs_loc
529
real, dimension(mesh_dim(U_res),ele_loc(U_res,ele)) :: U_val
530
integer :: uloc,dloc, d_start, d_end, dim1, mdim
531
integer, dimension(mesh_dim(U_res)) :: U_start, U_end
535
!Calculate indices in a vector containing all the U and D dofs in
536
!element ele, First the u1 components, then the u2 components, then the
537
!D components are stored.
538
uloc = ele_loc(U_res,ele)
539
dloc = ele_loc(D_res,ele)
540
d_end = mesh_dim(U_res)*uloc+dloc
541
mdim = mesh_dim(U_res)
543
u_start(dim1) = uloc*(dim1-1)+1
544
u_end(dim1) = uloc*dim1
546
d_start = uloc*mdim + 1
547
d_end = uloc*mdim+dloc
549
U_val = ele_val(U_res,ele)
550
do dim1 = 1, mesh_dim(U_res)
551
rhs_loc(u_start(dim1):u_end(dim1)) = u_val(dim1,:)
553
rhs_loc(d_start:d_end) = &
556
call solve(local_solver_matrix,Rhs_loc)
557
do dim1 = 1, mesh_dim(U_res)
558
call set(U_res,dim1,ele_nodes(U_res,ele),&
559
rhs_loc(u_start(dim1):u_end(dim1)))
561
call set(D_res,ele_nodes(D_res,ele),&
562
rhs_loc(d_start:d_end))
563
end subroutine local_solve_residuals_ele
565
subroutine assemble_newton_solver_ele(D,f,U,X,down,lambda_rhs,ele, &
567
&lambda_mat,continuity_mat,&
568
&Local_solver_matrix,Local_solver_rhs)
570
type(scalar_field), intent(in) :: D,f
571
type(scalar_field), intent(in) :: lambda_rhs
572
type(vector_field), intent(in) :: U,X,down
573
integer, intent(in) :: ele
574
real, intent(in) :: g,dt,theta,D0
575
type(csr_matrix), intent(inout) :: lambda_mat
576
type(block_csr_matrix), intent(inout) :: continuity_mat
577
real, dimension(:,:), intent(inout) ::&
578
& local_solver_matrix
579
real, dimension(:,:), intent(inout) ::&
582
real, allocatable, dimension(:,:),target :: &
583
&l_continuity_mat, l_continuity_mat2
584
real, allocatable, dimension(:,:) :: helmholtz_loc_mat
585
real, allocatable, dimension(:,:,:) :: continuity_face_mat
586
real, allocatable, dimension(:,:) :: scalar_continuity_face_mat
588
integer, dimension(:), pointer :: neigh
589
type(element_type) :: U_shape
590
integer :: stat, d_start, d_end, dim1, mdim, uloc,dloc, lloc, iloc
591
integer, dimension(mesh_dim(U)) :: U_start, U_end
592
type(real_matrix), dimension(mesh_dim(U)) :: &
593
& continuity_mat_u_ptr
594
logical :: have_constraint
595
integer :: constraint_choice, n_constraints, constraints_start
598
lloc = ele_loc(lambda_rhs,ele)
600
uloc = ele_loc(U,ele)
601
dloc = ele_loc(d,ele)
602
U_shape = ele_shape(U,ele)
605
&have_option(trim(U%mesh%option_path)//"/from_mesh/constraint_type")
607
if(have_constraint) then
608
n_constraints = ele_n_constraints(U,ele)
611
!Calculate indices in a vector containing all the U and D dofs in
612
!element ele, First the u1 components, then the u2 components, then the
613
!D components are stored.
615
u_start(dim1) = uloc*(dim1-1)+1
616
u_end(dim1) = uloc*dim1
618
d_start = uloc*mdim + 1
619
d_end = uloc*mdim+dloc
621
!Get pointers to different parts of l_continuity_mat
622
allocate(l_continuity_mat(2*uloc+dloc+n_constraints,lloc))
624
continuity_mat_u_ptr(dim1)%ptr => &
625
& l_continuity_mat(u_start(dim1):u_end(dim1),:)
629
! ( -C^T N 0 )(h) = (j)
632
! (u) (M C)^{-1}(v) (M C)^{-1}(L)
633
! (h) = (-C^T N) (j) + (-C^T N) (0)(l)
635
! (M C)^{-1}(L) (M C)^{-1}(v)
636
! (L^T 0)(-C^T N) (0)=-(L^T 0)(-C^T N) (j)
638
!Get the local_solver matrix that obtains U and D from Lambda on the
640
call get_local_solver(local_solver_matrix,U,X,down,D,f,ele,&
641
& g,dt,theta,D0,pullback=.false.,weight=1.0,&
642
& have_constraint=have_constraint,&
643
& projection=.false.,poisson=.false.,&
644
& local_solver_rhs=local_solver_rhs)
646
!!!Construct the continuity matrix that multiplies lambda in
648
!allocate l_continuity_mat
649
l_continuity_mat = 0.
650
!get list of neighbours
651
neigh => ele_neigh(D,ele)
652
!calculate l_continuity_mat
653
do ni = 1, size(neigh)
654
face=ele_face(U, ele, neigh(ni))
655
allocate(continuity_face_mat(mdim,face_loc(U,face)&
656
&,face_loc(lambda_rhs,face)))
657
continuity_face_mat = 0.
658
call get_continuity_face_mat(continuity_face_mat,face,&
661
continuity_mat_u_ptr(dim1)%ptr(face_local_nodes(U,face),&
662
face_local_nodes(lambda_rhs,face))=&
663
continuity_mat_u_ptr(dim1)%ptr(face_local_nodes(U,face),&
664
face_local_nodes(lambda_rhs,face))+&
665
continuity_face_mat(dim1,:,:)
668
call addto(continuity_mat,dim1,1,face_global_nodes(U,face)&
669
&,face_global_nodes(lambda_rhs,face),&
670
&continuity_face_mat(dim1,:,:))
673
deallocate(continuity_face_mat)
676
!compute l_continuity_mat2 = inverse(local_solver)*l_continuity_mat
677
allocate(l_continuity_mat2(uloc*2+dloc+n_constraints,lloc))
678
l_continuity_mat2 = l_continuity_mat
679
call solve(local_solver_matrix,l_continuity_mat2)
681
!compute helmholtz_loc_mat
682
allocate(helmholtz_loc_mat(lloc,lloc))
683
helmholtz_loc_mat = matmul(transpose(l_continuity_mat),l_continuity_mat2)
685
!insert helmholtz_loc_mat into global lambda matrix
686
call addto(lambda_mat,ele_nodes(lambda_rhs,ele),&
687
ele_nodes(lambda_rhs,ele),helmholtz_loc_mat)
688
end subroutine assemble_newton_solver_ele
279
690
subroutine assemble_hybridized_helmholtz_ele(D,f,U,X,down,ele, &
280
691
g,dt,theta,D0,pullback,weight,lambda_mat,lambda_rhs,U_rhs,D_rhs,&
815
1226
end subroutine get_local_solver
817
subroutine get_up_gi(X,ele,up_gi,orientation)
818
!subroutine to replace up_gi with a normal to the surface
819
!with the same orientation
821
type(vector_field), intent(in) :: X
822
integer, intent(in) :: ele
823
real, dimension(X%dim,ele_ngi(X,ele)), intent(inout) :: up_gi
824
integer, intent(out), optional :: orientation
826
real, dimension(mesh_dim(X), X%dim, ele_ngi(X,ele)) :: J
828
real, dimension(X%dim,ele_ngi(X,ele)) :: normal_gi
829
real, dimension(ele_ngi(X,ele)) :: orientation_gi
830
integer :: l_orientation
833
call compute_jacobian(ele_val(X,ele), ele_shape(X,ele), J=J)
835
select case(mesh_dim(X))
837
do gi = 1, ele_ngi(X,ele)
838
normal_gi(:,gi) = cross_product(J(1,:,gi),J(2,:,gi))
839
norm = sqrt(sum(normal_gi(:,gi)**2))
840
normal_gi(:,gi) = normal_gi(:,gi)/norm
842
do gi = 1, ele_ngi(X,ele)
843
orientation_gi(gi) = dot_product(normal_gi(:,gi),up_gi(:,gi))
845
do gi = 1, ele_ngi(X,ele)
846
if(sign(1.0,orientation_gi(gi)).ne.sign(1.0,orientation_gi(1))) then
848
ewrite(0,*) 'normal=',normal_gi(:,gi)
849
ewrite(0,*) 'up=',up_gi(:,gi)
850
ewrite(0,*) 'orientation=',orientation_gi(gi)
851
ewrite(0,*) 'orientation(1)=',orientation_gi(1)
852
FLAbort('Nasty geometry problem')
857
if(orientation_gi(1)>0.0) then
862
if(present(orientation)) then
863
orientation =l_orientation
865
do gi = 1, ele_ngi(X,ele)
866
up_gi(:,gi) = normal_gi(:,gi)*l_orientation
869
FLAbort('not implemented')
871
end subroutine get_up_gi
873
1228
function get_orientation(X_val, up) result (orientation)
874
1229
!function compares the orientation of the element with the