Path: blob/devel/elmerice/Solvers/Adjoint/Adjoint_CostDiscSolver.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! *****************************************************************************31SUBROUTINE Adjoint_CostDiscSolver_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.)4950CALL ListAddInteger(Solver % Values, 'Nonlinear System Norm Degree',0)5152END SUBROUTINE Adjoint_CostDiscSolver_init053!------------------------------------------------------------------------------54!------------------------------------------------------------------------------55SUBROUTINE Adjoint_CostDiscSolver( Model,Solver,dt,TransientSimulation )56!------------------------------------------------------------------------------57!------------------------------------------------------------------------------58! Discrete cost function evaluated as a sum of the differences at observations points59! See documentation under ELMER_SRC/elmerice/Solvers/Documentation/Adjoint_CostDiscSolver.md60!******************************************************************************61USE ParticleUtils62USE GeneralUtils63USE DefUtils64USE Interpolation65#ifdef HAVE_NETCDF66USE Netcdf67#endif68IMPLICIT NONE69!------------------------------------------------------------------------------70TYPE(Solver_t) :: Solver71TYPE(Model_t) :: Model72REAL(KIND=dp) :: dt73LOGICAL :: TransientSimulation74!75TYPE(Mesh_t),POINTER :: Mesh76TYPE(ValueList_t), POINTER :: SolverParams7778CHARACTER(LEN=MAX_NAME_LEN) :: SolverName="Adjoint_CostDiscSolver"79CHARACTER(LEN=MAX_NAME_LEN),SAVE :: CostSolName,VariableName80CHARACTER(LEN=MAX_NAME_LEN) :: FVarName81CHARACTER(LEN=MAX_NAME_LEN):: ObsFileName82CHARACTER(LEN=MAX_NAME_LEN):: SideFile,SideParFile83CHARACTER(LEN=MAX_NAME_LEN),SAVE :: CostFile84CHARACTER(:), ALLOCATABLE :: OutPutDirectory85CHARACTER(*), PARAMETER :: DefaultCostFile = 'CostOfT.dat'8687TYPE(Variable_t), POINTER :: TimeVar ! Time88TYPE(Variable_t), POINTER :: CostVar ! Cost Value89TYPE(Variable_t), POINTER :: Variable ! Active variable90TYPE(Variable_t), POINTER :: VbSol ! The sensitivity91REAL(KIND=dp), POINTER :: Vb(:),Values(:)92INTEGER, POINTER :: VbPerm(:),Perm(:)93INTEGER,SAVE :: VDOFs9495! Variable related to elements96TYPE(Element_t),POINTER :: Element97TYPE(Nodes_t),SAVE :: ElementNodes98INTEGER :: ElementIndex99INTEGER, POINTER :: NodeIndexes(:)100REAL(KIND=dp),ALLOCATABLE,SAVE :: Basis(:), dBasisdx(:,:)101REAL(KIND=dp) :: SqrtElementMetric102INTEGER :: n103LOGICAL :: stat104105LOGICAL,SAVE :: Firsttime=.true.,Parallel106LOGICAL,SAVE :: FirstRound=.True.107LOGICAL,SAVE :: SAVE_USED_DATA=.False.108LOGICAL,SAVE :: HaveSTD=.FALSE.109LOGICAL,SAVE :: CompNorm=.FALSE.110LOGICAL :: Found111LOGICAL :: ParallelFile,ProcessedFile,ActiveNumbering112113INTEGER :: CoordDIM ! Coordinate system dimension for the observations points114INTEGER,SAVE :: VarDIM ! Dimension of the observed Variable115REAL(KIND=dp),SAVE :: Lambda116117integer :: i,j,s118INTEGER :: k119real(kind=dp) :: StdMin120real(kind=dp) :: Cost,Cost_S121real(kind=dp) :: rms,rms_s122real(kind=dp) :: misfit123REAL(Kind=dp) :: VmNorm,VoNorm,StdNorm,VmNormb,um,umb124real(kind=dp) :: Coord(3),UVW(3)125REAL(KIND=dp) :: V(3)126INTEGER,SAVE :: NTOT=-1,NTOT_S127INTEGER :: AI128CHARACTER*10 :: date,temps129INTEGER,PARAMETER :: IO=12130INTEGER :: ok131LOGICAL :: WarnActive132LOGICAL :: BoundarySolver133134! Variables with obs.135REAL(KIND=dp),ALLOCATABLE,SAVE :: xobs(:,:),Vobs(:,:),StdObs(:,:)136INTEGER,ALLOCATABLE,SAVE :: InElement(:)137INTEGER,SAVE :: nobs138139! Variables related to netcdf140CHARACTER(LEN=MAX_NAME_LEN) :: Xdim,Ydim,VarName141REAL(KIND=dp),ALLOCATABLE :: Fillv(:)142REAL(KIND=dp),ALLOCATABLE :: xx(:),yy(:),ObsArray(:,:,:),StdObsArray(:,:,:)143INTEGER :: XMinIndex,XMaxIndex,YMinIndex,YMaxIndex,nx,ny144INTEGER :: NetcdfStatus,varid,ncid,ierr145LOGICAL :: NETCDFFormat146REAL(KIND=dp) :: xmin,ymin,xmax,ymax147148149SolverParams => GetSolverParams()150151!! check if we are on a boundary or in the bulk152BoundarySolver = ( Solver % ActiveElements(1) > Model % Mesh % NumberOfBulkElements )153IF (BoundarySolver) THEN154CoordDIM = CoordinateSystemDimension() - 1155ELSE156CoordDIM = CoordinateSystemDimension()157ENDIF158159! Get min/max coordinates of current mesh160xmin=MINVAL(Solver%Mesh%Nodes%x(:))161xmax=MAXVAL(Solver%Mesh%Nodes%x(:))162IF (CoordDIM.GE.2) THEN163ymin=MINVAL(Solver%Mesh%Nodes%y(:))164ymax=MAXVAL(Solver%Mesh%Nodes%y(:))165ENDIF166167168If (Firsttime) then169N = model % MaxElementNodes170allocate(ElementNodes % x(N), ElementNodes % y(N), ElementNodes % z(N))171allocate(Basis(N), dBasisdx(N,3))172173!!!!!!! Check for parallel run174Parallel = .FALSE.175IF ( ASSOCIATED( Solver % Matrix % ParMatrix ) ) THEN176IF ( Solver % Matrix % ParMatrix % ParEnv % PEs > 1 ) THEN177Parallel = .TRUE.178END IF179END IF180181Lambda = GetConstReal( SolverParams,'Lambda', Found)182IF(.NOT.Found) THEN183CALL WARN(SolverName,'Keyword >Lambda< not found in section >Solver<')184CALL WARN(SolverName,'Taking default value Lambda=1.0')185Lambda = 1.0_dp186CALL ListAddConstReal( SolverParams,'Lambda',Lambda)187End if188189! error is the difference of the norm?190CompNorm = ListGetLogical(SolverParams,'Compute norm difference', Found)191IF(.NOT.Found) CompNorm=.FALSE.192193!! Give information about standard error194HaveSTD=ListGetLogical(SolverParams,'Use standard error',Found)195IF (.NOT.Found) HaveSTD=.False.196IF (HaveSTD) THEN197StdMin=ListGetConstReal(SolverParams,'standard error Min Value',Found)198IF (.NOT.Found) StdMin=100*AEPS199END IF200201!!!!!!!!!!! get Solver Variables202203CostFile = ListGetString(Solver % Values,'Cost Filename',Found )204IF (.NOT. Found) CostFile = DefaultCostFile205CALL DATE_AND_TIME(date,temps)206If (Parallel) then207if (ParEnv % MyPe.EQ.0) then208OPEN (IO, FILE=CostFile)209write(IO,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)210write(IO,1001) Lambda211IF (HaveSTD) THEN212write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs),rms'213ELSE214write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs)'215END IF216CLOSE(IO)217End if218Else219OPEN (IO, FILE=CostFile)220write(IO,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)221write(IO,1001) Lambda222IF (HaveSTD) THEN223write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs),rms'224ELSE225write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs)'226END IF227CLOSE(IO)228End if229230CostSolName = GetString( SolverParams,'Cost Variable Name', Found)231IF(.NOT.Found) THEN232CALL WARN(SolverName,'Keyword >Cost Variable Name< not found in section >Solver<')233CALL WARN(SolverName,'Taking default value >CostValue<')234WRITE(CostSolName,'(A)') 'CostValue'235END IF236237VariableName = ListGetString( SolverParams,'Observed Variable Name', UnFoundFatal=.TRUE.)238Variable => VariableGet( Solver % Mesh % Variables, Trim(VariableName) ,UnFoundFatal=.TRUE. )239VDOFs=Variable%DOFs240241VarDIM=GetInteger(SolverParams ,'Observed Variable Dimension',Found)242IF (.NOT.Found) THEN243VarDIM=MIN(VDOFs,CoordDIM)244WRITE(message,*) 'Keyword >Observed Variable Dimension< not found, assume VarDIM = ',VarDIM245CALL WARN(SolverName,message)246ENDIF247248!! Get the obs249ObsFileName = ListGetString( SolverParams,'Observation File Name', UnFoundFatal=.TRUE.)250251!! I the file netcf?252k = INDEX(ObsFileName ,'.nc' )253NETCDFFormat = ( k /= 0 )254255IF (NETCDFFormat) then256257#ifdef HAVE_NETCDF258259IF (CoordDIM.NE.2) CALL FATAL(Trim(SolverName),'Netcdf only supported for 2D')260261CALL INFO(Trim(SolverName),'Data File is in netcdf format', Level=5)262263NetCDFstatus = NF90_OPEN(trim(ObsFileName),NF90_NOWRITE,ncid)264IF ( NetCDFstatus /= NF90_NOERR ) &265CALL FATAL(Trim(SolverName), 'Unable to open NETCDF File')266267Xdim=ListGetString( SolverParams,"X Dim Name", Found )268if (.NOT.Found) Xdim='x'269270NetCDFstatus = nf90_inq_dimid(ncid, trim(Xdim) , varid)271IF ( NetCDFstatus /= NF90_NOERR ) &272CALL FATAL(Trim(SolverName),'Unable to get netcdf x-dim Id')273274NetCDFstatus = nf90_inquire_dimension(ncid,varid,len=nx)275IF ( NetCDFstatus /= NF90_NOERR ) &276CALL FATAL(Trim(SolverName), 'Unable to get netcdf nx')277278Ydim=ListGetString( SolverParams,"Y Dim Name", Found )279if (.NOT.Found) Ydim='y'280281NetCDFstatus = nf90_inq_dimid(ncid, trim(Ydim) , varid)282IF ( NetCDFstatus /= NF90_NOERR ) &283CALL FATAL(Trim(SolverName),'Unable to get netcdf y-dim Id')284285NetCDFstatus = nf90_inquire_dimension(ncid,varid,len=ny)286IF ( NetCDFstatus /= NF90_NOERR ) &287CALL FATAL(Trim(SolverName), 'Unable to get netcdf ny')288289ALLOCATE(xx(nx),yy(ny))290291!! Get X and Y variable292Xdim=ListGetString( SolverParams, "X Var Name", Found )293if (.NOT.Found) Xdim='x'294NetCDFstatus = nf90_inq_varid(ncid,trim(Xdim),varid)295IF ( NetCDFstatus /= NF90_NOERR ) &296CALL FATAL(Trim(SolverName),'Unable to get netcdf x-variable id')297298NetCDFstatus = nf90_get_var(ncid, varid,xx)299IF ( NetCDFstatus /= NF90_NOERR ) &300CALL FATAL(Trim(SolverName), 'Unable to get netcdf x-variable ')301302Ydim=ListGetString( SolverParams, "Y Var Name", Found )303if (.NOT.Found) Ydim='y'304NetCDFstatus = nf90_inq_varid(ncid,trim(Ydim),varid)305IF ( NetCDFstatus /= NF90_NOERR ) &306CALL FATAL(Trim(SolverName),'Unable to get netcdf x-variable id')307308NetCDFstatus = nf90_get_var(ncid, varid,yy)309IF ( NetCDFstatus /= NF90_NOERR ) &310CALL FATAL(Trim(SolverName), 'Unable to get netcdf x-variable ')311312!! Check that there is data within the domain313IF ((MAXVAL(xx).LT.xmin).OR.(MINVAL(xx).GT.xmax)&314.OR.(MAXVAL(yy).LT.ymin).OR.(MINVAL(yy).GT.ymax)) &315CALL Fatal(Trim(SolverName), &316'No data within model domain')317!!! get the index of values that are within the mesh bounding box318CALL MinMaxIndex(xx,nx,xmin,xmax,XMinIndex,XMaxIndex)319CALL MinMaxIndex(yy,ny,ymin,ymax,YMinIndex,YMaxIndex)320321322!! get ux and uy323nx=XMaxIndex-XMinIndex+1324ny=YMaxIndex-YMinIndex+1325ALLOCATE(ObsArray(nx,ny,VarDIM),fillv(VarDIM))326IF (HaveSTD) ALLOCATE(StdObsArray(nx,ny,VarDIM))327328DO k=1,VarDIM329IF (VarDIM==1) THEN330VarName=ListGetString( SolverParams, "Netcdf Var Name", Found )331IF (.NOT.Found) VarName=TRIM(VariableName)332ELSE333VarName=ListGetString( SolverParams, TRIM(ComponentName("Netcdf Var",k)) // " Name", Found )334IF (.NOT.Found) THEN335CALL WARN(SolverName,'keyword <' // &336TRIM(ComponentName("Netcdf Var",k)) // " Name" // ' not found, taking default')337select case (k)338case (1)339VarName='vx'340case (2)341VarName='vy'342end select343ENDIF344ENDIF345NetCDFstatus = nf90_inq_varid(ncid,trim(VarName),varid)346IF ( NetCDFstatus /= NF90_NOERR ) &347CALL Fatal(Trim(SolverName),'Unable to get netcdf variable id for ' // TRIM(VarName))348NetCDFstatus = nf90_get_var(ncid, Varid, ObsArray(:, :,k), &349start = (/ XMinIndex, YMinIndex /), &350count = (/ nx,ny/))351IF ( NetCDFstatus /= NF90_NOERR ) &352CALL Fatal(Trim(SolverName),'Unable to get netcdf variable' // TRIM(VarName))353NetCDFstatus = nf90_get_att(ncid, varid,"_FillValue",fillv(k))354IF ( NetCDFstatus /= NF90_NOERR ) &355CALL FATAL(Trim(SolverName),TRIM(VarName) // 'has no attribute _FillValue')356END DO357358IF (HaveSTD) THEN359DO k=1,VarDIM360IF (VarDIM==1) THEN361VarName=ListGetString( SolverParams, "Netcdf Std Var Name", UnFoundFatal=.True. )362ELSE363VarName=ListGetString( SolverParams, TRIM(ComponentName("Netcdf Std Var",k)) // " Name", Found )364IF (.NOT.Found) THEN365CALL WARN(SolverName,'keyword <' // &366TRIM(ComponentName("Netcdf Std Var",k)) // " Name" // ' not found, taking default')367select case (k)368case (1)369VarName='ex'370case (2)371VarName='ey'372end select373ENDIF374ENDIF375NetCDFstatus = nf90_inq_varid(ncid,trim(VarName),varid)376IF ( NetCDFstatus /= NF90_NOERR ) &377CALL Fatal(Trim(SolverName),'Unable to get netcdf variable id for ' // TRIM(VarName))378NetCDFstatus = nf90_get_var(ncid, Varid, StdObsArray(:, :,k), &379start = (/ XMinIndex, YMinIndex /), &380count = (/ nx,ny/))381IF ( NetCDFstatus /= NF90_NOERR ) &382CALL Fatal(Trim(SolverName),'Unable to get netcdf variable' // TRIM(VarName))383END DO384END IF385386!! close netcdf387NetCDFstatus = nf90_close(ncid)388389!!390ALLOCATE(xobs(nx*ny,3),Vobs(nx*ny,VarDIM))391IF (HaveSTD) ALLOCATE(StdObs(nx*ny,VarDIM))392393ALLOCATE(InElement(nx*ny))394InElement(:)=-1395xobs=0._dp396Vobs=0._dp397398nobs=0399Do i=1,nx400Do j=1,ny401IF (ANY(abs(ObsArray(i,j,:)-fillv(:)).LT.AEPS)) CYCLE402nobs=nobs+1403xobs(nobs,1)=xx(XMinIndex+i-1)404xobs(nobs,2)=yy(YMinIndex+j-1)405Do k=1,VarDIM406Vobs(nobs,k)=ObsArray(i,j,k)407IF (HaveSTD) &408StdObs(nobs,k)=max(StdObsArray(i,j,k),StdMin)409END DO410End do411End do412413DEALLOCATE(xx,yy,ObsArray,fillv)414IF (HaveSTD) DEALLOCATE(StdObsArray)415416#else417418CALL FATAL(Trim(SolverName),'Elmer/Ice has not been installed with netcdf -convert your file to ASCII table--')419420#endif421422Else !.not.NETCDFFormat423424ParallelFile = .False.425ParallelFile = GetLogical(SolverParams,'Parallel Observation Files', Found)426if (Parallel.AND.ParallelFile) THEN427SideParFile = AddFilenameParSuffix(ObsFileName,'dat',Parallel,ParEnv % MyPe)428ELSE429SideParFile = trim(ObsFileName)430ENDIF431432ProcessedFile = ListGetLogical(SolverParams,'Pre-Processed File')433IF (ProcessedFile) THEN434ActiveNumbering=ListGetLogical(SolverParams,"Element Number is Active Number")435ENDIF436437open(IO,file=trim(SideParFile),status = 'old',iostat = ok)438if(ok /= 0) then439write(message,'(A,A)') 'Unable to open file ',TRIM(ObsFileName)440CALL Fatal(Trim(SolverName),Trim(message))441end if442nobs=0443do while(ok == 0)444read(io,*,iostat = ok)445if (ok == 0) nobs = nobs + 1446end do447close(IO)448449ALLOCATE(xobs(nobs,3),Vobs(nobs,VarDIM))450IF (HaveSTD) ALLOCATE(StdObs(nobs,VarDIM))451ALLOCATE(InElement(nobs))452InElement(:)=-1453454Vobs=0.0_dp455xobs=0.0_dp456open(IO,file=trim(SideParFile))457do i=1,nobs458IF (ProcessedFile) THEN459IF (HaveSTD) THEN460read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM),(StdObs(i,j),j=1,VarDIM),AI461ELSE462read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM),AI463END IF464465IF (ActiveNumbering) THEN466Element => GetActiveElement(AI)467IF (.NOT.ASSOCIATED(Element)) &468CALL FATAL(SolverName,'No Active Element')469InElement(i) = Element % ElementIndex470ELSE471InElement(i) = AI472ENDIF473ELSE474IF (HaveSTD) THEN475read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM),(StdObs(i,j),j=1,VarDIM)476ELSE477read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM)478ENDIF479ENDIF480end do481close(IO)482ENDIF483484SAVE_USED_DATA = GetLogical(SolverParams,'Save used data', Found)485IF (SAVE_USED_DATA) THEN486SideFile =ListGetString(SolverParams,"output data file name",UnfoundFatal=.TRUE.)487CALL SolverOutputDirectory( Solver, SideFile, OutputDirectory )488SideFile = TRIM(OutputDirectory)// '/' //TRIM(SideFile)489SideParFile = AddFilenameParSuffix(SideFile,'dat',Parallel,ParEnv % MyPe)490END IF491492!!! End of First visit493Firsttime=.false.494Endif495496! Get the variable solution497Variable => VariableGet( Solver % Mesh % Variables, Trim(VariableName), UnFoundFatal=.TRUE. )498Values => Variable % Values499Perm => Variable % Perm500501! Get the sensitivity variable502IF ( SEQL(TRIM(VariableName),'flow solution').OR.SEQL(TRIM(VariableName),'ssavelocity')) THEN503FVarName = 'Velocityb'504ELSE505FVarName = TRIM(VariableName) // 'b'506ENDIF507VbSol => VariableGet( Solver % Mesh % Variables,TRIM(FVarName), UnFoundFatal=.TRUE. )508Vb => VbSol % Values509VbPerm => VbSol % Perm510Vb=0.0_dp511512IF (VbSol%DOFs.NE.Variable%DOFs) &513CALL FATAL(Trim(SolverName),'DOFs do not correspond')514IF (VarDIM.GT.Variable%DOFs) &515CALL FATAL(Trim(SolverName),'Observed Variable DIM too large')516!517Mesh => GetMesh()518519! Temporary trick to disable Warnings as LocateParticleInMeshOctree520! will send a lot of warning for data points not found in the emsh521IF (FirstRound) THEN522WarnActive=OutputLevelMask(2)523OutputLevelMask(2)=.FALSE.524ENDIF525526! Compute the cost527Cost=0._dp528rms=0._dp529530Element => GetActiveElement(1)531ElementIndex = Element % ElementIndex532533CALL StartAdvanceOutput(SolverName,'Compute cost')534Do s=1,nobs535536CALL AdvanceOutput(s,nobs)537538IF (FirstRound.AND.(InElement(s)<0)) then539!Need to find in which Element the data point resides540! First check that it is within the computation domain541Coord=0._dp542Coord(1:CoordDIM)=xobs(s,1:CoordDIM)543IF ((Coord(1).GT.xmax).OR.(Coord(1).LT.xmin)) CYCLE544IF (CoordDIM.GE.2) THEN545IF ((Coord(2).GT.ymax).OR.(Coord(2).LT.ymin)) CYCLE546END IF547548IF (CoordDIM.LT.CoordinateSystemDimension()) THEN549! we are in a lower dimension than the mesh550! => use brute force search551552! first check in the current elmement553Element => Mesh % Elements(ElementIndex)554n = GetElementNOFNodes(Element)555NodeIndexes => Element % NodeIndexes556ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)557IF (CoordDIM == 1) THEN558ElementNodes % y(1:n) = 0.0_dp559ElementNodes % z(1:n) = 0.0_dp560ELSE IF (CoordDIM == 2) THEN561ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)562ElementNodes % z(1:n) = 0.0_dp563ENDIF564IF (PointInElement(Element,ElementNodes,Coord(:),UVW)) THEN565IF (.NOT.CheckPassiveElement(Element)) &566InElement(s)=ElementIndex567568ELSE569! go through all elements570Do i=1,Solver%NumberOfActiveElements571Element => GetActiveElement(i)572n = GetElementNOFNodes(Element)573NodeIndexes => Element % NodeIndexes574ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)575IF (CoordDIM == 1) THEN576ElementNodes % y(1:n) = 0.0_dp577ElementNodes % z(1:n) = 0.0_dp578ELSE IF (CoordDIM == 2) THEN579ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)580ElementNodes % z(1:n) = 0.0_dp581ENDIF582IF (PointInElement(Element,ElementNodes,Coord(:),UVW)) THEN583IF (CheckPassiveElement(Element)) Exit584ElementIndex= Element % ElementIndex585InElement(s)=ElementIndex586Exit587END IF588End Do589END IF590591ELSE592!> use particles meshoctree593ElementIndex=-1 ! don't know why but if i don't reset ElmentIndex it fails594CALL LocateParticleInMeshOctree( ElementIndex,Coord)595If (ElementIndex.NE.0) THEN596InElement(s)=ElementIndex597Element => Mesh % Elements(ElementIndex)598IF (CheckPassiveElement(Element).OR. &599(Element % PartIndex /= ParEnv % myPE)) THEN600InElement(s)=-1601END IF602END IF603604END IF605ENDIF !End if FirstRound606607608! Data Point has been found in one element609IF (InElement(s)>0) THEN610Element => Mesh % Elements(InElement(s))611n = GetElementNOFNodes(Element)612NodeIndexes => Element % NodeIndexes613! set coords of highest occurring dimension to zero (to get correct path element)614!-------------------------------------------------------------------------------615ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)616IF (CoordDIM == 1) THEN617ElementNodes % y(1:n) = 0.0_dp618ElementNodes % z(1:n) = 0.0_dp619ELSE IF (CoordDIM == 2) THEN620ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)621ElementNodes % z(1:n) = 0.0_dp622ELSE IF (CoordDIM == 3) THEN623ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)624ElementNodes % z(1:n) = Solver % Mesh % Nodes % z(NodeIndexes)625END IF626627IF (.NOT.PointInElement(Element,ElementNodes,xobs(s,1:3),UVW)) THEN628PRINT *,ParEnv%MyPE,'eindex',Element % ElementIndex629PRINT *,ParEnv%MyPE,'obs. coords',xobs(s,1:2)630PRINT *,ParEnv%MyPE,'node indexes',NodeIndexes(1:n)631PRINT *,ParEnv%MyPE,'nodex',ElementNodes % x(1:n)632PRINT *,ParEnv%MyPE,'nodey',ElementNodes % y(1:n)633634CALL FATAL(SolverName,'Point was supposed to be found in this element')635ELSE636stat = ElementInfo( Element,ElementNodes,UVW(1),UVW(2),UVW(3),SqrtElementMetric, &637Basis,dBasisdx )638639IF (CompNorm) THEN640VmNorm=0._dp641VoNorm=0._dp642StdNorm=0._dp643Do i=1,VarDIM644um=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))645VmNorm=VmNorm+um**2646VoNorm=VoNorm+Vobs(s,i)**2647IF (HaveSTD) &648StdNorm=StdNorm+StdObs(s,i)**2649END DO650misfit=sqrt(VmNorm)-sqrt(VoNorm)651IF (HaveSTD) then652rms=rms+misfit**2653misfit=misfit/sqrt(StdNorm)654ENDIF655Cost = Cost + 0.5*Lambda*misfit**2656VmNormb=Lambda*misfit657IF (HaveSTD) &658VmNormb=VmNormb/sqrt(StdNorm)659IF (VmNorm.GT.10*AEPS) THEN660VmNormb=0.5*VmNormb*VmNorm**(-0.5)661ELSE662VmNormb=0._dp663END IF664665Do i=1,VarDIM666um=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))667umb=2*um*VmNormb668Do j=1,n669k=VDOFS*(VbPerm(NodeIndexes(j))-1)+i670Vb(k)=Vb(k)+umb*basis(j)671End do672END DO673674675ELSE676! Update cost677Do i=1,VarDIM678V(i)=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))679misfit=(V(i)-Vobs(s,i))680IF (HaveSTD) then681rms=rms+misfit**2682misfit=misfit/StdObs(s,i)683END IF684Cost=Cost+0.5*Lambda*misfit**2685End do686687!Derivative of Cost at nodal Point688! derivative of (V(i)-Vobs(s,i))**2/std**2=689! 2*(V(i)-Vobs(s,i))/std**2 * (dV(i)/Vnodal)690Do j=1,n691Do i=1,VarDIM692k=VDOFS*(VbPerm(NodeIndexes(j))-1)+i693misfit=(V(i)-Vobs(s,i))694IF (HaveSTD) misfit=misfit/StdObs(s,i)**2695Vb(k)=Vb(k)+Lambda*misfit*basis(j)696End do697End Do698699ENDIF700701END IF702703ELSE704705WRITE(Message,'(a,I0,ES20.11E3,ES20.11E3,ES20.11E3,a)')&706'Data Point ',s,xobs(s,1:3),' found in no element'707CALL Info( SolverName, Message,level=15)708END IF709710END DO !Do on s711712713if (NTOT < 0) NTOT=COUNT(InElement(:)>0)714!! Save Cost as a function of time715716TimeVar => VariableGet( Solver % Mesh % Variables, 'Time' )717718IF (Parallel) THEN719CALL MPI_ALLREDUCE(NTOT,NTOT_S,1,&720MPI_INTEGER,MPI_SUM,ELMER_COMM_WORLD,ierr)721CALL MPI_ALLREDUCE(Cost,Cost_S,1,&722MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)723IF (HaveSTD) &724CALL MPI_ALLREDUCE(rms,rms_S,1,&725MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)726CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )727IF (ASSOCIATED(CostVar)) THEN728CostVar % Values(1)=Cost_S729END IF730IF (Solver % Matrix % ParMatrix % ParEnv % MyPE == 0) then731OPEN (IO, FILE=CostFile,POSITION='APPEND')732IF (HaveSTD) THEN733write(IO,'(4(ES20.11E3))') TimeVar % Values(1),Cost_S,&734sqrt(2.0*Cost_S/(NTOT_S*Lambda)),sqrt(rms_S/NTOT_S)735ELSE736write(IO,'(3(ES20.11E3))') TimeVar % Values(1),Cost_S,sqrt(2.0*Cost_S/(NTOT_S*Lambda))737END IF738CLOSE(IO)739write(Message,'(A,A,I0)') trim(SolverName),'total number of data points:',NTOT_S740call INFO(SolverName,Message,level=3)741End if742ELSE743CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )744IF (ASSOCIATED(CostVar)) THEN745CostVar % Values(1)=Cost746END IF747OPEN (IO, FILE=CostFile,POSITION='APPEND')748IF (HaveSTD) THEN749write(IO,'(4(ES20.11E3))') TimeVar % Values(1),Cost,&750sqrt(2.0*Cost/(NTOT*Lambda)),sqrt(rms/NTOT)751ELSE752write(IO,'(3(ES20.11E3))') TimeVar % Values(1),Cost,sqrt(2.0*Cost/(NTOT*Lambda))753END IF754close(IO)755write(Message,'(A,A,I0)') trim(SolverName),'total number of data points:',NTOT756call INFO(SolverName,Message,level=3)757Cost_S=Cost758END IF759760Solver % Variable % Values(1)=Cost_S761762If (FirstRound.AND.SAVE_USED_DATA) THEN763764765open(IO,File=SideParFile)766Do s=1,nobs767If (InElement(s)>0) then768DO i=1,CoordDIM769write(IO,'(ES20.11E3)',ADVANCE='NO') xobs(s,i)770END DO771DO i=1,VarDIM772write(IO,'(ES20.11E3)',ADVANCE='NO') Vobs(s,i)773END DO774IF (HaveSTD) THEN775DO i=1,VarDIM776write(IO,'(ES20.11E3)',ADVANCE='NO') StdObs(s,i)777END DO778END IF779write(IO,'(x,I0)') InElement(s)780End if781End do782close(IO)783784END IF785786! Reset Warning level to previous value787IF (FirstRound) THEN788OutputLevelMask(2)=WarnActive789ENDIF790791FirstRound=.False.792Return7937941000 format('#date,time,',a2,'/',a2,'/',a4,',',a2,':',a2,':',a2)7951001 format('#lambda,',e15.8)796797CONTAINS798! Find the min and max indexes of values within bBox799SUBROUTINE MinMaxIndex(x,n,minx,maxx,MinIndex,MaxIndex)800IMPLICIT NONE801REAL(KIND=dp),INTENT(IN) :: x(:),minx,maxx802INTEGER,INTENT(IN) :: n803INTEGER,INTENT(OUT) :: MinIndex,MaxIndex804805IF (n.EQ.1) THEN806MinIndex=1807MaxIndex=1808Return809ENDIF810811! coordinates should be monotonically increasing or812! decreasing813IF ((x(2)>x(1)).AND.(x(n)>x(n-1))) THEN814MinIndex = MAXLOC(x, DIM=1,MASK=(x < minx))815MinIndex=MAX(MinIndex,1)816817MaxIndex = MINLOC(x, DIM=1,MASK=(x > maxx))818IF (MaxIndex.LE.1) MaxIndex=n819ELSE IF ((x(2)<x(1)).AND.(x(n)<x(n-1))) THEN820MaxIndex = MAXLOC(x, DIM=1,MASK=(x < minx))821IF (MaxIndex.LE.1) MaxIndex=n822823MinIndex = MINLOC(x, DIM=1,MASK=(x > maxx))824MinIndex=MAX(MinIndex,1)825ELSE826CALL FATAL(SolverName,'coordinate is neither monotonically increasing or decreasing')827ENDIF828829IF (MaxIndex.LT.MinIndex) THEN830WRITE(message,*) 'Error Min Max Indexes ',MinIndex,MaxIndex831CALL WARN(SolverName,message)832WRITE(message,*) 'Min values ',MINVAL(x),minx833CALL WARN(SolverName,message)834WRITE(message,*) 'Max values ',MAXVAL(x),maxx835CALL WARN(SolverName,message)836CALL FATAL(SolverName,'This is a fatal error')837ENDIF838839END SUBROUTINE MinMaxIndex840841!------------------------------------------------------------------------------842END SUBROUTINE Adjoint_CostDiscSolver843!------------------------------------------------------------------------------844! *****************************************************************************845846847