Ulambators BoundaryBlock class (bndblock.cpp
) v0.3
This class contains functions to create and store information of boundaries and interfaces
Contents:
-
Initialisation
-
Wall and Droplet creation
-
Droplet evolution
-
Special functions for drop merging, repulsion etc
-
Data writing
-
Drolet statistics
-
Remeshing procedures
-
Ubiquitous subroutines
The header optionally contains OpenMP support.
#include "bndblock.h" #include "bndelement.h" #ifdef _WIN32 #define _USE_MATH_DEFINES // for C++ #include <cmath> #endif #include <math.h> #include <iostream> #include <stdio.h> #include "combase.h" #include <stdlib.h> #include <fstream> #include <assert.h> #ifdef _WIN32 #include <Winsock2.h> #include <algorithm> #include <time.h> #endif using namespace std;
Initialization
BndBlock::BndBlock(int blocks){ Elements = new FlowFace[blocks](); nbBlocks = blocks; runstep = 0; runtime = 0.0; nbPanels = -1; rlim = 0; //elementsPerLength; workdir = new char[120]; panel2block = new int[64]; // only 64 panels can exist, increase if mor are needed writeEnabled = 0; remesh_threshold = 2.0; SeedOption = 0; // 1 - Variable, else Constant IGP = new double[6]; IGW = new double[6]; IGP[0] = -0.932469514203152; IGP[1] = -0.661209386466265; IGP[2] = -0.238619186083197; IGP[3] = 0.238619186083197; IGP[4] = 0.661209386466265; IGP[5] = 0.932469514203152; IGW[0] = 0.171324492379170; IGW[1] = 0.360761573048139; IGW[2] = 0.467913934572691; IGW[3] = 0.467913934572691; IGW[4] = 0.360761573048139; IGW[5] = 0.171324492379170; } void BndBlock::Init(){ int counter = 0; ifid = 0; ifblock = 0; dynblock = 0; dynpanels = 0; nbPanels = 0; for (int k=0; k<nbBlocks; k++) { for (int j=nbPanels; j<(nbPanels+Elements[k].nbPanels); j++) { panel2block[j] = k; } nbPanels += Elements[k].nbPanels; } allBCX = (double*) calloc (nbPanels,sizeof(double)); allBCY = (double*) calloc (nbPanels,sizeof(double)); allBCZ = (double*) calloc (nbPanels,sizeof(double)); allXId = (double**) calloc (nbPanels,sizeof(double*)); allYId = (double**) calloc (nbPanels,sizeof(double*)); allBCtype = (int*) calloc (nbPanels,sizeof(int)); allSize = (int*) calloc (nbPanels,sizeof(int)); allRdist = (double**) calloc (nbPanels,sizeof(double*)); allCdist = (double**) calloc (nbPanels,sizeof(double*)); allWdist = (double**) calloc (nbPanels,sizeof(double*)); for (int k=0; k<nbBlocks; k++) { switch (Elements[k].BCkind) { case 0: // Outer Boundary for (int j=0; j<Elements[k].nbPanels; j++) { allBCX[counter] = Elements[k].BCvalueX[j]; allBCY[counter] = Elements[k].BCvalueY[j]; allBCtype[counter] = Elements[k].BCtype[j]; allXId[counter] = Elements[k].XId[j]; allYId[counter] = Elements[k].YId[j]; allSize[counter] = Elements[k].PanelSize[j]; counter++; } break; /* case 1: // Fibers for (int j=0; j<Elements[k].nbPanels; j++) { allBCX[counter] = 0.0; allBCY[counter] = 0.0; allBCZ[counter] = 0.0; allBCtype[counter] = 4; allXId[counter] = Elements[k].XId[j]; allYId[counter] = Elements[k].YId[j]; allSize[counter] = Elements[k].PanelSize[j]; counter++; } break; */ case 2: // Droplet allRdist[counter] = Elements[k].Rdist; allCdist[counter] = Elements[k].Cdist; allWdist[counter] = Elements[k].Wdist; for (int j=0; j<Elements[k].nbPanels; j++) { allBCX[counter] = 0.0; allBCY[counter] = 0.0; allBCtype[counter] = 21; if (Elements[k].BCtype[j]==22) { allBCtype[counter] = 22; } allXId[counter] = Elements[k].XId[j]; allYId[counter] = Elements[k].YId[j]; allSize[counter] = Elements[k].PanelSize[j]; counter++; } break; /* case 3: // Bordtrac allRdist[counter] = Elements[k].Rdist; allCdist[counter] = Elements[k].Cdist; allWdist[counter] = Elements[k].Wdist; for (int j=0; j<Elements[k].nbPanels; j++) { allBCX[counter] = 0.0; allBCY[counter] = 0.0; allBCtype[counter] = 23; allXId[counter] = Elements[k].XId[j]; allYId[counter] = Elements[k].YId[j]; allSize[counter] = Elements[k].PanelSize[j]; counter++; } break; */ default: cout<<"No valid boundary selected !"<<flush; exit(0); break; } if (Elements[k].BCkind<2) { ifid += Elements[k].nbPanels; ifblock++; } if (Elements[k].BCkind<1) { dynpanels += Elements[k].nbPanels; dynblock++; } } WrapAll(); allStock(); } void BndBlock::PanelInit(int blockId, int Size, int ofKind, int Btype, double *BCvalue, double *PosVec){ // One could check here that the number of panels is not exceeded int index; int numPanels = Elements[blockId].nbPanels; if (numPanels>=1) { index = Elements[blockId].PanelSize[numPanels-1]; if(!((fabs(Elements[blockId].XId[numPanels-1][index]-PosVec[0])<1e-6)&&(fabs(Elements[blockId].YId[numPanels-1][index]-PosVec[1])<1e-6))){ std::cout<<"ATTENTION: Geometry NOT closed, check boundary output!!!\n"; } } index = 0; for (int k = 0; k<numPanels; k++) { index += Elements[blockId].PanelSize[k]; } Elements[blockId].XId[numPanels] = &Elements[blockId].XE[index+5]; Elements[blockId].YId[numPanels] = &Elements[blockId].YE[index+5]; Elements[blockId].PanelSize[numPanels] = Size; switch (ofKind){ case 0: // Straight line for walls or in- outflow DrawLine(Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1], PosVec[2], PosVec[3], Size); break; case 1: // Curved line for walls Pos4 is curvature positive for outwards DrawSegm(Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1], PosVec[2], PosVec[3], PosVec[4], Size); break; case 2: // Pancake droplet DoCircle(Size, PosVec[2], Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1], int(PosVec[4]), PosVec[3]); break; case 3: // Elliptic droplet Pos0 is the major halfaxis and its inverse minor ha DoEllipse(Size, PosVec[2], PosVec[3], Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1]); break; case 4: // droplet with recangular middle section and caps, Pos0 is length of middle section DoEgg(Size, PosVec[2], PosVec[3], Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1]); break; case 5: // Droplet interface for attached boundaries DrawLine(&Elements[blockId].XId[numPanels][-1], &Elements[blockId].YId[numPanels][-1], PosVec[0], PosVec[1], PosVec[2], PosVec[3], Size+1); break; case 6: // Hyperbolic walls DrawHyperbel(Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1], PosVec[2], PosVec[3], Size); case 7: // Sinus shape walls with amplitude and wavenumber DrawSine(Elements[blockId].XId[numPanels], Elements[blockId].YId[numPanels], PosVec[0], PosVec[1], PosVec[2], PosVec[3], Size,PosVec[4], int(PosVec[5])); break; } Elements[blockId].BCtype[numPanels] = Btype; Elements[blockId].BCvalueX[numPanels] = BCvalue[0]; Elements[blockId].BCvalueY[numPanels] = BCvalue[1]; numPanels++; Elements[blockId].nbPanels = numPanels; if((numPanels>1)&&(numPanels==Elements[blockId].nbPanRes)){ if(!((fabs(Elements[blockId].XId[numPanels-1][Size]-Elements[blockId].XId[0][0])<1e-6)&&(fabs(Elements[blockId].YId[numPanels-1][Size]-Elements[blockId].YId[0][0])<1e-6))){ std::cout<<"ATTENTION: Geometry NOT closed, check boundary output!!!\n"; } Elements[blockId].XId[numPanels-1][Size+1] = Elements[blockId].XId[0][1]; Elements[blockId].YId[numPanels-1][Size+1] = Elements[blockId].YId[0][1]; } std::cout<<" Block "<<blockId<<" Panel "<<numPanels<<" of "<<Elements[blockId].nbPanRes<<" initialized.\n"<<flush; }
Dedicated to droplet creation
void BndBlock::DoCircle(int prec, double radius, double *Xcir, double *Ycir, double XPos, double YPos, int Nmode, double Namp){
Creates droplet, optional with perturbation single/multiple/noise
double radstep = 2*M_PI/prec; double radus; srand(time(NULL)); radus = 0.0; for(int n=0; n<=prec; n++){ if (Nmode>0) { radus = Namp*(cos(Nmode*n*radstep)); } else { radus = Namp*rand()/(float(RAND_MAX)+1); } Xcir[n] = radius*(1.0+radus)*cos(n*radstep)+ XPos; Ycir[n] = fabs(radius)*(1.0+radus)*sin(n*radstep)+ YPos; } } void BndBlock::DoEgg(int prec, double longeur, double largeur, double *Xcir, double *Ycir, double X0, double Y0){
Make droplet which is elongated by a straight section – Option 4
double radius = largeur; double signum = 1.0-2.0*(longeur<0); longeur= fabs(longeur); int straight = (prec*longeur/(2*M_PI*radius+2*longeur)); int curved = prec/2-straight; double radstep = M_PI/curved; int n=0; int keep; for(int j=0; j<curved; j++){ Xcir[n] = -radius*cos(n*radstep)+X0; Ycir[n] = -signum*(longeur*1.0/2.0+radius*sin(n*radstep))+Y0; n++; } keep=n; for(int j=0; j<straight; j++){ Xcir[n] = radius+X0; Ycir[n] = signum*longeur*((n-keep)*1.0/straight-0.5)+Y0; n++; } keep = n; for(int j= 0; j<curved; j++){ Xcir[n] = radius*cos((n-keep)*radstep)+X0; Ycir[n] = signum*(longeur*1.0/2.0+radius*sin((n-keep)*radstep))+Y0; n++; } keep = n; for(int j=keep; j<prec; j++){ Xcir[n] = -radius+X0; Ycir[n] = signum*longeur*(0.5-(n-keep)*1.0/straight)+Y0; n++; } } void BndBlock::DoEllipse(int prec, double axisx, double axisy, double *Xcir, double *Ycir, double X0, double Y0){ // Make droplet which is elliptic major/minor axisx and axisy double radstep = 2*M_PI/prec; for(int n=0; n<prec; n++){ Xcir[n] = axisx*cos((n)*radstep)+X0; Ycir[n] = axisy*sin((n)*radstep)+Y0; } } void BndBlock::DrawLine(double *Xdraw, double *Ydraw, double X0, double Y0, double X1, double Y1, int nElm){ // Standard routine for straight lines refined at the end. Ovstp is tunable. double dx = (X1-X0); double dy = (Y1-Y0); double stlen = 2.0/nElm; double AQ, BQ, Ovstp,Sva; int keep=0; Ovstp = 1.1; if (Ovstp ==1) { double stlen = 1.0/nElm; for (int j=0; j<=nElm; j++) { Xdraw[j] = X0+dx*stlen*j; Ydraw[j] = Y0+dy*stlen*j; } } else { AQ = 2.5*(2-Ovstp)/(Ovstp-1); BQ = AQ+4/(2+AQ)-2; for (int j=0; j<nElm/2; j++) { Sva = j*1.0/nElm; // stlen = Sva; stlen = (AQ*Sva+1.0/(1.0+Sva*AQ)-1.0)/BQ; Xdraw[j] = X0+dx*stlen; Ydraw[j] = Y0+dy*stlen; keep = j; } for (int j=keep; j<=nElm; j++) { Sva = 1-j*1.0/nElm; // stlen = 1.0-Sva; stlen = 1.0 - (AQ*Sva+1.0/(1.0+Sva*AQ)-1.0)/BQ; Xdraw[j] = X0+dx*stlen; Ydraw[j] = Y0+dy*stlen; } } } void BndBlock::DrawSegm(double*Xdraw, double *Ydraw, double X0, double Y0, double X1, double Y1, double R, int nElm){ // Makes curved boundary segments, needs care when used double D = sqrt((X1-X0)*(X1-X0) + (Y1-Y0)*(Y1-Y0)); double Ym = -R/fabs(R)*sqrt(R*R - D*D/4); double gam = asin(D/(2*R)); double Xm = 0.5*(X0+X1) - Ym*(Y1-Y0)/D; double phi; double stlen = 1.0/nElm; double AQ, BQ, Ovstp,Sva; int keep=0; Ovstp = 1.3; AQ = 2.5*(2-Ovstp)/(Ovstp-1); BQ = AQ+4/(2+AQ)-2; Ym = 0.5*(Y0+Y1) + Ym*(X1-X0)/D; for (int j=0; j<nElm/2; j++) { Sva = j*1.0/nElm; stlen = (AQ*Sva+1.0/(1.0+Sva*AQ)-1.0)/BQ; phi = gam - stlen*gam*2.0; Xdraw[j] = Xm - R*(sin(phi)*(X1-X0)/D + cos(phi)*(Y1-Y0)/D); Ydraw[j] = Ym + R*(cos(phi)*(X1-X0)/D - sin(phi)*(Y1-Y0)/D); keep = j; } for (int j=keep; j<=nElm; j++) { Sva = 1-j*1.0/nElm; stlen = 1.0 - (AQ*Sva+1.0/(1.0+Sva*AQ)-1.0)/BQ; phi = gam - stlen*gam*2.0; Xdraw[j] = Xm - R*(sin(phi)*(X1-X0)/D + cos(phi)*(Y1-Y0)/D); Ydraw[j] = Ym + R*(cos(phi)*(X1-X0)/D - sin(phi)*(Y1-Y0)/D); } } void BndBlock::DrawSine(double*Xdraw, double *Ydraw, double X0, double Y0, double X1, double Y1, int nElm, double sinamp, int sinewave){ // Makes curved boundary segments, needs care when used double dx = (X1-X0); double dy = (Y1-Y0); double dabs = sqrt(dx*dx+dy*dy); double stlen = 2.0/nElm; double AQ, BQ, Ovstp,Sva; int keep=0; Ovstp = 1.0; if (Ovstp ==1) { double stlen = 1.0/nElm; for (int j=0; j<=nElm; j++) { Xdraw[j] = X0+dx*stlen*j+dy/dabs*sinamp*sin(sinewave*2.0*j*M_PI/nElm); Ydraw[j] = Y0+dy*stlen*j-dx/dabs*sinamp*sin(sinewave*2.0*j*M_PI/nElm); } } else { AQ = 2.5*(2-Ovstp)/(Ovstp-1); BQ = AQ+4/(2+AQ)-2; for (int j=0; j<nElm/2; j++) { Sva = j*1.0/nElm; // stlen = Sva; stlen = (AQ*Sva+1.0/(1.0+Sva*AQ)-1.0)/BQ; Xdraw[j] = X0+dx*stlen; Ydraw[j] = Y0+dy*stlen; keep = j; } for (int j=keep; j<=nElm; j++) { Sva = 1-j*1.0/nElm; // stlen = 1.0-Sva; stlen = 1.0 - (AQ*Sva+1.0/(1.0+Sva*AQ)-1.0)/BQ; Xdraw[j] = X0+dx*stlen; Ydraw[j] = Y0+dy*stlen; } } } void BndBlock::DrawHyperbel(double*Xdraw, double *Ydraw, double X0, double Y0, double X1, double Y1, int nElm){ double C = X0*Y0; assert(C==(Y1*X1)); double D1 = X0*X0-Y0*Y0; double D2 = X1*X1-Y1*Y1; double dd = (D2-D1)/nElm; for (int j=0; j<=nElm; j++){ Ydraw[j] = (( Y0 > 0 ) - ( Y0 < 0 ))*sqrt(sqrt(pow(D1+dd*j,2)/4+C*C)-(D1+dd*j)/2); Xdraw[j] = C/Ydraw[j]; } } void BndBlock::DropRead(int dropId, int timestep){ // Load droplet from solution used for visualization if(!writeEnabled){ std::cout<<"Writing is not enabled! No folder available.\nCall EnableWrite(dir) before ReadDrop(). Aborting program!\n"<<std::flush; exit(0); } char str[100]; char* thisdir = new char[120]; string kio, kio2; string delim = " "; // or " " double xpos, ypos; int npos, cutat; Elements[dropId].XId[0] = &Elements[dropId].XE[5]; Elements[dropId].YId[0] = &Elements[dropId].YE[5]; double *XId = Elements[dropId].XId[0]; double *YId = Elements[dropId].YId[0]; sprintf(thisdir,"%s/drop%its%i.dat", workdir.c_str(), dropId, timestep); fstream file(thisdir,ios::in); if (file.is_open()) { // Read Header file.getline(str,100); kio = str; cutat = kio.find_first_of(delim); kio2 = kio.substr(0,cutat); runtime = strtod(kio2.c_str(),NULL); kio = kio.substr(cutat+1); cutat = kio.find_first_of(delim); kio2 = kio.substr(0,cutat); Elements[dropId].Xrelativ = strtod(kio2.c_str(), NULL); kio = kio.substr(cutat+1); cutat = kio.find_first_of(delim); kio = kio.substr(0,cutat); Elements[0].Xrelativ = strtod(kio.c_str(), NULL); // Read Geometry npos =-1; while (file.eof()!=1) { npos++; file.getline(str,100); kio = str; cutat = kio.find_first_of(delim); kio2 = kio.substr(0,cutat); kio = kio.substr(cutat+1); cutat = kio.find_first_of(delim); kio = kio.substr(0,cutat); xpos = strtod(kio2.c_str(), NULL); ypos = strtod(kio.c_str(), NULL); XId[npos] = xpos; YId[npos] = ypos; } Elements[dropId].nbPanels = 1; Elements[dropId].PanelSize[0] = npos; runstep = timestep; if(nbPanels>=0){ allSize[ifid+dropId-ifblock] = Elements[dropId].PanelSize[0]; } file.close(); WrapInterface(dropId); Stock(dropId); std::cout<<"Drop Loaded with "<<npos<<" Elements.\n"; }else{ std::cout<<"Write directory could not be opened\n"; } }
Dedicated to droplet evolution
void BndBlock::Evolve(int blockId, double Cold, double Cnew, double deltaT, double* xvec){ // Evolves droplets from buffer IntfXY to XYId int dynNodes; double *Xn, *Yn, *Xo, *Yo; dynNodes = 0; dynNodes = Elements[blockId].getFullSize(); Xn = Elements[blockId].XId[0]; Yn = Elements[blockId].YId[0]; Xo = &Elements[blockId].IntfX[5]; Yo = &Elements[blockId].IntfY[5]; for (int n=0; n<dynNodes; n++) { Xn[n] = Cold*Xo[n] + Cnew*Xn[n] + xvec[2*n]*deltaT;//*fabs(lnx); Yn[n] = Cold*Yo[n] + Cnew*Yn[n] + xvec[2*n+1]*deltaT;//*fabs(lny); } WrapInterface(blockId); } void BndBlock::Translate(int blockId, double Xdep, double Ydep, double Theta){ // Displace droplet by a solid body movement int dynNodes = Elements[blockId].getFullSize(); double* XA = Elements[blockId].XId[0]; double* YA = Elements[blockId].YId[0]; double* XT = &Elements[blockId].IntfX[5]; double* YT = &Elements[blockId].IntfY[5]; double BY, coz, xcm, ycm; getCoM(blockId, xcm, ycm); for (int n=0; n<dynNodes; n++) { BY = sqrt(pow(XT[n]-xcm,2)+pow(YT[n]-ycm,2)); coz = acos((XT[n]-xcm)/BY)*((YT[n]-ycm)>=0)+(2*M_PI-acos((XT[n]-xcm)/BY))*((YT[n]-ycm)<0); XA[n] = BY*cos(Theta+coz)+Xdep+xcm; YA[n] = BY*sin(Theta+coz)+Ydep+ycm; } WrapInterface(blockId); } void BndBlock::correctArea(int blockId){ // Corrects the Area by normal displacement of the interface double A1 = getArea(blockId); double A0 = Elements[blockId].initialArea; double circumference = 0; int dynNodes = Elements[blockId].getFullSize(); double* XA = Elements[blockId].XId[0]; double* YA = Elements[blockId].YId[0]; double* XT = &Elements[blockId].IntfX[5]; double* YT = &Elements[blockId].IntfY[5]; double lnx, lny, rr; if(A0!=0){ WrapInterface(blockId); Stock(blockId); for (int n=0; n<dynNodes; n++) { lnx = YA[n+1]-YA[n]; lny = XA[n+1]-XA[n]; rr = sqrt(lnx*lnx+lny*lny); circumference += rr; } circumference = (A0-A1)/circumference; for (int n=0; n<dynNodes; n++) { lnx = YT[n+1]-YT[n-1]; lny = XT[n-1]-XT[n+1]; rr = 1.0/sqrt(lnx*lnx+lny*lny); XA[n] += circumference*lnx*rr; YA[n] += circumference*lny*rr; } WrapInterface(blockId); } } void BndBlock::correctArea(){ for(int i=ifblock;i<nbBlocks;i++){ correctArea(i); } } void BndBlock::Stock(int blockId){ // Move droplet positins from XYId to buffer IntfXY int size = Elements[blockId].getFullSize(); for (int n=0; n<size+10;n++){ Elements[blockId].IntfX[n] = Elements[blockId].XE[n]; Elements[blockId].IntfY[n] = Elements[blockId].YE[n]; } } void BndBlock::UpdateCourbure(int blockId){ double *IX, *IY; int size; double dxl, dxr, dyl, dyr, delta1, delta2; IX = Elements[blockId].XId[0]; IY = Elements[blockId].YId[0]; size = Elements[blockId].getFullSize(); for(int n=0; n<size;n++){ dxl = IX[n]-IX[n-1]; dxr = IX[n+1]-IX[n]; dyl = IY[n]-IY[n-1]; dyr = IY[n+1]-IY[n]; delta1 = sqrt(dxl*dxl+dyl*dyl); delta2 = sqrt(dxr*dxr+dyr*dyr); dxl = -2.0*(dxr/delta2-dxl/delta1)/(delta1+delta2); dyl = -2.0*(dyr/delta2-dyl/delta1)/(delta1+delta2); Elements[blockId].KC[n] = sqrt(dxl*dxl+dyl*dyl)*(1.0-2.0*((dxl*dyr/delta2-dyl*dxr/delta2)<0)); } } void BndBlock::UpdateCourbure(){ for (int k=ifblock; k<nbBlocks; k++) { UpdateCourbure(k); } } void BndBlock::UpdateSize(){ int count=0; for (int n=ifblock; n<nbBlocks; n++) { for (int m=0; m<Elements[n].nbPanels; m++){ allSize[ifid+count] = Elements[n].PanelSize[m]; count++; } } } void BndBlock::WrapInterface(int blockId){ // Sets the ghost points int size = Elements[blockId].getFullSize(); double *Xp, *Yp; if(Elements[blockId].BCkind!=3){ for (int n=0; n<5; n++) { Elements[blockId].XId[0][n-5] = Elements[blockId].XId[0][size-5+n]; Elements[blockId].YId[0][n-5] = Elements[blockId].YId[0][size-5+n]; Elements[blockId].XId[0][size+n] = Elements[blockId].XId[0][n]; Elements[blockId].YId[0][size+n] = Elements[blockId].YId[0][n]; } } else { Xp = Elements[blockId].XId[0]; Yp = Elements[blockId].YId[0]; // Zero Angle - Problematic because implicit curvature assumes immobile ghostpoints Elements[blockId].XId[0][-2] = 2.0*Xp[-1]-Xp[0]; Elements[blockId].YId[0][-2] = 2.0*Yp[-1]-Yp[0]; Elements[blockId].YId[0][-3] = 3.0*Yp[-1]-2.0*Yp[0]; Elements[blockId].XId[0][-3] = 3.0*Xp[-1]-2.0*Xp[0]; Elements[blockId].XId[0][size+1] = 2.0*Xp[size]-Xp[size-1]; Elements[blockId].YId[0][size+1] = 2.0*Yp[size]-Yp[size-1]; Elements[blockId].YId[0][size+2] = 3.0*Yp[size]-2.0*Yp[size-1]; Elements[blockId].XId[0][size+2] = 3.0*Xp[size]-2.0*Xp[size-1]; } }
Special functions for topography change currently disabled
void BndBlock::WallRepuls(){
double BndBlock::DropCorrect(int Drop1, int Drop2){
double BndBlock::DropApproach(int Drop1, int Drop2){
void BndBlock::PerformFusion(int Drop1, int Drop2, int proxL, int proxR){
int BndBlock::CheckBreakUp(int blockId, double kF){
void BndBlock::PerformCut(int blockId, int cutHere1, int cutHere2){
Dedicated to data writing
void BndBlock::EnableWrite(char* save2dir){ workdir = save2dir; writeEnabled = 1; } void BndBlock::WritePos(int blockId, int nbSlice){
Write the droplet positions and curvature
if (writeEnabled) { char strL[128]; int nbEle; double* Xpos; double* Ypos; FILE* pfile; int saveshed = 0; if(blockId == 99){ saveshed = 1; blockId = 1; } nbEle = Elements[blockId].getFullSize(); Xpos = Elements[blockId].XId[0]; Ypos = Elements[blockId].YId[0]; // std::cout<<" Elements present "<<nbEle<<" "; if (saveshed) { sprintf(strL,"%s/drop1ts999.dat",workdir.c_str()); pfile = fopen(strL,"w"); UpdateCourbure(blockId); fprintf(pfile, "%1.15f %1.15f %1.15f\n", runtime, Elements[blockId].Xrelativ, Elements[blockId].Yrelativ); for (int n=nbSlice; n<nbEle; n++) { fprintf(pfile, "%1.15f %1.15f %1.15f\n",Xpos[n],Ypos[n],Elements[blockId].KC[n]); } }else if (Elements[blockId].BCkind<1) { sprintf(strL,"%s/bnd%ipos.dat", workdir.c_str(), blockId); pfile = fopen(strL,"w"); for (int j=0; j<nbEle; j++) { fprintf(pfile, "%1.15f %1.15f \n",Xpos[j],Ypos[j]); } } else { sprintf(strL,"%s/drop%its%d.dat",workdir.c_str(), blockId, nbSlice); pfile = fopen(strL,"w"); UpdateCourbure(blockId); fprintf(pfile, "%1.15f %1.15f %1.15f\n", runtime, Elements[blockId].Xrelativ, Elements[blockId].Yrelativ); for (int n=0; n<nbEle; n++) { fprintf(pfile, "%1.15f %1.15f %1.15f\n",Xpos[n],Ypos[n],Elements[blockId].KC[n]); } } fclose(pfile); cout <<"Position "<<nbSlice<<" written for "<<blockId<<" object"<<" at time "<<runtime<<"\n"; } } void BndBlock::LogAreaPos(int logId, int blockId){ char logurl[120]; FILE* logfile; double A0, Xp, Yp; A0 = getCoM(blockId, Xp, Yp); sprintf(logurl,"%s/log%i.txt", workdir.c_str(),logId); logfile = fopen(logurl, "a"); fprintf(logfile, "%2.9f %2.9f %2.9f\n", A0, Xp, Yp); fclose(logfile); } void BndBlock::LogTimeStep(int logId){ char logurl[120]; FILE* logfile; sprintf(logurl,"%s/log%i.txt", workdir.c_str(),logId); logfile = fopen(logurl, "a"); fprintf(logfile, "%i %f ", runstep, runtime); fclose(logfile); } double BndBlock::LogCustom(int logid, int modusid){
To write a log file with customized data. Delete or add routines as you like.
char logurl[120]; FILE* logfile; double xcm, ycm, perimeter; int imax; switch(modusid){ case 0: break; case 1: { // FOR ARTULAM double perimeter = 0; for(int i=0; i<Elements[1].PanelSize[0];i++){ perimeter += sqrt( pow(Elements[1].XId[0][i+1]-Elements[1].XId[0][i] ,2)+pow(Elements[1].YId[0][i+1]-Elements[1].YId[0][i],2)); } sprintf(logurl,"%s/log%i.txt", workdir.c_str(),logid); logfile = fopen(logurl, "a"); getCoM(1, xcm, ycm); someWay += xcm; fprintf(logfile, "%f %f %f %f\n", xcm, ycm, perimeter, runtime); fclose(logfile); return xcm; break; } case 2: { // FOR CORDERO STRETCH perimeter = 0; double xmax = -10.0; double xmin = 10.0; double ymax = -10.0; double ymin = 10.0; for(int i=0; i<Elements[1].PanelSize[0];i++){ perimeter += sqrt( pow(Elements[1].XId[0][i+1]-Elements[1].XId[0][i] ,2)+pow(Elements[1].YId[0][i+1]-Elements[1].YId[0][i],2)); xmax = max(xmax, Elements[1].XId[0][i]); xmin = min(xmin, Elements[1].XId[0][i]); ymax = max(ymax, Elements[1].YId[0][i]); ymin = min(ymin, Elements[1].YId[0][i]); } char logurl[120]; FILE* logfile; sprintf(logurl,"%s/log%i.txt", workdir.c_str(),logid); logfile = fopen(logurl, "a"); getCoM(1, xcm, ycm); someWay += xcm; fprintf(logfile, "%f %f %f %f %f %f\n", xcm, ycm, xmax-xmin, ymax-ymin, perimeter, runtime); fclose(logfile); return xcm; break; } case 3: { //get extreme points for relax study double ynord, ysud, xest, xouest, kapnord, kapsud, kapest, kapouest; int blockid = ifblock; // Droplet Element sprintf(logurl,"%s/log%i.txt", workdir.c_str(),logid); logfile = fopen(logurl, "a"); double nordmin, sudmin, estmin, ouestmin; int imin, jmax, jmin; double *XA = Elements[blockid].XId[0]; double *YA = Elements[blockid].YId[0]; nordmin = 10; sudmin = 10; estmin =10; ouestmin = 10; for (int j=0; j<Elements[blockid].PanelSize[0]; j++) { if ((YA[j]>0)&&(fabs(XA[j])<nordmin)) { nordmin = fabs(XA[j]); jmax = j; } if ((YA[j]<0)&&(fabs(XA[j])<sudmin)) { sudmin = fabs(XA[j]); jmin = j; } if ((XA[j]>0)&&(fabs(YA[j])<estmin)) { estmin = fabs(YA[j]); imax = j; } if ((XA[j]<0)&&(fabs(YA[j])<ouestmin)) { ouestmin = fabs(YA[j]); imin = j; } } UpdateCourbure(blockid); kapnord = Elements[blockid].KC[jmax]; kapsud = Elements[blockid].KC[jmin]; kapest = Elements[blockid].KC[imax]; kapouest = Elements[blockid].KC[imin]; ynord = YA[jmax]; ysud = YA[jmin]; xest = XA[imax]; xouest = XA[imin]; fprintf(logfile, "%f %f %f %f %f %f %f %f %f\n", runtime, kapnord, kapsud, kapest, kapouest, ynord, ysud, xest, xouest); fclose(logfile); return kapest; break; } } return 0; } void BndBlock::DisableWrite(){ writeEnabled = 0; }
Dedicated to determine basic droplet statistics
double BndBlock::getArea(int blockId){
Integration of the droplet Area
double xgs, ygs, dx, dy, r, lnx, lny; int nbElms = Elements[blockId].getFullSize(); double A = 0.0; double *Xc = Elements[blockId].XId[0]; double *Yc = Elements[blockId].YId[0]; if (Elements[blockId].BCkind!=3) { WrapInterface(blockId); for(int n=0; n<nbElms; n++){ xgs = 0.5*(Xc[n+1]+Xc[n]); ygs = 0.5*(Yc[n+1]+Yc[n]); dx = Xc[n+1]-Xc[n]; dy = Yc[n+1]-Yc[n]; r = dx*dx+dy*dy; r = sqrt(r); lnx = dy/r; lny = -dx/r; A += r*(xgs*lnx+ygs*lny); } A = A*0.5; // because div(x) = 2 and GW6 integrates over 2 length }else{ for(int n=-1; n<=nbElms; n++){ xgs = 0.5*(Xc[n+1]+Xc[n]); ygs = 0.5*(Yc[n+1]+Yc[n]); dx = Xc[n+1]-Xc[n]; dy = Yc[n+1]-Yc[n]; r = dx*dx+dy*dy; r = sqrt(r); lnx = dy/r; lny = -dx/r; A += (ygs*lny+xgs*lnx)*r; } A = A*0.5; } return A; } double BndBlock::getCoM(int blockId, double& Xcm, double& Ycm){
Integration of center of area
double xgs, ygs, dx, dy, r, lnx, lny; int nbElms; double* Xc = Elements[blockId].XId[0]; double* Yc = Elements[blockId].YId[0]; double A = 0.0; nbElms = Elements[blockId].getFullSize(); A = 0; Xcm = 0; Ycm = 0; for(int n=0; n<nbElms; n++){ xgs = 0.5*(Xc[n+1]+Xc[n]); ygs = 0.5*(Yc[n+1]+Yc[n]); dx = Xc[n+1]-Xc[n]; dy = Yc[n+1]-Yc[n]; r = dx*dx+dy*dy; r = sqrt(r); lnx = dy/r; lny = -dx/r; A += ygs*lny*r;
A -= xgs*lnx*r;
Xcm += r*xgs*ygs*lny; Ycm += r*0.5*ygs*ygs*lny; } Xcm = Xcm/A; Ycm = Ycm/A; return A; } double BndBlock::getHiMo(int blockId, double& Xcm, double& Ycm, double& Mcm){
Integration of center of area
double xgs, ygs, dx, dy, x1, y1, r, lnx, lny; int nbElms; double* Xc = Elements[blockId].XId[0]; double* Yc = Elements[blockId].YId[0]; double A = 0.0; Xcm = 0.0; Ycm = 0.0; Mcm = 0.0; nbElms = Elements[blockId].getFullSize(); for(int n=0; n<nbElms; n++){ xgs = 0.5*(Xc[n+1]+Xc[n]); ygs = 0.5*(Yc[n+1]+Yc[n]); dx = Xc[n+1]-Xc[n]; dy = Yc[n+1]-Yc[n]; r = dx*dx+dy*dy; r = sqrt(r); lnx = dy/r; lny = -dx/r; for (int i=0; i<6; i++) { x1 = xgs+dx*IGP[i]*0.5; y1 = ygs+dy*IGP[i]*0.5; A += r*(x1*lnx+y1*lny)*0.5*IGW[i]; Xcm += r*(y1*x1*lny)*0.5*IGW[i]; Ycm += r*(y1*x1*lnx)*0.5*IGW[i]; // Mcm += r*(x1*y1*y1*lnx+x1*x1*y1*lny); } } Xcm = 2.0*Xcm/A; Ycm = 2.0*Ycm/A; A = -A/2.0; for(int n=0; n<nbElms; n++){ xgs = 0.5*(Xc[n+1]+Xc[n])-Xcm; ygs = 0.5*(Yc[n+1]+Yc[n])-Ycm; dx = Xc[n+1]-Xc[n]; dy = Yc[n+1]-Yc[n]; r = dx*dx+dy*dy; r = sqrt(r); lnx = dy/r; lny = -dx/r; for (int i=0; i<6; i++) { x1 = xgs+dx*IGP[i]*0.5; y1 = ygs+dy*IGP[i]*0.5; Mcm += r*(x1*y1*y1*lnx+x1*x1*y1*lny)*IGW[i]*0.5; } } Mcm = -Mcm; return A; } void BndBlock::LoadNOrder(int blockId){
Compute 5th order polynomial of the droplet interfaces No longer functional because no memory assigned to polynomial coefficients
int order = 5; double *FaceX; double *FaceY; int size; double *AR = new double[order*order]; double *rhsx = new double[order]; double *rhsy = new double[order]; double dx,dy,rp; int ip,rs, frac; FaceX = Elements[blockId].XId[0]; FaceY = Elements[blockId].YId[0]; size = Elements[blockId].getFullSize(); for (int k = 0; k<size; k++) { frac = (order+0.5)/2; ip = 0; rs = -1.0; for (int i = 0; i<order; i++) { if(i==frac){ ip++; rs = 1; } dx = FaceX[k+ip-frac]-FaceX[k]; dy = FaceY[k+ip-frac]-FaceY[k]; rp = rs*sqrt(dx*dx+dy*dy); rhsx[i] = dx; rhsy[i] = dy; for (int j = 0; j<order; j++) { AR[i+j*order] = pow(rp,j+1); } ip++; } dgsev2rhs(AR, rhsx, rhsy, order); } }
Dedicated to Remeshing
void BndBlock::SeedDrop(){ if (rlim>0.0) { for (int j=ifblock; j<nbBlocks; j++) { SeedEquiDist(j, rlim); } } } void BndBlock::RemeshOn(double targetsize, int modus){ rlim = targetsize; SeedOption = modus; } void BndBlock::SeedEquiDist(int blockId, double limp){
Redistributes the droplet elements uniformly
int order = 3; double *XA, *XB; double *YA, *YB; double* AR = new double[order*order]; double *ace = new double[order]; double *bce = new double[order]; double rd, dx, dy, newx, newy, rmin, rnorm,rp; int jump, size, ReDist; int decal = 0; double rmax; double dsremain = 0; int nremain=0; double difadap=0; int ip,rs, frac; XB = Elements[blockId].XId[0]; YB = Elements[blockId].YId[0]; XA = &Elements[blockId].IntfX[5]; YA = &Elements[blockId].IntfY[5]; jump = 0; size = Elements[blockId].getFullSize(); ReDist = 0; rmax = remesh_threshold*limp; rmin = limp/remesh_threshold; dx = XB[-1]-XB[0]; dy = YB[-1]-YB[0]; rd = sqrt(dx*dx+dy*dy); if((rd>rmax)||(rd<rmin)){ ReDist = 1; } int kstart = 1; if(Elements[blockId].BCkind==3){ jump--; kstart=0; } for (int k=kstart; k<=size; k++) { // k should be 1 dx = XB[k]-XB[k-1]; dy = YB[k]-YB[k-1]; rd = sqrt(dx*dx+dy*dy); if((rd>rmax)||(rd<rmin)){ ReDist = 1; break; } } if(ReDist){ Stock(blockId); // LoadNOrder(blockId); //Copy Point XB[decal] = XA[kstart-1]; YB[decal] = YA[kstart-1]; rnorm = limp; for (int k=kstart; k<=(size); k++) { // k should be 1 dx = XA[k]-XA[k-1]; dy = YA[k]-YA[k-1]; rd = sqrt(dx*dx+dy*dy);
This piece of code smoothes over the last elements the distance so no reconnection no size contrast exists
if (k>=size-10) { dsremain = limp-rnorm; for (int j=k; j<=size; j++) { dx = XA[k]-XA[k-1]; dy = YA[k]-YA[k-1]; dsremain += sqrt(dx*dx+dy*dy); } nremain = int(round(dsremain/limp)); difadap = (dsremain/(nremain*limp)); rnorm += (difadap-1.0)*limp; limp = limp*difadap; } { frac = int((order+0.5)/2.0); ip = 0; rs = -1.0; for (int i = 0; i<order; i++) { if(i==frac){ ip++; rs = 1; } dx = XA[k+ip-frac-1]-XA[k-1]; dy = YA[k+ip-frac-1]-YA[k-1]; rp = rs*sqrt(dx*dx+dy*dy); ace[i] = dx; bce[i] = dy; for (int j = 0; j<order; j++) { AR[i+j*order] = pow(rp,j+1); } ip++; } } dgsev2rhs(AR, ace, bce, order); while (rnorm<rd){ newx = XA[k-1]; newy = YA[k-1]; for (int j=0; j<order; j++) { newx += ace[j]*pow(rnorm, j+1); newy += bce[j]*pow(rnorm, j+1); } jump++; XB[jump+decal] = newx; YB[jump+decal] = newy; rnorm += limp; } rnorm += -rd; } if (Elements[blockId].BCkind==3) { rd = sqrt(pow(XB[jump]-XA[size],2) + pow(YB[jump]-YA[size],2)); } else { rd = sqrt(pow(XB[jump+decal]-XB[decal],2) + pow(YB[jump+decal]-YB[decal],2)); } if(Elements[blockId].BCkind!=3){ jump += (rd>(0.75*limp)); for (int k=0; k<decal; k++) { XB[k] = XB[jump+k]; YB[k] = YB[jump+k]; } } else { jump += (rd>(0.5*limp)); XB[-1] = XA[-1]; YB[-1] = YA[-1]; XB[jump] = XA[size]; YB[jump] = YA[size]; } Elements[blockId].PanelSize[0] = jump; std::cout<<"\br"; } allSize[ifid+blockId-ifblock] = Elements[blockId].PanelSize[0]; WrapInterface(blockId); Stock(blockId); }
void BndBlock::SeedVarDist(int blockId, double rliming){
Ubiquitous subroutines
void BndBlock::allWrite(){ for (int k=0; k<nbBlocks; k++) { if((Elements[k].BCkind>0)||(runstep==0)){ WritePos(k, runstep); } } } void BndBlock::allStock(){ for (int k=0; k<nbBlocks; k++) { if(Elements[k].BCkind>0){ Stock(k); } } } void BndBlock::allEvolve(double weightOldPos, double weightNewPos, double deltaT, double *Uvec){ int index = 0; /* for (int k=0; k<ifblock; k++) { index += 2*Elements[k].getFullSize(); } */ for (int k=ifblock; k<nbBlocks; k++) { Evolve(k, weightOldPos, weightNewPos, deltaT, &Uvec[index]); index += 2*Elements[k].getFullSize(); } } void BndBlock::WrapAll(){ for (int k=dynblock; k<nbBlocks; k++) { WrapInterface(k); } } int BndBlock::getFixSize(){ int size=0; for (int k=0; k<nbBlocks; k++) { if(Elements[k].BCkind>0){ break; } size += Elements[k].getFullSize(); } return size; } int BndBlock::getAllSize(){ int size=0; for (int k=0; k<nbBlocks; k++) { size += 2*Elements[k].getFullSize(); if (Elements[k].BCkind==1) { size += 3; } } return size; }
Created by Mathias Nagel on 31.05.12.
Copyright (c) 2012 EPFL. All rights reserved.