!================================================================================================= !================================================================================================= ! Module module_front: ! Includes the data for the points and the linked list definitions and procedures for adding and ! deleting from the list. !------------------------------------------------------------------------------------------------- module module_front use module_2phase implicit none save private public :: InitFront, backup_front_write, backup_front_read, print_fronts, CalcVolume, & CalcSurfaceTension, Front2GridVector, AdvanceFront2, GetFront, DistributeFront, & InitConditionFront, StoreOldFront, AverageFront, RegridFront, SmoothFront, & CorrectVolume, & amin, amax, aspmax, sigma, smooth, nsmooth, MaxPoint, MaxElem, MaxFront, & maxErrorVol, FrontProps, nregrid, & test_frdroplet integer :: MaxPoint, MaxElem, MaxFront, FirstEmptyPoint, FirstEmptyElem, FirstEmptyFront, & FrontLength, FrontFirst, NumEmptyPoint, NumEmptyElem, NumEmptyFront, NumLocPoint integer, dimension( : ), allocatable :: PointLength, PointFirst, ElemLength, ElemFirst, & LocalPointIndex, LocalElemIndex integer, dimension(:,:), allocatable :: FrontConnect, ElemConnect, ElemNgbr, & PointConnect, ElemCorner real(8), dimension(:,:), allocatable :: PointCoords, PointCoordsOld, FrontForce, gradIFront, & PointCoordsBuff, PointCoordsBuffo, FrontProps real(8), dimension( : ), allocatable :: SurfaceTension ! , rad, xc, yc, zc, vol ! Two-phase properties now defined in Two-Phase module integer, dimension( : ), allocatable :: GlobPointIndex, GlobElemIndex integer, dimension(:,:), allocatable :: ElemNgbrBuff, ElemCornerBuff real(8) :: amin, amax, aspmax, maxErrorVol real(8), dimension(:,:), allocatable :: smin, smax real(8), dimension( 3 ) :: mysmin, mysmax logical :: smooth integer :: nsmooth, nregrid integer, allocatable, dimension(:,:) :: request integer, allocatable, dimension(:,:,:) :: status logical :: test_frdroplet contains !================================================================================================= !================================================================================================= ! subroutine to add object NewObject to a linked list. The object comes from the unused part of ! the array. !------------------------------------------------------------------------------------------------- subroutine add_obj(NewObject, connect, NumObjects, FirstObject, NumEmptyObjects, & FirstEmptyObject, MaxObjects) implicit none integer :: NewObject, NumObjects, FirstObject, NumEmptyObjects, FirstEmptyObject, MaxObjects integer :: connect(MaxObjects,2),m if(NumEmptyObjects.eq.0)then write(*,*)'NO MORE OBJECTS IN LIST 1' return endif if(NumObjects==0)then NewObject = FirstEmptyObject FirstObject = NewObject FirstEmptyObject = connect(FirstEmptyObject,1) connect(NewObject,1) = NewObject connect(NewObject,2) = NewObject NumObjects = NumObjects+1 NumEmptyObjects = NumEmptyObjects-1 else NewObject = FirstEmptyObject m = connect(FirstObject,2) FirstEmptyObject = connect(FirstEmptyObject,1) connect(NewObject,1) = FirstObject connect(m,1) = NewObject connect(NewObject,2) = m connect(FirstObject,2) = NewObject NumObjects = NumObjects+1 NumEmptyObjects = NumEmptyObjects-1 endif return end subroutine add_obj !================================================================================================= !================================================================================================= ! subroutine to delete object OldObject from a linked list. The object remains in the unused part ! of the array. !------------------------------------------------------------------------------------------------- subroutine delete_obj(OldObject, connect, NumObjects, FirstObject, NumEmptyObjects, & FirstEmptyObject, MaxObjects) implicit none integer OldObject, NumObjects, FirstObject, NumEmptyObjects, FirstEmptyObject, MaxObjects integer connect(MaxObjects,2) if(OldObject.eq.firstObject) firstObject = connect(firstObject,1) if(NumObjects.eq.1) firstObject = 0 NumObjects = NumObjects-1 connect(connect(OldObject,2),1)=connect(OldObject,1) connect(connect(OldObject,1),2)=connect(OldObject,2) ! connect(FirstEmptyObject,2) = OldObject connect(OldObject,1) = FirstEmptyObject connect(OldObject,2) = 0 FirstEmptyObject = OldObject NumEmptyObjects = NumEmptyObjects+1 return end subroutine delete_obj !================================================================================================= !================================================================================================= !------------------------------------------------------------------------------------------------- subroutine InitFront use module_grid implicit none include 'mpif.h' integer :: i, ierr, root !, numProcess test_frdroplet=.true. FirstEmptyPoint = 1; NumEmptyPoint = MaxPoint FirstEmptyElem = 1; NumEmptyElem = MaxElem FirstEmptyFront = 1; NumemptyFront = MaxFront allocate( FrontConnect(MaxFront,2), ElemConnect (MaxElem,2), PointConnect (MaxPoint,2), & PointLength (MaxFront ), ElemCorner (MaxElem,3), PointCoords (MaxPoint,3), & PointFirst (MaxFront ), ElemNgbr (MaxElem,3), LocalPointIndex(MaxPoint ), & ElemLength (MaxFront ), LocalElemIndex(MaxElem ), FrontForce (3,MaxPoint), & ElemFirst (MaxFront ), SurfaceTension(MaxPoint) ) allocate( GlobPointIndex(MaxPoint), GlobElemIndex(MaxElem), ElemNgbrBuff(MaxElem,3), & PointCoordsBuff(9,MaxPoint),PointCoordsBuffo(9,MaxPoint),ElemCornerBuff(MaxElem,3),& PointCoordsOld(MaxPoint,3), gradIFront(3,MaxPoint) ) FrontLength = 0; FrontFirst = 0 PointLength = 0; PointFirst = 0 ElemLength = 0; ElemFirst = 0 ElemCorner = 0; ElemNgbr = 0 ! Set initial connectivity PointConnect = 0 do i=1,MaxPoint-1 PointConnect(i,1)=i+1 enddo ElemConnect = 0 do i=1,MaxElem-1 ElemConnect(i,1)=i+1 enddo FrontConnect = 0 do i=1,MaxFront-1 FrontConnect(i,1)=i+1 enddo ! smin ans smax are used to decide which points on the front belongs to which process if(rank volume=V=int(dV) ! 2 -> initial volume ! 3 -> volume error ! 4 -> area=int(dA) ! First moments of inertia: ! 5 -> xc=int(x*dV)/V ! 6 -> yc=int(y*dV)/V ! 7 -> zc=int(z*dV)/V ! Second moments of inertia: ! 8 -> x3c=int(x*x*dV)-xc^2*V ! 9 -> y3c=int(y*y*dV)-yc^2*V ! 10-> z3c=int(z*z*dV)-zc^2*V ! 11-> xy3c=int(x*y*dV)-xc*yc*V ! 12-> xz3c=int(x*z*dV)-xc*zc*V ! 13-> yz3c=int(y*z*dV)-yc*zc*V !------------------------------------------------------------------------------------------------- subroutine CalcVolume implicit none real(8) :: xx1(3), xx2(3), xx3(3), p1x,p1y,p1z, p2x,p2y,p2z, p3x,p3y,p3z, xc,yc,zc, x1,y1,z1,& x2,y2,z2, rx,ry,rz, ar, rnx,rny,rnz, xxr,yyr,zzr, M(3,3), a,b,c,d, x0(3) complex(8) :: roots(3) real(8), parameter :: r3=1.0d0/3.0d0 integer :: elem, i, p1, p2, p3, front, ifr front = FrontFirst do ifr = 1,FrontLength p1 = PointFirst(front) call GetCoords(x0,p1) FrontProps(1,front) = 0d0 FrontProps(3:14,front) = 0d0 elem = ElemFirst(front) do i = 1,ElemLength(front) p1 = ElemCorner(elem,1) p2 = ElemCorner(elem,2) p3 = ElemCorner(elem,3) call GetCoords(xx1,p1) call GetCoords(xx2,p2) call GetCoords(xx3,p3) p1x = xx1(1)-x0(1) p1y = xx1(2)-x0(2) p1z = xx1(3)-x0(3) p2x = xx2(1)-x0(1) p2y = xx2(2)-x0(2) p2z = xx2(3)-x0(3) p3x = xx3(1)-x0(1) p3y = xx3(2)-x0(2) p3z = xx3(3)-x0(3) xc = r3*(p1x+p2x+p3x) yc = r3*(p1y+p2y+p3y) zc = r3*(p1z+p2z+p3z) x1 = p2x-p1x y1 = p2y-p1y z1 = p2z-p1z x2 = p3x-p1x y2 = p3y-p1y z2 = p3z-p1z ! ! components of n.dA and n ! rx = 0.5d0*(y1*z2-y2*z1) ry = 0.5d0*(z1*x2-z2*x1) rz = 0.5d0*(x1*y2-x2*y1) ar = sqrt(rx*rx+ry*ry+rz*rz) rnx = rx/ar rny = ry/ar rnz = rz/ar ! ! increments due to element elem ! FrontProps( 1,front) = FrontProps( 1,front)+xc*rx+yc*ry+zc*rz FrontProps( 4,front) = FrontProps( 4,front)+ar xxr = xc*xc*rx yyr = yc*yc*ry zzr = zc*zc*rz FrontProps( 5,front) = FrontProps( 5,front)+xxr FrontProps( 6,front) = FrontProps( 6,front)+yyr FrontProps( 7,front) = FrontProps( 7,front)+zzr FrontProps( 8,front) = FrontProps( 8,front)+xc*xxr FrontProps( 9,front) = FrontProps( 9,front)+yc*yyr FrontProps(10,front) = FrontProps(10,front)+zc*zzr FrontProps(11,front) = FrontProps(11,front)+yc*xxr+xc*yyr FrontProps(12,front) = FrontProps(12,front)+zc*xxr+xc*zzr FrontProps(13,front) = FrontProps(13,front)+zc*yyr+yc*zzr elem = ElemConnect(elem,1) !ke = elcon(ke,kf) end do FrontProps( 1,front) = FrontProps( 1,front) * r3 FrontProps( 3,front) = FrontProps( 3,front) - FrontProps(2,front) FrontProps( 5,front) = FrontProps( 5,front) * 0.5d0 / FrontProps(1,front) + x0(1) FrontProps( 6,front) = FrontProps( 6,front) * 0.5d0 / FrontProps(1,front) + x0(2) FrontProps( 7,front) = FrontProps( 7,front) * 0.5d0 / FrontProps(1,front) + x0(3) FrontProps( 8,front) = FrontProps( 8,front) * r3 FrontProps( 9,front) = FrontProps( 9,front) * r3 FrontProps(10,front) = FrontProps(10,front) * r3 FrontProps(11,front) = FrontProps(11,front) * 0.25d0 FrontProps(12,front) = FrontProps(12,front) * 0.25d0 FrontProps(13,front) = FrontProps(13,front) * 0.25d0 ! calculate centered versions of second moments of inertia x1 = FrontProps(5,front) - x0(1) y1 = FrontProps(6,front) - x0(2) z1 = FrontProps(7,front) - x0(3) FrontProps( 8,front) = FrontProps( 8,front)-x1*x1*FrontProps(1,front) FrontProps( 9,front) = FrontProps( 9,front)-y1*y1*FrontProps(1,front) FrontProps(10,front) = FrontProps(10,front)-z1*z1*FrontProps(1,front) FrontProps(11,front) = FrontProps(11,front)-x1*y1*FrontProps(1,front) FrontProps(12,front) = FrontProps(12,front)-x1*z1*FrontProps(1,front) FrontProps(13,front) = FrontProps(13,front)-y1*z1*FrontProps(1,front) ! calculate bubble deformation M(1,1)=FrontProps(8 ,front) M(2,2)=FrontProps(9 ,front) M(3,3)=FrontProps(10,front) M(1,2)=FrontProps(11,front) M(2,1)=FrontProps(11,front) M(1,3)=FrontProps(12,front) M(3,1)=FrontProps(12,front) M(2,3)=FrontProps(13,front) M(3,2)=FrontProps(13,front) a = -1 b = tr(M) c = 0.5*(tr(matmul(M,M))-(tr(M))**2) d = det(M) call cubic_solve(a,b,c,d,roots) a=real(roots(1)) b=real(roots(2)) c=real(roots(3)) d=min(a,b,c) a=max(a,b,c) FrontProps(14,front) = sqrt(a/d) front = FrontConnect(front,1) enddo end subroutine CalcVolume !================================================================================================= !================================================================================================= ! subroutine CorrectVolume ! Corrects the volume of each bubble by putting a source at the centroid of each bubble ! proportional to its volume loss. !------------------------------------------------------------------------------------------------- subroutine CorrectVolume use module_grid implicit none real(8) :: frontCenter(3), x1(3), dr(3), factor, r3, shift(3) integer :: point, i, front, ifr, ip, jfr, front2 real(8) :: pi=3.141592653 front = FrontFirst do ifr = 1, FrontLength if(abs(FrontProps(1,front)/FrontProps(2,front)-1d0)>maxErrorVol)then factor = (FrontProps(2,front)-FrontProps(1,front))/4d0/pi frontCenter = (/FrontProps(5,front), FrontProps(6,front), FrontProps(7,front)/) front2 = FrontFirst do jfr = 1, FrontLength shift(1) = xLength*floor((FrontProps(5,front2)-FrontProps(5,front))/xLength+0.5) shift(2) = yLength*floor((FrontProps(6,front2)-FrontProps(6,front))/yLength+0.5) shift(3) = zLength*floor((FrontProps(7,front2)-FrontProps(7,front))/zLength+0.5) point = PointFirst(front2) do ip = 1, PointLength(front2) call GetCoords(x1,point) dr = x1-frontCenter-shift r3 = (dr(1)**2+dr(2)**2+dr(3)**2)**1.5 dr = factor * dr / r3 i = floor(PointCoords(point,1)); i = Ng+modulo(i-Ng,Nx) PointCoords(point,1) = PointCoords(point,1) + dr(1)/dx(i+1) i = floor(PointCoords(point,2)); i = Ng+modulo(i-Ng,Ny) PointCoords(point,2) = PointCoords(point,2) + dr(2)/dy(i+1) i = floor(PointCoords(point,3)); i = Ng+modulo(i-Ng,Nz) PointCoords(point,3) = PointCoords(point,3) + dr(3)/dz(i+1) point = PointConnect(point,1) enddo front2 = FrontConnect(front2,1) enddo endif front = FrontConnect(front,1) enddo end subroutine CorrectVolume !================================================================================================= !================================================================================================= ! subroutine MapCoords ! Maps the point xp(:) in physical domain to PointCoords(point,:) in the front domain. !------------------------------------------------------------------------------------------------- subroutine MapCoords(xp,point) use module_grid implicit none real(8) :: xp(3) integer :: point,i1, Ndomain Ndomain = floor(xp(1)/xLength) xp(1) = xp(1)-xLength*Ndomain do i1=Ng,Nx+Ng-1 if(xp(1)>xh(i1+1))cycle PointCoords(point,1)=0.5+( dfloat(i1)*(xh(i1+1)-xp(1)) + dfloat(i1+1)*(xp(1)-xh(i1)) )/dx(i1+1) exit enddo PointCoords(point,1) = PointCoords(point,1)+dfloat(Nx*Ndomain) Ndomain = floor(xp(2)/yLength) xp(2) = xp(2)-yLength*Ndomain do i1=Ng,Ny+Ng-1 if(xp(2)>yh(i1+1))cycle PointCoords(point,2)=0.5+( dfloat(i1)*(yh(i1+1)-xp(2)) + dfloat(i1+1)*(xp(2)-yh(i1)) )/dy(i1+1) exit enddo PointCoords(point,2) = PointCoords(point,2)+dfloat(Ny*Ndomain) Ndomain = floor(xp(3)/zLength) xp(3) = xp(3)-zLength*Ndomain do i1=Ng,Nz+Ng-1 if(xp(3)>zh(i1+1))cycle PointCoords(point,3)=0.5+( dfloat(i1)*(zh(i1+1)-xp(3)) + dfloat(i1+1)*(xp(3)-zh(i1)) )/dz(i1+1) exit enddo PointCoords(point,3) = PointCoords(point,3)+dfloat(Nz*Ndomain) end subroutine MapCoords !================================================================================================= !================================================================================================= ! subroutine GetCoords ! Converts the mapped location of front points to the physical domain !------------------------------------------------------------------------------------------------- subroutine GetCoords(xp,point) use module_grid implicit none real(8) :: xp(3) integer :: point,i,i1 i = floor(PointCoords(point,1)-0.5); i1 = Ng+modulo(i-Ng,Nx) !if(i>Nx .or. i<1)call pariserror("Error: GetCoords"); xp(1)=xh(i1)+dx(i1+1)*(PointCoords(point,1)-dfloat(i)-0.5)+xLength*floor(dfloat(i-Ng)/dfloat(Nx)) i = floor(PointCoords(point,2)-0.5); i1 = Ng+modulo(i-Ng,Ny) !if(i>Ny .or. i<1)call pariserror("Error: GetCoords"); xp(2)=yh(i1)+dy(i1+1)*(PointCoords(point,2)-dfloat(i)-0.5)+yLength*floor(dfloat(i-Ng)/dfloat(Ny)) i = floor(PointCoords(point,3)-0.5); i1 = Ng+modulo(i-Ng,Nz) !if(i>Nz .or. i<1)call pariserror("Error: GetCoords"); xp(3)=zh(i1)+dz(i1+1)*(PointCoords(point,3)-dfloat(i)-0.5)+zLength*floor(dfloat(i-Ng)/dfloat(Nz)) end subroutine GetCoords !================================================================================================= !================================================================================================= ! subroutine CalcSurfaceTension ! Calculates the surface tension and the color function gradient on the front grid !------------------------------------------------------------------------------------------------- subroutine CalcSurfaceTension use module_flow implicit none real(8) :: l real(8), dimension(3) :: xcen, xn, xn1, sm, x1, x2, x3, x21, x32 !, area real(8), dimension(3,3) :: xm, xs integer :: front, elem, ifr, point, i, p1, p2, p3 ! reset the surface tension force front = FrontFirst do ifr = 1, FrontLength point = PointFirst(front) do i = 1, PointLength(front) FrontForce(:,point)=0d0 gradIFront(:,point)=0d0 point = PointConnect(point,1) enddo front = FrontConnect(front,1) enddo ! add up the surface tension forces front = FrontFirst do ifr = 1, FrontLength elem = ElemFirst(front) do i = 1, ElemLength(front) p1=ElemCorner(elem,1) p2=ElemCorner(elem,2) p3=ElemCorner(elem,3) call GetCoords(x1,p1) call GetCoords(x2,p2) call GetCoords(x3,p3) xm(:,1) = 0.5d0*(x2+x3) xm(:,2) = 0.5d0*(x3+x1) xm(:,3) = 0.5d0*(x1+x2) xcen = (x1+x2+x3)/3d0 !normal vector to the element x21 = x2-x1 x32 = x3-x2 xn = cross(x21,x32) l = dsqrt(xn(1)**2+xn(2)**2+xn(3)**2) xn1 = xn/l !unit length x21 = xcen-xm(:,1); xs(:,1) = cross(x21,xn1) x21 = xcen-xm(:,2); xs(:,2) = cross(x21,xn1) x21 = xcen-xm(:,3); xs(:,3) = cross(x21,xn1) !average surface tension sm(1) = (SurfaceTension(2)+SurfaceTension(3))/2.4d0+SurfaceTension(1)/6d0 sm(2) = (SurfaceTension(3)+SurfaceTension(1))/2.4d0+SurfaceTension(2)/6d0 sm(3) = (SurfaceTension(1)+SurfaceTension(2))/2.4d0+SurfaceTension(3)/6d0 FrontForce(:,p1) = FrontForce(:,p1) + (xs(:,3)*sm(3) - xs(:,2)*sm(2)) FrontForce(:,p2) = FrontForce(:,p2) + (xs(:,1)*sm(1) - xs(:,3)*sm(3)) FrontForce(:,p3) = FrontForce(:,p3) + (xs(:,2)*sm(2) - xs(:,1)*sm(1)) ! density gradient terms gradIFront(:,p1) = gradIFront(:,p1) + xn/6d0 gradIFront(:,p2) = gradIFront(:,p2) + xn/6d0 gradIFront(:,p3) = gradIFront(:,p3) + xn/6d0 elem = ElemConnect(elem,1) enddo front = FrontConnect(front,1) enddo end subroutine CalcSurfaceTension !================================================================================================= !================================================================================================= ! subroutine Front2GridVector ! Maps the surface tension and color function gradient from the front to the flow grid !------------------------------------------------------------------------------------------------- subroutine Front2GridVector(fx1, fy1, fz1, fx2, fy2, fz2) use module_grid use module_BC use module_tmpvar implicit none include 'mpif.h' real(8), dimension(imin:imax,jmin:jmax,kmin:kmax) :: fx1, fy1, fz1, fx2, fy2, fz2 real(8) :: xp,yp,zp, xt,yt,zt, xth,yth,zth, ffx1,ffy1,ffz1, ffx2,ffy2,ffz2, & drx,dry,drz,drxh,dryh,drzh, pd2 integer :: point,ir,jr,kr,irh,jrh,krh,ii,jj,kk,iih,jjh,kkh,i1,j1,k1 !,i,front,ifr integer :: req(12),sta(MPI_STATUS_SIZE,12), ierr pd2 = 3.14159265358979323846/2d0 ! add up the surface tension forces onto the fixed grid ! front = FrontFirst ! do ifr = 1, FrontLength ! point = PointFirst(front) ! do i = 1, PointLength(front) do point = 1, NumLocPoint xp = PointCoordsBuff(1,point) yp = PointCoordsBuff(2,point) zp = PointCoordsBuff(3,point) ffx1 = PointCoordsBuff(4,point) ffy1 = PointCoordsBuff(5,point) ffz1 = PointCoordsBuff(6,point) ffx2 = PointCoordsBuff(7,point) ffy2 = PointCoordsBuff(8,point) ffz2 = PointCoordsBuff(9,point) ir = floor(xp); irh = floor(xp-0.5d0); xt = xp; xth = xp-0.5d0 jr = floor(yp); jrh = floor(yp-0.5d0); yt = yp; yth = yp-0.5d0 kr = floor(zp); krh = floor(zp-0.5d0); zt = zp; zth = zp-0.5d0 if(bdry_cond(1)==1) then ir = is-1+modulo(ir-is+1,Nx) irh = is-1+modulo(irh-is+1,Nx) xt = dfloat(is-1)+modulo(xp-dfloat(is-1),dfloat(Nx)) xth = dfloat(is-1)+modulo(xp-dfloat(is-1)-0.5d0,dfloat(Nx)) endif if(bdry_cond(2)==1) then jr = js-1+modulo(jr-js+1,Ny) jrh = js-1+modulo(jrh-js+1,Ny) yt = dfloat(js-1)+modulo(yp-dfloat(js-1),dfloat(Ny)) yth = dfloat(js-1)+modulo(yp-dfloat(js-1)-0.5d0,dfloat(Ny)) endif if(bdry_cond(3)==1) then kr = ks-1+modulo(kr-ks+1,Nz) krh = ks-1+modulo(krh-ks+1,Nz) zt = dfloat(ks-1)+modulo(zp-dfloat(ks-1),dfloat(Nz)) zth = dfloat(ks-1)+modulo(zp-dfloat(ks-1)-0.5d0,dfloat(Nz)) endif do i1=1,4; do j1=1,4; do k1=1,4 ii = ir -2+i1; iih = irh-2+i1 jj = jr -2+j1; jjh = jrh-2+j1 kk = kr -2+k1; kkh = krh-2+k1 drx = 1d0 + cos((xt -float(ii ))*pd2) dry = 1d0 + cos((yt -float(jj ))*pd2) drz = 1d0 + cos((zt -float(kk ))*pd2) drxh = 1d0 + cos((xth-float(iih))*pd2) dryh = 1d0 + cos((yth-float(jjh))*pd2) drzh = 1d0 + cos((zth-float(kkh))*pd2) fx1(iih,jj,kk) = fx1(iih,jj,kk) + drxh*dry*drz*ffx1/64d0 /dxh(iih)/dy(jj)/dz(kk) fy1(ii,jjh,kk) = fy1(ii,jjh,kk) + drx*dryh*drz*ffy1/64d0 /dx(ii)/dyh(jjh)/dz(kk) fz1(ii,jj,kkh) = fz1(ii,jj,kkh) + drx*dry*drzh*ffz1/64d0 /dx(ii)/dy(jj)/dzh(kkh) fx2(iih,jj,kk) = fx2(iih,jj,kk) + drxh*dry*drz*ffx2/64d0 /dxh(iih)/dy(jj)/dz(kk) fy2(ii,jjh,kk) = fy2(ii,jjh,kk) + drx*dryh*drz*ffy2/64d0 /dx(ii)/dyh(jjh)/dz(kk) fz2(ii,jj,kkh) = fz2(ii,jj,kkh) + drx*dry*drzh*ffz2/64d0 /dx(ii)/dy(jj)/dzh(kkh) enddo; enddo; enddo ! point = PointConnect(point,1) ! enddo ! front = FrontConnect(front,1) enddo !------------------------------------------------------------------------------------------------- call ghost_xAdd(fx1,is-1,ie,1,req(1:4 )) call ghost_xAdd(fy1,is,ie+1,2,req(5:8 )) call ghost_xAdd(fz1,is,ie+1,3,req(9:12)) call MPI_WAITALL(12,req,sta,ierr) fx1(is-1:is,:,:) = fx1(is-1:is,:,:) + work(is-1:is,:,:,1) fx1(ie-1:ie,:,:) = fx1(ie-1:ie,:,:) + work(ie-1:ie,:,:,1) fy1(is:is+1,:,:) = fy1(is:is+1,:,:) + work(is:is+1,:,:,2) fy1(ie-1:ie,:,:) = fy1(ie-1:ie,:,:) + work(ie-1:ie,:,:,2) fz1(is:is+1,:,:) = fz1(is:is+1,:,:) + work(is:is+1,:,:,3) fz1(ie-1:ie,:,:) = fz1(ie-1:ie,:,:) + work(ie-1:ie,:,:,3) call ghost_yAdd(fx1,js,je+1,1,req(1:4 )) call ghost_yAdd(fy1,js-1,je,2,req(5:8 )) call ghost_yAdd(fz1,js,je+1,3,req(9:12)) call MPI_WAITALL(12,req,sta,ierr) fx1(:,js:js+1,:) = fx1(:,js:js+1,:) + work(:,js:js+1,:,1) fx1(:,je-1:je,:) = fx1(:,je-1:je,:) + work(:,je-1:je,:,1) fy1(:,js-1:js,:) = fy1(:,js-1:js,:) + work(:,js-1:js,:,2) fy1(:,je-1:je,:) = fy1(:,je-1:je,:) + work(:,je-1:je,:,2) fz1(:,js:js+1,:) = fz1(:,js:js+1,:) + work(:,js:js+1,:,3) fz1(:,je-1:je,:) = fz1(:,je-1:je,:) + work(:,je-1:je,:,3) call ghost_zAdd(fx1,ks,ke+1,1,req(1:4 )) call ghost_zAdd(fy1,ks,ke+1,2,req(5:8 )) call ghost_zAdd(fz1,ks-1,ke,3,req(9:12)) call MPI_WAITALL(12,req,sta,ierr) fx1(:,:,ks:ks+1) = fx1(:,:,ks:ks+1) + work(:,:,ks:ks+1,1) fx1(:,:,ke-1:ke) = fx1(:,:,ke-1:ke) + work(:,:,ke-1:ke,1) fy1(:,:,ks:ks+1) = fy1(:,:,ks:ks+1) + work(:,:,ks:ks+1,2) fy1(:,:,ke-1:ke) = fy1(:,:,ke-1:ke) + work(:,:,ke-1:ke,2) fz1(:,:,ks-1:ks) = fz1(:,:,ks-1:ks) + work(:,:,ks-1:ks,3) fz1(:,:,ke-1:ke) = fz1(:,:,ke-1:ke) + work(:,:,ke-1:ke,3) !------------------------------------------------------------------------------------------------- call ghost_xAdd(fx2,is-1,ie,1,req(1:4 )) call ghost_xAdd(fy2,is,ie+1,2,req(5:8 )) call ghost_xAdd(fz2,is,ie+1,3,req(9:12)) call MPI_WAITALL(12,req,sta,ierr) fx2(is-1:is,:,:) = fx2(is-1:is,:,:) + work(is-1:is,:,:,1) fx2(ie-1:ie,:,:) = fx2(ie-1:ie,:,:) + work(ie-1:ie,:,:,1) fy2(is:is+1,:,:) = fy2(is:is+1,:,:) + work(is:is+1,:,:,2) fy2(ie-1:ie,:,:) = fy2(ie-1:ie,:,:) + work(ie-1:ie,:,:,2) fz2(is:is+1,:,:) = fz2(is:is+1,:,:) + work(is:is+1,:,:,3) fz2(ie-1:ie,:,:) = fz2(ie-1:ie,:,:) + work(ie-1:ie,:,:,3) call ghost_yAdd(fx2,js,je+1,1,req(1:4 )) call ghost_yAdd(fy2,js-1,je,2,req(5:8 )) call ghost_yAdd(fz2,js,je+1,3,req(9:12)) call MPI_WAITALL(12,req,sta,ierr) fx2(:,js:js+1,:) = fx2(:,js:js+1,:) + work(:,js:js+1,:,1) fx2(:,je-1:je,:) = fx2(:,je-1:je,:) + work(:,je-1:je,:,1) fy2(:,js-1:js,:) = fy2(:,js-1:js,:) + work(:,js-1:js,:,2) fy2(:,je-1:je,:) = fy2(:,je-1:je,:) + work(:,je-1:je,:,2) fz2(:,js:js+1,:) = fz2(:,js:js+1,:) + work(:,js:js+1,:,3) fz2(:,je-1:je,:) = fz2(:,je-1:je,:) + work(:,je-1:je,:,3) call ghost_zAdd(fx2,ks,ke+1,1,req(1:4 )) call ghost_zAdd(fy2,ks,ke+1,2,req(5:8 )) call ghost_zAdd(fz2,ks-1,ke,3,req(9:12)) call MPI_WAITALL(12,req,sta,ierr) fx2(:,:,ks:ks+1) = fx2(:,:,ks:ks+1) + work(:,:,ks:ks+1,1) fx2(:,:,ke-1:ke) = fx2(:,:,ke-1:ke) + work(:,:,ke-1:ke,1) fy2(:,:,ks:ks+1) = fy2(:,:,ks:ks+1) + work(:,:,ks:ks+1,2) fy2(:,:,ke-1:ke) = fy2(:,:,ke-1:ke) + work(:,:,ke-1:ke,2) fz2(:,:,ks-1:ks) = fz2(:,:,ks-1:ks) + work(:,:,ks-1:ks,3) fz2(:,:,ke-1:ke) = fz2(:,:,ke-1:ke) + work(:,:,ke-1:ke,3) !move the vectors that fall outside of a wall into the domain call SetVectorBC(fx1,fy1,fz1) call SetVectorBC(fx2,fy2,fz2) end subroutine Front2GridVector !================================================================================================= !================================================================================================= ! subroutine AdvanceFront ! Moves the points on the front by interpolating the velocity from flow to front grid !------------------------------------------------------------------------------------------------- subroutine AdvanceFront2(u, v, w,color, dt) use module_grid use module_BC implicit none ! real(8) :: PointCoordsBuff(9,Maxpoint) real(8), dimension(imin:imax,jmin:jmax,kmin:kmax) :: u, v, w, color real(8) :: xp,yp,zp, xt,yt,zt, xth,yth,zth, drx,dry,drz,drxh,dryh,drzh, pd2, dt, up, vp, wp, & colorp, xn(3),rn integer :: point,ir,jr,kr,irh,jrh,krh,ii,jj,kk,iih,jjh,kkh,i1,j1,k1 pd2 = 3.14159265358979323846/2d0 ! add up the surface tension forces onto the fixed grid do point = 1, NumLocPoint xp = PointCoordsBuff(1,point) yp = PointCoordsBuff(2,point) zp = PointCoordsBuff(3,point) up=0d0; vp=0d0; wp=0d0; colorp=0d0 ir = floor(xp); irh = floor(xp-0.5d0); xt = xp; xth = xp-0.5d0 jr = floor(yp); jrh = floor(yp-0.5d0); yt = yp; yth = yp-0.5d0 kr = floor(zp); krh = floor(zp-0.5d0); zt = zp; zth = zp-0.5d0 if(bdry_cond(1)==1) then ir = is-1+modulo(ir-is+1,Nx) irh = is-1+modulo(irh-is+1,Nx) xt = dfloat(is-1)+modulo(xp-dfloat(is-1),dfloat(Nx)) xth = dfloat(is-1)+modulo(xp-dfloat(is-1)-0.5d0,dfloat(Nx)) endif if(bdry_cond(2)==1) then jr = js-1+modulo(jr-js+1,Ny) jrh = js-1+modulo(jrh-js+1,Ny) yt = dfloat(js-1)+modulo(yp-dfloat(js-1),dfloat(Ny)) yth = dfloat(js-1)+modulo(yp-dfloat(js-1)-0.5d0,dfloat(Ny)) endif if(bdry_cond(3)==1) then kr = ks-1+modulo(kr-ks+1,Nz) krh = ks-1+modulo(krh-ks+1,Nz) zt = dfloat(ks-1)+modulo(zp-dfloat(ks-1),dfloat(Nz)) zth = dfloat(ks-1)+modulo(zp-dfloat(ks-1)-0.5d0,dfloat(Nz)) endif do i1=1,4; do j1=1,4; do k1=1,4 ii = ir -2+i1; iih = irh-2+i1 jj = jr -2+j1; jjh = jrh-2+j1 kk = kr -2+k1; kkh = krh-2+k1 drx = 1d0 + cos((xt -float(ii ))*pd2) dry = 1d0 + cos((yt -float(jj ))*pd2) drz = 1d0 + cos((zt -float(kk ))*pd2) drxh = 1d0 + cos((xth-float(iih))*pd2) dryh = 1d0 + cos((yth-float(jjh))*pd2) drzh = 1d0 + cos((zth-float(kkh))*pd2) up = up + drxh*dry*drz/64d0*u(iih,jj,kk) /dxh(iih) vp = vp + drx*dryh*drz/64d0*v(ii,jjh,kk) /dyh(jjh) wp = wp + drx*dry*drzh/64d0*w(ii,jj,kkh) /dzh(kkh) colorp = colorp + drx*dry*drz/64d0*color(ii,jj,kk) enddo; enddo; enddo ! avoid bubbles to overlap ! if color function is less than 0.1 move the points inward 0.01dx if(colorp<0.02)then !find the unit normal outward vector xn(1:3) = PointCoordsBuff(7:9,point) rn = sqrt(sum(xn**2)) xn = xn / rn up = up - 0.01*xn(1)/dt vp = vp - 0.01*xn(2)/dt wp = wp - 0.01*xn(3)/dt endif PointCoordsBuff(1,point) = PointCoordsBuff(1,point) + up*dt PointCoordsBuff(2,point) = PointCoordsBuff(2,point) + vp*dt PointCoordsBuff(3,point) = PointCoordsBuff(3,point) + wp*dt enddo ! wall boundary condition if(bdry_cond(1)/=1 .and. coords(1)==0 ) then do point = 1, NumLocPoint PointCoordsBuff(1,point) = max(PointCoordsBuff(1,point), 2.51d0) enddo endif if(bdry_cond(4)/=1 .and. coords(1)==nPx-1) then do point = 1, NumLocPoint PointCoordsBuff(1,point) = min(PointCoordsBuff(1,point), dble(ie)+0.49d0) enddo endif if(bdry_cond(2)/=1 .and. coords(2)==0 ) then do point = 1, NumLocPoint PointCoordsBuff(2,point) = max(PointCoordsBuff(2,point), 2.51d0) enddo endif if(bdry_cond(5)/=1 .and. coords(2)==nPy-1) then do point = 1, NumLocPoint PointCoordsBuff(2,point) = min(PointCoordsBuff(2,point), dble(je)+0.49d0) enddo endif if(bdry_cond(3)/=1 .and. coords(3)==0 ) then do point = 1, NumLocPoint PointCoordsBuff(3,point) = max(PointCoordsBuff(3,point), 2.51d0) enddo endif if(bdry_cond(6)/=1 .and. coords(3)==nPz-1) then do point = 1, NumLocPoint PointCoordsBuff(3,point) = min(PointCoordsBuff(3,point), dble(ke)+0.49d0) enddo endif end subroutine AdvanceFront2 !================================================================================================= !================================================================================================= ! subroutine DistributeFront ! Called by the front master, distributes the front nodes between flow processes and gets it back. !------------------------------------------------------------------------------------------------- subroutine DistributeFront(dest,send_recv) !,request) use module_grid use module_BC implicit none include 'mpif.h' character(len=4) :: send_recv integer :: dest, request(1:2), front, point, ifr, i !, iunit, elem integer :: sta(MPI_STATUS_SIZE,1:2), ierr integer, allocatable, dimension(:), save :: ptcount !, send_type logical, save :: first_time=.true. real(8) :: xp, yp, zp if(first_time) then first_time = .false. allocate(ptcount(0:nPdomain) ) !,send_type(0:nPdomain) ) endif if(send_recv=='send') then ptcount(dest)=0 front = FrontFirst do ifr = 1, FrontLength point = PointFirst(front) do i = 1, PointLength(front) xp = PointCoords(point,1) yp = PointCoords(point,2) zp = PointCoords(point,3) if(bdry_cond(1)==1)xp = dfloat(is)-0.5d0+modulo(xp-dfloat(is)+0.5d0,dfloat(Nx)) if(bdry_cond(2)==1)yp = dfloat(js)-0.5d0+modulo(yp-dfloat(js)+0.5d0,dfloat(Ny)) if(bdry_cond(3)==1)zp = dfloat(ks)-0.5d0+modulo(zp-dfloat(ks)+0.5d0,dfloat(Nz)) if( xp>=smin(1,dest) .and. xp=smin(2,dest) .and. yp=smin(3,dest) .and. zp0, one real and two complex roots. ! Step 3a: For D>0 and D=0, ! Calculate u and v ! u = cubic_root(-q/2 + sqrt(D)) ! v = cubic_root(-q/2 - sqrt(D)) ! Find the three transformed roots ! y1 = u + v ! y2 = -(u+v)/2 + i (u-v)*sqrt(3)/2 ! y3 = -(u+v)/2 - i (u-v)*sqrt(3)/2 ! Step 3b Alternately, for D<0, a trigonometri! formulation is more convenient ! y1 = 2 * sqrt(|p|/3) * cos(phi/3) ! y2 = -2 * sqrt(|p|/3) * cos((phi+pi)/3) ! y3 = -2 * sqrt(|p|/3) * cos((phi-pi)/3) ! where phi = acos(-q/2/sqrt(|p|**3/27)) ! pi = 3.141592654... ! Step 4 Finally, find the three roots ! x = y - b/a/3 ! ! ---------------------------------------------------------------------- ! Instructor: Nam Sun Wang ! ---------------------------------------------------------------------- ! Declare variables complex(8) :: x(3) real(8) :: pi=3.141592654 real(8) :: DD, p, q, phi, temp1, temp2, y1,y2,y3, u, v, y2r, y2i DD=0d0; p=0d0; q=0d0; phi=0d0; temp1=0d0; temp2=0d0; y1=0d0; y2=0d0; y3=0d0; u=0d0; v=0d0; y2r=0d0; y2i=0d0 ! Step 0: If a is 0 use the quadratic formula. ------------------------- IF(a .eq. 0.)THEN if(b .eq. 0.)then if(c .eq. 0.)then ! We have a non-equation; therefore, we have no valid solution nroot = 0 else ! We have a linear equation with 1 root. nroot = 1 x(1) = cmplx(-d/c, 0.,kind=8) endif else ! We have a true quadratic equation. Apply the quadratic formula to find two roots. nroot = 2 DD = c*c-4.*b*d if(DD .ge. 0.)then x(1) = cmplx((-c+sqrt(DD))/2./b, 0.,kind=8) x(2) = cmplx((-c-sqrt(DD))/2./b, 0.,kind=8) else x(1) = cmplx(-c/2./b, +sqrt(-DD)/2./b,kind=8) x(2) = cmplx(-c/2./b, -sqrt(-DD)/2./b,kind=8) endif endif ELSE ! Cubic equation with 3 roots nroot = 3 ! Step 1: Calculate p and q -------------------------------------------- p = c/a - b*b/a/a/3. q = (2.*b*b*b/a/a/a - 9.*b*c/a/a + 27.*d/a) / 27. ! Step 2: Calculate DD (discriminant) ---------------------------------- DD = p*p*p/27. + q*q/4. ! Step 3: Branch to different algorithms based on DD ------------------- if(DD .lt. 0.)then ! Step 3b: ! 3 real unequal roots -- use the trigonometric formulation phi = acos(-q/2./sqrt(abs(p*p*p)/27.)) temp1=2.*sqrt(abs(p)/3.) y1 = temp1*cos(phi/3.) y2 = -temp1*cos((phi+pi)/3.) y3 = -temp1*cos((phi-pi)/3.) else ! Step 3a: ! 1 real root & 2 conjugate complex roots OR 3 real roots (some are equal) temp1 = -q/2. + sqrt(DD) temp2 = -q/2. - sqrt(DD) u = abs(temp1)**(1./3.) v = abs(temp2)**(1./3.) if(temp1 .lt. 0.) u=-u if(temp2 .lt. 0.) v=-v y1 = u + v y2r = -(u+v)/2. y2i = (u-v)*sqrt(3.)/2. endif ! Step 4: Final transformation ----------------------------------------- temp1 = b/a/3. y1 = y1-temp1 y2 = y2-temp1 y3 = y3-temp1 y2r=y2r-temp1 ! Assign answers ------------------------------------------------------- if(DD .lt. 0.)then x(1) = cmplx( y1, 0.,kind=8) x(2) = cmplx( y2, 0.,kind=8) x(3) = cmplx( y3, 0.,kind=8) elseif(DD .eq. 0.)then x(1) = cmplx( y1, 0.,kind=8) x(2) = cmplx(y2r, 0.,kind=8) x(3) = cmplx(y2r, 0.,kind=8) else x(1) = cmplx( y1, 0.,kind=8) x(2) = cmplx(y2r, y2i,kind=8) x(3) = cmplx(y2r,-y2i,kind=8) endif ENDIF roots = x end subroutine cubic_solve !------------------------------------------------------------------------------------------------- end module module_front !================================================================================================= !================================================================================================= !-------------------------------------------------------------------------------------------------