phd-scripts/Unpublished/XFEM/2D_Solver/LevelSet.f90

404 lines
11 KiB
Fortran
Raw Normal View History

2024-05-13 19:50:21 +00:00
! This Subroutine Implements the Level Set Method
! J. Grogan - 07/10/13
subroutine uexternaldb(lop,lrestart,time,dtime,kstep,kinc)
include 'aba_param.inc'
dimension time(2)
integer Element (100,4)
real Node(100,2),LSet(100)
!
if(lop==0)then
! Get Mesh Data
call getMesh(Element,Node,numElem,numNodes)
! Get Initial Level Set
call initialLSet(LSet,Node,numNodes)
elseif(lop==1)then
! Update Level Set
call updateLSet(Node,numNodes,Element,numElem,dtime,LSet)
endif
return
end
! This subroutine returns the finite element mesh connectivity data
subroutine getMesh(Element,Node,numElem,numNodes)
include 'aba_param.inc'
integer Element (100,4)
real Node(100,2)
character(256) outdir,jobname,input
call getoutdir(outdir,lenoutdir)
call getjobname(jobname,lenjobname)
filename=trim(outdir)//trim(jobname)//'.inp'
open(unit=107,file=filename,status='old')
read(107,*)input
do while (index(input,'*Node')==0)
read(107,*)input
enddo
ierr=0
numNodes=0
do while (ierr==0)
read(107,*)nodeNum,xcor,ycor,zcor
if(ierr==0)then
Node(nodeNum,1)=xcor
Node(nodeNum,2)=ycor
numNodes=numNodes+1
endif
enddo
do while (index(input,'*Element')==0)
read(107,*)input
enddo
numElem=0
do while (ierr==0)
read(107,*)elNum,n1,n2,n3,n4
if(ierr==0)then
Element(elNum,1)=n1
Element(elNum,2)=n2
Element(elNum,3)=n3
Element(elNum,4)=n4
numElem=numElem+1
endif
enddo
close(107)
end subroutine
! This subroutine calculates the initial Level Set
subroutine initialLSet(LSet,Node,numNodes)
include 'aba_param.inc'
real Node(100,2),LSet(100)
!centx=4.
!centy=4.
!rad=2.1
!do i=1,numNodes
! dist=sqrt((Node(i,1)-centx)*(Node(i,1)-centx)+(Node(i,2)-centy)*(Node(i,2)-centy))
! LSet(i)=dist-rad
!enddo
do i=1,numNodes
dist=Node(i,1)-0.1
LSet(i)=dist
enddo
end subroutine
! This subroutine updates the Level Set
subroutine updateLSet(Node,numNodes,Element,numElem,dtime,LSet)
include 'aba_param.inc'
integer Element(100,4),NBelem(100,4)
real Node(100,2),NGlobal(100,2),NLocal(100,2)
real LSet(100),LSetLocal(100),F(100),Fred(100)
real A(100,100),Ared(100,100),RHS(100),RHSred(100)
real M(100,100),MGL(100,100),f1(100),f2(100),f3(100)
! parameters
bandWidth=10.
av_Length=1.
h2=0.00001*av_Length
visc=0.0005
dt=0.01
! explicit update of Level Set
do istep=1:floor(dtime/dt)
! Identify Narrow Band Elements and Get Local Level Set
call getNarrowBand(NBelem,NBElems,NGlobal,NLocal,NBNodes,LSetLocal, &
& bandWidth,LSet,Element,numElem,numNodes)
! Identify Scalar Velocity on Nodes Crossed By Interface - F
call getF(F,LSetLocal,NBElems,NBNodes,NBelem)
! Get 'Stiffness' Matrix - A
call getA(A,Node,NLocal,NBelem,NBNodes,NBElems,LSetLocal)
! Apply BCs
RHS=-matmul(A,F)
iindex=0
do i=1,NBNodes
if (F(i)==0.)then
iindex=iindex+1
RHSred(iindex)=RHS(i)
jindex=0
do j=1,NBNodes
if (F(j)==0.)then
jindex=jindex+1;
Ared(iindex,jindex)=A(i,j)
endif
enddo
endif
enddo
! Solve for Fred
Fred=(Ared^-1)*RHSred'
! Get F
iindex=0
do i=1,NBNodes
if (F(i)==0.)then
iindex=iindex+1
F(i)=Fred(iindex)
endif
enddo
! Get Level Set Equation Terms
call getTerms(M,MGLS,f1,f2,f3,Node,NLocal,NBelem,NBNodes,NBElems,&
& LSetLocal,visc,h2,F)
LSetLocal=LSetLocal-((((M+MGLS)^-1)*dt)*(f1+f2+f3))'
! Reinitialize LS
!call fastMarch(LSetLocal,NBelem,Node,NLocal,NBNodes)
do i=1,NBNodes
LSet(NLocal(i))=LSetLocal(i)
end
enddo
end subroutine
! This subroutine identifies elements in the narrow band
subroutine getNarrowBand(NBelem,NBElems,NGlobal,NLocal,NBNodes,LSetLocal,&
& bandWidth,LSet,Element,numElem,numNodes)
include 'aba_param.inc'
integer Element(100,4),NBelem(100,4)
real Node(100,2),NGlobal(100,2),NLocal(100,2)
real LSet(100),LSetLocal(100)
! Identify Narrow Band Elements
NBElems=0
NBNodes=0
NGlobal=0.
do i=1,numElem
check=0
do iNd=1,4
if (abs(LSet(Element(i,iNd)))<=bandWidth*(delX+delY)/2.)then
check=1
endif
enddo
! If an element is in the narrow band split it into triangles
if (check==1)then
for j=1,4
if (NGlobal(Element(i,j))==0)then
NBNodes=NBNodes+1
NGlobal(Element(i,j))=NBNodes
NLocal(NBNodes)=Element(i,j)
endif
endddo
NBElems=NBElems+1
NBelem(NBElems,1)=NGlobal(Element(i,1))
NBelem(NBElems,2)=NGlobal(Element(i,2))
NBelem(NBElems,3)=NGlobal(Element(i,3))
NBElems=NBElems+1
NBelem(NBElems,1)=NGlobal(Element(i,1))
NBelem(NBElems,2)=NGlobal(Element(i,3))
NBelem(NBElems,3)=NGlobal(Element(i,4))
endif
enddo
! Get local Level Set
do i=1,NBNodes
LSetLocal(i)=LSet(NLocal(i))
enddo
end subroutine
! This subroutine extends the interface velocity throughout the computational domain
subroutine getF(F,LSetLocal,NBElems,NBNodes,NBelem)
include 'aba_param.inc'
real LSetLocal(100),F(100),L(3)
F=0.
do i=1,NBElems
do j=1,3
L(j)=sign(1.,LSetLocal(NBelem(i,j)))
enddo
if (L(1) /= L(2) .or. L(1) /= L(3))then
do j=1,3
F(NBelem(i,j))= 1.
enddo
endif
enddo
end subroutine
! This subroutine gets the 'stiffness' matrix - A
subroutine getA(A,Node,NLocal,NBelem,NBNodes,NBElems,LSetLocal)
include 'aba_param.inc'
integer NBelem(100,4)
real Node(100,2),NLocal(100,2)
real LSetLocal(100),A(100,100),AfL(3,3),AfLGLS(3,3)
real gx(3),hx(3),phi(3),phig(3),phih(3),phix(3),phiy(3)
A=0.
do i=1,NBElems
gx(1)=2./3.
gx(2)=1./6.
gx(3)=1./6.
hx(1)=1./6.
hx(2)=1./6.
hx(3)=2./3.
AfL=0.
AfLGLS=0.
x1=Node(NLocal(NBelem(i,1)),1)
y1=Node(NLocal(NBelem(i,1)),2)
x2=Node(NLocal(NBelem(i,2)),1)
y2=Node(NLocal(NBelem(i,2)),2)
x3=Node(NLocal(NBelem(i,3)),1)
y3=Node(NLocal(NBelem(i,3)),2)
do j=1,3
g=gx(j)
h=hx(j)
phi(1)=1.-g-h
phi(2)=g
phi(3)=h
phig(1)=-1.
phig(2)=1.
phig(3)=0.
phih(1)=-1.
phih(2)=0.
phih(3)=1.
djac=2.*abs(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2))
do k=1,3
phix(k)=(1./djac)*((-y1+y3)*phig(k)+(y1-y2)*phih(k))
phiy(k)=(1./djac)*((x1-x3)*phig(k)+(-x1+x2)*phih(k))
enddo
delphi=[phix;phiy]
nodalLset=[LSetLocal(NBelem(i,1));LSetLocal(NBelem(i,2));LSetLocal(NBelem(i,3))]
set=phi*nodalLset
delset=delphi*nodalLset
AfL=AfL+(phi'*sign(set))*(delset'*delphi)/3.
AfLGLS=AfLGLS+(delphi'*delset)*(1./norm(delset))*(delset'*delphi)/3.
enddo
do k=1,3
do j=1,3
A(NBelem(i,j),NBelem(i,k))=A(NBelem(i,j),NBelem(i,k))+AfL(j,k)+AfLGLS(j,k)
enddo
enddo
enddo
end subroutine
! This subroutine gets the neccessary terms for the level set equation
subroutine getTerms(M,MGLS,f1,f2,f3,Node,NLocal,NBelem,NBNodes,NBElems,&
& LSetLocal,visc,h2,F)
include 'aba_param.inc'
integer NBelem(100,4)
real Node(100,2),NLocal(100,2),LSetLocal(100)
real M(100,100),MGLS(100,100),f1(100),f2(100),f3(100)
real ML(3,3),MGLSL(3,3),f1L(3),f2L(3),f3L(3)
real gx(3),hx(3),phi(3),phig(3),phih(3),phix(3),phiy(3)
M=0.
MGLS=0.
f1=0.
f2=0.
f3=0.
do i=1,NBElems
ML=0.
MGLSL=0.
f1L=0.
f2L=0.
f3L=0.
gx(1)=2./3.
gx(2)=1./6.
gx(3)=1./6.
hx(1)=1./6.
hx(2)=1./6.
hx(3)=2./3.
x1=Node(NLocal(NBelem(i,1)),1)
y1=Node(NLocal(NBelem(i,1)),2)
x2=Node(NLocal(NBelem(i,2)),1)
y2=Node(NLocal(NBelem(i,2)),2)
x3=Node(NLocal(NBelem(i,3)),1)
y3=Node(NLocal(NBelem(i,3)),2)
do j=1,3
g=gx(j)
h=hx(j)
phi(1)=1.-g-h
phi(2)=g
phi(3)=h
phig(1)=-1.
phig(2)=1.
phig(3)=0.
phih(1)=-1.
phih(2)=0.
phih(3)=1.
djac=abs(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2))
do k=1,3
phix(k)=(1./djac)*((-y1+y3)*phig(k)+(y1-y2)*phih(k))
phiy(k)=(1./djac)*((x1-x3)*phig(k)+(-x1+x2)*phih(k))
end
delphi=[phix;phiy]
nodalLset=[LSetLocal(NBelem(i,1));LSetLocal(NBelem(i,2));LSetLocal(NBelem(i,3))]
nodalF=[F(NBelem(i,1));F(NBelem(i,2));F(NBelem(i,3))]
delset=delphi*nodalLset;
Floc=phi*nodalF
ML=ML+(phi'*phi)/3.
MGLSL=MGLSL+((delphi'*(delset/norm(delset)))*Floc*(h2/abs(Floc)))*phi/3.
f1L=f1L+phi'*Floc*norm(delset)/3.
f2L=f2L+(delphi'*(delset/norm(delset))*Floc)*(h2/abs(Floc))*Floc*norm(delset)/3.
vs=h2*((abs(visc+Floc*norm(delset)))/(norm(Floc*delset)+h2))
f3L=f3L+vs*delphi'*delset/3.
enddo
do k=1,3
do j=1,3
M(NBelem(i,j),NBelem(i,k))=M(NBelem(i,j),NBelem(i,k))+ML(j,k)
MGLS(NBelem(i,j),NBelem(i,k))=MGLS(NBelem(i,j),NBelem(i,k))+MGLSL(j,k)
enddo
f1(NBelem(i,k))=f1(NBelem(i,k))+f1L(k)
f2(NBelem(i,k))=f2(NBelem(i,k))+f2L(k)
f3(NBelem(i,k))=f3(NBelem(i,k))+f3L(k)
enddo
enddo
end subroutine
! This subroutine uses the fast marching method to re-initialize the level set
call fastMarch(LSetLocal,NBelem,Node,NLocal,NBNodes)
include 'aba_param.inc'
integer NBelem(100,4),nstat(100)
real Node(100,2),NLocal(100,2),LSetLocal(100),newlSet(100),L(3)
newlSet=LSetLocal
! Reinitialize LS
nstat=0
do i=1,NBElems
do j=1,3
L(j)=sign(1.,lSetLocal(NBelem(i,j)))
enddo
if (L(1) /= L(2) .or. L(1) /= L(3))then
do j=1,3
nstat(NBelem(i,j))=1
enddo
endif
enddo
maincheck=0
do while(maincheck==0)
lmin=1000.
avlmin=1000.
eindex=0
nindex=0
maincheck=1
do i=1,NBElems
if (nstat(NBelem(i,1))+nstat(NBelem(i,2))+nstat(NBelem(i,3))==2)then
maincheck=0
check=0
ltot=0.
do j=1,3
if (nstat(NBelem(i,j))==0)then
if (abs(lSetLocal(NBelem(i,j)))<=lmin)then
check=1
tempindex=j
endif
endif
ltot=ltot+abs(lSetLocal(NBelem(i,j)))
enddo
if (check==1 .and. ltot/3.<=avlmin)then
eindex=i
nindex=tempindex
lmin=lSetLocal(NBelem(eindex,nindex))
avlmin=ltot/3.
endif
endif
enddo
if (maincheck==0)then
! Find New LS for point
xp=Node(NLocal(NBelem(eindex,nindex)),1)
yp=Node(NLocal(NBelem(eindex,nindex)),2)
count=0
do i=1,3
if (i/=nindex)then
icount=icount+1
x(icount)=Node(NLocal(NBelem(eindex,i)),1)
y(icount)=Node(NLocal(NBelem(eindex,i)),2)
lloc(icount)=newlSet(NBelem(eindex,i))
endif
enddo
delxa=x(1)-xp
delya=y(1)-yp
delxb=x(2)-xp
delyb=y(2)-yp
N=[delxa delya; delxb delyb]
M=N^-1
A=(M(1)*M(1)+M(2)*M(2))
B=(M(3)*M(3)+M(4)*M(4))
C=2.*(M(1)*M(3)+M(2)*M(4))
a=A+B+C
b=-2.*lloc(1)*A-2.*lloc(2)*B-C*(lloc(1)+lloc(2))
c=lloc(1)*lloc(1)*A+lloc(2)*lloc(2)*B+lloc(1)*lloc(2)*C-1.
templ1=(-b+sqrt(b*b-4.*a*c))/(2.*a)
templ2=(-b-sqrt(b*b-4.*a*c))/(2.*a)
if (abs(templ1)>abs(templ2))then
newlSet(NBelem(eindex,nindex))=templ1
else
newlSet(NBelem(eindex,nindex))=templ2
endif
nstat(NBelem(eindex,nindex))=1
endif
enddo
LSetLocal=newlSet
end subroutine