/* 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; k < Nzh - 1; k++) { for (int j = 1; j < Nyh - 1; j++) { for (int i = 1; i < Nxh - 1; i++) { PhaseValues(i - 1, j - 1, k - 1) = PhaseWideHalo(i, j, k); } } } } void ScaLBL_FreeLeeModel::getPotential(DoubleArray &PressureValues, DoubleArray &MuValues) { ScaLBL_Comm->RegularLayout(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 < Nz; k++) { for (j = 0; j < Ny; j++) { for (i = 0; i < Nx; i++) { idx = Map(i, j, k); if (!(idx < 0)) { value = data[idx]; regdata(i, j, k) = value; } } } } } void ScaLBL_FreeLeeModel::ReadParams(string filename) { // read the input database db = std::make_shared(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; i < Nx * Ny * Nz; i++) Dm->id[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; i < Nx * Ny * Nz; i++) id[i] = Mask->id[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; k < Nz; k++) { for (int j = 0; j < Ny; j++) { for (int i = 0; i < Nx; i++) { int n = k * Nx * Ny + j * Nx + i; // Initialize the solid phase signed char label = Mask->id[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; k < Nz; k++) { for (int j = 0; j < Ny; j++) { for (int i = 0; i < Nx; i++) { // Initialize distance to +/- 1 SignDist(i, j, k) = 2.0 * double(id_solid(i, j, k)) - 1.0; } } } if (rank == 0) printf("Initialized solid phase -- Converting to Signed Distance " "function \n"); CalcDist(SignDist, id_solid, *Mask); if (rank == 0) cout << "Domain set." << endl; } void ScaLBL_FreeLeeModel::Create_TwoFluid() { /* * This function creates the variables needed to run two-fluid Lee model */ //......................................................... // Initialize communication structures in averaging domain for (int i = 0; i < Nx * Ny * Nz; i++) Dm->id[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; k < Nz - 1; k++) { for (int j = 1; j < Ny - 1; j++) { for (int i = 1; i < Nx - 1; i++) { int idx = Map(i, j, k); if (!(idx < 0)) TmpMap[idx] = ScaLBL_Comm_WideHalo->Map(i, j, k); } } } // check that TmpMap is valid for (int idx = 0; idx < ScaLBL_Comm->LastExterior(); 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(); idx < ScaLBL_Comm->LastInterior(); 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; i < Nx * Ny * Nz; i++) Dm->id[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; idx < NLABELS; idx++) label_count[idx] = 0; for (int k = 0; k < Nzh; k++) { for (int j = 0; j < Nyh; j++) { for (int i = 0; i < Nxh; i++) { //idx for double-halo array 'phase' int nh = k * Nxh * Nyh + j * Nxh + i; //idx for single-halo array Mask->id[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; i < Nx * Ny * Nz; i++) Dm->id[i] = Mask->id[i]; for (size_t idx = 0; idx < NLABELS; idx++) label_count_global[idx] = Dm->Comm.sumReduce(label_count[idx]); if (rank == 0) { printf("Number of component labels: %lu \n", NLABELS); for (unsigned int idx = 0; idx < NLABELS; idx++) { VALUE = LabelList[idx]; AFFINITY = AffinityList[idx]; double volume_fraction = double(label_count_global[idx]) / double((Nx - 2) * (Ny - 2) * (Nz - 2) * nprocs); printf(" label=%d, affinity=%f, volume fraction==%f\n", VALUE, AFFINITY, volume_fraction); } } //compute color gradient and laplacian of phase field double *ColorGrad_host, *mu_phi_host; ColorGrad_host = new double[3 * Np]; mu_phi_host = new double[Np]; double *Dst; Dst = new double[3 * 3 * 3]; for (int kk = 0; kk < 3; kk++) { for (int jj = 0; jj < 3; jj++) { for (int ii = 0; ii < 3; ii++) { int index = kk * 9 + jj * 3 + ii; Dst[index] = sqrt(double(ii - 1) * double(ii - 1) + double(jj - 1) * double(jj - 1) + double(kk - 1) * double(kk - 1)); } } } double w_face = 1.0 / 18.0; double w_edge = 1.0 / 36.0; double w_corner = 0.f; //local Dst[13] = 0.f; //faces Dst[4] = w_face; Dst[10] = w_face; Dst[12] = w_face; Dst[14] = w_face; Dst[16] = w_face; Dst[22] = w_face; // corners Dst[0] = w_corner; Dst[2] = w_corner; Dst[6] = w_corner; Dst[8] = w_corner; Dst[18] = w_corner; Dst[20] = w_corner; Dst[24] = w_corner; Dst[26] = w_corner; // edges Dst[1] = w_edge; Dst[3] = w_edge; Dst[5] = w_edge; Dst[7] = w_edge; Dst[9] = w_edge; Dst[11] = w_edge; Dst[15] = w_edge; Dst[17] = w_edge; Dst[19] = w_edge; Dst[21] = w_edge; Dst[23] = w_edge; Dst[25] = w_edge; double cs2_inv = 3.0; //inverse of c_s^2 for D3Q19 lattice int width = 2; //For better readability: make halo width explicity wherever possible for (int k = width; k < Nzh - width; k++) { for (int j = width; j < Nyh - width; j++) { for (int i = width; i < Nxh - width; i++) { //idx for double-halo array 'phase' int nh = k * Nxh * Nyh + j * Nxh + i; int idx = Map(i - width + 1, j - width + 1, k - width + 1); if (!(idx < 0)) { double phi_x = 0.f; double phi_y = 0.f; double phi_z = 0.f; double phi_Lap = 0.f; //Laplacian of the phase field for (int kk = 0; kk < 3; kk++) { for (int jj = 0; jj < 3; jj++) { for (int ii = 0; ii < 3; ii++) { int index = kk * 9 + jj * 3 + ii; double weight = Dst[index]; int idi = i + ii - 1; int idj = j + jj - 1; int idk = k + kk - 1; if (idi < 0) idi = 0; if (idj < 0) idj = 0; if (idk < 0) idk = 0; if (!(idi < Nxh)) idi = Nxh - 1; if (!(idj < Nyh)) idj = Nyh - 1; if (!(idk < Nzh)) idk = Nzh - 1; int nn = idk * Nxh * Nyh + idj * Nxh + idi; double vec_x = double(ii - 1); double vec_y = double(jj - 1); double vec_z = double(kk - 1); double GWNS = phase[nn]; double GWNS_local = phase[nh]; phi_x += GWNS * weight * vec_x; phi_y += GWNS * weight * vec_y; phi_z += GWNS * weight * vec_z; phi_Lap += weight * (GWNS - GWNS_local); //Laplacian of the phase field } } } //store color gradient ColorGrad_host[idx + 0 * Np] = cs2_inv * phi_x; ColorGrad_host[idx + 1 * Np] = cs2_inv * phi_y; ColorGrad_host[idx + 2 * Np] = cs2_inv * phi_z; //compute chemical potential phi_Lap = 2.0 * cs2_inv * phi_Lap; mu_phi_host[idx] = 4.0 * beta * phase[nh] * (phase[nh] + 1.0) * (phase[nh] - 1.0) - kappa * phi_Lap; } } } } //copy all data to device ScaLBL_CopyToDevice(Phi, phase, Nh * sizeof(double)); ScaLBL_CopyToDevice(ColorGrad, ColorGrad_host, 3 * Np * sizeof(double)); ScaLBL_CopyToDevice(mu_phi, mu_phi_host, Np * sizeof(double)); ScaLBL_Comm->Barrier(); 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; n < Np; n++) { File.read((char *)&va, sizeof(va)); File.read((char *)&vb, sizeof(vb)); cDen[n] = va; cDen[Np + n] = vb; } for (int n = 0; n < Np; n++) { // Read the distributions for (int q = 0; q < 19; q++) { File.read((char *)&value, sizeof(value)); cDist[q * Np + n] = value; } } File.close(); for (int n = 0; n < ScaLBL_Comm->LastExterior(); n++) { va = cDen[n]; vb = cDen[Np + n]; value = (va - vb) / (va + vb); idx = TmpMap[n]; if (!(idx < 0) && idx < N) cPhi[idx] = value; } for (int n = ScaLBL_Comm->FirstInterior(); n < ScaLBL_Comm->LastInterior(); n++) { va = cDen[n]; vb = cDen[Np + n]; value = (va - vb) / (va + vb); idx = TmpMap[n]; if (!(idx < 0) && idx < N) cPhi[idx] = value; } // Copy the restart data to the GPU ScaLBL_CopyToDevice(Den, cDen, 2 * Np * sizeof(double)); ScaLBL_CopyToDevice(gqbar, cDist, 19 * Np * sizeof(double)); ScaLBL_CopyToDevice(Phi, cPhi, N * sizeof(double)); ScaLBL_Comm->Barrier(); 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; i < Nx * Ny * Nz; i++) Dm->id[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; k < Nz - 1; k++) { for (int j = 1; j < Ny - 1; j++) { for (int i = 1; i < Nx - 1; i++) { int idx = Map(i, j, k); if (!(idx < 0)) TmpMap[idx] = ScaLBL_Comm_WideHalo->Map(i, j, k); } } } // check that TmpMap is valid for (int idx = 0; idx < ScaLBL_Comm->LastExterior(); 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(); idx < ScaLBL_Comm->LastInterior(); 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; k < Nzh; k++) { for (int j = 0; j < Nyh; j++) { for (int i = 0; i < Nxh; i++) { //idx for double-halo array 'phase' int nh = k * Nxh * Nyh + j * Nxh + i; //idx for single-halo array Mask->id[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(); i < ScaLBL_Comm->LastInterior(); 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; i < ScaLBL_Comm->LastExterior(); 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; }