Skip to content
Snippets Groups Projects
move_surface.f90 13.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Douglas Guptill's avatar
    Douglas Guptill committed
    !------------------------------------------------------------------------------|
    !------------------------------------------------------------------------------|
    !                                                                              |
    !              ||===\\                                                         | 
    !              ||    \\                                                        |
    !              ||     ||   //==\\   ||  ||   //==||  ||/==\\                   |
    !              ||     ||  ||    ||  ||  ||  ||   ||  ||    ||                  |
    !              ||    //   ||    ||  ||  ||  ||   ||  ||                        |
    !              ||===//     \\==//    \\==\\  \\==\\  ||                        |
    !                                                                              |
    !------------------------------------------------------------------------------|
    !------------------------------------------------------------------------------|
    !                                                                              |
    !              MOVE_SURFACE    Nov. 2007                                       |
    !                                                                              |
    !------------------------------------------------------------------------------|
    !------------------------------------------------------------------------------|
    
    
    subroutine move_surface (surface,surface0,flag0,flag1,ov,dt,params,istep,is)
    
    Douglas Guptill's avatar
    Douglas Guptill committed
    
    !------------------------------------------------------------------------------|
    !(((((((((((((((( 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!!
    
    ! flag1 is 1 if surface is only being shifted vertically due to isostasy
    
    Douglas Guptill's avatar
    Douglas Guptill committed
    ! 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
    
    Douglas Guptill's avatar
    Douglas Guptill committed
    
    implicit none
    
    
    Douglas Guptill's avatar
    Douglas Guptill committed
    type (sheet) surface
    type (sheet) surface0
    type (octreev) ov
    
    Douglas Guptill's avatar
    Douglas Guptill committed
    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
    
    !-------------------------------------------------------------------------------
    !-------------------------------------------------------------------------------
          
    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
    
          if (flag1) then
            ! Only vertical velocity from isostasy
            call octree_interpolate_three (3,ov%octree,ov%noctree,ov%icon,ov%nleaves, &
                                          ov%nnode,xi,yi,zi,0.d0*ov%unode,u,0.d0*ov%vnode,v,ov%wnodeiso,w)
          else
            ! Full velocity field
            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/params%vex,w)
          endif
    
    Douglas Guptill's avatar
    Douglas Guptill committed
    
          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
    
          if (flag1) then
            ! Only vertical velocity from isostasy
            call octree_interpolate_three_derivative (3,ov%octree,ov%noctree,ov%icon,ov%nleaves, &
                                                     ov%nnode,xi,yi,zi, &
                                                     0.d0*ov%unode,u,ux,uy,uz, &
                                                     0.d0*ov%vnode,v,vx,vy,vz, &
                                                     ov%wnodeiso,w,wx,wy,wz)
          else
            ! Full velocity field
            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/params%vex,w,wx,wy,wz)
          endif
    
    
    Douglas Guptill's avatar
    Douglas Guptill committed
          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)
    
    Douglas Guptill's avatar
    Douglas Guptill committed
          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