Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/Adjoint/Adjoint_LinearSolver.F90
3206 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer/Ice, a glaciological add-on to Elmer
4
! * http://elmerice.elmerfem.org
5
! *
6
! *
7
! * This program is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU General Public License
9
! * as published by the Free Software Foundation; either version 2
10
! * of the License, or (at your option) any later version.
11
! *
12
! * This program is distributed in the hope that it will be useful,
13
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
! * GNU General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU General Public License
18
! * along with this program (in file fem/GPL-2); if not, write to the
19
! * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
! * Boston, MA 02110-1301, USA.
21
! *
22
! *****************************************************************************/
23
! ******************************************************************************
24
! *
25
! * Authors: f. Gillet-Chaulet (IGE-Grenoble/France)
26
! * Email:
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date:
30
! *
31
! *****************************************************************************
32
!------------------------------------------------------------------------------
33
SUBROUTINE Adjoint_LinearSolver( Model,Solver,dt,TransientSimulation )
34
!------------------------------------------------------------------------------
35
!> Compute the adjoint of the linear Solver and dirichlet conditions.
36
!
37
! OUTPUT is : Solver % Variable the adjoint variable
38
!
39
! INPUT PARAMETERS are:
40
!
41
! In solver section:
42
! Direct Equation Name = String
43
!
44
! Variables:
45
! VarName_b
46
!
47
!******************************************************************************
48
! ARGUMENTS:
49
!
50
! TYPE(Model_t) :: Model,
51
! INPUT: All model information (mesh, materials, BCs, etc...)
52
!
53
! TYPE(Solver_t) :: Solver
54
! INPUT: Linear & nonlinear equation solver options
55
!
56
! REAL(KIND=dp) :: dt,
57
! INPUT: Timestep size for time dependent simulations
58
!
59
! LOGICAL :: TransientSimulation
60
! INPUT: Steady state or transient simulation
61
!
62
!******************************************************************************
63
USE DefUtils
64
IMPLICIT NONE
65
!------------------------------------------------------------------------------
66
TYPE(Solver_t) :: Solver
67
TYPE(Model_t) :: Model
68
REAL(KIND=dp) :: dt
69
LOGICAL :: TransientSimulation
70
!------------------------------------------------------------------------------
71
! Local variables
72
!------------------------------------------------------------------------------
73
TYPE(Solver_t),Pointer :: DSolver ! Pointer to the Direct Solver
74
TYPE(Variable_t), POINTER :: Sol ! Solution Variable
75
INTEGER :: DOFs
76
77
TYPE(Matrix_t),POINTER :: InitMat,TransMat,StiffMatrix
78
REAL(KIND=dp),POINTER :: ForceVector(:)
79
INTEGER, POINTER :: Perm(:)
80
81
TYPE(ValueList_t),POINTER :: BC,BF,SolverParams
82
TYPE(Element_t),POINTER :: Element
83
INTEGER, POINTER :: NodeIndexes(:)
84
85
! Variables related to the frocing
86
TYPE(Variable_t), POINTER :: VbSol
87
REAL(KIND=dp), POINTER :: Vb(:)
88
INTEGER, POINTER :: VbPerm(:)
89
90
integer :: i,j,k,t,n
91
INTEGER :: kmax
92
Logical :: Gotit
93
integer :: p,q,dim,c,m
94
Real(KIND=dp) :: Unorm
95
Real(KIND=dp) :: RotVec(3)
96
97
! Var related to Normal-Tangential stuff and Dirchlet BCs
98
TYPE(ValueListEntry_t),POINTER :: NormalTangential,NormalTangentialC
99
REAL(KIND=dp), POINTER :: BoundaryNormals(:,:)=> NULL(), &
100
BoundaryTangent1(:,:)=> NULL(), &
101
BoundaryTangent2(:,:)=> NULL()
102
REAL(KIND=dp),ALLOCATABLE,SAVE :: Condition(:)
103
INTEGER, POINTER,SAVE :: BoundaryReorder(:)=> NULL()
104
INTEGER,SAVE :: NormalTangentialNOFNodes
105
CHARACTER(LEN=MAX_NAME_LEN),SAVE :: NormalTangentialName,NormalTangentialNameb
106
LOGICAL :: AnyNT
107
LOGICAL :: Conditional,CheckNT
108
109
CHARACTER(LEN=MAX_NAME_LEN),SAVE :: SolverName="Adjoint Solver" ! SolverName for messages
110
CHARACTER(LEN=MAX_NAME_LEN) :: DEqName ! Equation Name of Direct Solver
111
CHARACTER(LEN=MAX_NAME_LEN) :: DVarName ! Var Name of The Direct Solver
112
CHARACTER(LEN=MAX_NAME_LEN) :: FVarName ! Sensitivity Var Name (velocityb or DVarNameb)
113
INTEGER, SAVE :: SolverInd ! Indice of the direct solver in the solver list
114
LOGICAL, SAVE :: Firsttime=.TRUE.
115
116
117
StiffMatrix => Solver % Matrix
118
ForceVector => StiffMatrix % RHS
119
120
Sol => Solver % Variable
121
DOFs = Sol % DOFs
122
Perm => Sol % Perm
123
124
DIM = CoordinateSystemDimension()
125
! IF DIM = 3 and DOFs=2; e.g. solving SSA on a 3D mesh
126
!Normal-Tangential can not be used => trick temporary set Model Dimension to 2
127
IF (DIM.eq.(DOFs+1)) CurrentModel % Dimension = DOFs
128
129
IF (Firsttime) then
130
Firsttime=.False.
131
132
N = Model % MaxElementNodes
133
ALLOCATE(Condition(N))
134
135
! Get solver associated to the direct problem
136
SolverParams => GetSolverParams(Solver)
137
DEqName = ListGetString( SolverParams,'Direct Solver Equation Name',UnFoundFatal=.TRUE.)
138
DO i=1,Model % NumberOfSolvers
139
if (TRIM(DEqName) == ListGetString(Model % Solvers(i) % Values, 'Equation')) exit
140
End do
141
if (i.eq.(Model % NumberOfSolvers+1)) &
142
CALL FATAL(SolverName,'Could not find Equation Name ' // TRIM(DEqName))
143
SolverInd=i
144
DSolver => Model % Solvers(SolverInd)
145
146
!# Check For NT boundaries
147
IF (DOFs>1) THEN
148
NormalTangentialName = 'normal-tangential'
149
IF ( SEQL(DSolver % Variable % Name, 'flow solution') ) THEN
150
NormalTangentialName = TRIM(NormalTangentialName) // ' velocity'
151
ELSE
152
NormalTangentialName = TRIM(NormalTangentialName) // ' ' // &
153
GetVarName(DSolver % Variable)
154
END IF
155
156
AnyNT = ListGetLogicalAnyBC( Model, TRIM(NormalTangentialName) )
157
IF (AnyNT) THEN
158
159
!# We will stay in NT to impose dirichlet conditions
160
CALL ListAddLogical(SolverParams,'Back Rotate N-T Solution',.FALSE.)
161
162
!# !!! Has to be in lower case to copy item
163
NormalTangentialNameb='normal-tangential' // ' ' // GetVarName(Solver % Variable)
164
165
DO i=1,Model % NumberOfBCs
166
BC => Model % BCs(i) % Values
167
NormalTangential => ListFind( BC , NormalTangentialName , GotIt )
168
IF (.NOT.Gotit) CYCLE
169
170
WRITE(Message,'(A,I0)') 'Copy Normal-Tangential keyword in BC ',i
171
CALL Info(SolverName,Message,level=4)
172
CALL ListCopyItem( NormalTangential, BC, NormalTangentialNameb)
173
174
NormalTangentialC => ListFind( BC , TRIM(NormalTangentialName) // ' condition' , GotIt )
175
IF (.NOT.Gotit) CYCLE
176
177
WRITE(Message,'(A,I0)') 'Copy Normal-Tangential Condition keyword in BC ',i
178
CALL Info(SolverName,Message,level=4)
179
CALL ListCopyItem( NormalTangentialC, BC, TRIM(NormalTangentialNameb) // ' condition' )
180
END DO
181
182
CALL CheckNormalTangentialBoundary( Model, TRIM(NormalTangentialNameb), &
183
NormalTangentialNOFNodes, BoundaryReorder, &
184
BoundaryNormals, BoundaryTangent1, BoundaryTangent2, dim )
185
186
END IF
187
END IF
188
END IF
189
190
! Get Matrix from the Direct Solver
191
DSolver => Model % Solvers(SolverInd)
192
193
IF ( SEQL(DSolver % Variable % Name, 'flow solution') ) THEN
194
DVarName = 'Velocity'
195
ELSE
196
DVarName = GetVarName(DSolver % Variable)
197
END IF
198
199
CALL DefaultInitialize()
200
201
InitMat => AllocateMatrix()
202
InitMat % NumberOfRows = DSolver % Matrix % NumberOfRows
203
InitMat % Values => DSolver % Matrix % Values
204
InitMat % Rows => DSolver % Matrix % Rows
205
InitMat % Cols => DSolver % Matrix % Cols
206
InitMat % Diag => DSolver % Matrix % Diag
207
208
IF ( SEQL(DVarName,'velocity').OR.SEQL(DVarName,'ssavelocity')) THEN
209
FVarName = 'Velocityb'
210
ELSE
211
FVarName = TRIM(DVarName) // 'b'
212
ENDIF
213
VbSol => VariableGet( Solver % Mesh % Variables, TRIM(FVarName),UnFoundFatal=.TRUE. )
214
Vb => VbSol % Values
215
VbPerm => VbSol % Perm
216
IF (VbSol % DOFs.NE.DOFs) then
217
WRITE(Message,'(A,I1,A,I1)') &
218
'Variable Vb has ',VbSol % DOFs,' DOFs, should be',DOFs
219
CALL FATAL(SolverName,Message)
220
END IF
221
222
TransMat => NULL()
223
TransMat => CRS_Transpose(InitMat)
224
225
NULLIFY( InitMat % Rows, InitMat % Cols, InitMat % Diag, InitMat % Values )
226
CALL FreeMatrix( InitMat )
227
228
CALL CRS_SortMatrix( TransMat , .true. )
229
230
StiffMatrix % Values = TransMat % Values
231
StiffMatrix % Rows = TransMat % Rows
232
StiffMatrix % Cols = TransMat % Cols
233
IF(ASSOCIATED(TransMat % Diag)) StiffMatrix % Diag = TransMat % Diag
234
ForceVector = 0.0
235
Perm = DSolver % Variable % Perm
236
237
deallocate( TransMat % Rows, TransMat % Cols , TransMat % Values)
238
IF(ASSOCIATED(TransMat % Diag)) DEALLOCATE(TransMat % Diag)
239
nullify(TransMat)
240
241
!forcing of the adjoint system comes from the Vb variable computed
242
!with the cost function
243
244
!! Vb is expressed in the model coordinate system => Rotate to NT
245
CALL RotateNTSystemAll( Vb, VbPerm, DOFs )
246
247
c = DOFs
248
Do t=1,Solver%Mesh%NumberOfNodes
249
Do i=1,c
250
p=(Perm(t)-1)*c+i
251
q=(VbPerm(t)-1)*c+i
252
ForceVector(p)=Vb(q)
253
End Do
254
EndDo
255
256
CALL FinishAssembly( Solver, ForceVector )
257
258
Unorm = DefaultSolve()
259
260
! Go through BC to check if dirichlet was applied to direct solver
261
! Go to the boundary elements
262
Do t=1,GetNOFBoundaryElements()
263
Element => GetBoundaryElement(t)
264
BC => GetBC(Element)
265
IF (.NOT.ASSOCIATED( BC ) ) CYCLE
266
267
NodeIndexes => Element % NodeIndexes
268
n = Element % TYPE % NumberOfNodes
269
270
! Cf correspond lines in SolverUtils
271
! Check for nodes belonging to n-t boundary getting set by other bcs.
272
! -------------------------------------------------------------------
273
CheckNT = .FALSE.
274
IF ( NormalTangentialNOFNodes>0 .AND. DOFs>0 ) THEN
275
CheckNT = .TRUE.
276
IF ( ALL(BoundaryReorder(NodeIndexes(1:n))<1) ) CheckNT = .FALSE.
277
IF ( ListGetLogical(BC,'normal-tangential' // ' ' // DVarName,Gotit)) CheckNT=.FALSE.
278
END IF
279
280
! set BC for DOFs=1 or applied to the whole vector
281
IF( ListCheckPresent( BC, DVarName ) ) THEN
282
Condition(1:n) = ListGetReal( BC, &
283
TRIM(DVarName) // ' Condition', n, NodeIndexes, Conditional )
284
DO j=1,n
285
IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE
286
DO i=1,DOFS
287
Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp
288
END DO
289
END DO
290
ENDIF
291
292
! Do the same for each component
293
IF (DOFs>1) THEN
294
DO i=1,DOFS
295
IF( ListCheckPresent( BC, ComponentName(DVarName,i)) ) THEN
296
Condition(1:n) = ListGetReal( BC, &
297
TRIM(ComponentName(DVarName,i)) // ' Condition', n, NodeIndexes, Conditional )
298
299
DO j=1,n
300
IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE
301
302
k = Perm(NodeIndexes(j))
303
IF ( k > 0 ) THEN
304
305
m = 0
306
IF ( NormalTangentialNOFNodes>0 ) m=BoundaryReorder(NodeIndexes(j))
307
!! set in the NT system
308
IF ( m>0 .AND. CheckNT ) THEN
309
RotVec = 0._dp
310
RotVec(i) = 1._dp
311
CALL RotateNTSystem( RotVec, NodeIndexes(j) )
312
313
! When cartesian component "DOF" is defined set the N-T component
314
! closest to its direction.
315
kmax = 1
316
DO k=2,dim
317
IF ( ABS(RotVec(k)) > ABS(RotVec(kmax)) ) THEN
318
kmax = k
319
END IF
320
END DO
321
Sol%Values(DOFs*(Perm(NodeIndexes(j))-1) + kmax)=0._dp
322
!else set the given DOF
323
ELSE
324
Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp
325
END IF
326
327
ENDIF
328
END DO
329
330
ENDIF
331
332
END DO
333
ENDIF
334
END DO
335
336
! Go through the Body forces
337
Do t=1,Solver % NumberOfActiveElements
338
Element => GetActiveElement(t)
339
340
BF => GetBodyForce(Element)
341
IF (.NOT.ASSOCIATED( BF ) ) CYCLE
342
343
NodeIndexes => Element % NodeIndexes
344
n = Element % TYPE % NumberOfNodes
345
346
! set BC for DOFs=1 or applied to the whole vector
347
IF( ListCheckPresent( BF, DVarName ) ) THEN
348
Condition(1:n) = ListGetReal( BF, &
349
TRIM(DVarName) // ' Condition', n, NodeIndexes, Conditional )
350
DO j=1,n
351
IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE
352
DO i=1,DOFS
353
Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp
354
END DO
355
END DO
356
ENDIF
357
358
! Do the same for each component
359
IF (DOFs>1) THEN
360
DO i=1,DOFS
361
IF( ListCheckPresent( BF, ComponentName(DVarName,i)) ) THEN
362
Condition(1:n) = ListGetReal( BF, &
363
TRIM(ComponentName(DVarName,i)) // ' Condition', n, NodeIndexes, Conditional )
364
365
DO j=1,n
366
IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE
367
Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp
368
END DO
369
END IF
370
END DO
371
END IF
372
373
END DO
374
375
! Back Rotate to model coordinate system
376
CALL BackRotateNTSystem(Sol%Values,Perm,DOFs)
377
378
! reset Dimension to DIM
379
IF (DIM.eq.(DOFs+1)) CurrentModel % Dimension = DIM
380
381
RETURN
382
!------------------------------------------------------------------------------
383
END SUBROUTINE Adjoint_LinearSolver
384
!------------------------------------------------------------------------------
385
386
387