LBPM/tests/lbpm_morph_pp.cpp

245 lines
6.5 KiB
C++
Raw Normal View History

/*
* Pre-processor to generate signed distance function from segmented data
* segmented data should be stored in a raw binary file as 1-byte integer (type char)
* will output distance functions for phases
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include "common/Array.h"
#include "common/Domain.h"
2019-04-23 06:22:15 -05:00
#include "analysis/distance.h"
#include "analysis/morphology.h"
//*************************************************************************
2019-04-23 06:22:15 -05:00
// Morpohologica pre-processor
// Initialize phase distribution using morphological approach
// Signed distance function is used to determine fluid configuration
//*************************************************************************
int main(int argc, char **argv)
{
// Initialize MPI
2021-01-05 17:43:44 -06:00
Utilities::startup( argc, argv );
2020-01-28 07:51:32 -06:00
Utilities::MPI comm( MPI_COMM_WORLD );
2021-01-05 17:43:44 -06:00
int rank = comm.getRank();
2019-04-23 06:22:15 -05:00
{
//.......................................................................
// Reading the domain information file
//.......................................................................
2019-10-09 11:17:55 -05:00
int n, nx, ny, nz;
2019-04-23 06:22:15 -05:00
char LocalRankFilename[40];
string filename;
2019-10-09 11:17:55 -05:00
double SW;
2019-04-23 06:22:15 -05:00
if (argc > 1){
filename=argv[1];
2019-10-09 11:17:55 -05:00
//Rcrit_new=0.f;
2019-04-23 06:22:15 -05:00
//SW=strtod(argv[2],NULL);
2017-08-16 14:47:20 -05:00
}
2019-04-23 06:22:15 -05:00
else ERROR("No input database provided\n");
// read the input database
auto db = std::make_shared<Database>( filename );
auto domain_db = db->getDatabase( "Domain" );
// Read domain parameters
auto size = domain_db->getVector<int>( "n" );
auto nproc = domain_db->getVector<int>( "nproc" );
auto ReadValues = domain_db->getVector<int>( "ReadValues" );
auto WriteValues = domain_db->getVector<int>( "WriteValues" );
SW = domain_db->getScalar<double>("Sw");
2019-10-09 11:11:51 -05:00
auto READFILE = domain_db->getScalar<std::string>( "Filename" );
2019-04-23 06:22:15 -05:00
// Generate the NWP configuration
//if (rank==0) printf("Initializing morphological distribution with critical radius %f \n", Rcrit);
if (rank==0) printf("Performing morphological imbibition with target saturation %f \n", SW);
// GenerateResidual(id,nx,ny,nz,Saturation);
nx = size[0];
ny = size[1];
nz = size[2];
int N = (nx+2)*(ny+2)*(nz+2);
std::shared_ptr<Domain> Dm (new Domain(domain_db,comm));
2019-10-09 11:11:51 -05:00
std::shared_ptr<Domain> Mask (new Domain(domain_db,comm));
2019-04-23 06:22:15 -05:00
// std::shared_ptr<Domain> Dm (new Domain(nx,ny,nz,rank,nprocx,nprocy,nprocz,Lx,Ly,Lz,BC));
for (n=0; n<N; n++) Dm->id[n]=1;
Dm->CommInit();
signed char *id;
id = new signed char [N];
2019-10-09 11:17:55 -05:00
signed char *id_connected;
id_connected = new signed char [N];
2019-10-09 11:11:51 -05:00
Mask->Decomp(READFILE);
Mask->CommInit();
2019-04-23 06:22:15 -05:00
nx+=2; ny+=2; nz+=2;
// Generate the signed distance map
// Initialize the domain and communication
Array<char> id_solid(nx,ny,nz);
2019-04-23 12:49:23 -05:00
Array<int> phase_label(nx,ny,nz);
2019-04-23 06:22:15 -05:00
DoubleArray SignDist(nx,ny,nz);
DoubleArray phase(nx,ny,nz);
for (int k=0; k<nz; k++){
for (int j=0; j<ny; j++){
for (int i=0; i<nx; i++){
n=k*nx*ny+j*nx+i;
2019-10-09 11:11:51 -05:00
id[n] = Mask->id[n];
2019-04-23 06:22:15 -05:00
if (id[n] == 1){
phase(i,j,k) = 1.0;
}
else
phase(i,j,k) = -1.0;
}
2017-08-16 14:47:20 -05:00
}
}
2019-04-23 06:22:15 -05:00
// 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
2019-10-09 11:11:51 -05:00
if (Mask->id[n] > 0){
id_solid(i,j,k) = 1;
}
else
id_solid(i,j,k) = 0;
2017-08-16 14:47:20 -05:00
}
}
}
2019-04-23 06:22:15 -05:00
// 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;
2017-08-16 18:45:10 -05:00
}
}
}
2019-04-23 06:22:15 -05:00
if (rank==0) printf("Initialized solid phase -- Converting to Signed Distance function \n");
CalcDist(SignDist,id_solid,*Dm);
2021-01-05 17:43:44 -06:00
comm.barrier();
2019-04-23 06:22:15 -05:00
// Extract only the connected part of NWP
double vF=0.0; double vS=0.0;
ComputeGlobalBlobIDs(nx-2,ny-2,nz-2,Dm->rank_info,phase,SignDist,vF,vS,phase_label,Dm->Comm);
2021-01-05 17:43:44 -06:00
Dm->Comm.barrier();
2019-04-23 06:22:15 -05:00
int count_connected=0;
int count_porespace=0;
int count_water=0;
for (int k=1; k<nz-1; k++){
for (int j=1; j<ny-1; j++){
for (int i=1; i<nx-1; i++){
n=k*nx*ny+j*nx+i;
// only apply opening to connected component
if ( phase_label(i,j,k) == 0){
count_connected++;
}
if (id[n] > 0){
count_porespace++;
}
if (id[n] == 2){
count_water++;
}
2017-08-16 18:45:10 -05:00
}
}
}
2021-01-05 17:43:44 -06:00
count_connected = Dm->Comm.sumReduce( count_connected );
count_porespace = Dm->Comm.sumReduce( count_porespace );
count_water = Dm->Comm.sumReduce( count_water );
2019-04-23 06:22:15 -05:00
for (int k=0; k<nz; k++){
for (int j=0; j<ny; j++){
for (int i=0; i<nx; i++){
n=k*nx*ny+j*nx+i;
// only apply opening to connected component
if ( phase_label(i,j,k) == 0){
2019-04-23 12:49:23 -05:00
id_solid(i,j,k) = 1;
2019-04-23 06:22:15 -05:00
id_connected[n] = 2;
id[n] = 2;
}
else{
2019-04-23 12:49:23 -05:00
id_solid(i,j,k) = 0;
2019-04-23 06:22:15 -05:00
id_connected[n] = 0;
}
}
}
}
2019-04-23 06:22:15 -05:00
CalcDist(SignDist,id_solid,*Dm);
// target water increase in voxels, normalized by connected volume
double St = (SW*count_porespace - count_water)/count_porespace;
2019-04-26 16:38:21 -05:00
signed char water=2;
signed char notwater=1;
2019-04-23 06:22:15 -05:00
// Run the morphological opening
if (St > 0.0)
2019-04-26 16:38:21 -05:00
MorphOpen(SignDist, id_connected, Dm, St, water, notwater);
2019-04-23 06:22:15 -05:00
else {
if(rank==0) printf("Initial condition satisfies condition for saturation target \n");
}
// re-label
for (int k=0; k<nz; k++){
for (int j=0; j<ny; j++){
for (int i=0; i<nx; i++){
n=k*nx*ny+j*nx+i;
// only apply opening to connected component
if ( id_connected[n] == 1){
id[n] = 1;
}
}
}
}
2019-04-23 06:22:15 -05:00
2019-04-23 06:25:57 -05:00
count_water=0;
for (int k=1; k<nz-1; k++){
for (int j=1; j<ny-1; j++){
for (int i=1; i<nx-1; i++){
n=k*nx*ny+j*nx+i;
if (id[n] == 2){
count_water++;
}
}
}
}
2021-01-05 17:43:44 -06:00
count_water = Dm->Comm.sumReduce( count_water );
2019-04-23 06:25:57 -05:00
SW = double(count_water) / count_porespace;
if(rank==0) printf("Final saturation: %f \n", SW);
2019-04-23 06:22:15 -05:00
if (rank==0) printf("Writing ID file \n");
sprintf(LocalRankFilename,"ID.%05i",rank);
2017-08-16 14:47:20 -05:00
2019-04-23 06:22:15 -05:00
FILE *ID = fopen(LocalRankFilename,"wb");
fwrite(id,1,N,ID);
fclose(ID);
2019-10-09 11:11:51 -05:00
// write the geometry to a single file
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;
Mask->id[n] = id[n];
}
}
}
2021-01-05 17:43:44 -06:00
comm.barrier();
2019-10-09 11:11:51 -05:00
2020-01-22 11:01:29 -06:00
auto filename2 = READFILE + ".morph.raw";
if (rank==0) printf("Writing file to: %s \n", filename2.c_str());
Mask->AggregateLabels(filename2);
2017-08-16 14:47:20 -05:00
}
2021-01-05 17:43:44 -06:00
Utilities::shutdown();
}