Path: blob/devel/elmerice/Solvers/Adjoint/Adjoint_LinearSolver.F90
3206 views
!/*****************************************************************************/1! *2! * Elmer/Ice, a glaciological add-on to Elmer3! * http://elmerice.elmerfem.org4! *5! *6! * This program is free software; you can redistribute it and/or7! * modify it under the terms of the GNU General Public License8! * as published by the Free Software Foundation; either version 29! * of the License, or (at your option) any later version.10! *11! * This program is distributed in the hope that it will be useful,12! * but WITHOUT ANY WARRANTY; without even the implied warranty of13! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14! * GNU General Public License for more details.15! *16! * You should have received a copy of the GNU General Public License17! * along with this program (in file fem/GPL-2); if not, write to the18! * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19! * Boston, MA 02110-1301, USA.20! *21! *****************************************************************************/22! ******************************************************************************23! *24! * Authors: f. Gillet-Chaulet (IGE-Grenoble/France)25! * Email:26! * Web: http://elmerice.elmerfem.org27! *28! * Original Date:29! *30! *****************************************************************************31!------------------------------------------------------------------------------32SUBROUTINE Adjoint_LinearSolver( Model,Solver,dt,TransientSimulation )33!------------------------------------------------------------------------------34!> Compute the adjoint of the linear Solver and dirichlet conditions.35!36! OUTPUT is : Solver % Variable the adjoint variable37!38! INPUT PARAMETERS are:39!40! In solver section:41! Direct Equation Name = String42!43! Variables:44! VarName_b45!46!******************************************************************************47! ARGUMENTS:48!49! TYPE(Model_t) :: Model,50! INPUT: All model information (mesh, materials, BCs, etc...)51!52! TYPE(Solver_t) :: Solver53! INPUT: Linear & nonlinear equation solver options54!55! REAL(KIND=dp) :: dt,56! INPUT: Timestep size for time dependent simulations57!58! LOGICAL :: TransientSimulation59! INPUT: Steady state or transient simulation60!61!******************************************************************************62USE DefUtils63IMPLICIT NONE64!------------------------------------------------------------------------------65TYPE(Solver_t) :: Solver66TYPE(Model_t) :: Model67REAL(KIND=dp) :: dt68LOGICAL :: TransientSimulation69!------------------------------------------------------------------------------70! Local variables71!------------------------------------------------------------------------------72TYPE(Solver_t),Pointer :: DSolver ! Pointer to the Direct Solver73TYPE(Variable_t), POINTER :: Sol ! Solution Variable74INTEGER :: DOFs7576TYPE(Matrix_t),POINTER :: InitMat,TransMat,StiffMatrix77REAL(KIND=dp),POINTER :: ForceVector(:)78INTEGER, POINTER :: Perm(:)7980TYPE(ValueList_t),POINTER :: BC,BF,SolverParams81TYPE(Element_t),POINTER :: Element82INTEGER, POINTER :: NodeIndexes(:)8384! Variables related to the frocing85TYPE(Variable_t), POINTER :: VbSol86REAL(KIND=dp), POINTER :: Vb(:)87INTEGER, POINTER :: VbPerm(:)8889integer :: i,j,k,t,n90INTEGER :: kmax91Logical :: Gotit92integer :: p,q,dim,c,m93Real(KIND=dp) :: Unorm94Real(KIND=dp) :: RotVec(3)9596! Var related to Normal-Tangential stuff and Dirchlet BCs97TYPE(ValueListEntry_t),POINTER :: NormalTangential,NormalTangentialC98REAL(KIND=dp), POINTER :: BoundaryNormals(:,:)=> NULL(), &99BoundaryTangent1(:,:)=> NULL(), &100BoundaryTangent2(:,:)=> NULL()101REAL(KIND=dp),ALLOCATABLE,SAVE :: Condition(:)102INTEGER, POINTER,SAVE :: BoundaryReorder(:)=> NULL()103INTEGER,SAVE :: NormalTangentialNOFNodes104CHARACTER(LEN=MAX_NAME_LEN),SAVE :: NormalTangentialName,NormalTangentialNameb105LOGICAL :: AnyNT106LOGICAL :: Conditional,CheckNT107108CHARACTER(LEN=MAX_NAME_LEN),SAVE :: SolverName="Adjoint Solver" ! SolverName for messages109CHARACTER(LEN=MAX_NAME_LEN) :: DEqName ! Equation Name of Direct Solver110CHARACTER(LEN=MAX_NAME_LEN) :: DVarName ! Var Name of The Direct Solver111CHARACTER(LEN=MAX_NAME_LEN) :: FVarName ! Sensitivity Var Name (velocityb or DVarNameb)112INTEGER, SAVE :: SolverInd ! Indice of the direct solver in the solver list113LOGICAL, SAVE :: Firsttime=.TRUE.114115116StiffMatrix => Solver % Matrix117ForceVector => StiffMatrix % RHS118119Sol => Solver % Variable120DOFs = Sol % DOFs121Perm => Sol % Perm122123DIM = CoordinateSystemDimension()124! IF DIM = 3 and DOFs=2; e.g. solving SSA on a 3D mesh125!Normal-Tangential can not be used => trick temporary set Model Dimension to 2126IF (DIM.eq.(DOFs+1)) CurrentModel % Dimension = DOFs127128IF (Firsttime) then129Firsttime=.False.130131N = Model % MaxElementNodes132ALLOCATE(Condition(N))133134! Get solver associated to the direct problem135SolverParams => GetSolverParams(Solver)136DEqName = ListGetString( SolverParams,'Direct Solver Equation Name',UnFoundFatal=.TRUE.)137DO i=1,Model % NumberOfSolvers138if (TRIM(DEqName) == ListGetString(Model % Solvers(i) % Values, 'Equation')) exit139End do140if (i.eq.(Model % NumberOfSolvers+1)) &141CALL FATAL(SolverName,'Could not find Equation Name ' // TRIM(DEqName))142SolverInd=i143DSolver => Model % Solvers(SolverInd)144145!# Check For NT boundaries146IF (DOFs>1) THEN147NormalTangentialName = 'normal-tangential'148IF ( SEQL(DSolver % Variable % Name, 'flow solution') ) THEN149NormalTangentialName = TRIM(NormalTangentialName) // ' velocity'150ELSE151NormalTangentialName = TRIM(NormalTangentialName) // ' ' // &152GetVarName(DSolver % Variable)153END IF154155AnyNT = ListGetLogicalAnyBC( Model, TRIM(NormalTangentialName) )156IF (AnyNT) THEN157158!# We will stay in NT to impose dirichlet conditions159CALL ListAddLogical(SolverParams,'Back Rotate N-T Solution',.FALSE.)160161!# !!! Has to be in lower case to copy item162NormalTangentialNameb='normal-tangential' // ' ' // GetVarName(Solver % Variable)163164DO i=1,Model % NumberOfBCs165BC => Model % BCs(i) % Values166NormalTangential => ListFind( BC , NormalTangentialName , GotIt )167IF (.NOT.Gotit) CYCLE168169WRITE(Message,'(A,I0)') 'Copy Normal-Tangential keyword in BC ',i170CALL Info(SolverName,Message,level=4)171CALL ListCopyItem( NormalTangential, BC, NormalTangentialNameb)172173NormalTangentialC => ListFind( BC , TRIM(NormalTangentialName) // ' condition' , GotIt )174IF (.NOT.Gotit) CYCLE175176WRITE(Message,'(A,I0)') 'Copy Normal-Tangential Condition keyword in BC ',i177CALL Info(SolverName,Message,level=4)178CALL ListCopyItem( NormalTangentialC, BC, TRIM(NormalTangentialNameb) // ' condition' )179END DO180181CALL CheckNormalTangentialBoundary( Model, TRIM(NormalTangentialNameb), &182NormalTangentialNOFNodes, BoundaryReorder, &183BoundaryNormals, BoundaryTangent1, BoundaryTangent2, dim )184185END IF186END IF187END IF188189! Get Matrix from the Direct Solver190DSolver => Model % Solvers(SolverInd)191192IF ( SEQL(DSolver % Variable % Name, 'flow solution') ) THEN193DVarName = 'Velocity'194ELSE195DVarName = GetVarName(DSolver % Variable)196END IF197198CALL DefaultInitialize()199200InitMat => AllocateMatrix()201InitMat % NumberOfRows = DSolver % Matrix % NumberOfRows202InitMat % Values => DSolver % Matrix % Values203InitMat % Rows => DSolver % Matrix % Rows204InitMat % Cols => DSolver % Matrix % Cols205InitMat % Diag => DSolver % Matrix % Diag206207IF ( SEQL(DVarName,'velocity').OR.SEQL(DVarName,'ssavelocity')) THEN208FVarName = 'Velocityb'209ELSE210FVarName = TRIM(DVarName) // 'b'211ENDIF212VbSol => VariableGet( Solver % Mesh % Variables, TRIM(FVarName),UnFoundFatal=.TRUE. )213Vb => VbSol % Values214VbPerm => VbSol % Perm215IF (VbSol % DOFs.NE.DOFs) then216WRITE(Message,'(A,I1,A,I1)') &217'Variable Vb has ',VbSol % DOFs,' DOFs, should be',DOFs218CALL FATAL(SolverName,Message)219END IF220221TransMat => NULL()222TransMat => CRS_Transpose(InitMat)223224NULLIFY( InitMat % Rows, InitMat % Cols, InitMat % Diag, InitMat % Values )225CALL FreeMatrix( InitMat )226227CALL CRS_SortMatrix( TransMat , .true. )228229StiffMatrix % Values = TransMat % Values230StiffMatrix % Rows = TransMat % Rows231StiffMatrix % Cols = TransMat % Cols232IF(ASSOCIATED(TransMat % Diag)) StiffMatrix % Diag = TransMat % Diag233ForceVector = 0.0234Perm = DSolver % Variable % Perm235236deallocate( TransMat % Rows, TransMat % Cols , TransMat % Values)237IF(ASSOCIATED(TransMat % Diag)) DEALLOCATE(TransMat % Diag)238nullify(TransMat)239240!forcing of the adjoint system comes from the Vb variable computed241!with the cost function242243!! Vb is expressed in the model coordinate system => Rotate to NT244CALL RotateNTSystemAll( Vb, VbPerm, DOFs )245246c = DOFs247Do t=1,Solver%Mesh%NumberOfNodes248Do i=1,c249p=(Perm(t)-1)*c+i250q=(VbPerm(t)-1)*c+i251ForceVector(p)=Vb(q)252End Do253EndDo254255CALL FinishAssembly( Solver, ForceVector )256257Unorm = DefaultSolve()258259! Go through BC to check if dirichlet was applied to direct solver260! Go to the boundary elements261Do t=1,GetNOFBoundaryElements()262Element => GetBoundaryElement(t)263BC => GetBC(Element)264IF (.NOT.ASSOCIATED( BC ) ) CYCLE265266NodeIndexes => Element % NodeIndexes267n = Element % TYPE % NumberOfNodes268269! Cf correspond lines in SolverUtils270! Check for nodes belonging to n-t boundary getting set by other bcs.271! -------------------------------------------------------------------272CheckNT = .FALSE.273IF ( NormalTangentialNOFNodes>0 .AND. DOFs>0 ) THEN274CheckNT = .TRUE.275IF ( ALL(BoundaryReorder(NodeIndexes(1:n))<1) ) CheckNT = .FALSE.276IF ( ListGetLogical(BC,'normal-tangential' // ' ' // DVarName,Gotit)) CheckNT=.FALSE.277END IF278279! set BC for DOFs=1 or applied to the whole vector280IF( ListCheckPresent( BC, DVarName ) ) THEN281Condition(1:n) = ListGetReal( BC, &282TRIM(DVarName) // ' Condition', n, NodeIndexes, Conditional )283DO j=1,n284IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE285DO i=1,DOFS286Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp287END DO288END DO289ENDIF290291! Do the same for each component292IF (DOFs>1) THEN293DO i=1,DOFS294IF( ListCheckPresent( BC, ComponentName(DVarName,i)) ) THEN295Condition(1:n) = ListGetReal( BC, &296TRIM(ComponentName(DVarName,i)) // ' Condition', n, NodeIndexes, Conditional )297298DO j=1,n299IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE300301k = Perm(NodeIndexes(j))302IF ( k > 0 ) THEN303304m = 0305IF ( NormalTangentialNOFNodes>0 ) m=BoundaryReorder(NodeIndexes(j))306!! set in the NT system307IF ( m>0 .AND. CheckNT ) THEN308RotVec = 0._dp309RotVec(i) = 1._dp310CALL RotateNTSystem( RotVec, NodeIndexes(j) )311312! When cartesian component "DOF" is defined set the N-T component313! closest to its direction.314kmax = 1315DO k=2,dim316IF ( ABS(RotVec(k)) > ABS(RotVec(kmax)) ) THEN317kmax = k318END IF319END DO320Sol%Values(DOFs*(Perm(NodeIndexes(j))-1) + kmax)=0._dp321!else set the given DOF322ELSE323Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp324END IF325326ENDIF327END DO328329ENDIF330331END DO332ENDIF333END DO334335! Go through the Body forces336Do t=1,Solver % NumberOfActiveElements337Element => GetActiveElement(t)338339BF => GetBodyForce(Element)340IF (.NOT.ASSOCIATED( BF ) ) CYCLE341342NodeIndexes => Element % NodeIndexes343n = Element % TYPE % NumberOfNodes344345! set BC for DOFs=1 or applied to the whole vector346IF( ListCheckPresent( BF, DVarName ) ) THEN347Condition(1:n) = ListGetReal( BF, &348TRIM(DVarName) // ' Condition', n, NodeIndexes, Conditional )349DO j=1,n350IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE351DO i=1,DOFS352Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp353END DO354END DO355ENDIF356357! Do the same for each component358IF (DOFs>1) THEN359DO i=1,DOFS360IF( ListCheckPresent( BF, ComponentName(DVarName,i)) ) THEN361Condition(1:n) = ListGetReal( BF, &362TRIM(ComponentName(DVarName,i)) // ' Condition', n, NodeIndexes, Conditional )363364DO j=1,n365IF ( Conditional .AND. Condition(j)<0._dp ) CYCLE366Sol%Values(DOFs*(Perm(NodeIndexes(j))-1)+i)=0._dp367END DO368END IF369END DO370END IF371372END DO373374! Back Rotate to model coordinate system375CALL BackRotateNTSystem(Sol%Values,Perm,DOFs)376377! reset Dimension to DIM378IF (DIM.eq.(DOFs+1)) CurrentModel % Dimension = DIM379380RETURN381!------------------------------------------------------------------------------382END SUBROUTINE Adjoint_LinearSolver383!------------------------------------------------------------------------------384385386387