/* color lattice boltzmann model */ #include "models/FreeLeeModel.h" #include "analysis/distance.h" #include "analysis/morphology.h" #include "common/Communication.h" #include "common/ReadMicroCT.h" #include #include ScaLBL_FreeLeeModel::ScaLBL_FreeLeeModel(int RANK, int NP, const Utilities::MPI& COMM): rank(RANK), nprocs(NP), Restart(0),timestep(0),timestepMax(2),tauA(1.0),tauB(1.0),tauM(1.0),rhoA(1.0),rhoB(1.0),W(5.0),gamma(0.001),kappa(0.0075),beta(0.0024), Fx(0),Fy(0),Fz(0),flux(0),din(0),dout(0),inletA(0),inletB(0),outletA(0),outletB(0), tau(1.0),rho0(1.0), Nx(0),Ny(0),Nz(0),N(0),Np(0),nprocx(0),nprocy(0),nprocz(0),BoundaryCondition(0),Lx(0),Ly(0),Lz(0),comm(COMM) { } ScaLBL_FreeLeeModel::~ScaLBL_FreeLeeModel(){ } void ScaLBL_FreeLeeModel::getPhase(DoubleArray &PhaseValues){ DoubleArray PhaseWideHalo(Nxh,Nyh,Nzh); ScaLBL_CopyToHost(PhaseWideHalo.data(), Phi, sizeof(double)*Nh); // use halo width = 1 for analysis data for (int k=1; kRegularLayout(Map,Pressure,PressureValues); ScaLBL_Comm->Barrier(); comm.barrier(); ScaLBL_Comm->RegularLayout(Map,mu_phi,MuValues); ScaLBL_Comm->Barrier(); comm.barrier(); } void ScaLBL_FreeLeeModel::getVelocity(DoubleArray &Vel_x, DoubleArray &Vel_y, DoubleArray &Vel_z){ ScaLBL_Comm->RegularLayout(Map,&Velocity[0],Vel_x); ScaLBL_Comm->Barrier(); comm.barrier(); ScaLBL_Comm->RegularLayout(Map,&Velocity[Np],Vel_y); ScaLBL_Comm->Barrier(); comm.barrier(); ScaLBL_Comm->RegularLayout(Map,&Velocity[2*Np],Vel_z); ScaLBL_Comm->Barrier(); comm.barrier(); } void ScaLBL_FreeLeeModel::getData_RegularLayout(const double *data, DoubleArray ®data){ // Gets data (in optimized layout) from the HOST and stores in regular layout // Primarly for debugging int i,j,k,idx; // initialize the array regdata.fill(0.f); double value; for (k=0; k( filename ); domain_db = db->getDatabase( "Domain" ); freelee_db = db->getDatabase( "FreeLee" ); analysis_db = db->getDatabase( "Analysis" ); vis_db = db->getDatabase( "Visualization" ); // set defaults timestepMax = 100000; tauA = tauB = 1.0; tauM = 1.0;//relaxation time for phase field rhoA = rhoB = 1.0; tau = 1.0;//only for single-fluid Lee model rho0 = 1.0;//only for single-fluid Lee model Fx = Fy = Fz = 0.0; gamma=1e-3;//surface tension W=5.0;//interfacial thickness //beta = 12.0*gamma/W; //kappa = 3.0*gamma*W/2.0;//beta and kappa are related to surface tension \gamma beta = 0.75*gamma/W; kappa = 0.375*gamma*W;//beta and kappa are related to surface tension \gamma Restart=false; din=dout=1.0; flux=0.0; // Color Model parameters if (freelee_db->keyExists( "timestepMax" )){ timestepMax = freelee_db->getScalar( "timestepMax" ); } if (freelee_db->keyExists( "tau" )){//only for single-fluid Lee model tau = freelee_db->getScalar( "tau" ); } if (freelee_db->keyExists( "tauA" )){ tauA = freelee_db->getScalar( "tauA" ); } if (freelee_db->keyExists( "tauB" )){ tauB = freelee_db->getScalar( "tauB" ); } if (freelee_db->keyExists( "tauM" )){ tauM = freelee_db->getScalar( "tauM" ); } if (freelee_db->keyExists( "rho0" )){ rho0 = freelee_db->getScalar( "rho0" ); } if (freelee_db->keyExists( "rhoA" )){ rhoA = freelee_db->getScalar( "rhoA" ); } if (freelee_db->keyExists( "rhoB" )){ rhoB = freelee_db->getScalar( "rhoB" ); } if (freelee_db->keyExists( "F" )){ Fx = freelee_db->getVector( "F" )[0]; Fy = freelee_db->getVector( "F" )[1]; Fz = freelee_db->getVector( "F" )[2]; } if (freelee_db->keyExists( "gamma" )){ gamma = freelee_db->getScalar( "gamma" ); } if (freelee_db->keyExists( "W" )){ W = freelee_db->getScalar( "W" ); } if (freelee_db->keyExists( "Restart" )){ Restart = freelee_db->getScalar( "Restart" ); } if (freelee_db->keyExists( "din" )){ din = freelee_db->getScalar( "din" ); } if (freelee_db->keyExists( "dout" )){ dout = freelee_db->getScalar( "dout" ); } if (freelee_db->keyExists( "flux" )){ flux = freelee_db->getScalar( "flux" ); } inletA=1.f; inletB=0.f; outletA=0.f; outletB=1.f; //update secondary parameters //beta = 12.0*gamma/W; //kappa = 3.0*gamma*W/2.0;//beta and kappa are related to surface tension \gamma beta = 0.75*gamma/W; kappa = 0.375*gamma*W;//beta and kappa are related to surface tension \gamma //if (BoundaryCondition==4) flux *= rhoA; // mass flux must adjust for density (see formulation for details) BoundaryCondition = 0; if (domain_db->keyExists( "BC" )){ BoundaryCondition = domain_db->getScalar( "BC" ); } } void ScaLBL_FreeLeeModel::SetDomain(){ Dm = std::shared_ptr(new Domain(domain_db,comm)); // full domain for analysis Mask = std::shared_ptr(new Domain(domain_db,comm)); // mask domain removes immobile phases // domain parameters Nx = Dm->Nx; Ny = Dm->Ny; Nz = Dm->Nz; Lx = Dm->Lx; Ly = Dm->Ly; Lz = Dm->Lz; N = Nx*Ny*Nz; Nxh = Nx+2; Nyh = Ny+2; Nzh = Nz+2; Nh = Nxh*Nyh*Nzh; id = new signed char [N]; for (int i=0; iid[i] = 1; // initialize this way comm.barrier(); Dm->CommInit(); comm.barrier(); // Read domain parameters rank = Dm->rank(); nprocx = Dm->nprocx(); nprocy = Dm->nprocy(); nprocz = Dm->nprocz(); } void ScaLBL_FreeLeeModel::ReadInput(){ sprintf(LocalRankString,"%05d",rank); sprintf(LocalRankFilename,"%s%s","ID.",LocalRankString); sprintf(LocalRestartFile,"%s%s","Restart.",LocalRankString); if (freelee_db->keyExists( "image_sequence" )){ auto ImageList = freelee_db->getVector( "image_sequence"); int IMAGE_INDEX = freelee_db->getWithDefault( "image_index", 0 ); std::string first_image = ImageList[IMAGE_INDEX]; Mask->Decomp(first_image); IMAGE_INDEX++; } else if (domain_db->keyExists( "GridFile" )){ // Read the local domain data auto input_id = readMicroCT( *domain_db, MPI_COMM_WORLD ); // Fill the halo (assuming GCW of 1) array size0 = { (int) input_id.size(0), (int) input_id.size(1), (int) input_id.size(2) }; ArraySize size1 = { (size_t) Mask->Nx, (size_t) Mask->Ny, (size_t) Mask->Nz }; ASSERT( (int) size1[0] == size0[0]+2 && (int) size1[1] == size0[1]+2 && (int) size1[2] == size0[2]+2 ); fillHalo fill( MPI_COMM_WORLD, Mask->rank_info, size0, { 1, 1, 1 }, 0, 1 ); Array id_view; id_view.viewRaw( size1, Mask->id.data() ); fill.copy( input_id, id_view ); fill.fill( id_view ); } else if (domain_db->keyExists( "Filename" )){ auto Filename = domain_db->getScalar( "Filename" ); Mask->Decomp(Filename); } else{ Mask->ReadIDs(); } for (int i=0; iid[i]; // save what was read // Generate the signed distance map // Initialize the domain and communication Array id_solid(Nx,Ny,Nz); // Solve for the position of the solid phase for (int k=0;kid[n]; if (label > 0) id_solid(i,j,k) = 1; else id_solid(i,j,k) = 0; } } } SignDist.resize(Nx,Ny,Nz); // Initialize the signed distance function for (int k=0;kid[i] = Mask->id[i]; Mask->CommInit(); Np=Mask->PoreCount(); //........................................................................... if (rank==0) printf ("Create ScaLBL_Communicator \n"); // Create a communicator for the device (will use optimized layout) // ScaLBL_Communicator ScaLBL_Comm(Mask); // original ScaLBL_Comm = std::shared_ptr(new ScaLBL_Communicator(Mask)); //ScaLBL_Comm_Regular = std::shared_ptr(new ScaLBL_Communicator(Mask)); ScaLBL_Comm_WideHalo = std::shared_ptr(new ScaLBLWideHalo_Communicator(Mask,2)); // create the layout for the LBM int Npad=(Np/16 + 2)*16; if (rank==0) printf ("Set up memory efficient layout, %i | %i | %i \n", Np, Npad, N); Map.resize(Nx,Ny,Nz); Map.fill(-2); auto neighborList= new int[18*Npad]; Np = ScaLBL_Comm->MemoryOptimizedLayoutAA(Map,neighborList,Mask->id.data(),Np,2); comm.barrier(); //........................................................................... // MAIN VARIABLES ALLOCATED HERE //........................................................................... // LBM variables if (rank==0) printf ("Allocating distributions \n"); //......................device distributions................................. dist_mem_size = Np*sizeof(double); neighborSize=18*(Np*sizeof(int)); //........................................................................... ScaLBL_AllocateDeviceMemory((void **) &NeighborList, neighborSize); ScaLBL_AllocateDeviceMemory((void **) &dvcMap, sizeof(int)*Np); ScaLBL_AllocateDeviceMemory((void **) &gqbar, 19*dist_mem_size); ScaLBL_AllocateDeviceMemory((void **) &hq, 7*dist_mem_size); ScaLBL_AllocateDeviceMemory((void **) &mu_phi, dist_mem_size); ScaLBL_AllocateDeviceMemory((void **) &Den, dist_mem_size); ScaLBL_AllocateDeviceMemory((void **) &Phi, sizeof(double)*Nh); ScaLBL_AllocateDeviceMemory((void **) &Pressure, sizeof(double)*Np); ScaLBL_AllocateDeviceMemory((void **) &Velocity, 3*sizeof(double)*Np); ScaLBL_AllocateDeviceMemory((void **) &ColorGrad, 3*sizeof(double)*Np); //........................................................................... // Update GPU data structures if (rank==0) printf ("Setting up device map and neighbor list \n"); fflush(stdout); int *TmpMap; TmpMap=new int[Np]; for (int k=1; kMap(i,j,k); } } } // check that TmpMap is valid for (int idx=0; idxLastExterior(); idx++){ auto n = TmpMap[idx]; if (n > Nxh*Nyh*Nzh){ printf("Bad value! idx=%i \n", n); TmpMap[idx] = Nxh*Nyh*Nzh-1; } } for (int idx=ScaLBL_Comm->FirstInterior(); idxLastInterior(); idx++){ auto n = TmpMap[idx]; if ( n > Nxh*Nyh*Nzh ){ printf("Bad value! idx=%i \n",n); TmpMap[idx] = Nxh*Nyh*Nzh-1; } } // copy the device map ScaLBL_CopyToDevice(dvcMap, TmpMap, sizeof(int)*Np); // copy the neighbor list ScaLBL_CopyToDevice(NeighborList, neighborList, neighborSize); comm.barrier(); delete [] TmpMap; delete [] neighborList; } void ScaLBL_FreeLeeModel::Create_SingleFluid(){ /* * This function creates the variables needed to run single-fluid Lee model */ //......................................................... // Initialize communication structures in averaging domain for (int i=0; iid[i] = Mask->id[i]; Mask->CommInit(); Np=Mask->PoreCount(); //........................................................................... if (rank==0) printf ("Create ScaLBL_Communicator \n"); // Create a communicator for the device (will use optimized layout) // ScaLBL_Communicator ScaLBL_Comm(Mask); // original ScaLBL_Comm = std::shared_ptr(new ScaLBL_Communicator(Mask)); // create the layout for the LBM int Npad=(Np/16 + 2)*16; if (rank==0) printf ("Set up memory efficient layout, %i | %i | %i \n", Np, Npad, N); Map.resize(Nx,Ny,Nz); Map.fill(-2); auto neighborList= new int[18*Npad]; Np = ScaLBL_Comm->MemoryOptimizedLayoutAA(Map,neighborList,Mask->id.data(),Np,1); comm.barrier(); //........................................................................... // MAIN VARIABLES ALLOCATED HERE //........................................................................... // LBM variables if (rank==0) printf ("Allocating distributions \n"); //......................device distributions................................. dist_mem_size = Np*sizeof(double); neighborSize=18*(Np*sizeof(int)); //........................................................................... ScaLBL_AllocateDeviceMemory((void **) &NeighborList, neighborSize); ScaLBL_AllocateDeviceMemory((void **) &gqbar, 19*dist_mem_size); ScaLBL_AllocateDeviceMemory((void **) &Pressure, sizeof(double)*Np); ScaLBL_AllocateDeviceMemory((void **) &Velocity, 3*sizeof(double)*Np); //........................................................................... // Update GPU data structures if (rank==0) printf ("Setting up device map and neighbor list \n"); // copy the neighbor list ScaLBL_CopyToDevice(NeighborList, neighborList, neighborSize); comm.barrier(); delete [] neighborList; } void ScaLBL_FreeLeeModel::AssignComponentLabels_ChemPotential_ColorGrad() { double *phase; phase = new double[Nh]; size_t NLABELS=0; signed char VALUE=0; double AFFINITY=0.f; auto LabelList = freelee_db->getVector( "ComponentLabels" ); auto AffinityList = freelee_db->getVector( "ComponentAffinity" ); NLABELS=LabelList.size(); if (NLABELS != AffinityList.size()){ ERROR("Error: ComponentLabels and ComponentAffinity must be the same length! \n"); } double *label_count; double *label_count_global; label_count = new double [NLABELS]; label_count_global = new double [NLABELS]; // Assign the labels for (size_t idx=0; idxid[n] int x=i-1; int y=j-1; int z=k-1; if (x<0) x=0; if (y<0) y=0; if (z<0) z=0; if (x>=Nx) x=Nx-1; if (y>=Ny) y=Ny-1; if (z>=Nz) z=Nz-1; int n = z*Nx*Ny+y*Nx+x; VALUE=id[n]; // Assign the affinity from the paired list for (unsigned int idx=0; idx < NLABELS; idx++){ //printf("idx=%i, value=%i, %i, \n",idx, VALUE,LabelList[idx]); if (VALUE == LabelList[idx]){ AFFINITY=AffinityList[idx]; label_count[idx] += 1.0; idx = NLABELS; //Mask->id[n] = 0; // set mask to zero since this is an immobile component } } // fluid labels are reserved if (VALUE == 1) AFFINITY=1.0; else if (VALUE == 2) AFFINITY=-1.0; phase[nh] = AFFINITY; } } } // Set Dm to match Mask for (int i=0; iid[i] = Mask->id[i]; for (size_t idx=0; idxComm.sumReduce(label_count[idx]); if (rank==0){ printf("Number of component labels: %lu \n",NLABELS); for (unsigned int idx=0; idxBarrier(); comm.barrier(); //debug //save the phase field and check it //FILE *OUTFILE; //sprintf(LocalRankFilename,"Phase_Init.%05i.raw",rank); //OUTFILE = fopen(LocalRankFilename,"wb"); //fwrite(phase,8,Nh,OUTFILE); //fclose(OUTFILE); DoubleArray PhaseField(Nx,Ny,Nz); FILE *OUTFILE; getData_RegularLayout(mu_phi_host,PhaseField); sprintf(LocalRankFilename,"Chem_Init.%05i.raw",rank); OUTFILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,OUTFILE); fclose(OUTFILE); getData_RegularLayout(&ColorGrad_host[0],PhaseField); FILE *CGX_FILE; sprintf(LocalRankFilename,"Gradient_X_Init.%05i.raw",rank); CGX_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CGX_FILE); fclose(CGX_FILE); getData_RegularLayout(&ColorGrad_host[Np],PhaseField); FILE *CGY_FILE; sprintf(LocalRankFilename,"Gradient_Y_Init.%05i.raw",rank); CGY_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CGY_FILE); fclose(CGY_FILE); getData_RegularLayout(&ColorGrad_host[2*Np],PhaseField); FILE *CGZ_FILE; sprintf(LocalRankFilename,"Gradient_Z_Init.%05i.raw",rank); CGZ_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CGZ_FILE); fclose(CGZ_FILE); delete [] phase; delete [] ColorGrad_host; delete [] mu_phi_host; delete [] Dst; } void ScaLBL_FreeLeeModel::Initialize_TwoFluid(){ /* * This function initializes two-fluid Lee model */ if (rank==0) printf ("Initializing phase field, chemical potential and color gradient\n"); AssignComponentLabels_ChemPotential_ColorGrad();//initialize phase field Phi if (rank==0) printf ("Initializing distributions for momentum transport\n"); ScaLBL_D3Q19_FreeLeeModel_TwoFluid_Init(gqbar, mu_phi, ColorGrad, Fx, Fy, Fz, Np); if (rank==0) printf ("Initializing density field and distributions for phase-field transport\n"); ScaLBL_FreeLeeModel_PhaseField_Init(dvcMap, Phi, Den, hq, ColorGrad, rhoA, rhoB, tauM, W, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_FreeLeeModel_PhaseField_Init(dvcMap, Phi, Den, hq, ColorGrad, rhoA, rhoB, tauM, W, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); if (Restart == true){ //TODO need to revise this function if (rank==0){ printf("Reading restart file! \n"); } // Read in the restart file to CPU buffers int *TmpMap; TmpMap = new int[Np]; double *cPhi, *cDist, *cDen; cPhi = new double[N]; cDen = new double[2*Np]; cDist = new double[19*Np]; ScaLBL_CopyToHost(TmpMap, dvcMap, Np*sizeof(int)); //ScaLBL_CopyToHost(cPhi, Phi, N*sizeof(double)); ifstream File(LocalRestartFile,ios::binary); int idx; double value,va,vb; for (int n=0; nLastExterior(); n++){ va = cDen[n]; vb = cDen[Np + n]; value = (va-vb)/(va+vb); idx = TmpMap[n]; if (!(idx < 0) && idxFirstInterior(); nLastInterior(); n++){ va = cDen[n]; vb = cDen[Np + n]; value = (va-vb)/(va+vb); idx = TmpMap[n]; if (!(idx < 0) && idxBarrier(); comm.barrier(); if (rank==0) printf ("Initializing phase and density fields on device from Restart\n"); //TODO the following function is to be updated. //ScaLBL_FreeLeeModel_PhaseField_InitFromRestart(Den, hq, 0, ScaLBL_Comm->LastExterior(), Np); //ScaLBL_FreeLeeModel_PhaseField_InitFromRestart(Den, hq, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); } // establish reservoirs for external bC // TODO to be revised if (BoundaryCondition == 1 || BoundaryCondition == 2 || BoundaryCondition == 3 || BoundaryCondition == 4 ){ if (Dm->kproc()==0){ ScaLBL_SetSlice_z(Phi,1.0,Nx,Ny,Nz,0); ScaLBL_SetSlice_z(Phi,1.0,Nx,Ny,Nz,1); ScaLBL_SetSlice_z(Phi,1.0,Nx,Ny,Nz,2); } if (Dm->kproc() == nprocz-1){ ScaLBL_SetSlice_z(Phi,-1.0,Nx,Ny,Nz,Nz-1); ScaLBL_SetSlice_z(Phi,-1.0,Nx,Ny,Nz,Nz-2); ScaLBL_SetSlice_z(Phi,-1.0,Nx,Ny,Nz,Nz-3); } } //ScaLBL_CopyToHost(Averages->Phi.data(),Phi,N*sizeof(double)); } void ScaLBL_FreeLeeModel::Initialize_SingleFluid(){ /* * This function initializes single-fluid Lee model */ if (rank==0) printf ("Initializing distributions for momentum transport\n"); ScaLBL_D3Q19_FreeLeeModel_SingleFluid_Init(gqbar, Fx, Fy, Fz, Np); if (Restart == true){ //TODO need to revise this function //remove the phase-related part } } double ScaLBL_FreeLeeModel::Run_TwoFluid(int returntime){ int START_TIME = timestep; int EXIT_TIME = min(returntime, timestepMax); //************ MAIN ITERATION LOOP ***************************************/ comm.barrier(); auto t1 = std::chrono::system_clock::now(); PROFILE_START("Loop"); while (timestep < EXIT_TIME ) { //if ( rank==0 ) { printf("Running timestep %i (%i MB)\n",timestep+1,(int)(Utilities::getMemoryUsage()/1048576)); } PROFILE_START("Update"); // *************ODD TIMESTEP************* timestep++; //------------------------------------------------------------------------------------------------------------------- // Compute the Phase indicator field // Read for hq happens in this routine (requires communication) ScaLBL_Comm->SendD3Q7AA(hq,0); //READ FROM NORMAL ScaLBL_D3Q7_AAodd_FreeLeeModel_PhaseField(NeighborList, dvcMap, hq, Den, Phi, rhoA, rhoB, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); //ScaLBL_D3Q7_AAodd_FreeLee_PhaseField(NeighborList, dvcMap, hq, Den, Phi, ColorGrad, Velocity, rhoA, rhoB, tauM, W, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm->RecvD3Q7AA(hq,0); //WRITE INTO OPPOSITE ScaLBL_Comm->Barrier(); ScaLBL_D3Q7_AAodd_FreeLeeModel_PhaseField(NeighborList, dvcMap, hq, Den, Phi, rhoA, rhoB, 0, ScaLBL_Comm->LastExterior(), Np); //ScaLBL_D3Q7_AAodd_FreeLee_PhaseField(NeighborList, dvcMap, hq, Den, Phi, ColorGrad, Velocity, rhoA, rhoB, tauM, W, 0, ScaLBL_Comm->LastExterior(), Np); // Perform the collision operation //ScaLBL_D3Q7_ComputePhaseField(dvcMap, hq, Den, Phi, rhoA, rhoB, 0, ScaLBL_Comm->LastInterior(), Np); //ScaLBL_Comm_WideHalo->Send(Phi); //ScaLBL_Comm_WideHalo->Recv(Phi); ScaLBL_Comm->SendD3Q19AA(gqbar); //READ FROM NORMAL if (BoundaryCondition > 0 && BoundaryCondition < 5){ //TODO to be revised // Need to add BC for hq!!! ScaLBL_Comm->Color_BC_z(dvcMap, Phi, Den, inletA, inletB); ScaLBL_Comm->Color_BC_Z(dvcMap, Phi, Den, outletA, outletB); } // Halo exchange for phase field ScaLBL_Comm_WideHalo->Send(Phi); //ScaLBL_D3Q19_AAodd_FreeLeeModel(NeighborList, dvcMap, gqbar, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, // kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_D3Q19_AAodd_FreeLeeModel_Combined(NeighborList, dvcMap, gqbar, hq, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, tauM, kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm_WideHalo->Recv(Phi); ScaLBL_Comm->RecvD3Q19AA(gqbar); //WRITE INTO OPPOSITE ScaLBL_Comm->Barrier(); // Set BCs if (BoundaryCondition == 3){ ScaLBL_Comm->D3Q19_Pressure_BC_z(NeighborList, gqbar, din, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } if (BoundaryCondition == 4){ din = ScaLBL_Comm->D3Q19_Flux_BC_z(NeighborList, gqbar, flux, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } else if (BoundaryCondition == 5){ ScaLBL_Comm->D3Q19_Reflection_BC_z(gqbar); ScaLBL_Comm->D3Q19_Reflection_BC_Z(gqbar); } //ScaLBL_D3Q19_AAodd_FreeLeeModel(NeighborList, dvcMap, gqbar, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, // kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_D3Q19_AAodd_FreeLeeModel_Combined(NeighborList, dvcMap, gqbar, hq, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, tauM, kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_Comm->Barrier(); // *************EVEN TIMESTEP************* timestep++; // Compute the Phase indicator field ScaLBL_Comm->SendD3Q7AA(hq,0); //READ FROM NORMA ScaLBL_D3Q7_AAeven_FreeLeeModel_PhaseField(dvcMap, hq, Den, Phi, rhoA, rhoB, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); //ScaLBL_D3Q7_AAeven_FreeLee_PhaseField(dvcMap, hq, Den, Phi, ColorGrad, Velocity, rhoA, rhoB, tauM, W, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm->RecvD3Q7AA(hq,0); //WRITE INTO OPPOSITE ScaLBL_Comm->Barrier(); ScaLBL_D3Q7_AAeven_FreeLeeModel_PhaseField(dvcMap, hq, Den, Phi, rhoA, rhoB, 0, ScaLBL_Comm->LastExterior(), Np); //ScaLBL_D3Q7_AAeven_FreeLee_PhaseField(dvcMap, hq, Den, Phi, ColorGrad, Velocity, rhoA, rhoB, tauM, W, 0, ScaLBL_Comm->LastExterior(), Np); // Perform the collision operation //ScaLBL_D3Q7_ComputePhaseField(dvcMap, hq, Den, Phi, rhoA, rhoB, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); //ScaLBL_Comm_WideHalo->Send(Phi); //ScaLBL_Comm_WideHalo->Recv(Phi); ScaLBL_Comm->SendD3Q19AA(gqbar); //READ FORM NORMAL if (BoundaryCondition > 0 && BoundaryCondition < 5){ ScaLBL_Comm->Color_BC_z(dvcMap, Phi, Den, inletA, inletB); ScaLBL_Comm->Color_BC_Z(dvcMap, Phi, Den, outletA, outletB); } // Halo exchange for phase field ScaLBL_Comm_WideHalo->Send(Phi); //ScaLBL_D3Q19_AAeven_FreeLeeModel(dvcMap, gqbar, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, // kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_D3Q19_AAeven_FreeLeeModel_Combined(dvcMap, gqbar, hq, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, tauM, kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm_WideHalo->Recv(Phi); ScaLBL_Comm->RecvD3Q19AA(gqbar); //WRITE INTO OPPOSITE ScaLBL_Comm->Barrier(); // Set boundary conditions if (BoundaryCondition == 3){ ScaLBL_Comm->D3Q19_Pressure_BC_z(NeighborList, gqbar, din, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } else if (BoundaryCondition == 4){ din = ScaLBL_Comm->D3Q19_Flux_BC_z(NeighborList, gqbar, flux, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } else if (BoundaryCondition == 5){ ScaLBL_Comm->D3Q19_Reflection_BC_z(gqbar); ScaLBL_Comm->D3Q19_Reflection_BC_Z(gqbar); } //ScaLBL_D3Q19_AAeven_FreeLeeModel(dvcMap, gqbar, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, // kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_D3Q19_AAeven_FreeLeeModel_Combined(dvcMap, gqbar, hq, Den, Phi, mu_phi, Velocity, Pressure, ColorGrad, rhoA, rhoB, tauA, tauB, tauM, kappa, beta, W, Fx, Fy, Fz, Nxh, Nxh*Nyh, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_Comm->Barrier(); //************************************************************************ PROFILE_STOP("Update"); } PROFILE_STOP("Loop"); PROFILE_SAVE("lbpm_color_simulator",1); //************************************************************************ if (rank==0) printf("-------------------------------------------------------------------\n"); // Compute the walltime per timestep auto t2 = std::chrono::system_clock::now(); double cputime = std::chrono::duration( t2 - t1 ).count() / (EXIT_TIME-START_TIME); // Performance obtained from each node double MLUPS = double(Np)/cputime/1000000; return MLUPS; } void ScaLBL_FreeLeeModel::Run_SingleFluid(){ int nprocs=nprocx*nprocy*nprocz; const RankInfoStruct rank_info(rank,nprocx,nprocy,nprocz); if (rank==0){ printf("********************************************************\n"); printf("No. of timesteps: %i \n", timestepMax); fflush(stdout); } //.......create and start timer............ ScaLBL_Comm->Barrier(); comm.barrier(); //......................................... //************ MAIN ITERATION LOOP ***************************************/ PROFILE_START("Loop"); auto t1 = std::chrono::system_clock::now(); while (timestep < timestepMax ) { //if ( rank==0 ) { printf("Running timestep %i (%i MB)\n",timestep+1,(int)(Utilities::getMemoryUsage()/1048576)); } PROFILE_START("Update"); // *************ODD TIMESTEP************* timestep++; //------------------------------------------------------------------------------------------------------------------- // Perform the collision operation ScaLBL_Comm->SendD3Q19AA(gqbar); //READ FROM NORMAL ScaLBL_D3Q19_AAodd_FreeLeeModel_SingleFluid_BGK(NeighborList, gqbar, Velocity, Pressure, tau, rho0, Fx, Fy, Fz, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm->RecvD3Q19AA(gqbar); //WRITE INTO OPPOSITE ScaLBL_Comm->Barrier(); // Set boundary conditions // TODO to be revised! if (BoundaryCondition == 3){ ScaLBL_Comm->D3Q19_Pressure_BC_z(NeighborList, gqbar, din, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } if (BoundaryCondition == 4){ din = ScaLBL_Comm->D3Q19_Flux_BC_z(NeighborList, gqbar, flux, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } else if (BoundaryCondition == 5){ ScaLBL_Comm->D3Q19_Reflection_BC_z(gqbar); ScaLBL_Comm->D3Q19_Reflection_BC_Z(gqbar); } ScaLBL_D3Q19_AAodd_FreeLeeModel_SingleFluid_BGK(NeighborList, gqbar, Velocity, Pressure, tau, rho0, Fx, Fy, Fz, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_Comm->Barrier(); // *************EVEN TIMESTEP************* timestep++; //------------------------------------------------------------------------------------------------------------------- // Perform the collision operation ScaLBL_Comm->SendD3Q19AA(gqbar); //READ FORM NORMAL ScaLBL_D3Q19_AAeven_FreeLeeModel_SingleFluid_BGK(gqbar, Velocity, Pressure, tau, rho0, Fx, Fy, Fz, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm->RecvD3Q19AA(gqbar); //WRITE INTO OPPOSITE ScaLBL_Comm->Barrier(); // Set boundary conditions // TODO to be revised! if (BoundaryCondition == 3){ ScaLBL_Comm->D3Q19_Pressure_BC_z(NeighborList, gqbar, din, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } else if (BoundaryCondition == 4){ din = ScaLBL_Comm->D3Q19_Flux_BC_z(NeighborList, gqbar, flux, timestep); ScaLBL_Comm->D3Q19_Pressure_BC_Z(NeighborList, gqbar, dout, timestep); } else if (BoundaryCondition == 5){ ScaLBL_Comm->D3Q19_Reflection_BC_z(gqbar); ScaLBL_Comm->D3Q19_Reflection_BC_Z(gqbar); } ScaLBL_D3Q19_AAeven_FreeLeeModel_SingleFluid_BGK(gqbar, Velocity, Pressure, tau, rho0, Fx, Fy, Fz, 0, ScaLBL_Comm->LastExterior(), Np); ScaLBL_Comm->Barrier(); //************************************************************************ PROFILE_STOP("Update"); } PROFILE_STOP("Loop"); PROFILE_SAVE("lbpm_color_simulator",1); //************************************************************************ if (rank==0) printf("-------------------------------------------------------------------\n"); // Compute the walltime per timestep auto t2 = std::chrono::system_clock::now(); double cputime = std::chrono::duration( t2 - t1 ).count() / timestep; // Performance obtained from each node double MLUPS = double(Np)/cputime/1000000; if (rank==0) printf("********************************************************\n"); if (rank==0) printf("CPU time = %f \n", cputime); if (rank==0) printf("Lattice update rate (per core)= %f MLUPS \n", MLUPS); MLUPS *= nprocs; if (rank==0) printf("Lattice update rate (total)= %f MLUPS \n", MLUPS); if (rank==0) printf("********************************************************\n"); // ************************************************************************ } void ScaLBL_FreeLeeModel::WriteDebug_TwoFluid(){ // Copy back final phase indicator field and convert to regular layout DoubleArray PhaseData(Nxh,Nyh,Nzh); //ScaLBL_Comm->RegularLayout(Map,Phi,PhaseField); ScaLBL_CopyToHost(PhaseData.data(), Phi, sizeof(double)*Nh); /* IntArray MapData(Np); ScaLBL_CopyToHost(MapData.data(), dvcMap, sizeof(int)*Np); FILE *MAP; sprintf(LocalRankFilename,"Map.%05i.raw",rank); MAP = fopen(LocalRankFilename,"wb"); fwrite(MapData.data(),4,Np,MAP); fclose(MAP); FILE *NB; //IntArray Neighbors(18,Np); //ScaLBL_CopyToHost(Neighbors.data(), NeighborList, sizeof(int)*Np*18); sprintf(LocalRankFilename,"neighbors.%05i.raw",rank); NB = fopen(LocalRankFilename,"wb"); fwrite(NeighborList,4,18*Np,NB); fclose(NB); FILE *DIST; DoubleArray DistData(7, Np); ScaLBL_CopyToHost(DistData.data(), hq, 7*sizeof(double)*Np); sprintf(LocalRankFilename,"h.%05i.raw",rank); DIST = fopen(LocalRankFilename,"wb"); fwrite(DistData.data(),8,7*Np,DIST); fclose(DIST); */ FILE *OUTFILE; sprintf(LocalRankFilename,"Phase.%05i.raw",rank); OUTFILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseData.data(),8,Nh,OUTFILE); fclose(OUTFILE); DoubleArray PhaseField(Nx,Ny,Nz); FILE *DIST; for (int q=0; q<7; q++){ ScaLBL_Comm->RegularLayout(Map,&hq[q*Np],PhaseField); sprintf(LocalRankFilename,"h%i.%05i.raw",q,rank); DIST = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,Nx*Ny*Nz,DIST); fclose(DIST); } ScaLBL_Comm->RegularLayout(Map,Den,PhaseField); FILE *AFILE; sprintf(LocalRankFilename,"Density.%05i.raw",rank); AFILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,AFILE); fclose(AFILE); ScaLBL_Comm->RegularLayout(Map,Pressure,PhaseField); FILE *PFILE; sprintf(LocalRankFilename,"Pressure.%05i.raw",rank); PFILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,PFILE); fclose(PFILE); ScaLBL_Comm->RegularLayout(Map,mu_phi,PhaseField); FILE *CHEMFILE; sprintf(LocalRankFilename,"ChemPotential.%05i.raw",rank); CHEMFILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CHEMFILE); fclose(CHEMFILE); ScaLBL_Comm->RegularLayout(Map,&Velocity[0],PhaseField); FILE *VELX_FILE; sprintf(LocalRankFilename,"Velocity_X.%05i.raw",rank); VELX_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,VELX_FILE); fclose(VELX_FILE); ScaLBL_Comm->RegularLayout(Map,&Velocity[Np],PhaseField); FILE *VELY_FILE; sprintf(LocalRankFilename,"Velocity_Y.%05i.raw",rank); VELY_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,VELY_FILE); fclose(VELY_FILE); ScaLBL_Comm->RegularLayout(Map,&Velocity[2*Np],PhaseField); FILE *VELZ_FILE; sprintf(LocalRankFilename,"Velocity_Z.%05i.raw",rank); VELZ_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,VELZ_FILE); fclose(VELZ_FILE); ScaLBL_Comm->RegularLayout(Map,&ColorGrad[0],PhaseField); FILE *CGX_FILE; sprintf(LocalRankFilename,"Gradient_X.%05i.raw",rank); CGX_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CGX_FILE); fclose(CGX_FILE); ScaLBL_Comm->RegularLayout(Map,&ColorGrad[Np],PhaseField); FILE *CGY_FILE; sprintf(LocalRankFilename,"Gradient_Y.%05i.raw",rank); CGY_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CGY_FILE); fclose(CGY_FILE); ScaLBL_Comm->RegularLayout(Map,&ColorGrad[2*Np],PhaseField); FILE *CGZ_FILE; sprintf(LocalRankFilename,"Gradient_Z.%05i.raw",rank); CGZ_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,CGZ_FILE); fclose(CGZ_FILE); } void ScaLBL_FreeLeeModel::WriteDebug_SingleFluid(){ DoubleArray PhaseField(Nx,Ny,Nz); // Copy back final phase indicator field and convert to regular layout ScaLBL_Comm->RegularLayout(Map,Pressure,PhaseField); FILE *PFILE; sprintf(LocalRankFilename,"Pressure.%05i.raw",rank); PFILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,PFILE); fclose(PFILE); ScaLBL_Comm->RegularLayout(Map,&Velocity[0],PhaseField); FILE *VELX_FILE; sprintf(LocalRankFilename,"Velocity_X.%05i.raw",rank); VELX_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,VELX_FILE); fclose(VELX_FILE); ScaLBL_Comm->RegularLayout(Map,&Velocity[Np],PhaseField); FILE *VELY_FILE; sprintf(LocalRankFilename,"Velocity_Y.%05i.raw",rank); VELY_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,VELY_FILE); fclose(VELY_FILE); ScaLBL_Comm->RegularLayout(Map,&Velocity[2*Np],PhaseField); FILE *VELZ_FILE; sprintf(LocalRankFilename,"Velocity_Z.%05i.raw",rank); VELZ_FILE = fopen(LocalRankFilename,"wb"); fwrite(PhaseField.data(),8,N,VELZ_FILE); fclose(VELZ_FILE); } void ScaLBL_FreeLeeModel::Create_DummyPhase_MGTest(){ // Initialize communication structures in averaging domain for (int i=0; iid[i] = Mask->id[i]; Mask->CommInit(); Np=Mask->PoreCount(); //........................................................................... if (rank==0) printf ("Create ScaLBL_Communicator \n"); // Create a communicator for the device (will use optimized layout) // ScaLBL_Communicator ScaLBL_Comm(Mask); // original ScaLBL_Comm = std::shared_ptr(new ScaLBL_Communicator(Mask)); //ScaLBL_Comm_Regular = std::shared_ptr(new ScaLBL_Communicator(Mask)); ScaLBL_Comm_WideHalo = std::shared_ptr(new ScaLBLWideHalo_Communicator(Mask,2)); // create the layout for the LBM int Npad=(Np/16 + 2)*16; if (rank==0) printf ("Set up memory efficient layout, %i | %i | %i \n", Np, Npad, N); Map.resize(Nx,Ny,Nz); Map.fill(-2); auto neighborList= new int[18*Npad]; Np = ScaLBL_Comm->MemoryOptimizedLayoutAA(Map,neighborList,Mask->id.data(),Np,1); comm.barrier(); //........................................................................... // MAIN VARIABLES ALLOCATED HERE //........................................................................... // LBM variables if (rank==0) printf ("Allocating distributions \n"); //......................device distributions................................. dist_mem_size = Np*sizeof(double); neighborSize=18*(Np*sizeof(int)); //........................................................................... //ScaLBL_AllocateDeviceMemory((void **) &NeighborList, neighborSize); ScaLBL_AllocateDeviceMemory((void **) &dvcMap, sizeof(int)*Np); //ScaLBL_AllocateDeviceMemory((void **) &gqbar, 19*dist_mem_size); //ScaLBL_AllocateDeviceMemory((void **) &hq, 7*dist_mem_size); //ScaLBL_AllocateDeviceMemory((void **) &mu_phi, dist_mem_size); //ScaLBL_AllocateDeviceMemory((void **) &Den, dist_mem_size); ScaLBL_AllocateDeviceMemory((void **) &Phi, sizeof(double)*Nh); //ScaLBL_AllocateDeviceMemory((void **) &Pressure, sizeof(double)*Np); //ScaLBL_AllocateDeviceMemory((void **) &Velocity, 3*sizeof(double)*Np); ScaLBL_AllocateDeviceMemory((void **) &ColorGrad, 3*sizeof(double)*Np); //........................................................................... // Update GPU data structures if (rank==0) printf ("Setting up device map and neighbor list \n"); fflush(stdout); int *TmpMap; TmpMap=new int[Np]; for (int k=1; kMap(i,j,k); } } } // check that TmpMap is valid for (int idx=0; idxLastExterior(); idx++){ auto n = TmpMap[idx]; if (n > Nxh*Nyh*Nzh){ printf("Bad value! idx=%i \n", n); TmpMap[idx] = Nxh*Nyh*Nzh-1; } } for (int idx=ScaLBL_Comm->FirstInterior(); idxLastInterior(); idx++){ auto n = TmpMap[idx]; if ( n > Nxh*Nyh*Nzh ){ printf("Bad value! idx=%i \n",n); TmpMap[idx] = Nxh*Nyh*Nzh-1; } } // copy the device map ScaLBL_CopyToDevice(dvcMap, TmpMap, sizeof(int)*Np); // copy the neighbor list //ScaLBL_CopyToDevice(NeighborList, neighborList, neighborSize); comm.barrier(); double *phase; phase = new double[Nh]; for (int k=0;kid[n] int x=i-1; int y=j-1; int z=k-1; if (x<0) x=0; if (y<0) y=0; if (z<0) z=0; if (x>=Nx) x=Nx-1; if (y>=Ny) y=Ny-1; if (z>=Nz) z=Nz-1; int n = z*Nx*Ny+y*Nx+x; phase[nh]=id[n]; } } } ScaLBL_CopyToDevice(Phi, phase, Nh*sizeof(double)); ScaLBL_Comm->Barrier(); comm.barrier(); delete [] TmpMap; delete [] neighborList; delete [] phase; } void ScaLBL_FreeLeeModel::MGTest(){ comm.barrier(); ScaLBL_Comm_WideHalo->Send(Phi); ScaLBL_D3Q9_MGTest(dvcMap,Phi,ColorGrad,Nxh,Nxh*Nyh, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np); ScaLBL_Comm_WideHalo->Recv(Phi); ScaLBL_D3Q9_MGTest(dvcMap,Phi,ColorGrad,Nxh,Nxh*Nyh, 0, ScaLBL_Comm->LastExterior(), Np); //check the sum of ColorGrad double cgx_loc = 0.0; double cgy_loc = 0.0; double cgz_loc = 0.0; double cgx,cgy,cgz; double *ColorGrad_host; ColorGrad_host = new double [3*Np]; ScaLBL_CopyToHost(&ColorGrad_host[0],&ColorGrad[0], 3*Np*sizeof(double)); for (int i = ScaLBL_Comm->FirstInterior(); iLastInterior();i++){ cgx_loc+=ColorGrad_host[0*Np+i]; cgy_loc+=ColorGrad_host[1*Np+i]; cgz_loc+=ColorGrad_host[2*Np+i]; } for (int i = 0; iLastExterior();i++){ cgx_loc+=ColorGrad_host[0*Np+i]; cgy_loc+=ColorGrad_host[1*Np+i]; cgz_loc+=ColorGrad_host[2*Np+i]; } cgx=Dm->Comm.sumReduce( cgx_loc); cgy=Dm->Comm.sumReduce( cgy_loc); cgz=Dm->Comm.sumReduce( cgz_loc); if (rank==0){ printf("Sum of all x-component of the mixed gradient = %.2g \n",cgx); printf("Sum of all y-component of the mixed gradient = %.2g \n",cgy); printf("Sum of all z-component of the mixed gradient = %.2g \n",cgz); } delete [] ColorGrad_host; }