Skip to content
Snippets Groups Projects
isostasy.f90 9.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • subroutine isostasy (params,weightel,ov,surface,mat,flag0,zi)
    
    
    ! first go at imposing isostasy
    ! this routine assumes that the original surface are flat
    ! it takes the zref height of each surface and the density of the corresponding material
    !   to compute the reference isostatic column
    ! note also that this will not work when the courant condition is used
    
    ! flag0 is 1 if midpoint time step (dt/2) or 0 if full time step (dt)
    
    
    use definitions
    
    type(parameters) params
    type(octreev) ov
    double precision weightel(ov%nleaves)
    type(sheet) surface(params%ns)
    type(material) mat(0:params%nmat)
    
    type(ziso) zi
    !double precision zisodisp(2**params%levelmax_oct+1,2**params%levelmax_oct+1)
    
    double precision xc,yc,zc,eps,dtcur
    
    integer i,j,ii,jj,kk,ie,dlev,is,iproc,nproc,ierr,ic
    double precision x0,y0,z0,dxyz,dd
    integer leaf,level,loc
    double precision x0b,y0b,z0b,dxyzb
    integer leafb,levelb,locb
    double precision,dimension(:),allocatable::diso
    double precision weightref,disoel,w
    integer,dimension(:),allocatable::np
    character shift*72
    double precision,dimension(:,:),allocatable::weight,flex,work
    double precision pi,hx,dh,pihx,xk,fi,fj,tij,d
    integer nflex
    integer im,jm,ip,jp,nb
    
    integer iunit
    
    call mpi_comm_size (mpi_comm_world,nproc,ierr)
    call mpi_comm_rank (mpi_comm_world,iproc,ierr)
    
    eps=1.d-8
    shift=' '
    nb=2**params%levelmax_oct
    
    if (flag0) then
      dtcur=params%dt/2.d0
    else
      dtcur=params%dt
    endif
    
    
    allocate (weight(nb,nb))
    
    ! first calculates the weight of each column, based on the weight of each elements
    ! this is performed on a 2**levelmax X 2**levelmax grid at the base of the model
    ! the result is stored in weight(i,j)
    
    dd=1.d0/2.d0**(params%levelmax_oct+1)
    weight=0.d0
    
      do ie=1,ov%nleaves
      xc=0.d0;yc=0.d0;zc=0.d0
        do i=1,8
        xc=xc+ov%x(ov%icon(i,ie))
        yc=yc+ov%y(ov%icon(i,ie))
        zc=zc+ov%z(ov%icon(i,ie))
        enddo
      xc=xc/8.d0
      yc=yc/8.d0
      zc=zc/8.d0
      call octree_find_leaf (ov%octree,ov%noctree,xc,yc,zc,leaf,level,loc,x0,y0,z0,dxyz)
      dlev=params%levelmax_oct-level
      call find_integer_coordinates (x0+dd,y0+dd,z0+dd,ii,jj,kk,params%levelmax_oct)
      ii=min(ii,nb-2**dlev)
      jj=min(jj,nb-2**dlev)
        do i=1,2**dlev
          do j=1,2**dlev
          weight(ii+i,jj+j)=weight(ii+i,jj+j)+weightel(leaf)/(4.d0**dlev)*(4.d0**params%levelmax_oct)
          enddo
        enddo
    !  call octree_find_leaf (ov%octree,ov%noctree,xc,yc,eps,leafb,levelb,locb,x0b,y0b,z0b,dxyzb)
    !  dlev=max(0,levelb-level)
    !  w(leafb)=w(leafb)+weightel(leaf)/(4.d0**dlev)*(4.d0**levelb)
      enddo
    
    ! calculates the reference weight from the initial surface geometry and the density of the material
    ! near the base
    
    weightref=0.d0
      do is=1,params%ns-1
      weightref=weightref+mat(surface(is)%material)%density*(surface(is)%sp01-surface(is+1)%sp01)
      enddo
    weightref=weightref+mat(surface(params%ns)%material)%density*surface(params%ns)%sp01
    
    if (.not.params%flexure) then
    
    ! apply local isostasy
    ! the deflection is stored in array weight
    
      do j=1,nb
        do i=1,nb
        weight(i,j)=(weight(i,j)-weightref)/mat(surface(params%ns)%material)%density
        enddo
      enddo
    
    else
    
    ! flexural isostasy
    
    nflex=8*nb
    allocate(work(nflex,nflex),flex(nflex,nflex))
    hx=params%length_scale*8.d3
    xk=-mat(surface(params%ns)%material)%density*params%density_difference*9.81d0
    d=1.d11/12.d0/(1.d0-0.25d0**2)*params%elastic_plate_thickness**3
    dh=hx/(nflex-1)
    
    
    !if (iproc.eq.0) print*,'hx,dh,xk,d',hx,dh,xk,d
    
    
    ii=nflex/2-nb/2-1
    jj=ii
    flex=0.d0
      do j=1,nb
        do i=1,nb
        flex(ii+i,jj+j)=(weight(i,j)-weightref)*dh*dh*params%density_difference*9.81d0*params%length_scale*1.d3
        enddo
      enddo
    
    
    !if (iproc.eq.0) print*,'poids',minval(flex),maxval(flex)
    
    
      do j=1,nflex
      call dsinft (flex(1,j),nflex)
      enddo
    
      do j=1,nflex
        do i=1,nflex
        work(j,i)=flex(i,j)
        enddo
      enddo
    
      do i=1,nflex
      call dsinft (work(1,i),nflex)
      enddo
    
      do j=1,nflex
        do i=1,nflex
        work(j,i)=work(j,i)*4.d0/hx/hx
        enddo
      enddo
    
    pi=atan(1.d0)*4.d0
    pihx=pi/hx
      do j=1,nflex
      fj=(j*pihx)**2
        do i=1,nflex
        fi=(i*pihx)**2
        tij=d/xk*(fi**2+2.d0*fi*fj+fj**2)+1.d0
        work(j,i)=work(j,i)/xk/tij
        enddo
      enddo
    
      do i=1,nflex
      call dsinft (work(1,i),nflex)
      enddo
    
      do j=1,nflex
        do i=1,nflex
        flex(i,j)=work(j,i)
        enddo
      enddo
    
      do j=1,nflex
      call dsinft (flex(1,j),nflex)
      enddo
    
    
    !if (iproc.eq.0) print*,'def in m',minval(flex),maxval(flex)
    
    
    ii=nflex/2-nb/2-1
    jj=ii
      do j=1,nb
        do i=1,nb
        weight(i,j)=-flex(ii+i,jj+j)/params%length_scale/1.d3
        enddo
      enddo
    
    deallocate (flex,work)
    
    
    !if (iproc.eq.0) print*,'dimensionless def ',minval(weight),maxval(weight)
    
    
    endif
    
    ! redistributes the isostatic response onto the elements
    ! and distributes it onto the nodes into array diso(nnode)
    
    allocate (np(ov%nnode))
    allocate (diso(ov%nnode),work(nb+1,nb+1))
    
    do j=1,nb+1
    do i=1,nb+1
    im=max(i-1,1)
    jm=max(j-1,1)
    ip=min(i,nb)
    jp=min(j,nb)
    work(i,j)=(weight(ip,jp)+weight(im,jp)+weight(ip,jm)+weight(im,jm))/4.d0
    enddo
    enddo
    
    do i=1,ov%nnode
    call find_integer_coordinates(ov%x(i)+1.d-20,ov%y(i)+1.d-20,ov%z(i)+1.d-20,ii,jj,kk,params%levelmax_oct)
    ii=ii+1
    jj=jj+1
    kk=kk+1
    if ((ii-1)*(ii-nb-1).gt.0 .or. (jj-1)*(jj-nb-1).gt.0) stop 'error in isostasy'
    diso(i)=work(ii,jj)
    enddo
    
      if (params%debug>=1.and.iproc.eq.0) then
    
      write(*,'(a,f10.7,1x,f10.7)') shift//'Isostatic velocity range = ',minval(diso)/dtcur,maxval(diso)/dtcur
    
    ! Store the total displacement of the basal node plane 
    
      !if (params%isobc .and. iter.eq.1) zi%zisodisp=zi%zisodisp-work
    
    ! transforms the displacements into velocities and add this contribution to the velocity
    ! solution of the Stokes equation before interpolation onto the surfaces and their advection
    
      do i=1,ov%nnode
    
        ov%wnodeiso(i)=-diso(i)/dtcur
        ov%wnode(i)=ov%wnode(i)+ov%wnodeiso(i)
    
      enddo
    
    deallocate (np)
    deallocate (diso)
    deallocate (weight)
    deallocate (work)
    
    return
    end subroutine isostasy
    
    
    ! SINFT
    
    ! taken from numerical recipes (see book for further information)
    
    ! subroutines called:
    ! NONE
    
          SUBROUTINE DSINFT(Y,N)
          common /vocal/ ivocal
          REAL*8 WR,WI,WPR,WPI,WTEMP,THETA
          double precision Y(N)
          THETA=3.14159265358979D0/DBLE(N)
          WR=1.0D0
          WI=0.0D0
          WPR=-2.0D0*DSIN(0.5D0*THETA)**2
          WPI=DSIN(THETA)
          Y(1)=0.0
          M=N/2
          DO 11 J=1,M
            WTEMP=WR
            WR=WR*WPR-WI*WPI+WR
            WI=WI*WPR+WTEMP*WPI+WI
            Y1=WI*(Y(J+1)+Y(N-J+1))
            Y2=0.5*(Y(J+1)-Y(N-J+1))
            Y(J+1)=Y1+Y2
            Y(N-J+1)=Y1-Y2
    11    CONTINUE
          CALL DREALFT(Y,M,+1)
          SUM=0.0
          Y(1)=0.5*Y(1)
          Y(2)=0.0
          DO 12 J=1,N-1,2
            SUM=SUM+Y(J)
            Y(J)=Y(J+1)
            Y(J+1)=SUM
    12    CONTINUE
          RETURN
          END
    
    ! REALFT
    
    ! taken from numerical recipes (see book for further information)
    
    ! subroutines called:
    ! NONE
    
          SUBROUTINE DREALFT(DATA,N,ISIGN)
          common /vocal/ ivocal
          REAL*8 WR,WI,WPR,WPI,WTEMP,THETA
          double precision DATA(*)
          THETA=6.28318530717959D0/2.0D0/DBLE(N)
          C1=0.5
          IF (ISIGN.EQ.1) THEN
            C2=-0.5
            CALL DFOUR1(DATA,N,+1)
          ELSE
            C2=0.5
            THETA=-THETA
          ENDIF
          WPR=-2.0D0*DSIN(0.5D0*THETA)**2
          WPI=DSIN(THETA)
          WR=1.0D0+WPR
          WI=WPI
          N2P3=2*N+3
          DO 11 I=2,N/2+1
            I1=2*I-1
            I2=I1+1
            I3=N2P3-I2
            I4=I3+1
            WRS=SNGL(WR)
            WIS=SNGL(WI)
            H1R=C1*(DATA(I1)+DATA(I3))
            H1I=C1*(DATA(I2)-DATA(I4))
            H2R=-C2*(DATA(I2)+DATA(I4))
            H2I=C2*(DATA(I1)-DATA(I3))
            DATA(I1)=H1R+WRS*H2R-WIS*H2I
            DATA(I2)=H1I+WRS*H2I+WIS*H2R
            DATA(I3)=H1R-WRS*H2R+WIS*H2I
            DATA(I4)=-H1I+WRS*H2I+WIS*H2R
            WTEMP=WR
            WR=WR*WPR-WI*WPI+WR
            WI=WI*WPR+WTEMP*WPI+WI
    11    CONTINUE
          IF (ISIGN.EQ.1) THEN
            H1R=DATA(1)
            DATA(1)=H1R+DATA(2)
            DATA(2)=H1R-DATA(2)
          ELSE
            H1R=DATA(1)
            DATA(1)=C1*(H1R+DATA(2))
            DATA(2)=C1*(H1R-DATA(2))
            CALL DFOUR1(DATA,N,-1)
          ENDIF
          RETURN
          END
    
    ! FOUR1
    
    ! this routine is taken directly out of numerical recipes
    ! see the book for further information
    
    ! subroutines called:
    ! NONE
    
          SUBROUTINE DFOUR1(DATA,NN,ISIGN)
          common /vocal/ ivocal
          REAL*8 WR,WI,WPR,WPI,WTEMP,THETA
          double precision DATA(*)
          N=2*NN
          J=1
          DO 11 I=1,N,2
            IF(J.GT.I)THEN
              TEMPR=DATA(J)
              TEMPI=DATA(J+1)
              DATA(J)=DATA(I)
              DATA(J+1)=DATA(I+1)
              DATA(I)=TEMPR
              DATA(I+1)=TEMPI
            ENDIF
            M=N/2
    1       IF ((M.GE.2).AND.(J.GT.M)) THEN
              J=J-M
              M=M/2
            GO TO 1
            ENDIF
            J=J+M
    11    CONTINUE
          MMAX=2
    2     IF (N.GT.MMAX) THEN
            ISTEP=2*MMAX
            THETA=6.28318530717959D0/(ISIGN*MMAX)
            WPR=-2.D0*DSIN(0.5D0*THETA)**2
            WPI=DSIN(THETA)
            WR=1.D0
            WI=0.D0
            DO 13 M=1,MMAX,2
              DO 12 I=M,N,ISTEP
                J=I+MMAX
                TEMPR=SNGL(WR)*DATA(J)-SNGL(WI)*DATA(J+1)
                TEMPI=SNGL(WR)*DATA(J+1)+SNGL(WI)*DATA(J)
                DATA(J)=DATA(I)-TEMPR
                DATA(J+1)=DATA(I+1)-TEMPI
                DATA(I)=DATA(I)+TEMPR
                DATA(I+1)=DATA(I+1)+TEMPI
    12        CONTINUE
              WTEMP=WR
              WR=WR*WPR-WI*WPI+WR
              WI=WI*WPR+WTEMP*WPI+WI
    13      CONTINUE
            MMAX=ISTEP
          GO TO 2
          ENDIF
          RETURN
          END