2015-08-22 11:03:46 -04:00
|
|
|
// Run the analysis, blob identification, and write restart files
|
2018-03-08 13:03:22 -05:00
|
|
|
#include "analysis/runAnalysis.h"
|
|
|
|
|
#include "analysis/analysis.h"
|
2015-08-24 14:11:26 -04:00
|
|
|
#include "common/Array.h"
|
2015-11-05 10:32:54 -05:00
|
|
|
#include "common/Communication.h"
|
2015-11-10 14:47:52 -05:00
|
|
|
#include "common/MPI_Helpers.h"
|
2018-01-26 09:44:44 -05:00
|
|
|
#include "common/ScaLBL.h"
|
2015-11-10 14:47:52 -05:00
|
|
|
#include "IO/MeshDatabase.h"
|
2018-03-08 13:03:22 -05:00
|
|
|
#include "threadpool/thread_pool.h"
|
|
|
|
|
|
|
|
|
|
#include "ProfilerApp.h"
|
2015-08-22 11:03:46 -04:00
|
|
|
|
2018-02-06 10:50:43 -05:00
|
|
|
|
2015-08-22 11:03:46 -04:00
|
|
|
|
2018-02-06 10:50:43 -05:00
|
|
|
AnalysisType& operator |=(AnalysisType &lhs, AnalysisType rhs)
|
|
|
|
|
{
|
2018-03-08 13:03:22 -05:00
|
|
|
lhs = static_cast<AnalysisType>(
|
2018-02-06 10:50:43 -05:00
|
|
|
static_cast<std::underlying_type<AnalysisType>::type>(lhs) |
|
2018-03-08 13:03:22 -05:00
|
|
|
static_cast<std::underlying_type<AnalysisType>::type>(rhs)
|
2018-02-06 10:50:43 -05:00
|
|
|
);
|
|
|
|
|
return lhs;
|
|
|
|
|
}
|
|
|
|
|
bool matches( AnalysisType x, AnalysisType y )
|
|
|
|
|
{
|
|
|
|
|
return static_cast<std::underlying_type<AnalysisType>::type>(x) &
|
|
|
|
|
static_cast<std::underlying_type<AnalysisType>::type>(y) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-30 20:41:55 -04:00
|
|
|
|
2016-05-25 14:00:28 -04:00
|
|
|
template<class TYPE>
|
|
|
|
|
void DeleteArray( const TYPE *p )
|
|
|
|
|
{
|
|
|
|
|
delete [] p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-08-22 11:03:46 -04:00
|
|
|
// Helper class to write the restart file from a seperate thread
|
2018-02-06 10:50:43 -05:00
|
|
|
class WriteRestartWorkItem: public ThreadPool::WorkItemRet<void>
|
2015-08-22 11:03:46 -04:00
|
|
|
{
|
|
|
|
|
public:
|
2018-04-06 11:04:58 -04:00
|
|
|
WriteRestartWorkItem( const char* filename_, const DoubleArray& phase_, const DoubleArray& dist_, int N_ ):
|
|
|
|
|
filename(filename_), phase(phase_), dist(dist_), N(N_) {}
|
2015-08-22 11:03:46 -04:00
|
|
|
virtual void run() {
|
|
|
|
|
PROFILE_START("Save Checkpoint",1);
|
2018-04-06 11:04:58 -04:00
|
|
|
char *IDS;
|
|
|
|
|
IDS = new char [N];
|
|
|
|
|
char local_id=0;
|
|
|
|
|
for (int idx=0; idx<N; idx++){
|
|
|
|
|
if (dist(idx) < 0.f ) local_id = 0;
|
|
|
|
|
else if (phase(idx) > 0.f) local_id = 1;
|
|
|
|
|
else local_id=2;
|
|
|
|
|
IDS[idx] = local_id;
|
|
|
|
|
}
|
|
|
|
|
FILE *RESTART = fopen(filename,"wb");
|
|
|
|
|
fwrite(IDS,1,N,RESTART);
|
|
|
|
|
// fwrite(Distance.get(),8,Distance.length(),ID);
|
|
|
|
|
fclose(RESTART);
|
|
|
|
|
PROFILE_STOP("Save Checkpoint",1);
|
|
|
|
|
|
2015-08-22 11:03:46 -04:00
|
|
|
};
|
|
|
|
|
private:
|
|
|
|
|
WriteRestartWorkItem();
|
|
|
|
|
const char* filename;
|
2018-04-06 11:04:58 -04:00
|
|
|
// std::shared_ptr<double> cPhi, cDist;
|
|
|
|
|
const DoubleArray& phase;
|
|
|
|
|
const DoubleArray& dist;
|
2015-08-22 11:03:46 -04:00
|
|
|
const int N;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Helper class to compute the blob ids
|
2015-08-25 14:32:36 -04:00
|
|
|
static const std::string id_map_filename = "lbpm_id_map.txt";
|
2018-02-06 10:50:43 -05:00
|
|
|
class BlobIdentificationWorkItem1: public ThreadPool::WorkItemRet<void>
|
2015-08-22 11:03:46 -04:00
|
|
|
{
|
|
|
|
|
public:
|
2015-09-14 17:30:35 -04:00
|
|
|
BlobIdentificationWorkItem1( int timestep_, int Nx_, int Ny_, int Nz_, const RankInfoStruct& rank_info_,
|
2015-08-24 14:11:26 -04:00
|
|
|
std::shared_ptr<const DoubleArray> phase_, const DoubleArray& dist_,
|
2018-03-08 13:03:22 -05:00
|
|
|
BlobIDstruct last_id_, BlobIDstruct new_index_, BlobIDstruct new_id_, BlobIDList new_list_, runAnalysis::commWrapper&& comm_ ):
|
2015-08-25 14:32:36 -04:00
|
|
|
timestep(timestep_), Nx(Nx_), Ny(Ny_), Nz(Nz_), rank_info(rank_info_),
|
2018-03-08 13:03:22 -05:00
|
|
|
phase(phase_), dist(dist_), last_id(last_id_), new_index(new_index_), new_id(new_id_), new_list(new_list_), comm(std::move(comm_))
|
2016-10-28 09:04:23 -04:00
|
|
|
{
|
|
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
~BlobIdentificationWorkItem1() { }
|
2015-08-22 11:03:46 -04:00
|
|
|
virtual void run() {
|
|
|
|
|
// Compute the global blob id and compare to the previous version
|
2015-09-14 17:30:35 -04:00
|
|
|
PROFILE_START("Identify blobs",1);
|
2015-08-22 11:03:46 -04:00
|
|
|
double vF = 0.0;
|
2015-09-17 15:36:48 -04:00
|
|
|
double vS = -1.0; // one voxel buffer region around solid
|
2015-08-25 14:32:36 -04:00
|
|
|
IntArray& ids = new_index->second;
|
2018-03-08 13:03:22 -05:00
|
|
|
new_index->first = ComputeGlobalBlobIDs(Nx-2,Ny-2,Nz-2,rank_info,*phase,dist,vF,vS,ids,comm.comm);
|
2015-09-14 17:30:35 -04:00
|
|
|
PROFILE_STOP("Identify blobs",1);
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
BlobIdentificationWorkItem1();
|
|
|
|
|
int timestep;
|
|
|
|
|
int Nx, Ny, Nz;
|
|
|
|
|
const RankInfoStruct& rank_info;
|
|
|
|
|
std::shared_ptr<const DoubleArray> phase;
|
|
|
|
|
const DoubleArray& dist;
|
|
|
|
|
BlobIDstruct last_id, new_index, new_id;
|
|
|
|
|
BlobIDList new_list;
|
2018-03-08 13:03:22 -05:00
|
|
|
runAnalysis::commWrapper comm;
|
2015-09-14 17:30:35 -04:00
|
|
|
};
|
2018-02-06 10:50:43 -05:00
|
|
|
class BlobIdentificationWorkItem2: public ThreadPool::WorkItemRet<void>
|
2015-09-14 17:30:35 -04:00
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
BlobIdentificationWorkItem2( int timestep_, int Nx_, int Ny_, int Nz_, const RankInfoStruct& rank_info_,
|
|
|
|
|
std::shared_ptr<const DoubleArray> phase_, const DoubleArray& dist_,
|
2018-03-08 13:03:22 -05:00
|
|
|
BlobIDstruct last_id_, BlobIDstruct new_index_, BlobIDstruct new_id_, BlobIDList new_list_ , runAnalysis::commWrapper&& comm_ ):
|
2015-09-14 17:30:35 -04:00
|
|
|
timestep(timestep_), Nx(Nx_), Ny(Ny_), Nz(Nz_), rank_info(rank_info_),
|
2018-03-08 13:03:22 -05:00
|
|
|
phase(phase_), dist(dist_), last_id(last_id_), new_index(new_index_), new_id(new_id_), new_list(new_list_), comm(std::move(comm_))
|
2016-10-28 09:04:23 -04:00
|
|
|
{
|
|
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
~BlobIdentificationWorkItem2() { }
|
2015-09-14 17:30:35 -04:00
|
|
|
virtual void run() {
|
|
|
|
|
// Compute the global blob id and compare to the previous version
|
|
|
|
|
PROFILE_START("Identify blobs maps",1);
|
|
|
|
|
const IntArray& ids = new_index->second;
|
2015-08-25 14:32:36 -04:00
|
|
|
static int max_id = -1;
|
|
|
|
|
new_id->first = new_index->first;
|
|
|
|
|
new_id->second = new_index->second;
|
2016-01-12 14:26:48 -05:00
|
|
|
if ( last_id.get()!=NULL ) {
|
2015-08-22 11:03:46 -04:00
|
|
|
// Compute the timestep-timestep map
|
2015-08-25 14:32:36 -04:00
|
|
|
const IntArray& old_ids = last_id->second;
|
2018-03-08 13:03:22 -05:00
|
|
|
ID_map_struct map = computeIDMap(Nx,Ny,Nz,old_ids,ids,comm.comm);
|
2015-08-22 11:03:46 -04:00
|
|
|
// Renumber the current timestep's ids
|
2015-08-25 14:32:36 -04:00
|
|
|
getNewIDs(map,max_id,*new_list);
|
|
|
|
|
renumberIDs(*new_list,new_id->second);
|
|
|
|
|
writeIDMap(map,timestep,id_map_filename);
|
|
|
|
|
} else {
|
|
|
|
|
max_id = -1;
|
|
|
|
|
ID_map_struct map(new_id->first);
|
|
|
|
|
getNewIDs(map,max_id,*new_list);
|
|
|
|
|
writeIDMap(map,timestep,id_map_filename);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2015-09-14 17:30:35 -04:00
|
|
|
PROFILE_STOP("Identify blobs maps",1);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
|
|
|
|
private:
|
2015-09-14 17:30:35 -04:00
|
|
|
BlobIdentificationWorkItem2();
|
2015-08-25 14:32:36 -04:00
|
|
|
int timestep;
|
2015-08-22 11:03:46 -04:00
|
|
|
int Nx, Ny, Nz;
|
|
|
|
|
const RankInfoStruct& rank_info;
|
2015-08-24 14:11:26 -04:00
|
|
|
std::shared_ptr<const DoubleArray> phase;
|
2015-08-22 11:03:46 -04:00
|
|
|
const DoubleArray& dist;
|
2015-08-25 14:32:36 -04:00
|
|
|
BlobIDstruct last_id, new_index, new_id;
|
|
|
|
|
BlobIDList new_list;
|
2018-03-08 13:03:22 -05:00
|
|
|
runAnalysis::commWrapper comm;
|
2015-08-22 11:03:46 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-11-10 14:47:52 -05:00
|
|
|
// Helper class to write the vis file from a thread
|
2018-02-06 10:50:43 -05:00
|
|
|
class WriteVisWorkItem: public ThreadPool::WorkItemRet<void>
|
2015-11-05 10:13:05 -05:00
|
|
|
{
|
|
|
|
|
public:
|
2015-11-10 14:47:52 -05:00
|
|
|
WriteVisWorkItem( int timestep_, std::vector<IO::MeshDataStruct>& visData_,
|
2018-03-08 13:03:22 -05:00
|
|
|
TwoPhase& Avgerages_, fillHalo<double>& fillData_, runAnalysis::commWrapper&& comm_ ):
|
|
|
|
|
timestep(timestep_), visData(visData_), Averages(Avgerages_), fillData(fillData_), comm(std::move(comm_))
|
2016-10-28 09:04:23 -04:00
|
|
|
{
|
|
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
~WriteVisWorkItem() { }
|
2015-11-05 10:13:05 -05:00
|
|
|
virtual void run() {
|
2015-11-10 14:47:52 -05:00
|
|
|
PROFILE_START("Save Vis",1);
|
|
|
|
|
ASSERT(visData[0].vars[0]->name=="phase");
|
|
|
|
|
ASSERT(visData[0].vars[1]->name=="Pressure");
|
|
|
|
|
ASSERT(visData[0].vars[2]->name=="SignDist");
|
|
|
|
|
ASSERT(visData[0].vars[3]->name=="BlobID");
|
|
|
|
|
Array<double>& PhaseData = visData[0].vars[0]->data;
|
|
|
|
|
Array<double>& PressData = visData[0].vars[1]->data;
|
|
|
|
|
Array<double>& SignData = visData[0].vars[2]->data;
|
|
|
|
|
Array<double>& BlobData = visData[0].vars[3]->data;
|
|
|
|
|
fillData.copy(Averages.SDn,PhaseData);
|
|
|
|
|
fillData.copy(Averages.Press,PressData);
|
|
|
|
|
fillData.copy(Averages.SDs,SignData);
|
|
|
|
|
fillData.copy(Averages.Label_NWP,BlobData);
|
2018-03-08 13:03:22 -05:00
|
|
|
IO::writeData( timestep, visData, comm.comm );
|
2015-11-05 10:13:05 -05:00
|
|
|
PROFILE_STOP("Save Vis",1);
|
|
|
|
|
};
|
|
|
|
|
private:
|
2015-11-05 10:21:41 -05:00
|
|
|
WriteVisWorkItem();
|
2015-11-10 14:47:52 -05:00
|
|
|
int timestep;
|
|
|
|
|
std::vector<IO::MeshDataStruct>& visData;
|
2015-11-05 10:13:05 -05:00
|
|
|
TwoPhase& Averages;
|
2015-11-10 14:47:52 -05:00
|
|
|
fillHalo<double>& fillData;
|
2018-03-08 13:03:22 -05:00
|
|
|
runAnalysis::commWrapper comm;
|
2015-11-05 10:13:05 -05:00
|
|
|
};
|
|
|
|
|
|
2016-10-28 09:04:23 -04:00
|
|
|
|
2015-08-22 11:03:46 -04:00
|
|
|
// Helper class to run the analysis from within a thread
|
|
|
|
|
// Note: Averages will be modified after the constructor is called
|
2018-02-06 10:50:43 -05:00
|
|
|
class AnalysisWorkItem: public ThreadPool::WorkItemRet<void>
|
2015-08-22 11:03:46 -04:00
|
|
|
{
|
|
|
|
|
public:
|
2016-04-30 20:41:55 -04:00
|
|
|
AnalysisWorkItem( AnalysisType type_, int timestep_, TwoPhase& Averages_,
|
2015-08-25 14:32:36 -04:00
|
|
|
BlobIDstruct ids, BlobIDList id_list_, double beta_ ):
|
2016-04-30 20:41:55 -04:00
|
|
|
type(type_), timestep(timestep_), Averages(Averages_),
|
2015-08-25 14:32:36 -04:00
|
|
|
blob_ids(ids), id_list(id_list_), beta(beta_) { }
|
2016-10-28 09:04:23 -04:00
|
|
|
~AnalysisWorkItem() { }
|
2015-08-22 11:03:46 -04:00
|
|
|
virtual void run() {
|
|
|
|
|
Averages.NumberComponents_NWP = blob_ids->first;
|
|
|
|
|
Averages.Label_NWP = blob_ids->second;
|
2015-08-25 14:32:36 -04:00
|
|
|
Averages.Label_NWP_map = *id_list;
|
2015-08-22 11:03:46 -04:00
|
|
|
Averages.NumberComponents_WP = 1;
|
|
|
|
|
Averages.Label_WP.fill(0.0);
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::CopyPhaseIndicator) ) {
|
2015-08-22 11:03:46 -04:00
|
|
|
// Averages.ColorToSignedDistance(beta,Averages.Phase,Averages.Phase_tplus);
|
|
|
|
|
}
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::ComputeAverages) ) {
|
2016-04-30 20:41:55 -04:00
|
|
|
PROFILE_START("Compute dist",1);
|
2015-08-22 11:03:46 -04:00
|
|
|
Averages.Initialize();
|
|
|
|
|
Averages.ComputeDelPhi();
|
|
|
|
|
Averages.ColorToSignedDistance(beta,Averages.Phase,Averages.SDn);
|
2015-11-14 11:05:44 -05:00
|
|
|
Averages.ColorToSignedDistance(beta,Averages.Phase_tminus,Averages.Phase_tminus);
|
|
|
|
|
Averages.ColorToSignedDistance(beta,Averages.Phase_tplus,Averages.Phase_tplus);
|
2015-08-22 11:03:46 -04:00
|
|
|
Averages.UpdateMeshValues();
|
2016-02-29 11:14:22 -05:00
|
|
|
Averages.ComputeLocal();
|
|
|
|
|
Averages.Reduce();
|
|
|
|
|
Averages.PrintAll(timestep);
|
|
|
|
|
Averages.Initialize();
|
2015-08-22 11:03:46 -04:00
|
|
|
Averages.ComponentAverages();
|
|
|
|
|
Averages.SortBlobs();
|
|
|
|
|
Averages.PrintComponents(timestep);
|
2016-04-30 20:41:55 -04:00
|
|
|
PROFILE_STOP("Compute dist",1);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private:
|
2016-04-30 20:41:55 -04:00
|
|
|
AnalysisWorkItem();
|
2015-08-22 11:03:46 -04:00
|
|
|
AnalysisType type;
|
|
|
|
|
int timestep;
|
|
|
|
|
TwoPhase& Averages;
|
|
|
|
|
BlobIDstruct blob_ids;
|
2015-08-25 14:32:36 -04:00
|
|
|
BlobIDList id_list;
|
2015-08-22 11:03:46 -04:00
|
|
|
double beta;
|
|
|
|
|
};
|
|
|
|
|
|
2018-02-06 10:50:43 -05:00
|
|
|
|
2018-03-08 13:03:22 -05:00
|
|
|
/******************************************************************
|
|
|
|
|
* MPI comm wrapper for use with analysis *
|
|
|
|
|
******************************************************************/
|
|
|
|
|
runAnalysis::commWrapper::commWrapper( int tag_, MPI_Comm comm_, runAnalysis* analysis_ ):
|
|
|
|
|
tag(tag_),
|
|
|
|
|
comm(comm_),
|
|
|
|
|
analysis(analysis_)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
runAnalysis::commWrapper::commWrapper( commWrapper &&rhs ):
|
|
|
|
|
tag(rhs.tag),
|
|
|
|
|
comm(rhs.comm),
|
|
|
|
|
analysis(rhs.analysis)
|
2015-08-22 11:03:46 -04:00
|
|
|
{
|
2018-03-08 13:03:22 -05:00
|
|
|
rhs.tag = -1;
|
|
|
|
|
}
|
|
|
|
|
runAnalysis::commWrapper::~commWrapper()
|
|
|
|
|
{
|
|
|
|
|
if ( tag == -1 )
|
|
|
|
|
return;
|
|
|
|
|
MPI_Barrier( comm );
|
|
|
|
|
analysis->d_comm_used[tag] = false;
|
|
|
|
|
}
|
|
|
|
|
runAnalysis::commWrapper runAnalysis::getComm( )
|
|
|
|
|
{
|
|
|
|
|
// Get a tag from root
|
|
|
|
|
int tag = -1;
|
|
|
|
|
if ( d_rank == 0 ) {
|
|
|
|
|
for (int i=0; i<1024; i++) {
|
|
|
|
|
if ( !d_comm_used[i] ) {
|
|
|
|
|
tag = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( tag == -1 )
|
|
|
|
|
ERROR("Unable to get comm");
|
|
|
|
|
}
|
|
|
|
|
MPI_Bcast( &tag, 1, MPI_INT, 0, d_comm );
|
|
|
|
|
d_comm_used[tag] = true;
|
|
|
|
|
if ( d_comms[tag] == MPI_COMM_NULL )
|
|
|
|
|
MPI_Comm_dup( MPI_COMM_WORLD, &d_comms[tag] );
|
|
|
|
|
return commWrapper(tag,d_comms[tag],this);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-22 11:03:46 -04:00
|
|
|
|
2018-03-08 13:03:22 -05:00
|
|
|
/******************************************************************
|
|
|
|
|
* Constructor/Destructors *
|
|
|
|
|
******************************************************************/
|
2018-03-09 12:59:59 -05:00
|
|
|
runAnalysis::runAnalysis( int restart_interval, int analysis_interval,
|
2018-03-08 13:03:22 -05:00
|
|
|
int blobid_interval, const RankInfoStruct& rank_info, const ScaLBL_Communicator &ScaLBL_Comm, const Domain& Dm,
|
|
|
|
|
int Np, int Nx, int Ny, int Nz, double Lx, double Ly, double Lz, bool pBC, double beta, double err,
|
|
|
|
|
IntArray Map, const std::string& LocalRestartFile ):
|
|
|
|
|
d_Np( Np ),
|
|
|
|
|
d_restart_interval( restart_interval ),
|
|
|
|
|
d_analysis_interval( analysis_interval ),
|
|
|
|
|
d_blobid_interval( blobid_interval ),
|
|
|
|
|
d_beta( beta ),
|
|
|
|
|
d_ScaLBL_Comm( ScaLBL_Comm ),
|
|
|
|
|
d_rank_info( rank_info ),
|
|
|
|
|
d_Map( Map ),
|
|
|
|
|
d_fillData(Dm.Comm,Dm.rank_info,Nx-2,Ny-2,Nz-2,1,1,1,0,1),
|
|
|
|
|
d_restartFile( LocalRestartFile )
|
|
|
|
|
{
|
|
|
|
|
d_N[0] = Nx;
|
|
|
|
|
d_N[1] = Ny;
|
|
|
|
|
d_N[2] = Nz;
|
|
|
|
|
d_rank = MPI_WORLD_RANK();
|
|
|
|
|
writeIDMap(ID_map_struct(),0,id_map_filename);
|
|
|
|
|
// Create the MeshDataStruct
|
|
|
|
|
d_meshData.resize(1);
|
|
|
|
|
d_meshData[0].meshName = "domain";
|
|
|
|
|
d_meshData[0].mesh = std::make_shared<IO::DomainMesh>( Dm.rank_info,Nx-2,Ny-2,Nz-2,Lx,Ly,Lz );
|
|
|
|
|
auto PhaseVar = std::make_shared<IO::Variable>();
|
|
|
|
|
auto PressVar = std::make_shared<IO::Variable>();
|
|
|
|
|
auto SignDistVar = std::make_shared<IO::Variable>();
|
|
|
|
|
auto BlobIDVar = std::make_shared<IO::Variable>();
|
|
|
|
|
PhaseVar->name = "phase";
|
|
|
|
|
PhaseVar->type = IO::VariableType::VolumeVariable;
|
|
|
|
|
PhaseVar->dim = 1;
|
|
|
|
|
PhaseVar->data.resize(Nx-2,Ny-2,Nz-2);
|
|
|
|
|
d_meshData[0].vars.push_back(PhaseVar);
|
|
|
|
|
PressVar->name = "Pressure";
|
|
|
|
|
PressVar->type = IO::VariableType::VolumeVariable;
|
|
|
|
|
PressVar->dim = 1;
|
|
|
|
|
PressVar->data.resize(Nx-2,Ny-2,Nz-2);
|
|
|
|
|
d_meshData[0].vars.push_back(PressVar);
|
|
|
|
|
SignDistVar->name = "SignDist";
|
|
|
|
|
SignDistVar->type = IO::VariableType::VolumeVariable;
|
|
|
|
|
SignDistVar->dim = 1;
|
|
|
|
|
SignDistVar->data.resize(Nx-2,Ny-2,Nz-2);
|
|
|
|
|
d_meshData[0].vars.push_back(SignDistVar);
|
|
|
|
|
BlobIDVar->name = "BlobID";
|
|
|
|
|
BlobIDVar->type = IO::VariableType::VolumeVariable;
|
|
|
|
|
BlobIDVar->dim = 1;
|
|
|
|
|
BlobIDVar->data.resize(Nx-2,Ny-2,Nz-2);
|
|
|
|
|
d_meshData[0].vars.push_back(BlobIDVar);
|
|
|
|
|
// Initialize the comms
|
|
|
|
|
MPI_Comm_dup(MPI_COMM_WORLD,&d_comm);
|
|
|
|
|
for (int i=0; i<1024; i++) {
|
|
|
|
|
d_comms[i] = MPI_COMM_NULL;
|
|
|
|
|
d_comm_used[i] = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
runAnalysis::~runAnalysis( )
|
|
|
|
|
{
|
|
|
|
|
// Finish processing analysis
|
|
|
|
|
finish();
|
|
|
|
|
// Clear internal data
|
|
|
|
|
MPI_Comm_free( &d_comm );
|
|
|
|
|
for (int i=0; i<1024; i++) {
|
|
|
|
|
if ( d_comms[i] != MPI_COMM_NULL )
|
|
|
|
|
MPI_Comm_free(&d_comms[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void runAnalysis::finish( )
|
|
|
|
|
{
|
2018-03-08 16:04:57 -05:00
|
|
|
PROFILE_START("finish");
|
2018-03-08 13:03:22 -05:00
|
|
|
// Wait for the work items to finish
|
|
|
|
|
d_tpool.wait_pool_finished();
|
|
|
|
|
// Clear the wait ids
|
|
|
|
|
d_wait_blobID.reset();
|
|
|
|
|
d_wait_analysis.reset();
|
|
|
|
|
d_wait_vis.reset();
|
|
|
|
|
d_wait_restart.reset();
|
|
|
|
|
// Syncronize
|
|
|
|
|
MPI_Barrier( d_comm );
|
2018-03-08 16:04:57 -05:00
|
|
|
PROFILE_STOP("finish");
|
2018-03-08 13:03:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
|
* Set the thread affinities *
|
|
|
|
|
******************************************************************/
|
|
|
|
|
void print( const std::vector<int>& ids )
|
|
|
|
|
{
|
|
|
|
|
if ( ids.empty() )
|
|
|
|
|
return;
|
|
|
|
|
printf("%i",ids[0]);
|
|
|
|
|
for (size_t i=1; i<ids.size(); i++)
|
|
|
|
|
printf(", %i",ids[i]);
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
2018-03-09 12:59:59 -05:00
|
|
|
void runAnalysis::createThreads( const std::string& method, int N_threads )
|
2018-03-08 13:03:22 -05:00
|
|
|
{
|
2018-03-09 12:59:59 -05:00
|
|
|
// Check if we are not using analysis threads
|
|
|
|
|
if ( method == "none" )
|
|
|
|
|
return;
|
|
|
|
|
// Check if we have thread support
|
|
|
|
|
int thread_support;
|
|
|
|
|
MPI_Query_thread( &thread_support );
|
|
|
|
|
if ( thread_support < MPI_THREAD_MULTIPLE ) {
|
|
|
|
|
std::cerr << "Warning: Failed to start MPI with necessary thread support, thread support will be disabled" << std::endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Create the threads
|
|
|
|
|
const auto cores = d_tpool.getProcessAffinity();
|
|
|
|
|
if ( cores.empty() ) {
|
|
|
|
|
// We were not able to get the cores for the process
|
|
|
|
|
d_tpool.setNumThreads( N_threads );
|
|
|
|
|
} else if ( method == "default" ) {
|
|
|
|
|
// Create the given number of threads, but let the OS manage affinities
|
|
|
|
|
d_tpool.setNumThreads( N_threads );
|
|
|
|
|
} else if ( method == "independent" ) {
|
|
|
|
|
int N = cores.size() - 1;
|
|
|
|
|
d_tpool.setNumThreads( N );
|
|
|
|
|
d_tpool.setThreadAffinity( { cores[0] } );
|
|
|
|
|
for ( int i=0; i<N; i++)
|
|
|
|
|
d_tpool.setThreadAffinity( i, { cores[i+1] } );
|
|
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
// Print the current affinities
|
|
|
|
|
if ( d_rank == 0 ) {
|
|
|
|
|
printf("Affinities - rank 0:\n");
|
|
|
|
|
printf("Main: ");
|
|
|
|
|
print(d_tpool.getProcessAffinity());
|
|
|
|
|
for (int i=0; i<d_tpool.getNumThreads(); i++) {
|
|
|
|
|
printf("Thread %i: ",i+1);
|
|
|
|
|
print(d_tpool.getThreadAffinity(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
|
* Check which analysis we want to perform *
|
|
|
|
|
******************************************************************/
|
|
|
|
|
AnalysisType runAnalysis::computeAnalysisType( int timestep )
|
|
|
|
|
{
|
2018-02-06 10:50:43 -05:00
|
|
|
AnalysisType type = AnalysisType::AnalyzeNone;
|
2018-03-08 13:03:22 -05:00
|
|
|
if ( timestep%d_analysis_interval + 8 == d_analysis_interval ) {
|
2015-08-22 11:03:46 -04:00
|
|
|
// Copy the phase indicator field for the earlier timestep
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::CopyPhaseIndicator;
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
if ( timestep%d_blobid_interval == 0 ) {
|
2015-08-25 17:10:15 -04:00
|
|
|
// Identify blobs and update global ids in time
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::IdentifyBlobs;
|
2015-08-25 17:10:15 -04:00
|
|
|
}
|
2018-02-06 10:50:43 -05:00
|
|
|
/*#ifdef USE_CUDA
|
2015-09-16 11:00:36 -04:00
|
|
|
if ( tpool.getQueueSize()<=3 && tpool.getNumThreads()>0 && timestep%50==0 ) {
|
2015-09-14 17:30:35 -04:00
|
|
|
// Keep a few blob identifications queued up to keep the processors busy,
|
|
|
|
|
// allowing us to track the blobs as fast as possible
|
|
|
|
|
// Add more detailed estimates of the update frequency required to track blobs
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::IdentifyBlobs;
|
2015-09-14 17:30:35 -04:00
|
|
|
}
|
2018-02-06 10:50:43 -05:00
|
|
|
#endif */
|
2018-05-07 06:57:24 -04:00
|
|
|
if ( timestep%d_analysis_interval + 4 == d_analysis_interval ) {
|
2015-08-25 17:10:15 -04:00
|
|
|
// Copy the averages to the CPU (and identify blobs)
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::CopySimState;
|
|
|
|
|
type |= AnalysisType::IdentifyBlobs;
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
if ( timestep%d_analysis_interval == 0 ) {
|
2015-08-25 17:10:15 -04:00
|
|
|
// Run the analysis
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::ComputeAverages;
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
if (timestep%d_restart_interval == 0) {
|
2015-08-25 17:10:15 -04:00
|
|
|
// Write the restart file
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::CreateRestart;
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
if (timestep%d_restart_interval == 0) {
|
2015-11-10 14:47:52 -05:00
|
|
|
// Write the visualization data
|
2018-02-06 10:50:43 -05:00
|
|
|
type |= AnalysisType::WriteVis;
|
|
|
|
|
type |= AnalysisType::CopySimState;
|
|
|
|
|
type |= AnalysisType::IdentifyBlobs;
|
2015-11-10 14:47:52 -05:00
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
|
* Run the analysis *
|
|
|
|
|
******************************************************************/
|
|
|
|
|
void runAnalysis::run( int timestep, TwoPhase& Averages, const double *Phi,
|
2018-05-06 22:17:45 -04:00
|
|
|
double *Pressure, double *Velocity, double *fq, double *Den)
|
2018-03-08 13:03:22 -05:00
|
|
|
{
|
|
|
|
|
int N = d_N[0]*d_N[1]*d_N[2];
|
|
|
|
|
|
|
|
|
|
// Check which analysis steps we need to perform
|
|
|
|
|
auto type = computeAnalysisType( timestep );
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( type == AnalysisType::AnalyzeNone )
|
2015-08-22 11:03:46 -04:00
|
|
|
return;
|
|
|
|
|
|
2018-03-08 13:03:22 -05:00
|
|
|
// Check how may queued items we have
|
|
|
|
|
if ( d_tpool.N_queued() > 20 ) {
|
|
|
|
|
std::cerr << "Analysis queue is getting behind, waiting ...\n";
|
|
|
|
|
finish();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PROFILE_START("run");
|
2015-08-22 11:03:46 -04:00
|
|
|
|
|
|
|
|
// Copy the appropriate variables to the host (so we can spawn new threads)
|
2016-11-24 11:26:51 -05:00
|
|
|
ScaLBL_DeviceBarrier();
|
2015-08-22 11:03:46 -04:00
|
|
|
PROFILE_START("Copy data to host",1);
|
2015-08-24 14:11:26 -04:00
|
|
|
std::shared_ptr<DoubleArray> phase;
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::CopyPhaseIndicator) ||
|
2018-05-07 06:57:24 -04:00
|
|
|
matches(type,AnalysisType::ComputeAverages) ||
|
|
|
|
|
matches(type,AnalysisType::CopySimState) ||
|
|
|
|
|
matches(type,AnalysisType::IdentifyBlobs) )
|
2015-08-22 11:03:46 -04:00
|
|
|
{
|
2018-05-07 06:57:24 -04:00
|
|
|
phase = std::shared_ptr<DoubleArray>(new DoubleArray(d_N[0],d_N[1],d_N[2]));
|
|
|
|
|
//ScaLBL_CopyToHost(phase->data(),Phi,N*sizeof(double));
|
|
|
|
|
// try 2 d_ScaLBL_Comm.RegularLayout(d_Map,Phi,Averages.Phase);
|
|
|
|
|
// memcpy(Averages.Phase.data(),phase->data(),N*sizeof(double));
|
|
|
|
|
int Nx = d_N[0];
|
|
|
|
|
int Ny = d_N[1];
|
|
|
|
|
int Nz = d_N[2];
|
|
|
|
|
double *TmpDat;
|
|
|
|
|
double value;
|
|
|
|
|
TmpDat = new double [d_Np];
|
|
|
|
|
ScaLBL_CopyToHost(&TmpDat[0],&Phi[0], d_Np*sizeof(double));
|
|
|
|
|
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;
|
|
|
|
|
int idx=d_Map(i,j,k);
|
|
|
|
|
if (!(idx<0)){
|
|
|
|
|
double value=TmpDat[idx];
|
|
|
|
|
//regdata(i,j,k)=value;
|
|
|
|
|
phase->data()[n]=value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete [] TmpDat;
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::CopyPhaseIndicator) ) {
|
2016-05-25 14:00:28 -04:00
|
|
|
memcpy(Averages.Phase_tplus.data(),phase->data(),N*sizeof(double));
|
2018-03-08 13:03:22 -05:00
|
|
|
//Averages.ColorToSignedDistance(d_beta,Averages.Phase,Averages.Phase_tplus);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::ComputeAverages) ) {
|
2016-05-25 14:00:28 -04:00
|
|
|
memcpy(Averages.Phase_tminus.data(),phase->data(),N*sizeof(double));
|
2018-03-08 13:03:22 -05:00
|
|
|
//Averages.ColorToSignedDistance(d_beta,Averages.Phase,Averages.Phase_tminus);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::CopySimState) ) {
|
2015-08-22 11:03:46 -04:00
|
|
|
// Copy the members of Averages to the cpu (phase was copied above)
|
2015-11-10 14:47:52 -05:00
|
|
|
PROFILE_START("Copy-Pressure",1);
|
2018-03-08 13:03:22 -05:00
|
|
|
ScaLBL_D3Q19_Pressure(fq,Pressure,d_Np);
|
|
|
|
|
ScaLBL_D3Q19_Momentum(fq,Velocity,d_Np);
|
2016-11-24 11:26:51 -05:00
|
|
|
ScaLBL_DeviceBarrier();
|
2015-11-10 14:47:52 -05:00
|
|
|
PROFILE_STOP("Copy-Pressure",1);
|
2015-11-10 16:42:55 -05:00
|
|
|
PROFILE_START("Copy-Wait",1);
|
|
|
|
|
PROFILE_STOP("Copy-Wait",1);
|
2015-11-14 11:06:31 -05:00
|
|
|
PROFILE_START("Copy-State",1);
|
2016-05-25 14:00:28 -04:00
|
|
|
memcpy(Averages.Phase.data(),phase->data(),N*sizeof(double));
|
2018-03-08 13:03:22 -05:00
|
|
|
d_ScaLBL_Comm.RegularLayout(d_Map,Pressure,Averages.Press);
|
|
|
|
|
d_ScaLBL_Comm.RegularLayout(d_Map,&Velocity[0],Averages.Vel_x);
|
|
|
|
|
d_ScaLBL_Comm.RegularLayout(d_Map,&Velocity[d_Np],Averages.Vel_y);
|
|
|
|
|
d_ScaLBL_Comm.RegularLayout(d_Map,&Velocity[2*d_Np],Averages.Vel_z);
|
2015-11-14 11:06:31 -05:00
|
|
|
PROFILE_STOP("Copy-State",1);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2018-01-26 09:29:48 -05:00
|
|
|
std::shared_ptr<double> cDen, cfq;
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::CreateRestart) ) {
|
2015-08-22 11:03:46 -04:00
|
|
|
// Copy restart data to the CPU
|
2018-04-06 11:04:58 -04:00
|
|
|
//cDen = std::shared_ptr<double>(new double[2*d_Np],DeleteArray<double>);
|
|
|
|
|
//cfq = std::shared_ptr<double>(new double[19*d_Np],DeleteArray<double>);
|
|
|
|
|
//ScaLBL_CopyToHost(cfq.get(),fq,19*d_Np*sizeof(double));
|
|
|
|
|
//ScaLBL_CopyToHost(cDen.get(),Den,2*d_Np*sizeof(double));
|
|
|
|
|
//cPhi = std::shared_ptr<double>(new double[N],DeleteArray<double>);
|
|
|
|
|
//cDist = std::shared_ptr<double>(new double[N],DeleteArray<double>);
|
|
|
|
|
//ScaLBL_CopyToHost(cfq.get(),fq,19*d_Np*sizeof(double));
|
|
|
|
|
//ScaLBL_CopyToHost(cDen.get(),Den,2*d_Np*sizeof(double));
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
|
|
|
|
PROFILE_STOP("Copy data to host",1);
|
|
|
|
|
|
|
|
|
|
// Spawn threads to do blob identification work
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::IdentifyBlobs) ) {
|
2015-08-25 14:32:36 -04:00
|
|
|
BlobIDstruct new_index(new std::pair<int,IntArray>(0,IntArray()));
|
2015-08-24 14:11:26 -04:00
|
|
|
BlobIDstruct new_ids(new std::pair<int,IntArray>(0,IntArray()));
|
2015-08-25 14:32:36 -04:00
|
|
|
BlobIDList new_list(new std::vector<BlobIDType>());
|
2018-03-08 13:03:22 -05:00
|
|
|
auto work1 = new BlobIdentificationWorkItem1(timestep,d_N[0],d_N[1],d_N[2],d_rank_info,
|
|
|
|
|
phase,Averages.SDs,d_last_ids,new_index,new_ids,new_list,getComm());
|
|
|
|
|
auto work2 = new BlobIdentificationWorkItem2(timestep,d_N[0],d_N[1],d_N[2],d_rank_info,
|
|
|
|
|
phase,Averages.SDs,d_last_ids,new_index,new_ids,new_list,getComm());
|
|
|
|
|
work1->add_dependency(d_wait_blobID);
|
|
|
|
|
work2->add_dependency(d_tpool.add_work(work1));
|
|
|
|
|
d_wait_blobID = d_tpool.add_work(work2);
|
|
|
|
|
d_last_index = new_index;
|
|
|
|
|
d_last_ids = new_ids;
|
|
|
|
|
d_last_id_map = new_list;
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Spawn threads to do the analysis work
|
2018-02-06 10:50:43 -05:00
|
|
|
if ( matches(type,AnalysisType::ComputeAverages) ) {
|
2018-03-08 13:03:22 -05:00
|
|
|
auto work = new AnalysisWorkItem(type,timestep,Averages,d_last_index,d_last_id_map,d_beta);
|
|
|
|
|
work->add_dependency(d_wait_blobID);
|
|
|
|
|
work->add_dependency(d_wait_analysis);
|
|
|
|
|
work->add_dependency(d_wait_vis); // Make sure we are done using analysis before modifying
|
|
|
|
|
d_wait_analysis = d_tpool.add_work(work);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Spawn a thread to write the restart file
|
2018-04-06 11:04:58 -04:00
|
|
|
// if ( matches(type,AnalysisType::CreateRestart) ) {
|
|
|
|
|
if (timestep%d_restart_interval==0){
|
2018-02-06 10:50:43 -05:00
|
|
|
/* if (pBC) {
|
|
|
|
|
err = fabs(sat_w - sat_w_previous);
|
|
|
|
|
sat_w_previous = sat_w;
|
|
|
|
|
if (rank==0){
|
|
|
|
|
printf("Timestep %i: change in saturation since last checkpoint is %f \n",timestep,err);
|
|
|
|
|
}
|
|
|
|
|
} */
|
|
|
|
|
// Retain the timestep associated with the restart files
|
2018-03-08 13:03:22 -05:00
|
|
|
if (d_rank==0) {
|
2018-02-06 10:50:43 -05:00
|
|
|
FILE *Rst = fopen("Restart.txt","w");
|
2018-02-09 23:03:16 -05:00
|
|
|
fprintf(Rst,"%i\n",timestep+4);
|
2018-02-06 10:50:43 -05:00
|
|
|
fclose(Rst);
|
|
|
|
|
}
|
2015-08-22 11:03:46 -04:00
|
|
|
// Write the restart file (using a seperate thread)
|
2018-04-06 11:04:58 -04:00
|
|
|
auto work = new WriteRestartWorkItem(d_restartFile.c_str(),*phase,Averages.SDs,N);
|
2018-03-08 13:03:22 -05:00
|
|
|
work->add_dependency(d_wait_restart);
|
|
|
|
|
d_wait_restart = d_tpool.add_work(work);
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
2015-11-10 14:47:52 -05:00
|
|
|
|
|
|
|
|
// Save the results for visualization
|
2018-04-06 11:04:58 -04:00
|
|
|
// if ( matches(type,AnalysisType::CreateRestart) ) {
|
|
|
|
|
if (timestep%d_restart_interval==0){
|
2015-11-10 14:47:52 -05:00
|
|
|
// Write the vis files
|
2018-03-08 13:03:22 -05:00
|
|
|
auto work = new WriteVisWorkItem( timestep, d_meshData, Averages, d_fillData, getComm() );
|
|
|
|
|
work->add_dependency(d_wait_blobID);
|
|
|
|
|
work->add_dependency(d_wait_analysis);
|
|
|
|
|
work->add_dependency(d_wait_vis);
|
|
|
|
|
d_wait_vis = d_tpool.add_work(work);
|
2015-11-10 14:47:52 -05:00
|
|
|
}
|
2018-03-08 13:03:22 -05:00
|
|
|
PROFILE_STOP("run");
|
2015-08-22 11:03:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-11-10 14:47:52 -05:00
|
|
|
|