1 subroutine itrdrv (y, ac, 2 & uold, x, 3 & iBC, BC, 4 & iper, ilwork, shp, 5 & shgl, shpb, shglb, 6 & ifath, velbar, nsons ) 7c 8c---------------------------------------------------------------------- 9c 10c This iterative driver is the semi-discrete, predictor multi-corrector 11c algorithm. It contains the Hulbert Generalized Alpha method which 12c is 2nd order accurate for Rho_inf from 0 to 1. The method can be 13c made first-order accurate by setting Rho_inf=-1. It uses CGP and 14c GMRES iterative solvers. 15c 16c working arrays: 17c y (nshg,ndof) : Y variables 18c x (nshg,nsd) : node coordinates 19c iBC (nshg) : BC codes 20c BC (nshg,ndofBC) : BC constraint parameters 21c iper (nshg) : periodicity table 22c 23c 24c Zdenek Johan, Winter 1991. (Fortran 90) 25c Alberto Figueroa, Winter 2004. CMM-FSI 26c Irene Vignon, Fall 2004. Impedance BC 27c---------------------------------------------------------------------- 28c 29 use pvsQbi !gives us splag (the spmass at the end of this run 30 use specialBC !gives us itvn 31 use timedata !allows collection of time series 32 use convolImpFlow !for Imp bc 33 use convolRCRFlow !for RCR bc 34!MR CHANGE 35 use turbsa ! used to access d2wall 36!MR CHANGE END 37 use iso_c_binding 38 39c use readarrays !reads in uold and acold 40 41 include "common.h" 42 include "mpif.h" 43 include "auxmpi.h" 44c 45 46 47 real*8 y(nshg,ndof), ac(nshg,ndof), 48 & yold(nshg,ndof), acold(nshg,ndof), 49 & u(nshg,nsd), uold(nshg,nsd), 50 & x(numnp,nsd), solinc(nshg,ndof), 51 & BC(nshg,ndofBC), tf(nshg,ndof), 52 & GradV(nshg,nsdsq) 53 54c 55 real*8 res(nshg,ndof) 56c 57 real*8 shp(MAXTOP,maxsh,MAXQPT), 58 & shgl(MAXTOP,nsd,maxsh,MAXQPT), 59 & shpb(MAXTOP,maxsh,MAXQPT), 60 & shglb(MAXTOP,nsd,maxsh,MAXQPT) 61c 62 integer rowp(nshg,nnz), colm(nshg+1), 63 & iBC(nshg), 64 & ilwork(nlwork), 65 & iper(nshg), ifuncs(6) 66 67 real*8 vbc_prof(nshg,3) 68 69 integer stopjob 70 character*10 cname2 71 character*5 cname 72c 73c stuff for dynamic model s.w.avg and wall model 74c 75 dimension ifath(numnp), velbar(nfath,ndof), nsons(nfath) 76 77 dimension wallubar(2),walltot(2) 78c 79c.... For Farzin's Library 80c 81 integer eqnType, prjFlag, presPrjFlag, verbose 82c 83 real*8, allocatable, dimension(:,:) :: aperm, atemp, atempS 84 real*8, allocatable, dimension(:,:,:) :: apermS 85 86 real*8, allocatable, dimension(:,:) :: lhsP, lhsK, lhsS 87 real*8 almit, alfit, gamit 88c 89 character*1024 servername 90 character*20 fname1,fmt1 91 character*20 fname2,fmt2 92 character*60 fnamepold, fvarts 93 character*4 fname4c ! 4 characters 94 integer iarray(50) ! integers for headers 95 integer isgn(ndof), isgng(ndof) 96 97!MR CHANGE 98! real*8 rerr(nshg,10), ybar(nshg,13) ! including 7 sq. terms with 3 cross terms of uv, uw and vw 99! real*8 rerr(nshg,10), ybar(nshg,12) ! including 7 sq. terms with 3 cross terms of uv, uw and vw 100 real*8 rerr(nshg,10) 101 real*8, allocatable, dimension(:,:) :: ybar, strain, vorticity 102 real*8, allocatable, dimension(:,:) :: wallssVec, wallssVecbar 103!MR CHANGE 104 105 real*8 tcorecp(2), tcorecpscal(2) 106 107 integer, allocatable, dimension(:) :: ivarts 108 integer, allocatable, dimension(:) :: ivartsg 109 integer, allocatable, dimension(:) :: iv_rank 110 real*8, allocatable, dimension(:) :: vartssoln 111 real*8, allocatable, dimension(:) :: vartssolng 112 real*8, allocatable, dimension(:,:,:) :: yphbar 113 real*8 CFLworst(numel) 114 115!MR CHANGE 116 integer :: iv_rankpernode, iv_totnodes, iv_totcores 117 integer :: iv_node, iv_core, iv_thread 118!MR CHANGE 119 120 impistat = 0 121 impistat2 = 0 122 iISend = 0 123 iISendScal = 0 124 iIRecv = 0 125 iIRecvScal = 0 126 iWaitAll = 0 127 iWaitAllScal = 0 128 iAllR = 0 129 iAllRScal = 0 130 rISend = zero 131 rISendScal = zero 132 rIRecv = zero 133 rIRecvScal = zero 134 rWaitAll = zero 135 rWaitAllScal = zero 136 rAllR = zero 137 rAllRScal = zero 138 rCommu = zero 139 rCommuScal = zero 140 141 call initmemstat() 142 143c 144c hack SA variable 145c 146cHack BC(:,7)=BC(:,7)*0.001 147cHack if(lstep.eq.0) y(:,6)=y(:,6)*0.001 148 call SolverLicenseServer(servername) 149c 150c only master should be verbose 151c 152 153 if(numpe.gt.0 .and. myrank.ne.master)iverbose=0 154c 155 156 lskeep=lstep 157 158 inquire(file='xyzts.dat',exist=exts) 159 if(exts) then 160 161 open(unit=626,file='xyzts.dat',status='old') 162 read(626,*) ntspts, freq, tolpt, iterat, varcod 163 call sTD ! sets data structures 164 165 do jj=1,ntspts ! read coordinate data where solution desired 166 read(626,*) ptts(jj,1),ptts(jj,2),ptts(jj,3) 167 enddo 168 close(626) 169 170 statptts(:,:) = 0 171 parptts(:,:) = zero 172 varts(:,:) = zero 173 174 allocate (ivarts(ntspts*ndof)) 175 allocate (ivartsg(ntspts*ndof)) 176 allocate (iv_rank(ntspts)) 177 allocate (vartssoln(ntspts*ndof)) 178 allocate (vartssolng(ntspts*ndof)) 179 180 iv_rankpernode = iv_rankpercore*iv_corepernode 181 iv_totnodes = numpe/iv_rankpernode 182 iv_totcores = iv_corepernode*iv_totnodes 183 if (myrank .eq. 0) then 184 write(*,*) 'Info for probes:' 185 write(*,*) ' Ranks per core:',iv_rankpercore 186 write(*,*) ' Cores per node:',iv_corepernode 187 write(*,*) ' Ranks per node:',iv_rankpernode 188 write(*,*) ' Total number of nodes:',iv_totnodes 189 write(*,*) ' Total number of cores',iv_totcores 190 endif 191 192! if (myrank .eq. numpe-1) then 193 do jj=1,ntspts 194 195 ! Compute the adequate rank which will take care of probe jj 196 jjm1 = jj-1 197 iv_node = (iv_totnodes-1)-mod(jjm1,iv_totnodes) 198 iv_core = (iv_corepernode-1) - mod((jjm1 - 199 & mod(jjm1,iv_totnodes))/iv_totnodes,iv_corepernode) 200 iv_thread = (iv_rankpercore-1) - mod((jjm1- 201 & (mod(jjm1,iv_totcores)))/iv_totcores,iv_rankpercore) 202 iv_rank(jj) = iv_node*iv_rankpernode 203 & + iv_core*iv_rankpercore 204 & + iv_thread 205 206 if(myrank == 0) then 207 write(*,*) ' Probe', jj, 'handled by rank', 208 & iv_rank(jj), ' on node', iv_node 209 endif 210 211 ! Verification just in case 212 if(iv_rank(jj) .lt.0 .or. iv_rank(jj) .ge. numpe) then 213 write(*,*) 'WARNING: iv_rank(',jj,') is ', iv_rank(jj), 214 & ' and reset to numpe-1' 215 iv_rank(jj) = numpe-1 216 endif 217 218 ! Open the varts files 219 if(myrank == iv_rank(jj)) then 220 fvarts='varts/varts' 221 fvarts=trim(fvarts)//trim(cname2(jj)) 222 fvarts=trim(fvarts)//trim(cname2(lstep)) 223 fvarts=trim(fvarts)//'.dat' 224 fvarts=trim(fvarts) 225 open(unit=1000+jj, file=fvarts, status='unknown') 226 endif 227 enddo 228! endif 229 230 endif 231c 232c.... open history and aerodynamic forces files 233c 234 if (myrank .eq. master) then 235! open (unit=ihist, file=fhist, status='unknown') 236 open (unit=iforce, file=fforce, status='unknown') 237 open (unit=76, file="fort.76", status='unknown') 238 if(numImpSrfs.gt.0 .or. numRCRSrfs.gt.0) then 239 fnamepold = 'pold' 240 fnamepold = trim(fnamepold)//trim(cname2(lstep)) 241 fnamepold = trim(fnamepold)//'.dat' 242 fnamepold = trim(fnamepold) 243 open (unit=8177, file=fnamepold, status='unknown') 244 endif 245 endif 246c 247c.... initialize 248c 249 ifuncs(:) = 0 ! func. evaluation counter 250 istep = 0 251 yold = y 252 acold = ac 253 254 rerr = zero 255 256 if(ierrcalc.eq.1 .or. ioybar.eq.1) then ! we need ybar for error too 257 if (ivort == 1) then 258 allocate(ybar(nshg,17)) ! more space for vorticity if requested 259 else 260 allocate(ybar(nshg,13)) 261 endif 262 ybar = zero ! Initialize ybar to zero, which is essential 263 endif 264 265 if(ivort == 1) then 266 allocate(strain(nshg,6)) 267 allocate(vorticity(nshg,5)) 268 endif 269 270 if(abs(itwmod).ne.1 .and. iowflux.eq.1) then 271 allocate(wallssVec(nshg,3)) 272 if (ioybar .eq. 1) then 273 allocate(wallssVecbar(nshg,3)) 274 wallssVecbar = zero ! Initialization important if mean wss computed 275 endif 276 endif 277 278! both nstepsincycle and nphasesincycle needs to be set 279 if(nstepsincycle.eq.0) nphasesincycle = 0 280 if(nphasesincycle.ne.0) then 281! & allocate(yphbar(nshg,5,nphasesincycle)) 282 if (ivort == 1) then 283 allocate(yphbar(nshg,15,nphasesincycle)) ! more space for vorticity 284 else 285 allocate(yphbar(nshg,11,nphasesincycle)) 286 endif 287 yphbar = zero 288 endif 289 290!MR CHANGE END 291 292 vbc_prof(:,1:3) = BC(:,3:5) 293 if(iramp.eq.1) then 294 call BCprofileInit(vbc_prof,x) 295 endif 296 297c 298c.... ---------------> initialize Farzin's Library <--------------- 299c 300c.... assign parameter values 301c 302 do i = 1, 100 303 numeqns(i) = i 304 enddo 305 nKvecs = Kspace 306 prjFlag = iprjFlag 307 presPrjFlag = ipresPrjFlag 308 verbose = iverbose 309c 310c.... determine how many scalar equations we are going to need to solve 311c 312 nsolt=mod(impl(1),2) ! 1 if solving temperature 313 nsclrsol=nsolt+nsclr ! total number of scalars solved At 314 ! some point we probably want to create 315 ! a map, considering stepseq(), to find 316 ! what is actually solved and only 317 ! dimension lhs to the appropriate 318 ! size. (see 1.6.1 and earlier for a 319 ! "failed" attempt at this). 320 321 322 nsolflow=mod(impl(1),100)/10 ! 1 if solving flow 323 324c 325c.... Now, call Farzin's lesNew routine to initialize 326c memory space 327c 328 call genadj(colm, rowp, icnt ) ! preprocess the adjacency list 329 330 nnz_tot=icnt ! this is exactly the number of non-zero blocks on 331 ! this proc 332 333 if (nsolflow.eq.1) then 334 lesId = numeqns(1) 335 eqnType = 1 336 nDofs = 4 337 call myfLesNew( lesId, 41994, 338 & eqnType, 339 & nDofs, minIters, maxIters, 340 & nKvecs, prjFlag, nPrjs, 341 & presPrjFlag, nPresPrjs, epstol(1), 342 & prestol, verbose, statsflow, 343 & nPermDims, nTmpDims, servername ) 344 345 allocate (aperm(nshg,nPermDims)) 346 allocate (atemp(nshg,nTmpDims)) 347 allocate (lhsP(4,nnz_tot)) 348 allocate (lhsK(9,nnz_tot)) 349 350 call readLesRestart( lesId, aperm, nshg, myrank, lstep, 351 & nPermDims ) 352 353 else 354 nPermDims = 0 355 nTempDims = 0 356 endif 357 358 359 if(nsclrsol.gt.0) then 360 do isolsc=1,nsclrsol 361 lesId = numeqns(isolsc+1) 362 eqnType = 2 363 nDofs = 1 364 presPrjflag = 0 365 nPresPrjs = 0 366 prjFlag = 1 367 indx=isolsc+2-nsolt ! complicated to keep epstol(2) for 368 ! temperature followed by scalars 369 call myfLesNew( lesId, 41994, 370 & eqnType, 371 & nDofs, minIters, maxIters, 372 & nKvecs, prjFlag, nPrjs, 373 & presPrjFlag, nPresPrjs, epstol(indx), 374 & prestol, verbose, statssclr, 375 & nPermDimsS, nTmpDimsS, servername ) 376 enddo 377c 378c Assume all scalars have the same size needs 379c 380 allocate (apermS(nshg,nPermDimsS,nsclrsol)) 381 allocate (atempS(nshg,nTmpDimsS)) !they can all share this 382 allocate (lhsS(nnz_tot,nsclrsol)) 383c 384c actually they could even share with atemp but leave that for later 385c 386 else 387 nPermDimsS = 0 388 nTmpDimsS = 0 389 endif 390c 391c... prepare lumped mass if needed 392c 393 if((flmpr.ne.0).or.(flmpl.ne.0)) call genlmass(x, shp,shgl) 394c 395c.... -----------------> End of initialization <----------------- 396c 397c.....open the necessary files to gather time series 398c 399 lstep0 = lstep+1 400 nsteprcr = nstep(1)+lstep 401c 402c.... loop through the time sequences 403c 404 405 406 do 3000 itsq = 1, ntseq 407 itseq = itsq 408 409CAD tcorecp1 = second(0) 410CAD tcorewc1 = second(-1) 411c 412c.... set up the time integration parameters 413c 414 nstp = nstep(itseq) 415 nitr = niter(itseq) 416 LCtime = loctim(itseq) 417 dtol(:)= deltol(itseq,:) 418 419 call itrSetup ( y, acold ) 420c 421c...initialize the coefficients for the impedance convolution, 422c which are functions of alphaf so need to do it after itrSetup 423 if(numImpSrfs.gt.zero) then 424 call calcImpConvCoef (numImpSrfs, ntimeptpT) 425 endif 426c 427c...initialize the initial condition P(0)-RQ(0)-Pd(0) for RCR BC 428c need ndsurf so should be after initNABI 429 if(numRCRSrfs.gt.zero) then 430 call calcRCRic(y,nsrflistRCR,numRCRSrfs) 431 endif 432c 433c find the last solve of the flow in the step sequence so that we will 434c know when we are at/near end of step 435c 436c ilast=0 437 nitr=0 ! count number of flow solves in a step (# of iterations) 438 do i=1,seqsize 439 if(stepseq(i).eq.0) nitr=nitr+1 440 enddo 441 442 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 443 tcorecp(:) = zero ! used in solfar.f (solflow) 444 tcorecpscal(:) = zero ! used in solfar.f (solflow) 445 if(myrank.eq.0) then 446 tcorecp1 = TMRC() 447 endif 448 449c 450c.... loop through the time steps 451c 452 istop=0 453 rmub=datmat(1,2,1) 454 if(rmutarget.gt.0) then 455 rmue=rmutarget 456 else 457 rmue=datmat(1,2,1) ! keep constant 458 endif 459 460 if(iramp.eq.1) then 461 call BCprofileScale(vbc_prof,BC,yold) ! fix the yold values to the reset BC 462 isclr=1 ! fix scalar 463 do isclr=1,nsclr 464 call itrBCSclr(yold,ac,iBC,BC,iper,ilwork) 465 enddo 466 endif 467 468 do 2000 istp = 1, nstp 469 if(iramp.eq.1) 470 & call BCprofileScale(vbc_prof,BC,yold) 471 472 call rerun_check(stopjob) 473 if(myrank.eq.master) write(*,*) 474 & 'stopjob,lstep,istep', stopjob,lstep,istep 475 if(stopjob.eq.lstep) then 476 stopjob=-2 ! this is the code to finish 477 if ((irs .ge. 1) .and. (mod(lstep, ntout) .eq. 0)) then 478 if(myrank.eq.master) write(*,*) 479 & 'line 473 says last step written so exit' 480 goto 2002 ! the step was written last step so just exit 481 else 482 if(myrank.eq.master) 483 & write(*,*) 'line 473 says last step not written' 484 istep=nstp ! have to do this so that solution will be written 485 goto 2001 486 endif 487 endif 488 489 xi=istp*1.0/nstp 490 datmat(1,2,1)=rmub*(1.0-xi)+xi*rmue 491c write(*,*) "current mol. visc = ", datmat(1,2,1) 492c.... if we have time varying boundary conditions update the values of BC. 493c these will be for time step n+1 so use lstep+1 494c 495 if(itvn.gt.0) call BCint((lstep+1)*Delt(1), shp, shgl, 496 & shpb, shglb, x, BC, iBC) 497 498c 499c ... calculate the pressure contribution that depends on the history for the Imp. BC 500c 501 if(numImpSrfs.gt.0) then 502 call pHist(poldImp,QHistImp,ImpConvCoef, 503 & ntimeptpT,numImpSrfs) 504 if (myrank.eq.master) 505 & write(8177,*) (poldImp(n), n=1,numImpSrfs) 506 endif 507c 508c ... calc the pressure contribution that depends on the history for the RCR BC 509c 510 if(numRCRSrfs.gt.0) then 511 call CalcHopRCR (Delt(itseq), lstep, numRCRSrfs) 512 call CalcRCRConvCoef(lstep,numRCRSrfs) 513 call pHist(poldRCR,QHistRCR,RCRConvCoef,nsteprcr, 514 & numRCRSrfs) 515 if (myrank.eq.master) 516 & write(8177,*) (poldRCR(n), n=1,numRCRSrfs) 517 endif 518c 519c Decay of scalars 520c 521 if(nsclr.gt.0 .and. tdecay.ne.1) then 522 yold(:,6:ndof)=y(:,6:ndof)*tdecay 523 BC(:,7:6+nsclr)= BC(:,7:6+nsclr)*tdecay 524 endif 525 526 if(nosource.eq.1) BC(:,7:6+nsclr)= BC(:,7:6+nsclr)*0.8 527 528 529 if(iLES.gt.0) then !complicated stuff has moved to 530 !routine below 531 call lesmodels(yold, acold, shgl, shp, 532 & iper, ilwork, rowp, colm, 533 & nsons, ifath, x, 534 & iBC, BC) 535 536 537 endif 538 539c.... set traction BCs for modeled walls 540c 541 if (itwmod.ne.0) then 542 call asbwmod(yold, acold, x, BC, iBC, 543 & iper, ilwork, ifath, velbar) 544 endif 545 546!MR CHANGE 547c 548c.... Determine whether the vorticity field needs to be computed for this time step or not 549c 550 icomputevort = 0 551 if (ivort == 1) then ! Print vorticity = True in solver.inp 552 ! We then compute the vorticity only if we 553 ! 1) we write an intermediate checkpoint 554 ! 2) we reach the last time step and write the last checkpoint 555 ! 3) we accumulate statistics in ybar for every time step 556 ! BEWARE: we need here lstep+1 and istep+1 because the lstep and 557 ! istep gets incremened after the flowsolve, further below 558 if (((irs .ge. 1) .and. (mod(lstep+1, ntout) .eq. 0)) .or. 559 & istep+1.eq.nstep(itseq) .or. ioybar == 1) then 560 icomputevort = 1 561 endif 562 endif 563 564! write(*,*) 'icomputevort: ',icomputevort, ' - istep: ', 565! & istep,' - nstep(itseq):',nstep(itseq),'- lstep:', 566! & lstep, '- ntout:', ntout 567!MR CHANGE 568 569c 570c.... -----------------------> predictor phase <----------------------- 571c 572 call itrPredict(yold, y, acold, ac , uold, u, iBC) 573 call itrBC (y, ac, iBC, BC, iper,ilwork) 574 575 if(nsolt.eq.1) then 576 isclr=0 577 call itrBCSclr (y, ac, iBC, BC, iper, ilwork) 578 endif 579 do isclr=1,nsclr 580 call itrBCSclr (y, ac, iBC, BC, iper, ilwork) 581 enddo 582 iter=0 583 ilss=0 ! this is a switch thrown on first solve of LS redistance 584 do istepc=1,seqsize 585 icode=stepseq(istepc) 586 if(mod(icode,5).eq.0) then ! this is a solve 587 isolve=icode/10 588 if(icode.eq.0) then ! flow solve (encoded as 0) 589c 590 iter = iter+1 591 ifuncs(1) = ifuncs(1) + 1 592c 593 Force(1) = zero 594 Force(2) = zero 595 Force(3) = zero 596 HFlux = zero 597 lhs = 1 - min(1,mod(ifuncs(1)-1,LHSupd(1))) 598 599 call SolFlow(y, ac, u, 600 & yold, acold, uold, 601 & x, iBC, 602 & BC, res, 603 & nPermDims, nTmpDims, aperm, 604 & atemp, iper, 605 & ilwork, shp, shgl, 606 & shpb, shglb, rowp, 607 & colm, lhsK, lhsP, 608 & solinc, rerr, tcorecp, 609 & GradV) 610 611 else ! scalar type solve 612 if (icode.eq.5) then ! Solve for Temperature 613 ! (encoded as (nsclr+1)*10) 614 isclr=0 615 ifuncs(2) = ifuncs(2) + 1 616 j=1 617 else ! solve a scalar (encoded at isclr*10) 618 isclr=isolve 619 ifuncs(isclr+2) = ifuncs(isclr+2) + 1 620 j=isclr+nsolt 621 if((iLSet.eq.2).and.(ilss.eq.0) 622 & .and.(isclr.eq.2)) then 623 ilss=1 ! throw switch (once per step) 624 y(:,7)=y(:,6) ! redistance field initialized 625 ac(:,7) = zero 626 call itrBCSclr ( y, ac, iBC, BC, iper, 627 & ilwork) 628c 629c....store the flow alpha, gamma parameter values and assigm them the 630c....Backward Euler parameters to solve the second levelset scalar 631c 632 alfit=alfi 633 gamit=gami 634 almit=almi 635 Deltt=Delt(1) 636 Dtglt=Dtgl 637 alfi = 1 638 gami = 1 639 almi = 1 640c Delt(1)= Deltt ! Give a pseudo time step 641 Dtgl = one / Delt(1) 642 endif ! level set eq. 2 643 endif ! deciding between temperature and scalar 644 645 lhs = 1 - min(1,mod(ifuncs(isclr+2)-1, 646 & LHSupd(isclr+2))) 647 648 call SolSclr(y, ac, u, 649 & yold, acold, uold, 650 & x, iBC, 651 & BC, nPermDimsS,nTmpDimsS, 652 & apermS(1,1,j), atempS, iper, 653 & ilwork, shp, shgl, 654 & shpb, shglb, rowp, 655 & colm, lhsS(1,j), 656 & solinc(1,isclr+5), tcorecpscal) 657 658 659 endif ! end of scalar type solve 660 661 else ! this is an update (mod did not equal zero) 662 iupdate=icode/10 ! what to update 663 if(icode.eq.1) then !update flow 664 call itrCorrect ( y, ac, u, solinc, iBC) 665 call itrBC (y, ac, iBC, BC, iper, ilwork) 666 else ! update scalar 667 isclr=iupdate !unless 668 if(icode.eq.6) isclr=0 669 if(iRANS.lt.-100)then ! RANS 670 call itrCorrectSclrPos(y,ac,solinc(1,isclr+5)) 671 else 672 call itrCorrectSclr (y, ac, solinc(1,isclr+5)) 673 endif 674 if (ilset.eq.2 .and. isclr.eq.2) then 675 if (ivconstraint .eq. 1) then 676 call itrBCSclr ( y, ac, iBC, BC, iper, 677 & ilwork) 678c 679c ... applying the volume constraint on second level set scalar 680c 681 call solvecon (y, x, iBC, BC, 682 & iper, ilwork, shp, shgl) 683c 684 endif ! end of volume constraint calculations 685 endif ! end of redistance calculations 686c 687 call itrBCSclr ( y, ac, iBC, BC, iper, 688 & ilwork) 689 endif ! end of flow or scalar update 690 endif ! end of switch between solve or update 691 enddo ! loop over sequence in step 692c 693c 694c.... obtain the time average statistics 695c 696 if (ioform .eq. 2) then 697 698 call stsGetStats( y, yold, ac, acold, 699 & u, uold, x, 700 & shp, shgl, shpb, shglb, 701 & iBC, BC, iper, ilwork, 702 & rowp, colm, lhsK, lhsP ) 703 endif 704 705c 706c Find the solution at the end of the timestep and move it to old 707c 708c 709c ...First to reassign the parameters for the original time integrator scheme 710c 711 if((iLSet.eq.2).and.(ilss.eq.1)) then 712 alfi =alfit 713 gami =gamit 714 almi =almit 715 Delt(1)=Deltt 716 Dtgl =Dtglt 717 endif 718 call itrUpdate( yold, acold, uold, y, ac, u) 719 call itrBC (yold, acold, iBC, BC, iper,ilwork) 720 721 istep = istep + 1 722 lstep = lstep + 1 723c 724c .. Print memory consumption on BGQ 725c 726 call printmeminfo("itrdrv"//char(0)) 727 728c 729c .. Compute vorticity 730c 731 if ( icomputevort == 1) then 732 733 ! vorticity components and magnitude 734 vorticity(:,1) = GradV(:,8)-GradV(:,6) !omega_x 735 vorticity(:,2) = GradV(:,3)-GradV(:,7) !omega_y 736 vorticity(:,3) = GradV(:,4)-GradV(:,2) !omega_z 737 vorticity(:,4) = sqrt( vorticity(:,1)*vorticity(:,1) 738 & + vorticity(:,2)*vorticity(:,2) 739 & + vorticity(:,3)*vorticity(:,3) ) 740 ! Q 741 strain(:,1) = GradV(:,1) !S11 742 strain(:,2) = 0.5*(GradV(:,2)+GradV(:,4)) !S12 743 strain(:,3) = 0.5*(GradV(:,3)+GradV(:,7)) !S13 744 strain(:,4) = GradV(:,5) !S22 745 strain(:,5) = 0.5*(GradV(:,6)+GradV(:,8)) !S23 746 strain(:,6) = GradV(:,9) !S33 747 748 vorticity(:,5) = 0.25*( vorticity(:,4)*vorticity(:,4) !Q 749 & - 2.0*( strain(:,1)*strain(:,1) 750 & + 2* strain(:,2)*strain(:,2) 751 & + 2* strain(:,3)*strain(:,3) 752 & + strain(:,4)*strain(:,4) 753 & + 2* strain(:,5)*strain(:,5) 754 & + strain(:,6)*strain(:,6))) 755 756 endif 757c 758c .. write out the instantaneous solution 759c 7602001 continue ! we could get here by 2001 label if user requested stop 761 if (((irs .ge. 1) .and. (mod(lstep, ntout) .eq. 0)) .or. 762 & istep.eq.nstep(itseq)) then 763 764!so that we can see progress in force file close it so that it flushes 765!and then reopen in append mode 766 767 close(iforce) 768 open (unit=iforce, file=fforce, position='append') 769 770! Call to restar() will open restart file in write mode (and not append mode) 771! that is needed as other fields are written in append mode 772 773 call restar ('out ', yold ,ac) 774 if(ideformwall == 1) then 775 if(myrank.eq.master) then 776 write(*,*) 'ideformwall is 1 and is a dead code path... exiting' 777 endif 778 stop 779 endif 780 781 if(ivort == 1) then 782 call write_field(myrank,'a','vorticity',9,vorticity, 783 & 'd',nshg,5,lstep) 784 endif 785 786 call printmeminfo("itrdrv after checkpoint"//char(0)) 787 else if(stopjob.eq.-2) then 788 if(myrank.eq.master) then 789 write(*,*) 'line 755 says no write before stopping' 790 write(*,*) 'istep,nstep,irs',istep,nstep(itseq),irs 791 endif 792 endif !just the instantaneous stuff for videos 793c 794c.... compute the consistent boundary flux 795c 796 if(abs(itwmod).ne.1 .and. iowflux.eq.1) then 797 call Bflux ( yold, acold, uold, x, 798 & shp, shgl, shpb, 799 & shglb, ilwork, iBC, 800 & BC, iper, wallssVec) 801 endif 802 803 if(stopjob.eq.-2) goto 2003 804 805 806c 807c ... update the flow history for the impedance convolution, filter it and write it out 808c 809 if(numImpSrfs.gt.zero) then 810 call UpdHistConv(y,nsrflistImp,numImpSrfs) !uses Delt(1) 811 endif 812 813c 814c ... update the flow history for the RCR convolution 815c 816 if(numRCRSrfs.gt.zero) then 817 call UpdHistConv(y,nsrflistRCR,numRCRSrfs) !uses lstep 818 endif 819 820 821c... dump TIME SERIES 822 823 if (exts) then 824 if (mod(lstep-1,freq).eq.0) then 825 826 if (numpe > 1) then 827 do jj = 1, ntspts 828 vartssoln((jj-1)*ndof+1:jj*ndof)=varts(jj,:) 829 ivarts=zero 830 enddo 831 do k=1,ndof*ntspts 832 if(vartssoln(k).ne.zero) ivarts(k)=1 833 enddo 834 835! call MPI_REDUCE(vartssoln, vartssolng, ndof*ntspts, 836! & MPI_DOUBLE_PRECISION, MPI_SUM, master, 837! & MPI_COMM_WORLD, ierr) 838 839 call MPI_BARRIER(MPI_COMM_WORLD, ierr) 840 call MPI_ALLREDUCE(vartssoln, vartssolng, 841 & ndof*ntspts, 842 & MPI_DOUBLE_PRECISION, MPI_SUM, 843 & MPI_COMM_WORLD, ierr) 844 845! call MPI_REDUCE(ivarts, ivartsg, ndof*ntspts, 846! & MPI_INTEGER, MPI_SUM, master, 847! & MPI_COMM_WORLD, ierr) 848 849 call MPI_BARRIER(MPI_COMM_WORLD, ierr) 850 call MPI_ALLREDUCE(ivarts, ivartsg, ndof*ntspts, 851 & MPI_INTEGER, MPI_SUM, 852 & MPI_COMM_WORLD, ierr) 853 854! if (myrank.eq.zero) then 855 do jj = 1, ntspts 856 857 if(myrank .eq. iv_rank(jj)) then 858 ! No need to update all varts components, only the one treated by the expected rank 859 ! Note: keep varts as a vector, as multiple probes could be treated by one rank 860 indxvarts = (jj-1)*ndof 861 do k=1,ndof 862 if(ivartsg(indxvarts+k).ne.0) then ! none of the vartssoln(parts) were non zero 863 varts(jj,k)=vartssolng(indxvarts+k)/ 864 & ivartsg(indxvarts+k) 865 endif 866 enddo 867 endif !only if myrank eq iv_rank(jj) 868 enddo 869! endif !only on master 870 endif !only if numpe > 1 871 872! if (myrank.eq.zero) then 873 do jj = 1, ntspts 874 if(myrank .eq. iv_rank(jj)) then 875 ifile = 1000+jj 876 write(ifile,555) lstep, (varts(jj,k),k=1,ndof) !Beware of format 555 - check ndof 877c call flush(ifile) 878 if (((irs .ge. 1) .and. 879 & (mod(lstep, ntout) .eq. 0))) then 880 close(ifile) 881 fvarts='varts/varts' 882 fvarts=trim(fvarts)//trim(cname2(jj)) 883 fvarts=trim(fvarts)//trim(cname2(lskeep)) 884 fvarts=trim(fvarts)//'.dat' 885 fvarts=trim(fvarts) 886 open(unit=ifile, file=fvarts, 887 & position='append') 888 endif !only when dumping restart 889 endif 890 enddo 891! endif !only on master 892 893 varts(:,:) = zero ! reset the array for next step 894 895 896!555 format(i6,5(2x,E12.5e2)) 897555 format(i6,6(2x,E20.12e2)) !assuming ndof = 6 here 898 899 endif 900 endif 901 902c 903c.... update and the aerodynamic forces 904c 905 call forces ( yold, ilwork ) 906 907 if((irscale.ge.0).or.(itwmod.gt.0)) 908 & call getvel (yold, ilwork, iBC, 909 & nsons, ifath, velbar) 910 911 if((irscale.ge.0).and.(myrank.eq.master)) then 912 call genscale(yold, x, iper, 913 & iBC, ifath, velbar, 914 & nsons) 915 endif 916c 917c.... print out results. 918c 919 ntoutv=max(ntout,100) ! velb is not needed so often 920 if ((irs .ge. 1) .and. (mod(lstep, ntout) .eq. 0)) then 921 if( (mod(lstep, ntoutv) .eq. 0) .and. 922 & ((irscale.ge.0).or.(itwmod.gt.0) .or. 923 & ((nsonmax.eq.1).and.(iLES.gt.0)))) 924 & call rwvelb ('out ', velbar ,ifail) 925 endif 926c 927c.... end of the NSTEP and NTSEQ loops 928c 929 930 931c 932c.... -------------------> error calculation <----------------- 933c 934 if(ierrcalc.eq.1 .or. ioybar.eq.1) then 935c$$$c 936c$$$c compute average 937c$$$c 938c$$$ tfact=one/istep 939c$$$ ybar =tfact*yold + (one-tfact)*ybar 940 941c compute average 942c ybar(:,1:3) are average velocity components 943c ybar(:,4) is average pressure 944c ybar(:,5) is average speed 945c ybar(:,6:8) is average of sq. of each vel. component 946c ybar(:,9) is average of sq. of pressure 947c ybar(:,10:12) is average of cross vel. components : uv, uw and vw 948c averaging procedure justified only for identical time step sizes 949c ybar(:,13) is average of eddy viscosity 950c ybar(:,14:16) is average vorticity components 951c ybar(:,17) is average vorticity magnitude 952c istep is number of time step 953c 954 icollectybar = 0 955 if(nphasesincycle.eq.0 .or. 956 & istep.gt.ncycles_startphaseavg*nstepsincycle) then 957 icollectybar = 1 958 if((istep-1).eq.ncycles_startphaseavg*nstepsincycle) 959 & istepsinybar = 0 ! init. to zero in first cycle in avg. 960 endif 961 962 if(icollectybar.eq.1) then 963 istepsinybar = istepsinybar+1 964 tfact=one/istepsinybar 965 966 if(myrank.eq.master .and. nphasesincycle.ne.0 .and. 967 & mod((istep-1),nstepsincycle).eq.0) 968 & write(*,*)'nsamples in phase average:',istepsinybar 969 970c ybar to contain the averaged ((u,v,w),p)-fields 971c and speed average, i.e., sqrt(u^2+v^2+w^2) 972c and avg. of sq. terms including 973c u^2, v^2, w^2, p^2 and cross terms of uv, uw and vw 974 975 ybar(:,1) = tfact*yold(:,1) + (one-tfact)*ybar(:,1) 976 ybar(:,2) = tfact*yold(:,2) + (one-tfact)*ybar(:,2) 977 ybar(:,3) = tfact*yold(:,3) + (one-tfact)*ybar(:,3) 978 ybar(:,4) = tfact*yold(:,4) + (one-tfact)*ybar(:,4) 979 ybar(:,5) = tfact*sqrt(yold(:,1)**2+yold(:,2)**2+ 980 & yold(:,3)**2) + (one-tfact)*ybar(:,5) 981 ybar(:,6) = tfact*yold(:,1)**2 + 982 & (one-tfact)*ybar(:,6) 983 ybar(:,7) = tfact*yold(:,2)**2 + 984 & (one-tfact)*ybar(:,7) 985 ybar(:,8) = tfact*yold(:,3)**2 + 986 & (one-tfact)*ybar(:,8) 987 ybar(:,9) = tfact*yold(:,4)**2 + 988 & (one-tfact)*ybar(:,9) 989 ybar(:,10) = tfact*yold(:,1)*yold(:,2) + !uv 990 & (one-tfact)*ybar(:,10) 991 ybar(:,11) = tfact*yold(:,1)*yold(:,3) + !uw 992 & (one-tfact)*ybar(:,11) 993 ybar(:,12) = tfact*yold(:,2)*yold(:,3) + !vw 994 & (one-tfact)*ybar(:,12) 995!MR CHANGE 996 if(nsclr.gt.0) !nut 997 & ybar(:,13) = tfact*yold(:,6) + (one-tfact)*ybar(:,13) 998 999 if(ivort == 1) then !vorticity 1000 ybar(:,14) = tfact*vorticity(:,1) + 1001 & (one-tfact)*ybar(:,14) 1002 ybar(:,15) = tfact*vorticity(:,2) + 1003 & (one-tfact)*ybar(:,15) 1004 ybar(:,16) = tfact*vorticity(:,3) + 1005 & (one-tfact)*ybar(:,16) 1006 ybar(:,17) = tfact*vorticity(:,4) + 1007 & (one-tfact)*ybar(:,17) 1008 endif 1009 1010 if(abs(itwmod).ne.1 .and. iowflux.eq.1) then 1011 wallssVecBar(:,1) = tfact*wallssVec(:,1) 1012 & +(one-tfact)*wallssVecBar(:,1) 1013 wallssVecBar(:,2) = tfact*wallssVec(:,2) 1014 & +(one-tfact)*wallssVecBar(:,2) 1015 wallssVecBar(:,3) = tfact*wallssVec(:,3) 1016 & +(one-tfact)*wallssVecBar(:,3) 1017 endif 1018!MR CHANGE END 1019 endif 1020c 1021c compute phase average 1022c 1023 if(nphasesincycle.ne.0 .and. 1024 & istep.gt.ncycles_startphaseavg*nstepsincycle) then 1025 1026c beginning of cycle is considered as ncycles_startphaseavg*nstepsincycle+1 1027 if((istep-1).eq.ncycles_startphaseavg*nstepsincycle) 1028 & icyclesinavg = 0 ! init. to zero in first cycle in avg. 1029 1030 ! find number of steps between phases 1031 nstepsbtwphase = nstepsincycle/nphasesincycle ! integer value 1032 if(mod(istep-1,nstepsincycle).eq.0) then 1033 iphase = 1 ! init. to one in beginning of every cycle 1034 icyclesinavg = icyclesinavg + 1 1035 endif 1036 1037 icollectphase = 0 1038 istepincycle = mod(istep,nstepsincycle) 1039 if(istepincycle.eq.0) istepincycle=nstepsincycle 1040 if(istepincycle.eq.iphase*nstepsbtwphase) then 1041 icollectphase = 1 1042 iphase = iphase+1 ! use 'iphase-1' below 1043 endif 1044 1045 if(icollectphase.eq.1) then 1046 tfactphase = one/icyclesinavg 1047 1048 if(myrank.eq.master) then 1049 write(*,*) 'nsamples in phase ',iphase-1,': ', 1050 & icyclesinavg 1051 endif 1052 1053 yphbar(:,1,iphase-1) = tfactphase*yold(:,1) + 1054 & (one-tfactphase)*yphbar(:,1,iphase-1) 1055 yphbar(:,2,iphase-1) = tfactphase*yold(:,2) + 1056 & (one-tfactphase)*yphbar(:,2,iphase-1) 1057 yphbar(:,3,iphase-1) = tfactphase*yold(:,3) + 1058 & (one-tfactphase)*yphbar(:,3,iphase-1) 1059 yphbar(:,4,iphase-1) = tfactphase*yold(:,4) + 1060 & (one-tfactphase)*yphbar(:,4,iphase-1) 1061 yphbar(:,5,iphase-1) = tfactphase*sqrt(yold(:,1)**2 1062 & +yold(:,2)**2+yold(:,3)**2) + 1063 & (one-tfactphase)*yphbar(:,5,iphase-1) 1064!MR CHANGE 1065 yphbar(:,6,iphase-1) = 1066 & tfactphase*yold(:,1)*yold(:,1) 1067 & +(one-tfactphase)*yphbar(:,6,iphase-1) 1068 1069 yphbar(:,7,iphase-1) = 1070 & tfactphase*yold(:,1)*yold(:,2) 1071 & +(one-tfactphase)*yphbar(:,7,iphase-1) 1072 1073 yphbar(:,8,iphase-1) = 1074 & tfactphase*yold(:,1)*yold(:,3) 1075 & +(one-tfactphase)*yphbar(:,8,iphase-1) 1076 1077 yphbar(:,9,iphase-1) = 1078 & tfactphase*yold(:,2)*yold(:,2) 1079 & +(one-tfactphase)*yphbar(:,9,iphase-1) 1080 1081 yphbar(:,10,iphase-1) = 1082 & tfactphase*yold(:,2)*yold(:,3) 1083 & +(one-tfactphase)*yphbar(:,10,iphase-1) 1084 1085 yphbar(:,11,iphase-1) = 1086 & tfactphase*yold(:,3)*yold(:,3) 1087 & +(one-tfactphase)*yphbar(:,11,iphase-1) 1088 1089 if(ivort == 1) then 1090 yphbar(:,12,iphase-1) = 1091 & tfactphase*vorticity(:,1) 1092 & +(one-tfactphase)*yphbar(:,12,iphase-1) 1093 yphbar(:,13,iphase-1) = 1094 & tfactphase*vorticity(:,2) 1095 & +(one-tfactphase)*yphbar(:,13,iphase-1) 1096 yphbar(:,14,iphase-1) = 1097 & tfactphase*vorticity(:,3) 1098 & +(one-tfactphase)*yphbar(:,14,iphase-1) 1099 yphbar(:,15,iphase-1) = 1100 & tfactphase*vorticity(:,4) 1101 & +(one-tfactphase)*yphbar(:,15,iphase-1) 1102 endif 1103!MR CHANGE END 1104 endif 1105 endif 1106c 1107c compute rms 1108c 1109 if(icollectybar.eq.1) then 1110 rerr(:, 7)=rerr(:, 7)+(yold(:,1)-ybar(:,1))**2 1111 rerr(:, 8)=rerr(:, 8)+(yold(:,2)-ybar(:,2))**2 1112 rerr(:, 9)=rerr(:, 9)+(yold(:,3)-ybar(:,3))**2 1113 rerr(:,10)=rerr(:,10)+(yold(:,4)-ybar(:,4))**2 1114 endif 1115 endif 1116 2003 continue ! we get here if stopjob equals lstep and this jumped over 1117! the statistics computation because we have no new data to average in 1118! rather we are just trying to output the last state that was not already 1119! written 1120c 1121c.... ----------------------> Complete Restart Processing <---------------------- 1122c 1123! for now it is the same frequency but need to change this 1124! soon.... but don't forget to change the field counter in 1125! new_interface.cc 1126! 1127 if (((irs .ge. 1) .and. (mod(lstep, ntout) .eq. 0)) .or. 1128 & istep.eq.nstep(itseq)) then 1129 if ((irs .ge. 1) .and. ((mod(lstep, ntout) .ne. 0) .or. 1130 & (nstp .eq. 0))) then 1131 if( 1132 & ((irscale.ge.0).or.(itwmod.gt.0) .or. 1133 & ((nsonmax.eq.1).and.iLES.gt.0))) 1134 & call rwvelb ('out ', velbar ,ifail) 1135 endif 1136 1137 lesId = numeqns(1) 1138 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1139 if(myrank.eq.0) then 1140 tcormr1 = TMRC() 1141 endif 1142 call saveLesRestart( lesId, aperm , nshg, myrank, lstep, 1143 & nPermDims ) 1144 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1145 if(myrank.eq.0) then 1146 tcormr2 = TMRC() 1147 write(6,*) 'call saveLesRestart for projection and'// 1148 & 'pressure projection vectors', tcormr2-tcormr1 1149 endif 1150 1151 if(ierrcalc.eq.1) then 1152c 1153c.....smooth the error indicators 1154c 1155 do i=1,ierrsmooth 1156 call errsmooth( rerr, x, iper, ilwork, shp, shgl, iBC ) 1157 end do 1158 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1159 if(myrank.eq.0) then 1160 tcormr1 = TMRC() 1161 endif 1162 call write_error(myrank, lstep, nshg, 10, rerr ) 1163 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1164 if(myrank.eq.0) then 1165 tcormr2 = TMRC() 1166 write(6,*) 'Time to write the error fields to the disks', 1167 & tcormr2-tcormr1 1168 endif 1169 endif ! ierrcalc 1170 1171 if(ioybar.eq.1) then 1172 if(ivort == 1) then 1173 call write_field(myrank,'a','ybar',4, 1174 & ybar,'d',nshg,17,lstep) 1175 else 1176 call write_field(myrank,'a','ybar',4, 1177 & ybar,'d',nshg,13,lstep) 1178 endif 1179 1180 if(abs(itwmod).ne.1 .and. iowflux.eq.1) then 1181 call write_field(myrank,'a','wssbar',6, 1182 & wallssVecBar,'d',nshg,3,lstep) 1183 endif 1184 1185 if(nphasesincycle .gt. 0) then 1186 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1187 if(myrank.eq.0) then 1188 tcormr1 = TMRC() 1189 endif 1190 do iphase=1,nphasesincycle 1191 if(ivort == 1) then 1192 call write_phavg2(myrank,'a','phase_average',13,iphase, 1193 & nphasesincycle,yphbar(:,:,iphase),'d',nshg,15,lstep) 1194 else 1195 call write_phavg2(myrank,'a','phase_average',13,iphase, 1196 & nphasesincycle,yphbar(:,:,iphase),'d',nshg,11,lstep) 1197 endif 1198 end do 1199 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1200 if(myrank.eq.0) then 1201 tcormr2 = TMRC() 1202 write(6,*) 'write all phase avg to the disks = ', 1203 & tcormr2-tcormr1 1204 endif 1205 endif !nphasesincyle 1206 endif !ioybar 1207 1208 if ( ( ihessian .eq. 1 ) .and. ( numpe < 2 ) )then 1209 uhess = zero 1210 gradu = zero 1211 tf = zero 1212 1213 do ku=1,nshg 1214 tf(ku,1) = x(ku,1)**3 1215 end do 1216 call hessian( yold, x, shp, shgl, iBC, 1217 & shpb, shglb, iper, ilwork, uhess, gradu ) 1218 1219 call write_hessian( uhess, gradu, nshg ) 1220 endif 1221 1222 if(iRANS.lt.0) then 1223 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1224 if(myrank.eq.0) then 1225 tcormr1 = TMRC() 1226 endif 1227 call write_field(myrank,'a','dwal',4,d2wall,'d', 1228 & nshg,1,lstep) 1229 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1230 if(myrank.eq.0) then 1231 tcormr2 = TMRC() 1232 write(6,*) 'Time to write dwal to the disks = ', 1233 & tcormr2-tcormr1 1234 endif 1235 endif !iRANS 1236 1237 endif ! write out complete restart state 1238 !next 2 lines are two ways to end early 1239 if(stopjob.eq.-2) goto 2002 1240 if(istop.eq.1000) goto 2002 ! stop when delta small (see rstatic) 1241 2000 continue 1242 2002 continue 1243 1244! done with time stepping so deallocate fields already written 1245! 1246 if(ioybar.eq.1) then 1247 deallocate(ybar) 1248 if(abs(itwmod).ne.1 .and. iowflux.eq.1) then 1249 deallocate(wallssVecbar) 1250 endif 1251 if(nphasesincycle .gt. 0) then 1252 deallocate(yphbar) 1253 endif !nphasesincyle 1254 endif !ioybar 1255 if(ivort == 1) then 1256 deallocate(strain,vorticity) 1257 endif 1258 if(abs(itwmod).ne.1 .and. iowflux.eq.1) then 1259 deallocate(wallssVec) 1260 endif 1261 if(iRANS.lt.0) then 1262 deallocate(d2wall) 1263 endif 1264 1265 1266CAD tcorecp2 = second(0) 1267CAD tcorewc2 = second(-1) 1268 1269CAD write(6,*) 'T(core) cpu-wallclock = ',tcorecp2-tcorecp1, 1270CAD & tcorewc2-tcorewc1 1271 1272 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1273 if(myrank.eq.0) then 1274 tcorecp2 = TMRC() 1275 write(6,*) 'T(core) cpu = ',tcorecp2-tcorecp1 1276 write(6,*) '(Elm. form.',tcorecp(1), 1277 & ',Lin. alg. sol.',tcorecp(2),')' 1278 write(6,*) '(Elm. form. Scal.',tcorecpscal(1), 1279 & ',Lin. alg. sol. Scal.',tcorecpscal(2),')' 1280 write(6,*) '' 1281 1282 endif 1283 1284 call print_system_stats(tcorecp, tcorecpscal) 1285 call print_mesh_stats() 1286 call print_mpi_stats() 1287 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1288! return 1289c call MPI_Finalize() 1290c call MPI_ABORT(MPI_COMM_WORLD, ierr) 1291 1292 3000 continue 1293 1294 1295c 1296c.... close history and aerodynamic forces files 1297c 1298 if (myrank .eq. master) then 1299! close (ihist) 1300 close (iforce) 1301 close(76) 1302 if(numImpSrfs.gt.0 .or. numRCRSrfs.gt.0) then 1303 close (8177) 1304 endif 1305 endif 1306c 1307c.... close varts file for probes 1308c 1309 if(exts) then 1310 do jj=1,ntspts 1311 if (myrank == iv_rank(jj)) then 1312 close(1000+jj) 1313 endif 1314 enddo 1315 deallocate (ivarts) 1316 deallocate (ivartsg) 1317 deallocate (iv_rank) 1318 deallocate (vartssoln) 1319 deallocate (vartssolng) 1320 endif 1321 1322!MR CHANGE 1323 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1324 if(myrank.eq.0) then 1325 write(*,*) 'itrdrv - done with aerodynamic forces' 1326 endif 1327!MR CHANGE 1328 1329 do isrf = 0,MAXSURF 1330! if ( nsrflist(isrf).ne.0 ) then 1331 if ( nsrflist(isrf).ne.0 .and. 1332 & myrank.eq.irankfilesforce(isrf)) then 1333 iunit=60+isrf 1334 close(iunit) 1335 endif 1336 enddo 1337 1338!MR CHANGE 1339 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1340 if(myrank.eq.0) then 1341 write(*,*) 'itrdrv - done with MAXSURF' 1342 endif 1343!MR CHANGE 1344 1345 1346 5 format(1X,F15.10,3X,F15.10,3X,F15.10,3X,F15.10) 1347 444 format(6(2x,e14.7)) 1348c 1349c.... end 1350c 1351 if(nsolflow.eq.1) then 1352 deallocate (lhsK) 1353 deallocate (lhsP) 1354 deallocate (aperm) 1355 deallocate (atemp) 1356 endif 1357 if(nsclrsol.gt.0) then 1358 deallocate (lhsS) 1359 deallocate (apermS) 1360 deallocate (atempS) 1361 endif 1362 1363 if(iabc==1) deallocate(acs) 1364 1365!MR CHANGE 1366 if (numpe > 1) call MPI_BARRIER(MPI_COMM_WORLD, ierr) 1367 if(myrank.eq.0) then 1368 write(*,*) 'itrdrv - done - BACK TO process.f' 1369 endif 1370!MR CHANGE 1371 1372 1373 1374 return 1375 end 1376 1377 subroutine lesmodels(y, ac, shgl, shp, 1378 & iper, ilwork, rowp, colm, 1379 & nsons, ifath, x, 1380 & iBC, BC) 1381 1382 include "common.h" 1383 1384 real*8 y(nshg,ndof), ac(nshg,ndof), 1385 & x(numnp,nsd), 1386 & BC(nshg,ndofBC) 1387 real*8 shp(MAXTOP,maxsh,MAXQPT), 1388 & shgl(MAXTOP,nsd,maxsh,MAXQPT) 1389 1390c 1391 integer rowp(nshg,nnz), colm(nshg+1), 1392 & iBC(nshg), 1393 & ilwork(nlwork), 1394 & iper(nshg) 1395 dimension ifath(numnp), nsons(nfath) 1396 1397 real*8, allocatable, dimension(:) :: fwr2,fwr3,fwr4 1398 real*8, allocatable, dimension(:) :: stabdis,cdelsq1 1399 real*8, allocatable, dimension(:,:) :: xavegt, xavegt2,xavegt3 1400 1401 if( (iLES.gt.1) ) then ! Allocate Stuff for advanced LES models 1402 allocate (fwr2(nshg)) 1403 allocate (fwr3(nshg)) 1404 allocate (fwr4(nshg)) 1405 allocate (xavegt(nfath,12)) 1406 allocate (xavegt2(nfath,12)) 1407 allocate (xavegt3(nfath,12)) 1408 allocate (stabdis(nfath)) 1409 endif 1410 1411c.... get dynamic model coefficient 1412c 1413 ilesmod=iLES/10 1414c 1415c digit bit set filter rule, 10 bit set model 1416c 1417 if (ilesmod.eq.0) then ! 0 < iLES< 10 => dyn. model calculated 1418 ! at nodes based on discrete filtering 1419 1420 1421 if(isubmod.eq.2) then 1422 call SUPGdis(y, ac, shgl, shp, 1423 & iper, ilwork, 1424 & nsons, ifath, x, 1425 & iBC, BC, stabdis, xavegt3) 1426 endif 1427 1428 if( ((isubmod.eq.0).or.(isubmod.eq.2)))then ! If no 1429 ! sub-model 1430 ! or SUPG 1431 ! model wanted 1432 1433 if(i2filt.eq.0)then ! If simple filter 1434 1435 if(modlstats .eq. 0) then ! If no model stats wanted 1436 call getdmc (y, shgl, shp, 1437 & iper, ilwork, nsons, 1438 & ifath, x) 1439 else ! else get model stats 1440 call stdfdmc (y, shgl, shp, 1441 & iper, ilwork, nsons, 1442 & ifath, x) 1443 endif ! end of stats if statement 1444 1445 else ! else if twice filtering 1446 1447 call widefdmc(y, shgl, shp, 1448 & iper, ilwork, nsons, 1449 & ifath, x) 1450 1451 1452 endif ! end of simple filter if statement 1453 1454 endif ! end of SUPG or no sub-model if statement 1455 1456 1457 if( (isubmod.eq.1) ) then ! If DFWR sub-model wanted 1458 call cdelBHsq (y, shgl, shp, 1459 & iper, ilwork, nsons, 1460 & ifath, x, cdelsq1) 1461 call FiltRat (y, shgl, shp, 1462 & iper, ilwork, nsons, 1463 & ifath, x, cdelsq1, 1464 & fwr4, fwr3) 1465 1466 1467 if (i2filt.eq.0) then ! If simple filter wanted 1468 call DFWRsfdmc(y, shgl, shp, 1469 & iper, ilwork, nsons, 1470 & ifath, x, fwr2, fwr3) 1471 else ! else if twice filtering wanted 1472 call DFWRwfdmc(y, shgl, shp, 1473 & iper, ilwork, nsons, 1474 & ifath, x, fwr4, fwr4) 1475 endif ! end of simple filter if statement 1476 1477 endif ! end of DFWR sub-model if statement 1478 1479 if( (isubmod.eq.2) )then ! If SUPG sub-model wanted 1480 call dmcSUPG (y, ac, shgl, 1481 & shp, iper, ilwork, 1482 & nsons, ifath, x, 1483 & iBC, BC, rowp, colm, 1484 & xavegt2, stabdis) 1485 endif 1486 1487 if(idis.eq.1)then ! If SUPG/Model dissipation wanted 1488 call ediss (y, ac, shgl, 1489 & shp, iper, ilwork, 1490 & nsons, ifath, x, 1491 & iBC, BC, xavegt) 1492 endif 1493 1494 endif ! end of ilesmod 1495 1496 if (ilesmod .eq. 1) then ! 10 < iLES < 20 => dynamic-mixed 1497 ! at nodes based on discrete filtering 1498 call bardmc (y, shgl, shp, 1499 & iper, ilwork, 1500 & nsons, ifath, x) 1501 endif 1502 1503 if (ilesmod .eq. 2) then ! 20 < iLES < 30 => dynamic at quad 1504 ! pts based on lumped projection filt. 1505 1506 if(isubmod.eq.0)then 1507 call projdmc (y, shgl, shp, 1508 & iper, ilwork, x) 1509 else 1510 call cpjdmcnoi (y, shgl, shp, 1511 & iper, ilwork, x, 1512 & rowp, colm, 1513 & iBC, BC) 1514 endif 1515 1516 endif 1517 1518 if( (iLES.gt.1) ) then ! Deallocate Stuff for advanced LES models 1519 deallocate (fwr2) 1520 deallocate (fwr3) 1521 deallocate (fwr4) 1522 deallocate (xavegt) 1523 deallocate (xavegt2) 1524 deallocate (xavegt3) 1525 deallocate (stabdis) 1526 endif 1527 return 1528 end 1529 1530c 1531c...initialize the coefficients for the impedance convolution 1532c 1533 subroutine CalcImpConvCoef (numISrfs, numTpoints) 1534 1535 use convolImpFlow !uses flow history and impedance for convolution 1536 1537 include "common.h" !for alfi 1538 1539 integer numISrfs, numTpoints 1540 1541 allocate (ConvCoef(numTpoints+2,3)) !same time discret. for all imp. BC 1542 do j=1,numTpoints+2 1543 ConvCoef(j,:)=0.5/numTpoints !dt/2 divided by period T=N*dt 1544 ConvCoef(j,1)=ConvCoef(j,1)*(1.0-alfi)*(1.0-alfi) 1545 ConvCoef(j,2)=ConvCoef(j,2)*(1.0+2*alfi*(1.0-alfi)) 1546 ConvCoef(j,3)=ConvCoef(j,3)*alfi*alfi 1547 enddo 1548 ConvCoef(1,2)=zero 1549 ConvCoef(1,3)=zero 1550 ConvCoef(2,3)=zero 1551 ConvCoef(numTpoints+1,1)=zero 1552 ConvCoef(numTpoints+2,2)=zero 1553 ConvCoef(numTpoints+2,1)=zero 1554c 1555c...calculate the coefficients for the impedance convolution 1556c 1557 allocate (ImpConvCoef(numTpoints+2,numISrfs)) 1558 1559c..coefficients below assume Q linear in time step, Z constant 1560c do j=3,numTpoints 1561c ImpConvCoef(j,:) = ValueListImp(j-1,:)*ConvCoef(j,3) 1562c & + ValueListImp(j,:)*ConvCoef(j,2) 1563c & + ValueListImp(j+1,:)*ConvCoef(j,1) 1564c enddo 1565c ImpConvCoef(1,:) = ValueListImp(2,:)*ConvCoef(1,1) 1566c ImpConvCoef(2,:) = ValueListImp(2,:)*ConvCoef(2,2) 1567c & + ValueListImp(3,:)*ConvCoef(2,1) 1568c ImpConvCoef(numTpoints+1,:) = 1569c & ValueListImp(numTpoints,:)*ConvCoef(numTpoints+1,3) 1570c & + ValueListImp(numTpoints+1,:)*ConvCoef(numTpoints+1,2) 1571c ImpConvCoef(numTpoints+2,:) = 1572c & ValueListImp(numTpoints+1,:)*ConvCoef(numTpoints+2,3) 1573 1574c..try easiest convolution Q and Z constant per time step 1575 do j=3,numTpoints+1 1576 ImpConvCoef(j,:) = ValueListImp(j-1,:)/numTpoints 1577 enddo 1578 ImpConvCoef(1,:) =zero 1579 ImpConvCoef(2,:) =zero 1580 ImpConvCoef(numTpoints+2,:) = 1581 & ValueListImp(numTpoints+1,:)/numTpoints 1582c compensate for yalpha passed not y in Elmgmr() 1583 ImpConvCoef(numTpoints+1,:)= ImpConvCoef(numTpoints+1,:) 1584 & - ImpConvCoef(numTpoints+2,:)*(1.0-alfi)/alfi 1585 ImpConvCoef(numTpoints+2,:)= ImpConvCoef(numTpoints+2,:)/alfi 1586 return 1587 end 1588 1589c 1590c ... update the flow rate history for the impedance convolution, filter it and write it out 1591c 1592 subroutine UpdHistConv(y,nsrfIdList,numSrfs) 1593 1594 use convolImpFlow !brings ntimeptpT, QHistImp, QHistTry, QHistTryF, numImpSrfs 1595 use convolRCRFlow !brings QHistRCR, numRCRSrfs 1596 1597 include "common.h" 1598 1599 integer nsrfIdList(0:MAXSURF), numSrfs 1600 character*20 fname1 1601 character*10 cname2 1602 character*5 cname 1603 real*8 y(nshg,3) !velocity at time n+1 1604 real*8 NewQ(0:MAXSURF) !temporary unknown for the flow rate 1605 !that needs to be added to the flow history 1606 1607 call GetFlowQ(NewQ,y,nsrfIdList,numSrfs) !new flow at time n+1 1608c 1609c... for imp BC: shift QHist, add new constribution, filter and write out 1610c 1611 if(numImpSrfs.gt.zero) then 1612 do j=1, ntimeptpT 1613 QHistImp(j,1:numSrfs)=QHistImp(j+1,1:numSrfs) 1614 enddo 1615 QHistImp(ntimeptpT+1,1:numSrfs) = NewQ(1:numSrfs) 1616 1617c 1618c....filter the flow rate history 1619c 1620 cutfreq = 10 !hardcoded cutting frequency of the filter 1621 do j=1, ntimeptpT 1622 QHistTry(j,:)=QHistImp(j+1,:) 1623 enddo 1624 call Filter(QHistTryF,QHistTry,ntimeptpT,Delt(1),cutfreq) 1625c.... if no filter applied then uncomment next three lines 1626c do j=1, ntimeptpT 1627c QHistTryF(j,:)=QHistTry(j,:) 1628c enddo 1629 1630c QHistImp(1,:)=zero ! why do we do this? for beta(1,:) = zero it does not really matters 1631 do j=1, ntimeptpT 1632 QHistImp(j+1,:)=QHistTryF(j,:) 1633 enddo 1634c 1635c.... write out the new history of flow rates to Qhistor.dat 1636c 1637 if (((irs .ge. 1) .and. ((mod(lstep, ntout) .eq. 0) .or. 1638 & (istep .eq. nstep(1)))) .and. 1639 & (myrank .eq. master)) then 1640 open(unit=816, file='Qhistor.dat',status='replace') 1641 write(816,*) ntimeptpT 1642 do j=1,ntimeptpT+1 1643 write(816,*) (QHistImp(j,n),n=1, numSrfs) 1644 enddo 1645 close(816) 1646c... write out a copy with step number to be able to restart 1647 fname1 = 'Qhistor' 1648 fname1 = trim(fname1)//trim(cname2(lstep))//'.dat' 1649 open(unit=8166,file=trim(fname1),status='unknown') 1650 write(8166,*) ntimeptpT 1651 do j=1,ntimeptpT+1 1652 write(8166,*) (QHistImp(j,n),n=1, numSrfs) 1653 enddo 1654 close(8166) 1655 endif 1656 endif 1657 1658c 1659c... for RCR bc just add the new contribution 1660c 1661 if(numRCRSrfs.gt.zero) then 1662 QHistRCR(lstep+1,1:numSrfs) = NewQ(1:numSrfs) 1663c 1664c.... write out the new history of flow rates to Qhistor.dat 1665c 1666 if ((irs .ge. 1) .and. (myrank .eq. master)) then 1667 if(istep.eq.1) then 1668 open(unit=816,file='Qhistor.dat',status='unknown') 1669 else 1670 open(unit=816,file='Qhistor.dat',position='append') 1671 endif 1672 if(istep.eq.1) then 1673 do j=1,lstep 1674 write(816,*) j, (QHistRCR(j,n),n=1,numSrfs) ! read from file of previous run 1675 enddo 1676 endif 1677 write(816,*) lstep+1, (QHistRCR(lstep+1,n),n=1, numSrfs) 1678 close(816) 1679c... write out a copy with step number to be able to restart 1680 if (((irs .ge. 1) .and. ((mod(lstep, ntout) .eq. 0) .or. 1681 & (istep .eq. nstep(1)))) .and. 1682 & (myrank .eq. master)) then 1683 fname1 = 'Qhistor' 1684 fname1 = trim(fname1)//trim(cname2(lstep))//'.dat' 1685 open(unit=8166,file=trim(fname1),status='unknown') 1686 write(8166,*) lstep+1 1687 do j=1,lstep+1 1688 write(8166,*) (QHistRCR(j,n),n=1, numSrfs) 1689 enddo 1690 close(8166) 1691 endif 1692 endif 1693 endif 1694 1695 return 1696 end 1697 1698c 1699c...calculate the time varying coefficients for the RCR convolution 1700c 1701 subroutine CalcRCRConvCoef (stepn, numSrfs) 1702 1703 use convolRCRFlow !brings in ValueListRCR, dtRCR 1704 1705 include "common.h" !brings alfi 1706 1707 integer numSrfs, stepn 1708 1709 RCRConvCoef = zero 1710 if (stepn .eq. 0) then 1711 RCRConvCoef(1,:) = ValueListRCR(1,:)*(1.0-alfi) + 1712 & ValueListRCR(3,:)*(-alfi + 1.0 + 1/dtRCR(:) 1713 & - exp(-alfi*dtRCR(:))*(1 + 1/dtRCR(:))) 1714 RCRConvCoef(2,:) = ValueListRCR(1,:)*alfi 1715 & + ValueListRCR(3,:) 1716 & *(alfi - 1/dtRCR(:) + exp(-alfi*dtRCR(:))/dtRCR(:)) 1717 endif 1718 if (stepn .ge. 1) then 1719 RCRConvCoef(1,:) =-ValueListRCR(3,:)*exp(-dtRCR(:)*(stepn+alfi)) 1720 & *(1 + (1 - exp(dtRCR(:)))/dtRCR(:)) 1721 RCRConvCoef(stepn+1,:) = ValueListRCR(1,:)*(1-alfi) 1722 & - ValueListRCR(3,:)*(alfi - 1 - 1/dtRCR(:) 1723 & + exp(-alfi*dtRCR(:))/dtRCR(:)*(2 - exp(-dtRCR(:)))) 1724 RCRConvCoef(stepn+2,:) = ValueListRCR(1,:)*alfi 1725 & + ValueListRCR(3,:) 1726 & *(alfi - 1/dtRCR(:) + exp(-alfi*dtRCR(:))/dtRCR(:)) 1727 endif 1728 if (stepn .ge. 2) then 1729 do j=2,stepn 1730 RCRConvCoef(j,:) = ValueListRCR(3,:)/dtRCR(:)* 1731 & exp(-dtRCR(:)*(stepn + alfi + 2 - j))* 1732 & (1 - exp(dtRCR(:)))**2 1733 enddo 1734 endif 1735 1736c compensate for yalpha passed not y in Elmgmr() 1737 RCRConvCoef(stepn+1,:)= RCRConvCoef(stepn+1,:) 1738 & - RCRConvCoef(stepn+2,:)*(1.0-alfi)/alfi 1739 RCRConvCoef(stepn+2,:)= RCRConvCoef(stepn+2,:)/alfi 1740 1741 return 1742 end 1743 1744c 1745c...calculate the time dependent H operator for the RCR convolution 1746c 1747 subroutine CalcHopRCR (timestepRCR, stepn, numSrfs) 1748 1749 use convolRCRFlow !brings in HopRCR, dtRCR 1750 1751 include "common.h" 1752 1753 integer numSrfs, stepn 1754 real*8 PdistCur(0:MAXSURF), timestepRCR 1755 1756 HopRCR=zero 1757 call RCRint(timestepRCR*(stepn + alfi),PdistCur) 1758 HopRCR(1:numSrfs) = RCRic(1:numSrfs) 1759 & *exp(-dtRCR(1:numSrfs)*(stepn + alfi)) + PdistCur(1:numSrfs) 1760 return 1761 end 1762c 1763c ... initialize the influence of the initial conditions for the RCR BC 1764c 1765 subroutine calcRCRic(y,srfIdList,numSrfs) 1766 1767 use convolRCRFlow !brings RCRic, ValueListRCR, ValuePdist 1768 1769 include "common.h" 1770 1771 integer srfIdList(0:MAXSURF), numSrfs, irankCoupled 1772 real*8 y(nshg,4) !need velocity and pressure 1773 real*8 Qini(0:MAXSURF) !initial flow rate 1774 real*8 PdistIni(0:MAXSURF) !initial distal pressure 1775 real*8 Pini(0:MAXSURF),CoupleArea(0:MAXSURF) ! initial pressure 1776 real*8 VelOnly(nshg,3), POnly(nshg) 1777 1778 allocate (RCRic(0:MAXSURF)) 1779 1780 if(lstep.eq.0) then 1781 VelOnly(:,1:3)=y(:,1:3) 1782 call GetFlowQ(Qini,VelOnly,srfIdList,numSrfs) !get initial flow 1783 QHistRCR(1,1:numSrfs)=Qini(1:numSrfs) !initialize QHistRCR 1784 POnly(:)=y(:,4) ! pressure 1785 call integrScalar(Pini,POnly,srfIdList,numSrfs) !get initial pressure integral 1786 POnly(:)=one ! one to get area 1787 call integrScalar(CoupleArea,POnly,srfIdList,numSrfs) !get surf area 1788 Pini(1:numSrfs) = Pini(1:numSrfs)/CoupleArea(1:numSrfs) 1789 else 1790 Qini(1:numSrfs)=QHistRCR(1,1:numSrfs) 1791 Pini(1:numSrfs)=zero ! hack 1792 endif 1793 call RCRint(istep,PdistIni) !get initial distal P (use istep) 1794 RCRic(1:numSrfs) = Pini(1:numSrfs) 1795 & - ValueListRCR(1,:)*Qini(1:numSrfs)-PdistIni(1:numSrfs) 1796 return 1797 end 1798 1799c.........function that integrates a scalar over a boundary 1800 subroutine integrScalar(scalInt,scal,srfIdList,numSrfs) 1801 1802 use pvsQbi !brings ndsurf, NASC 1803 1804 include "common.h" 1805 include "mpif.h" 1806 1807 integer srfIdList(0:MAXSURF), numSrfs, irankCoupled, i, k 1808 real*8 scal(nshg), scalInt(0:MAXSURF), scalIntProc(0:MAXSURF) 1809 1810 scalIntProc = zero 1811 do i = 1,nshg 1812 if(numSrfs.gt.zero) then 1813 do k = 1,numSrfs 1814 irankCoupled = 0 1815 if (srfIdList(k).eq.ndsurf(i)) then 1816 irankCoupled=k 1817 scalIntProc(irankCoupled) = scalIntProc(irankCoupled) 1818 & + NASC(i)*scal(i) 1819 exit 1820 endif 1821 enddo 1822 endif 1823 enddo 1824c 1825c at this point, each scalint has its "nodes" contributions to the scalar 1826c accumulated into scalIntProc. Note, because NASC is on processor this 1827c will NOT be the scalar for the surface yet 1828c 1829c.... reduce integrated scalar for each surface, push on scalInt 1830c 1831 npars=MAXSURF+1 1832 call MPI_ALLREDUCE (scalIntProc, scalInt(:), npars, 1833 & MPI_DOUBLE_PRECISION,MPI_SUM, MPI_COMM_WORLD,ierr) 1834 1835 return 1836 end 1837 1838 subroutine writeTimingMessage(key,iomode,timing) 1839 use iso_c_binding 1840 use phstr 1841 implicit none 1842 1843 character(len=*) :: key 1844 integer :: iomode 1845 real*8 :: timing 1846 character(len=1024) :: timing_msg 1847 character(len=*), parameter :: 1848 & streamModeString = c_char_"stream"//c_null_char, 1849 & fileModeString = c_char_"disk"//c_null_char 1850 1851 timing_msg = c_char_"Time to write "//c_null_char 1852 call phstr_appendStr(timing_msg,key) 1853 if ( iomode .eq. -1 ) then 1854 call phstr_appendStr(timing_msg, streamModeString) 1855 else 1856 call phstr_appendStr(timing_msg, fileModeString) 1857 endif 1858 call phstr_appendStr(timing_msg, c_char_' = '//c_null_char) 1859 call phstr_appendDbl(timing_msg, timing) 1860 write(6,*) trim(timing_msg) 1861 return 1862 end subroutine 1863 1864