Path: blob/devel/elmerice/Solvers/Adjoint/Adjoint_GradientValidation.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: April 202029! *30! *****************************************************************************31SUBROUTINE Adjoint_GradientValidation_init0(Model,Solver,dt,TransientSimulation )32!------------------------------------------------------------------------------33USE DefUtils34IMPLICIT NONE35!------------------------------------------------------------------------------36TYPE(Solver_t), TARGET :: Solver37TYPE(Model_t) :: Model38REAL(KIND=dp) :: dt39LOGICAL :: TransientSimulation40!------------------------------------------------------------------------------41!------------------------------------------------------------------------------42! Local variables43!------------------------------------------------------------------------------44CHARACTER(LEN=MAX_NAME_LEN) :: Name4546Name = ListGetString( Solver % Values, 'Equation',UnFoundFatal=.TRUE.)47CALL ListAddNewString( Solver % Values,'Variable',&48'-nooutput '//TRIM(Name)//'_var')49CALL ListAddLogical(Solver % Values, 'Optimize Bandwidth',.FALSE.)50CALL ListAddInteger(Solver % Values, 'Nonlinear System Norm Degree',0)51END SUBROUTINE Adjoint_GradientValidation_init052! *****************************************************************************53SUBROUTINE Adjoint_GradientValidation ( Model,Solver,dt,TransientSimulation )54! *****************************************************************************55! Compare the total derivative of the cost function computed as:56! (1) dJ=P.G where P is a perturbation vector of the variable of interest57! G is the gradient of the cost function computed by an inverse method58! (2) [J(V+hP)-J(V)]/h : forward finite difference computation of the derivative59! V is the variable of interest60! h is the step size61!62!63! Compute (1) from at the first iteration and update V=Vini+hP, h=164! Compute (2) for all the other iteration with h^i+1=h^i/265!66! Serial/parallel 2D/3D67!68! Keyword in Solver section of the .sif:69! Cost Variable Name70! Optimized Variable Name71! Perturbed Variable Name !optional: take -g if not given72! Gradient Variable Name73! Result File74!75! Output: in result File: h , abs((1)-(2))/(1) , (1), (2)76!77!78!------------------------------------------------------------------------------79!******************************************************************************80USE DefUtils81IMPLICIT NONE82!------------------------------------------------------------------------------83TYPE(Solver_t) :: Solver84TYPE(Model_t) :: Model8586REAL(KIND=dp) :: dt87LOGICAL :: TransientSimulation88!89CHARACTER(LEN=MAX_NAME_LEN) :: SolverName90TYPE(Element_t),POINTER :: Element91TYPE(ValueList_t), POINTER :: SolverParams92TYPE(Variable_t), POINTER :: Var,PVar,CostVar,GradVar93REAL(KIND=dp), POINTER :: Values(:),PValues(:),CostValues(:),GradValues(:)94INTEGER, POINTER :: Perm(:),PPerm(:),GradPerm(:)95INTEGER, POINTER :: NodeIndexes(:)9697REAL(KIND=dp),allocatable :: x(:),xp(:),g(:)98REAL(KIND=dp) :: J,J0,h,dJ,dJd99100integer :: i,c,t,n,NMAX,NActiveNodes101integer :: ierr102integer,allocatable :: ActiveNodes(:)103integer,allocatable :: NewNode(:)104integer,parameter :: io=20105integer :: MyPe=-1106integer,SAVE :: DOFs107108Logical :: FirstVisit=.true.,Found,UnFoundFatal=.TRUE.109Logical :: Parallel110Logical :: haveP111logical,allocatable :: VisitedNode(:)112113CHARACTER(LEN=MAX_NAME_LEN) :: CostSolName,VarSolName,GradSolName,PSolName,ResultFile114CHARACTER*10 :: date,temps115116!117save FirstVisit118save SolverName119save CostSolName,VarSolName,GradSolName,ResultFile120save ActiveNodes,NActiveNodes121save x,xp122save J0,h,dJ123save MyPe124save Parallel125126127! Read Constant from sif solver section128IF(FirstVisit) Then129130WRITE(SolverName, '(A)') 'GradientValidation'131132! Check we have a parallel run133Parallel = .FALSE.134IF(ASSOCIATED(Solver % Matrix % ParMatrix)) Then135IF ( Solver % Matrix % ParMatrix % ParEnv % PEs > 1 ) Parallel =.True.136MyPe=ParEnv % MyPe137End if138139140SolverParams => GetSolverParams()141142CostSolName = ListGetString( SolverParams,'Cost Variable Name', UnFoundFatal=.TRUE.)143CostVar => VariableGet( Solver % Mesh % Variables, CostSolName,UnFoundFatal=UnFoundFatal)144CostValues => CostVar % Values145146VarSolName = ListGetString( SolverParams,'Optimized Variable Name', UnFoundFatal=.TRUE.)147Var => VariableGet( Solver % Mesh % Variables, VarSolName,UnFoundFatal=UnFoundFatal)148Values => Var % Values149Perm => Var % Perm150DOFs = Var % DOFs151152GradSolName = ListGetString( SolverParams,'Gradient Variable Name', UnFoundFatal=.TRUE.)153GradVar => VariableGet( Solver % Mesh % Variables, GradSolName,UnFoundFatal=UnFoundFatal)154GradValues => GradVar % Values155GradPerm => GradVar % Perm156IF (GradVar%DOFs.NE.DOFs) &157CALL FATAL(SolverName,'DOFs not corresponding for Gradient Variable')158159PSolName = ListGetString( SolverParams,'Perturbation Variable Name', Found=HaveP)160IF (HAVEP) THEN161PVar => VariableGet( Solver % Mesh % Variables, PSolName,UnFoundFatal=UnFoundFatal)162PValues => PVar % Values163PPerm => PVar % Perm164IF (PVar%DOFs.NE.DOFs) &165CALL FATAL(SolverName,'DOFs not corresponding for Perturbation Variable')166ENDIF167168!!!!!!!!!!!!find active nodes169NMAX=Solver % Mesh % NumberOfNodes170allocate(VisitedNode(NMAX),NewNode(NMAX))171VisitedNode=.false.172NewNode=-1173174NActiveNodes=0175DO t=1,Solver % NumberOfActiveElements176Element => GetActiveElement(t)177n = GetElementNOFNodes()178NodeIndexes => Element % NodeIndexes179Do i=1,n180if (VisitedNode(NodeIndexes(i))) then181cycle182else183VisitedNode(NodeIndexes(i))=.true.184NActiveNodes=NActiveNodes+1185NewNode(NActiveNodes)=NodeIndexes(i)186endif187End do188End do189190if (NActiveNodes.eq.0) THEN191WRITE(Message,'(A)') 'NActiveNodes = 0 !!!'192CALL FATAL(SolverName,Message)193End if194195allocate(ActiveNodes(NActiveNodes),x(DOFS*NActiveNodes),xp(DOFs*NActiveNodes),g(DOFs*NActiveNodes))196ActiveNodes(1:NActiveNodes)=NewNode(1:NActiveNodes)197198deallocate(VisitedNode,NewNode)199200!!!!!!! Solver Params201202203ResultFile=GetString( SolverParams,'Result File',Found)204IF(Found) Then205IF ((Parallel.AND.(MyPe.EQ.0)).OR.(.NOT.Parallel)) Then206open(io,file=trim(ResultFile))207CALL DATE_AND_TIME(date,temps)208write(io,'(a1,a2,a1,a2,a1,a4,5x,a2,a1,a2,a1,a2)')'#',date(5:6),'/',date(7:8),'/',date(1:4), &209temps(1:2),':',temps(3:4),':',temps(5:6)210write(io,'(A)') '# step size, relative error, Adjoint total der., FD total der.'211close(io)212ENDIF213ELSE214CALL FATAL(SolverName,'Keyword <Result File> Not Found')215ENDIF216217!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!218DO i=1,NActiveNodes219DO c=1,DOFs220x(DOFs*(i-1)+c)=Values(DOFs*(Perm(ActiveNodes(i))-1)+c)221g(DOFs*(i-1)+c)=GradValues(DOFs *(GradPerm(ActiveNodes(i))-1)+c)222IF (HaveP) THEN223xp(DOFs*(i-1)+c)=PValues(DOFs*(PPerm(ActiveNodes(i))-1)+c)224ELSE225xp(DOFs*(i-1)+c)=-g(DOFs*(i-1)+c)226ENDIF227END DO228END DO229230!!!!!! total derivative from gradient231dJ=0._dp232dJ=SUM(xp(:)*g(:))233deallocate(g)234235IF (Parallel) THEN236CALL MPI_ALLREDUCE(dJ,dJ,1,&237MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD,ierr)238ENDIF239240!!!!! Store cost value at first iteration241J0=CostValues(1)242243!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!244!!! new values for x=x+h*xp245h=1.0_dp246Do i=1,NActiveNodes247Do c=1,DOFs248Values(DOFs*(Perm(ActiveNodes(i))-1)+c)=x(DOFs*(i-1)+c)+h*xp(DOFs*(i-1)+c)249End do250END DO251252253FirstVisit=.FALSE.254Return255End if256!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!257258CostVar => VariableGet( Solver % Mesh % Variables, CostSolName,UnFoundFatal=UnFoundFatal)259CostValues => CostVar % Values260261Var => VariableGet( Solver % Mesh % Variables, VarSolName,UnFoundFatal=UnFoundFatal)262Values => Var % Values263Perm => Var % Perm264265266J=CostValues(1)267268dJd=(J-J0)/h269270IF (Parallel) MyPe=ParEnv % MyPe271IF ((Parallel.AND.(MyPe.EQ.0)).OR.(.NOT.Parallel)) Then272open(io,file=trim(ResultFile),position='append')273write(io,'(4(e15.8,2x))') h,abs(dJ-dJd)/abs(dJ),dJ,dJd274close(io)275ENDIF276277h=h/2.0_dp278Do i=1,NActiveNodes279Do c=1,DOFs280Values(DOFs*(Perm(ActiveNodes(i))-1)+c)=x(DOFs*(i-1)+c)+h*xp(DOFs*(i-1)+c)281End do282END DO283284Return285!------------------------------------------------------------------------------286END SUBROUTINE Adjoint_GradientValidation287!------------------------------------------------------------------------------288289290291292