!------------------------------------------------------------------------------| !------------------------------------------------------------------------------| ! | ! ||===\\ | ! || \\ | ! || || //==\\ || || //==|| ||/==\\ | ! || || || || || || || || || || | ! || // || || || || || || || | ! ||===// \\==// \\==\\ \\==\\ || | ! | !------------------------------------------------------------------------------| !------------------------------------------------------------------------------| ! | ! MOVE_SURFACE Nov. 2007 | ! | !------------------------------------------------------------------------------| !------------------------------------------------------------------------------| subroutine move_surface (surface,surface0,flag0,ov,dt,params,istep,is) !------------------------------------------------------------------------------| !(((((((((((((((( Purpose of the routine )))))))))))))))))))))))))))))))))))))) !------------------------------------------------------------------------------| ! subroutine to move a set of particles on a surface from a velocity ! field known at the nodes of an octree ! surface is the surface on which the particles need to be moved ! surface0 is the surface in its initial geometry ! flag0 is 1 if in midpoint configuration and 0 if at the end of the timestep ! if flag0=0, then the surface0 arrays are deallocated!! ! octree is the velocity octree ! noctree is its size ! unode,vnode and wnode are the components of the velocity ! nnode is the number of nodes on the octree ! icon_octree is the connectivity matrix on the octree ! nleaves is the number of leaves in the octree ! dt is the time step ! niter_move is the number of iterations used to move the particles ! it is read in input.txt ! here we use a simple method that performs a given (niter_move) ! number of iterations in a mid_point algorithm ! we also advect the normals by using the velocity gradient computed ! from the finite element shape function derivatives !------------------------------------------------------------------------------| !(((((((((((((((( declaration of the subroutine arguments )))))))))))))))))))) !------------------------------------------------------------------------------| use definitions implicit none type (sheet) surface type (sheet) surface0 type (octreev) ov integer flag0 double precision dt type(parameters) params integer istep,is !------------------------------------------------------------------------------| !(((((((((((((((( declaration of the subroutine internal variables ))))))))))))) !------------------------------------------------------------------------------| integer i,ip,iter,nremove,nedge,nrem integer i1,i2,i3,ij,k,err,nside integer iproc,nproc,ierr integer,dimension(:),allocatable::new,old type (sheet) surfacep,surfacep0 double precision u,v,w,rat,eps double precision x0,y0,z0,xi,yi,zi,x,y,z double precision,dimension(:),allocatable::xbuf,ybuf,zbuf double precision,dimension(:),allocatable::xnbuf,ynbuf,znbuf double precision,dimension(:),allocatable::pos,zzz double precision ux,uy,uz,vx,vy,vz,wx,wy,wz,xyzn double precision xn0,yn0,zn0,xyn,theta,phi double precision xn1,yn1,zn1,xn2,yn2,zn2 double precision xln1,yln1,zln1,xln2,yln2,zln2 double precision x1,x2,x3,y1,y2,y3,z1,z2,z3,xne,yne,zne logical remove character*72 :: shift !------------------------------------------------------------------------------- !------------------------------------------------------------------------------- INCLUDE 'mpif.h' call mpi_comm_size (mpi_comm_world,nproc,ierr) call mpi_comm_rank (mpi_comm_world,iproc,ierr) shift=' ' allocate (xbuf(surface%nsurface),stat=err) ; if (err.ne.0) call stop_run ('Error alloc xbuf in move_surface$') allocate (ybuf(surface%nsurface),stat=err) ; if (err.ne.0) call stop_run ('Error alloc ybuf in move_surface$') allocate (zbuf(surface%nsurface),stat=err) ; if (err.ne.0) call stop_run ('Error alloc zbuf in move_surface$') allocate (xnbuf(surface%nsurface),stat=err) ; if (err.ne.0) call stop_run ('Error alloc xnbuf in move_surface$') allocate (ynbuf(surface%nsurface),stat=err) ; if (err.ne.0) call stop_run ('Error alloc ynbuf in move_surface$') allocate (znbuf(surface%nsurface),stat=err) ; if (err.ne.0) call stop_run ('Error alloc znbuf in move_surface$') xbuf=0.d0 ybuf=0.d0 zbuf=0.d0 xnbuf=0.d0 ynbuf=0.d0 znbuf=0.d0 rat=1.d0-1.d-10 eps=1.d-10 !nside=2**surface%levelt+1 nside=2**surface%levelt+2 !opla do i=iproc+1,surface%nsurface,nproc u=0.d0 v=0.d0 w=0.d0 x0=surface%x(i) y0=surface%y(i) z0=surface%z(i) x=x0 y=y0 z=z0 do iter=1,params%niter_move xi=(x0+x)/2.d0 yi=(y0+y)/2.d0 zi=(z0+z)/2.d0 call octree_interpolate_three (3,ov%octree,ov%noctree,ov%icon,ov%nleaves, & ov%nnode,xi,yi,zi,ov%unode,u,ov%vnode,v,ov%wnode,w) if (i==1 .or. i==nside .or. i==2*nside-1 .or. i==3*nside-2) then !corner points z=z0+dt*w elseif (i>1 .and. i<nside) then !y=0 edge x=x0+dt*u z=z0+dt*w elseif (i>nside .and. i<2*nside-1) then !x=1 edge y=y0+dt*v z=z0+dt*w elseif (i>2*nside-1 .and. i<3*nside-2) then !y=1 edge x=x0+dt*u z=z0+dt*w elseif (i>3*nside-2 .and. i<4*nside-3) then !x=0 edge y=y0+dt*v z=z0+dt*w else x=x0+dt*u y=y0+dt*v z=z0+dt*w end if enddo xbuf(i)=x ybuf(i)=y zbuf(i)=z if (params%normaladvect) then call octree_interpolate_three_derivative (3,ov%octree,ov%noctree,ov%icon,ov%nleaves, & ov%nnode,xi,yi,zi, & ov%unode,u,ux,uy,uz, & ov%vnode,v,vx,vy,vz, & ov%wnode,w,wx,wy,wz) xn0=surface%xn(i) yn0=surface%yn(i) zn0=surface%zn(i) xyn=xn0**2+yn0**2 if (xyn.gt.0.d0) xyn=sqrt(xyn) theta=atan2(xyn,zn0) phi=0.d0 if (sin(theta).ne.0.d0) phi=atan2(yn0,xn0) xn1=cos(theta)*cos(phi) yn1=cos(theta)*sin(phi) zn1=-sin(theta) xn2=-sin(phi) yn2=cos(phi) zn2=0.d0 xln1=ux*xn1+uy*yn1+uz*zn1 yln1=vx*xn1+vy*yn1+vz*zn1 zln1=wx*xn1+wy*yn1+wz*zn1 xln2=ux*xn2+uy*yn2+uz*zn2 yln2=vx*xn2+vy*yn2+vz*zn2 zln2=wx*xn2+wy*yn2+wz*zn2 xnbuf(i)=xn0+(yn1*zln2-zn1*yln2+yln1*zn2-zln1*yn2)*dt+(yln1*zln2-zln1*yln2)*dt**2 ynbuf(i)=yn0+(zn1*xln2-xn1*zln2+zln1*xn2-xln1*zn2)*dt+(zln1*xln2-xln1*zln2)*dt**2 znbuf(i)=zn0+(xn1*yln2-yn1*xln2+xln1*yn2-yln1*xn2)*dt+(xln1*yln2-yln1*xln2)*dt**2 if (xnbuf(i).gt.1.d50) write(*,*) 'on proc ', iproc, ', xnbuf is large: ', xnbuf(i) if (ynbuf(i).gt.1.d50) write(*,*) 'on proc ', iproc, ', ynbuf is large: ', ynbuf(i) if (znbuf(i).gt.1.d50) write(*,*) 'on proc ', iproc, ', znbuf is large: ', znbuf(i) xyzn=sqrt(xnbuf(i)**2+ynbuf(i)**2+znbuf(i)**2) xnbuf(i)=xnbuf(i)/xyzn ynbuf(i)=ynbuf(i)/xyzn znbuf(i)=znbuf(i)/xyzn endif enddo surface%x=0.d0 surface%y=0.d0 surface%z=0.d0 call mpi_allreduce (xbuf,surface%x,surface%nsurface,mpi_double_precision,mpi_sum,mpi_comm_world,ierr) call mpi_allreduce (ybuf,surface%y,surface%nsurface,mpi_double_precision,mpi_sum,mpi_comm_world,ierr) call mpi_allreduce (zbuf,surface%z,surface%nsurface,mpi_double_precision,mpi_sum,mpi_comm_world,ierr) if (params%normaladvect) then surface%xn=0.d0 surface%yn=0.d0 surface%zn=0.d0 call mpi_allreduce (xnbuf,surface%xn,surface%nsurface,mpi_double_precision,mpi_sum,mpi_comm_world,ierr) call mpi_allreduce (ynbuf,surface%yn,surface%nsurface,mpi_double_precision,mpi_sum,mpi_comm_world,ierr) call mpi_allreduce (znbuf,surface%zn,surface%nsurface,mpi_double_precision,mpi_sum,mpi_comm_world,ierr) else call compute_normals (surface%nsurface,surface%x,surface%y,surface%z, & surface%nt,surface%icon,surface%xn,surface%yn,surface%zn) endif deallocate (xbuf) deallocate (ybuf) deallocate (zbuf) deallocate (xnbuf) deallocate (ynbuf) deallocate (znbuf) ! ------------------------------------------------------------------------------- ! At this point, all points of the surface (and possibly the normal they carry) ! have been advected. A little bit of extra work is needed for the points on the ! convex hull (those at the intersection of the surface with the cube). On each ! edge of the square, there are nside points of coordinates (x_i,z(x_i)). ! Because of advection, the x_i are no more equidistant, which after several time ! steps can lead to one these points to be advected outside the cube and removed, ! which in turn leads to other problems. In order to avoid this problem, and also ! to keep the triangulation somewhat regular near the edges, the curve (x_i,z(x_i)) ! is reinterpolated at equidistant X_i by means of the 'resample' routine in ! /RESAMPLE/libresample.a, based on linear interpolation (k=1) or spline ! interpolation (k=3,5). This procedure is carried out only at the end of a time ! step, i.e. when flag0=0. allocate(pos(nside)) allocate(zzz(nside)) pos=surface%x(1:nside) zzz=surface%z(1:nside) call resample (pos,zzz,nside,1) surface%x(1:nside)=pos surface%z(1:nside)=zzz pos=surface%y(nside:2*nside-1) zzz=surface%z(nside:2*nside-1) call resample (pos,zzz,nside,1) surface%y(nside:2*nside-1)=pos surface%z(nside:2*nside-1)=zzz pos=surface%x(3*nside-2:2*nside-1:-1) zzz=surface%z(3*nside-2:2*nside-1:-1) call resample (pos,zzz,nside,1) surface%x(3*nside-2:2*nside-1:-1)=pos surface%z(3*nside-2:2*nside-1:-1)=zzz pos(1)=surface%y(1) zzz(1)=surface%z(1) pos(2:nside)=surface%y(4*nside-4:3*nside-2:-1) zzz(2:nside)=surface%z(4*nside-4:3*nside-2:-1) call resample (pos,zzz,nside,1) surface%y(4*nside-4:3*nside-2:-1)=pos(2:nside) surface%z(4*nside-4:3*nside-2:-1)=zzz(2:nside) deallocate(pos) deallocate(zzz) !------------------------------------------------------------------------------- if (surface%itype.eq.0) then surface%r=surface%x surface%s=surface%y endif !------------------------------------------------------------------------------- ! We now check whether points have been advected outside the simulation domain ! (unit cube), and if so, we need to remove them. However, because the triangulation ! is only computed at startup and further updated, the removal of a point requires ! the triangulation to be sown back by hand. This will most probably lead to a ! non-Delaunay triangulation (locally), but this will be taken care of in the ! check_delaunay subroutine. The first 4*nside-4 points in the surface ! array correspond to those on the convex hull so that we need not test them. nrem=0 remove=.true. do while (remove) remove=.false. do i=4*nside-3,surface%nsurface if (surface%x(i).lt.-eps .or. surface%x(i).gt.1.d0+eps .or. & surface%y(i).lt.-eps .or. surface%y(i).gt.1.d0+eps .or. & surface%z(i).lt.-eps .or. surface%z(i).gt.1.d0+eps) then call remove_point(i,surface,flag0,surface0) nrem=nrem+1 remove=.true. exit endif end do end do if (iproc.eq.0 .and. nrem/=0) write(*,'(a,i4,a)') shift//'removing',nrem,' particle from surface' call check_delaunay (params,surface,is,istep,'delaunay_aft_remove',0) if (.not.params%normaladvect) then call compute_normals (surface%nsurface,surface%x,surface%y,surface%z, & surface%nt,surface%icon,surface%xn,surface%yn,surface%zn) end if if (flag0==0) then nedge=surface%nsurface+surface%nt-1 call DoRuRe_surf_stats (params%doDoRuRe,istep,50,is,surface%nt,surface%nsurface,nedge,-nrem) end if if (iproc.eq.0) write (8,*) 'Removal complete' end subroutine move_surface