Path: blob/devel/elmerice/Solvers/Adjoint/Adjoint_CostRegSolver.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 2020; Adapted from AdjointSSA_CostRegSolver29! *30! *****************************************************************************31SUBROUTINE Adjoint_CostRegSolver_init0(Model,Solver,dt,TransientSimulation )32!------------------------------------------------------------------------------33USE DefUtils34IMPLICIT NONE35!------------------------------------------------------------------------------36TYPE(Solver_t), TARGET :: Solver37TYPE(Model_t) :: Model38REAL(KIND=dp) :: dt39LOGICAL :: TransientSimulation40!------------------------------------------------------------------------------41! Local variables42!------------------------------------------------------------------------------43CHARACTER(LEN=MAX_NAME_LEN) :: Name4445Name = ListGetString( Solver % Values, 'Equation',UnFoundFatal=.TRUE.)46CALL ListAddNewString( Solver % Values,'Variable',&47'-nooutput '//TRIM(Name)//'_var')48CALL ListAddLogical(Solver % Values, 'Optimize Bandwidth',.FALSE.)49CALL ListAddInteger(Solver % Values, 'Nonlinear System Norm Degree',0)50END SUBROUTINE Adjoint_CostRegSolver_init051! *****************************************************************************52SUBROUTINE Adjoint_CostRegSolver( Model,Solver,dt,TransientSimulation )53!------------------------------------------------------------------------------54!******************************************************************************55!56! Compute a regularisation term and update the57! gradient of the cost function with respect to the regularized variable.58!59! Regularisation by default is: int_{Pb dimension} 0.5 * (d(var)/dx)**260! A priori regularisation can also be used ( A priori Regularisation=True) :61! int_{Pb dimension} 0.5 *(1/sigma**2)*(var-var{a_priori})**262!63! OUTPUT are : J and DJDvar64!65!66! !!!!! BE careful it will reset Cost and DJ to 0 by default !!!!67! !!! If other cost and gradient are computed before (i.e. from the adjoint pb,68! use "<Reset Cost Value> = False" to add cost and gradient to previously computed values !!!69!70!71! Required Sif parameters are:72!73! In the solver section:74! Cost Filename=File (default: CostOfT.dat),75! Optimized Variable Name= String (default='Beta'),76! Gradient Variable Name= String (default = 'DJDBeta'),77! Cost Variable Name= String (default='Cost Value'),78! Lambda= Real (default 1.0),79! Reset Cost Value= Logical (default = True),80! A priori Regularisation= Logical (default = .False.),81!82! In Body Force section:83! <VarSolName> a priori value = Real (default =0.0),84! <VarSolName> variance = real (default=1.0)85!86!87!******************************************************************************88USE DefUtils89IMPLICIT NONE90!------------------------------------------------------------------------------91TYPE(Solver_t) :: Solver92TYPE(Model_t) :: Model9394REAL(KIND=dp) :: dt95LOGICAL :: TransientSimulation96!97CHARACTER(LEN=MAX_NAME_LEN) :: SolverName='Adjoint_CostRegSolver'98CHARACTER(LEN=MAX_NAME_LEN), PARAMETER :: DefaultCostFile = 'CostOfT.dat'99CHARACTER(LEN=MAX_NAME_LEN) :: CostFile100CHARACTER(LEN=MAX_NAME_LEN) :: CostSolName,VarSolName,GradSolName,varname101102TYPE(Variable_t), POINTER :: TimeVar,CostVar103104TYPE(Variable_t), POINTER :: Variable,DJDVariable105REAL(KIND=dp), POINTER :: Values(:),DJDValues(:)106INTEGER, POINTER :: Perm(:),DJDPerm(:)107108TYPE(ValueList_t), POINTER :: SolverParams,BodyForce109110TYPE(Element_t),POINTER :: Element111TYPE(Nodes_t),SAVE :: ElementNodes112TYPE(GaussIntegrationPoints_t) :: IntegStuff113REAL(KIND=dp),ALLOCATABLE,SAVE :: Basis(:), dBasisdx(:,:)114INTEGER, POINTER :: NodeIndexes(:)115116LOGICAL, SAVE :: Firsttime=.true.,Parallel117LOGICAL :: Found,stat,Gotit118LOGICAL :: BoundarySolver119integer :: i,j,k,l,t,n,NMAX,DIM,ierr,c120121real(kind=dp) :: Cost,Cost_S,Lambda122real(kind=dp) :: Area,Area_S123real(kind=dp) :: u,v,w,s,coeff_reg,SqrtElementMetric,x124125REAL(KIND=dp),dimension(:),allocatable,SAVE :: NodeAp,NodeRMS,NodalRegb126REAL(KIND=dp),dimension(:),allocatable,SAVE :: NodeValues,NodalDer,NodalGrad127REAL(KIND=dp) :: IPerr,IPvar128129LOGICAL :: Apriori,Reset130LOGICAL :: HaveNodalVariable131LOGICAL :: HaveDer132133CHARACTER*10 :: date,temps134135136SolverParams => GetSolverParams()137138!! check if we are on a boundary or in the bulk139IF(ASSOCIATED(Solver % ActiveElements)) THEN140BoundarySolver = ( Solver % ActiveElements(1) > Model % Mesh % NumberOfBulkElements )141ELSE142BoundarySolver = .TRUE. ! must be true for other parts if no elements present143! if not boundarysolver would have active elements144END IF145146IF (BoundarySolver) THEN147DIM = CoordinateSystemDimension() - 1148ELSE149DIM = CoordinateSystemDimension()150ENDIF151152! get some needed solver parameters153!! Cost File for Output154CostFile = ListGetString(Solver % Values,'Cost Filename',Found )155IF (.NOT. Found) CostFile = DefaultCostFile156157!! Name of the variable to regularise158VarSolName = ListGetString( SolverParams,'Optimized Variable Name', Found=HaveNodalVariable)159160!! Name of the variable to regularise161GradSolName = ListGetString( SolverParams,'Gradient Variable Name', UnFoundFatal=.TRUE.)162!! Name of the variable with the cost function163CostSolName = ListGetString( SolverParams,'Cost Variable Name', Found )164IF(.NOT.Found) THEN165CALL WARN(SolverName,'Keyword >CostSolName< not found in section >Solver<')166CALL WARN(SolverName,'Taking default value CostValue')167CostSolName='CostValue'168End if169170!! Optional weighting term171Lambda = GetConstReal( SolverParams,'Lambda', Found)172IF(.NOT.Found) THEN173CALL WARN(SolverName,'Keyword >Lambda< not found in section >Solver<')174CALL WARN(SolverName,'Taking default value Lambda=1.0')175Lambda = 1.0176End if177178!! Do we need to reset cost and DJDVar to 0? Default YES179Reset = GetLogical( SolverParams,'Reset Cost Value', Found)180IF(.NOT.Found) Reset=.True.181182!! What type of regularistaion ? Default penalise 1st derivative183Apriori = GetLogical( SolverParams,'A priori Regularisation', Found)184IF(.NOT.Found) Apriori=.False.185186!!! SOME INITIALISATION AT FIRST TIME187If (Firsttime) then188N = model % MaxElementNodes189allocate(ElementNodes % x(N), ElementNodes % y(N), ElementNodes % z(N))190allocate(Basis(N),dBasisdx(N,3))191allocate(NodeAp(N),NodeRMS(N),NodeValues(N),NodalRegb(N),NodalDer(N),NodalGrad(N))192193!!!!!!! Check for parallel run194!Parallel = .FALSE.195!IF ( ASSOCIATED( Solver % Matrix % ParMatrix ) ) THEN196! IF ( Solver % Matrix % ParMatrix % ParEnv % PEs > 1 ) THEN197! Parallel = .TRUE.198! END IF199!END IF200Parallel = ParEnv % PEs > 1201202!!!!!!!!!!! initiate Cost File203204CALL DATE_AND_TIME(date,temps)205If (Parallel) then206if (ParEnv % MyPe.EQ.0) then207OPEN (12, FILE=CostFile)208write(12,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)209write(12,1001) Lambda210write(12,'(A)') '# iter, Jreg,sqrt(2*Jreg/area)'211CLOSE(12)212End if213Else214OPEN (12, FILE=CostFile)215write(12,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)216write(12,1001) Lambda217write(12,'(A)') '# iter, Jreg,sqrt(2*Jreg/area)'218CLOSE(12)219End if220221!!! End of First visit222Firsttime=.false.223Endif224!!!! INITIALISATION DONE225IF (HaveNodalVariable) THEN226Variable => VariableGet( Solver % Mesh % Variables, VarSolName , UnFoundFatal=.TRUE.)227Values => Variable % Values228Perm => Variable % Perm229END IF230231DJDVariable => VariableGet( Solver % Mesh % Variables, GradSolName , UnFoundFatal=.TRUE. )232DJDValues => DJDVariable % Values233DJDPerm => DJDVariable % Perm234IF (Reset) DJDValues=0.0_dp235236Cost=0._dp237Area=0._dp238239DO t=1,Solver % NumberOfActiveElements240Element => GetActiveElement(t)241IF (CheckPassiveElement(Element)) THEN242CYCLE243END IF244BodyForce => GetBodyForce(Element)245IF (.NOT.ASSOCIATED(BodyForce)) THEN246IF (Apriori.OR.(.NOT.HaveNodalVariable)) &247CALL FATAL(SolverName,'Body force should be associated for this regularisation')248ENDIF249250n = GetElementNOFNodes()251252NodeIndexes => Element % NodeIndexes253254! set coords of highest occurring dimension to zero (to get correct path element)255!-------------------------------------------------------------------------------256ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)257SELECT CASE (DIM)258CASE (1)259ElementNodes % y(1:n) = 0.0_dp260ElementNodes % z(1:n) = 0.0_dp261CASE (2)262ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)263ElementNodes % z(1:n) = 0.0_dp264CASE (3)265ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)266ElementNodes % z(1:n) = Solver % Mesh % Nodes % z(NodeIndexes)267END SELECT268269! Compute integrated cost270IF (Apriori) then271NodeAp(1:n) = ListGetReal( BodyForce, 'CostReg Nodal Prior', n, NodeIndexes, GotIt)272IF (.NOT.GotIt) Then273CALL WARN(SolverName,'No value for the prior found in <Body Force>, default is 0')274NodeAp(1:n) = 0._dp275END IF276NodeRMS(1:n)=ListGetReal( BodyForce,'CostReg Nodal std', n, NodeIndexes, GotIt)277IF (.NOT.GotIt) Then278CALL WARN(SolverName,'No value for the standard deviation found in <Body Force>, default is 1')279NodeRMS=1.0_dp280END IF281END IF282283! Nodal values of the variable284IF (HaveNodalVariable) THEN285NodeValues(1:n)=Values(Perm(NodeIndexes(1:n)))286HaveDer=.FALSE.287ELSE288NodeValues(1:n)=ListGetReal( BodyForce,'CostReg Nodal Variable',n, NodeIndexes, UnFoundFatal=.TRUE.)289NodalDer(1:n) = ListGetReal( BodyForce,'CostReg Nodal Variable derivative',n,NodeIndexes,Found=HaveDer)290END IF291292!------------------------------------------------------------------------------293! Numerical integration294!------------------------------------------------------------------------------295NodalRegb = 0.0_dp296297IntegStuff = GaussPoints( Element )298299DO i=1,IntegStuff % n300U = IntegStuff % u(i)301V = IntegStuff % v(i)302W = IntegStuff % w(i)303!------------------------------------------------------------------------------304! Basis function values & derivatives at the integration point305!------------------------------------------------------------------------------306stat = ElementInfo( Element,ElementNodes,U,V,W,SqrtElementMetric, &307Basis,dBasisdx )308309x = SUM( ElementNodes % x(1:n) * Basis(1:n) )310s = 1.0d0311312IF ( CurrentCoordinateSystem() /= Cartesian ) THEN313s = 2.0d0 * PI * x314END IF315s = s * SqrtElementMetric * IntegStuff % s(i)316317318319IF (Apriori) then320IPerr = SUM((NodeValues(1:n)-NodeAp(1:n))*Basis(1:n))321IPvar = SUM(NodeRMS(1:n)*Basis(1:n))322coeff_reg=IPerr/IPvar323coeff_reg = 0.5*coeff_reg*coeff_reg324325IF (HaveDer) THEN326NodalGrad(1:n)=Basis(1:n)*NodalDer(1:n)327ELSE328NodalGrad(1:n)=Basis(1:n)329ENDIF330331!Now compute the derivative332NodalRegb(1:n)=NodalRegb(1:n)+&333s*Lambda*IPerr*NodalGrad(1:n)/(IPVar**2.0)334Else335coeff_reg=0._dp336DO k=1,DIM337coeff_reg = coeff_reg + 0.5*SUM(NodeValues(1:n) * dBasisdx(1:n,k))**2338END DO339340!Now compute the derivative341DO k=1,DIM342343IF (HaveDer) THEN344NodalGrad(1:n)=dBasisdx(1:n,k)*NodalDer(1:n)345ELSE346NodalGrad(1:n)=dBasisdx(1:n,k)347ENDIF348349NodalRegb(1:n)=NodalRegb(1:n)+&350s*Lambda*(SUM(dBasisdx(1:n,k)*NodeValues(1:n))*NodalGrad(1:n))351END DO352Endif353354Cost=Cost+coeff_reg*s355Area=Area+s356357End do !IP358359DJDValues(DJDPerm(NodeIndexes(1:n)))=DJDValues(DJDPerm(NodeIndexes(1:n))) + NodalRegb(1:n)360361End do !Elements362363TimeVar => VariableGet( Solver % Mesh % Variables, 'Time' )364365IF (Parallel) THEN366CALL MPI_ALLREDUCE(Cost,Cost_S,1,&367MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)368CALL MPI_ALLREDUCE(Area,Area_S,1,&369MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)370CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )371IF (ASSOCIATED(CostVar)) THEN372IF (Reset) then373CostVar % Values(1)=Lambda*Cost_S374Else375CostVar % Values(1)=CostVar % Values(1)+Lambda*Cost_S376Endif377END IF378IF (ParEnv % MyPE == 0) then379OPEN (12, FILE=CostFile,POSITION='APPEND')380write(12,'(3(ES20.11E3))') TimeVar % Values(1),Cost_S,sqrt(2*Cost_S/Area_S)381CLOSE(12)382End if383ELSE384CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )385IF (ASSOCIATED(CostVar)) THEN386IF (Reset) then387CostVar % Values(1)=Lambda*Cost388Else389CostVar % Values(1)=CostVar % Values(1)+Lambda*Cost390Endif391END IF392OPEN (12, FILE=CostFile,POSITION='APPEND')393write(12,'(3(ES20.11E3))') TimeVar % Values(1),Cost,sqrt(2*Cost/Area)394close(12)395Cost_S=Cost396END IF397398Solver % Variable % Values(1)=Cost_S399400Return4014021000 format('#date,time,',a2,'/',a2,'/',a4,',',a2,':',a2,':',a2)4031001 format('#lambda,',e15.8)404!------------------------------------------------------------------------------405END SUBROUTINE Adjoint_CostRegSolver406!------------------------------------------------------------------------------407! *****************************************************************************408409410