-
Dave Whipp authoredDave Whipp authored
isostasy.f90 9.20 KiB
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
!use mpi
implicit none
include 'mpif.h'
type(parameters) params
type(octreev) ov
double precision weightel(ov%nleaves)
type(sheet) surface(params%ns)
type(material) mat(0:params%nmat)
integer flag0
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==1) 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
endif
! Store the total displacement of the basal node plane
!if (params%isobc .and. iter.eq.1) zi%zisodisp=zi%zisodisp-work
if (params%isobc) zi%zisoinc=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