Files
ThirdParty-6/ParaView-5.0.1/VTK/IO/Parallel/vtkPOpenFOAMReader.cxx

541 lines
17 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkPOpenFOAMReader.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// This class was developed by Takuya Oshima at Niigata University,
// Japan (oshima@eng.niigata-u.ac.jp).
#include "vtkPOpenFOAMReader.h"
#include "vtkAppendCompositeDataLeaves.h"
#include "vtkCharArray.h"
#include "vtkCollection.h"
#include "vtkDataArraySelection.h"
#include "vtkDirectory.h"
#include "vtkDoubleArray.h"
#include "vtkFieldData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkSortDataArray.h"
#include "vtkStdString.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkStringArray.h"
vtkStandardNewMacro(vtkPOpenFOAMReader);
vtkCxxSetObjectMacro(vtkPOpenFOAMReader, Controller, vtkMultiProcessController);
//-----------------------------------------------------------------------------
vtkPOpenFOAMReader::vtkPOpenFOAMReader()
{
this->Controller = NULL;
this->SetController(vtkMultiProcessController::GetGlobalController());
if (this->Controller == NULL)
{
this->NumProcesses = 1;
this->ProcessId = 0;
}
else
{
this->NumProcesses = this->Controller->GetNumberOfProcesses();
this->ProcessId = this->Controller->GetLocalProcessId();
}
this->CaseType = RECONSTRUCTED_CASE;
this->MTimeOld = 0;
}
//-----------------------------------------------------------------------------
vtkPOpenFOAMReader::~vtkPOpenFOAMReader()
{
this->SetController(NULL);
}
//-----------------------------------------------------------------------------
void vtkPOpenFOAMReader::PrintSelf(ostream &os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "Case Type: " << this->CaseType << endl;
os << indent << "MTimeOld: " << this->MTimeOld << endl;
os << indent << "Number of Processes: " << this->NumProcesses << endl;
os << indent << "Process Id: " << this->ProcessId << endl;
os << indent << "Controller: " << this->Controller << endl;
}
//-----------------------------------------------------------------------------
void vtkPOpenFOAMReader::SetCaseType(const int t)
{
if (this->CaseType != t)
{
this->CaseType = static_cast<caseType>(t);
this->Refresh = true;
this->Modified();
}
}
//-----------------------------------------------------------------------------
int vtkPOpenFOAMReader::RequestInformation(vtkInformation *request,
vtkInformationVector **inputVector, vtkInformationVector *outputVector)
{
if (this->CaseType == RECONSTRUCTED_CASE)
{
int ret = 1;
if (this->ProcessId == 0)
{
ret = this->Superclass::RequestInformation(request, inputVector,
outputVector);
}
if (this->NumProcesses > 1)
{
// if there was an error in process 0 abort all processes
this->BroadcastStatus(ret);
if (ret == 0)
{
vtkErrorMacro(<< "The master process returned an error.");
return 0;
}
vtkDoubleArray *timeValues;
if (this->ProcessId == 0)
{
timeValues = this->Superclass::GetTimeValues();
}
else
{
timeValues = vtkDoubleArray::New();
}
this->Controller->Broadcast(timeValues, 0);
if (this->ProcessId != 0)
{
this->Superclass::SetTimeInformation(outputVector, timeValues);
timeValues->Delete();
this->Superclass::Refresh = false;
}
this->GatherMetaData(); // pvserver deadlocks without this
}
return ret;
}
if (!this->Superclass::FileName || strlen(this->Superclass::FileName) == 0)
{
vtkErrorMacro("FileName has to be specified!");
return 0;
}
if (*this->Superclass::FileNameOld != this->Superclass::FileName
|| this->Superclass::ListTimeStepsByControlDict
!= this->Superclass::ListTimeStepsByControlDictOld
|| this->Superclass::Refresh)
{
// retain selection status when just refreshing a case
if (*this->Superclass::FileNameOld != "" && *this->Superclass::FileNameOld != this->Superclass::FileName)
{
// clear selections
this->Superclass::CellDataArraySelection->RemoveAllArrays();
this->Superclass::PointDataArraySelection->RemoveAllArrays();
this->Superclass::LagrangianDataArraySelection->RemoveAllArrays();
this->Superclass::PatchDataArraySelection->RemoveAllArrays();
}
*this->Superclass::FileNameOld = vtkStdString(this->FileName);
this->Superclass::Readers->RemoveAllItems();
this->Superclass::NumberOfReaders = 0;
vtkStringArray *procNames = vtkStringArray::New();
vtkDoubleArray *timeValues;
// recreate case information
vtkStdString masterCasePath, controlDictPath;
this->Superclass::CreateCasePath(masterCasePath, controlDictPath);
this->Superclass::CreateCharArrayFromString(this->Superclass::CasePath,
"CasePath", masterCasePath);
int ret = 1;
if (this->ProcessId == 0)
{
// search and list processor subdirectories
vtkDirectory *dir = vtkDirectory::New();
if (!dir->Open(masterCasePath.c_str()))
{
vtkErrorMacro(<< "Can't open " << masterCasePath.c_str());
dir->Delete();
this->BroadcastStatus(ret = 0);
return 0;
}
vtkIntArray *procNos = vtkIntArray::New();
for (int fileI = 0; fileI < dir->GetNumberOfFiles(); fileI++)
{
const vtkStdString subDir(dir->GetFile(fileI));
if (subDir.substr(0, 9) == "processor")
{
const vtkStdString procNoStr(subDir.substr(9, vtkStdString::npos));
char *conversionEnd;
const int procNo = strtol(procNoStr.c_str(), &conversionEnd, 10);
if (procNoStr.c_str() + procNoStr.length() == conversionEnd && procNo
>= 0)
{
procNos->InsertNextValue(procNo);
procNames->InsertNextValue(subDir);
}
}
}
procNos->Squeeze();
procNames->Squeeze();
dir->Delete();
// sort processor subdirectories by processor numbers
vtkSortDataArray::Sort(procNos, procNames);
procNos->Delete();
// get time directories from the first processor subdirectory
if (procNames->GetNumberOfTuples() > 0)
{
vtkOpenFOAMReader *masterReader = vtkOpenFOAMReader::New();
masterReader->SetFileName(this->FileName);
masterReader->SetParent(this);
if (!masterReader->MakeInformationVector(outputVector, procNames
->GetValue(0)) || !masterReader->MakeMetaDataAtTimeStep(true))
{
procNames->Delete();
masterReader->Delete();
this->BroadcastStatus(ret = 0);
return 0;
}
this->Superclass::Readers->AddItem(masterReader);
timeValues = masterReader->GetTimeValues();
masterReader->Delete();
}
else
{
timeValues = vtkDoubleArray::New();
this->Superclass::SetTimeInformation(outputVector, timeValues);
}
}
else
{
timeValues = vtkDoubleArray::New();
}
if (this->NumProcesses > 1)
{
// if there was an error in process 0 abort all processes
this->BroadcastStatus(ret);
if (ret == 0)
{
vtkErrorMacro(<< "The master process returned an error.");
timeValues->Delete(); // don't have to care about process 0
return 0;
}
this->Broadcast(procNames);
this->Controller->Broadcast(timeValues, 0);
if (this->ProcessId != 0)
{
this->Superclass::SetTimeInformation(outputVector, timeValues);
timeValues->Delete();
}
}
if (this->ProcessId == 0 && procNames->GetNumberOfTuples() == 0)
{
timeValues->Delete();
}
// create reader instances for other processor subdirectories
// skip processor0 since it's already created
for (int procI = (this->ProcessId ? this->ProcessId : this->NumProcesses); procI
< procNames->GetNumberOfTuples(); procI += this->NumProcesses)
{
vtkOpenFOAMReader *subReader = vtkOpenFOAMReader::New();
subReader->SetFileName(this->FileName);
subReader->SetParent(this);
// if getting metadata failed simply delete the reader instance
if (subReader->MakeInformationVector(NULL, procNames->GetValue(procI))
&& subReader->MakeMetaDataAtTimeStep(true))
{
this->Superclass::Readers->AddItem(subReader);
}
else
{
vtkWarningMacro(<<"Removing reader for processor subdirectory "
<< procNames->GetValue(procI).c_str());
}
subReader->Delete();
}
procNames->Delete();
this->GatherMetaData();
this->Superclass::Refresh = false;
}
outputVector->GetInformationObject(0)->Set(
CAN_HANDLE_PIECE_REQUEST(),
1);
return 1;
}
//-----------------------------------------------------------------------------
int vtkPOpenFOAMReader::RequestData(vtkInformation *request,
vtkInformationVector **inputVector, vtkInformationVector *outputVector)
{
if (this->CaseType == RECONSTRUCTED_CASE)
{
int ret = 1;
if (this->ProcessId == 0)
{
ret = this->Superclass::RequestData(request, inputVector, outputVector);
}
this->BroadcastStatus(ret);
this->GatherMetaData();
return ret;
}
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkMultiBlockDataSet
*output =
vtkMultiBlockDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
int ret = 1;
if (this->Superclass::Readers->GetNumberOfItems() > 0)
{
int nSteps = 0;
double requestedTimeValue(0);
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
{
requestedTimeValue
= outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
nSteps = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
if (nSteps > 0)
{
outInfo->Set(vtkDataObject::DATA_TIME_STEP(), requestedTimeValue);
}
}
vtkAppendCompositeDataLeaves *append = vtkAppendCompositeDataLeaves::New();
// append->AppendFieldDataOn();
vtkOpenFOAMReader *reader;
this->Superclass::CurrentReaderIndex = 0;
this->Superclass::Readers->InitTraversal();
while ((reader
= vtkOpenFOAMReader::SafeDownCast(this->Superclass::Readers->GetNextItemAsObject()))
!= NULL)
{
// even if the child readers themselves are not modified, mark
// them as modified if "this" has been modified, since they
// refer to the property of "this"
if ((nSteps > 0 && reader->SetTimeValue(requestedTimeValue))
|| this->MTimeOld != this->GetMTime())
{
reader->Modified();
}
if (reader->MakeMetaDataAtTimeStep(false))
{
append->AddInputConnection(reader->GetOutputPort());
}
}
this->GatherMetaData();
if (append->GetNumberOfInputConnections(0) == 0)
{
output->Initialize();
ret = 0;
}
else
{
// reader->RequestInformation() and RequestData() are called
// for all reader instances without setting UPDATE_TIME_STEPS
append->Update();
output->ShallowCopy(append->GetOutput());
}
append->Delete();
// known issue: output for process without sub-reader will not have CasePath
output->GetFieldData()->AddArray(this->Superclass::CasePath);
}
else
{
this->GatherMetaData();
// page 322 of The ParaView Guide says the output must be initialized
output->Initialize();
}
this->Superclass::UpdateStatus();
this->MTimeOld = this->GetMTime();
return ret;
}
//-----------------------------------------------------------------------------
void vtkPOpenFOAMReader::BroadcastStatus(int &status)
{
if (this->NumProcesses > 1)
{
this->Controller->Broadcast(&status, 1, 0);
}
}
//-----------------------------------------------------------------------------
void vtkPOpenFOAMReader::GatherMetaData()
{
if (this->NumProcesses > 1)
{
this->AllGather(this->Superclass::PatchDataArraySelection);
this->AllGather(this->Superclass::CellDataArraySelection);
this->AllGather(this->Superclass::PointDataArraySelection);
this->AllGather(this->Superclass::LagrangianDataArraySelection);
// omit removing duplicated entries of LagrangianPaths as well
// when the number of processes is 1 assuming there's no duplicate
// entry within a process
this->AllGather(this->Superclass::LagrangianPaths);
}
}
//-----------------------------------------------------------------------------
// Broadcast a vtkStringArray in process 0 to all processes
void vtkPOpenFOAMReader::Broadcast(vtkStringArray *sa)
{
vtkIdType lengths[2];
if (this->ProcessId == 0)
{
lengths[0] = sa->GetNumberOfTuples();
lengths[1] = 0;
for (int strI = 0; strI < sa->GetNumberOfTuples(); strI++)
{
lengths[1] += static_cast<vtkIdType>(sa->GetValue(strI).length()) + 1;
}
}
this->Controller->Broadcast(lengths, 2, 0);
char *contents = new char [lengths[1]];
if (this->ProcessId == 0)
{
for (int strI = 0, idx = 0; strI < sa->GetNumberOfTuples(); strI++)
{
const int len = static_cast<int>(sa->GetValue(strI).length()) + 1;
memmove(contents + idx, sa->GetValue(strI).c_str(), len);
idx += len;
}
}
this->Controller->Broadcast(contents, lengths[1], 0);
if (this->ProcessId != 0)
{
sa->Initialize();
sa->SetNumberOfTuples(lengths[0]);
for (int strI = 0, idx = 0; strI < lengths[0]; strI++)
{
sa->SetValue(strI, contents + idx);
idx += static_cast<int>(sa->GetValue(strI).length()) + 1;
}
}
delete [] contents;
}
//-----------------------------------------------------------------------------
// AllGather vtkStringArray from and to all processes
void vtkPOpenFOAMReader::AllGather(vtkStringArray *s)
{
vtkIdType length = 0;
for (int strI = 0; strI < s->GetNumberOfTuples(); strI++)
{
length += static_cast<vtkIdType>(s->GetValue(strI).length()) + 1;
}
vtkIdType *lengths = new vtkIdType [this->NumProcesses];
this->Controller->AllGather(&length, lengths, 1);
vtkIdType totalLength = 0;
vtkIdType *offsets = new vtkIdType [this->NumProcesses];
for (int procI = 0; procI < this->NumProcesses; procI++)
{
offsets[procI] = totalLength;
totalLength += lengths[procI];
}
char *allContents = new char [totalLength], *contents = new char [length];
for (int strI = 0, idx = 0; strI < s->GetNumberOfTuples(); strI++)
{
const int len = static_cast<int>(s->GetValue(strI).length()) + 1;
memmove(contents + idx, s->GetValue(strI).c_str(), len);
idx += len;
}
this->Controller->AllGatherV(contents, allContents, length, lengths, offsets);
delete [] contents;
delete [] lengths;
delete [] offsets;
s->Initialize();
for (int idx = 0; idx < totalLength; idx += static_cast<int>(strlen(allContents + idx)) + 1)
{
const char *str = allContents + idx;
// insert only when the same string is not found
if (s->LookupValue(str) == -1)
{
s->InsertNextValue(str);
}
}
s->Squeeze();
delete [] allContents;
}
//-----------------------------------------------------------------------------
// AllGather vtkDataArraySelections from and to all processes
void vtkPOpenFOAMReader::AllGather(vtkDataArraySelection *s)
{
vtkIdType length = 0;
for (int strI = 0; strI < s->GetNumberOfArrays(); strI++)
{
length += static_cast<vtkIdType>(strlen(s->GetArrayName(strI))) + 2;
}
vtkIdType *lengths = new vtkIdType [this->NumProcesses];
this->Controller->AllGather(&length, lengths, 1);
vtkIdType totalLength = 0;
vtkIdType *offsets = new vtkIdType [this->NumProcesses];
for (int procI = 0; procI < this->NumProcesses; procI++)
{
offsets[procI] = totalLength;
totalLength += lengths[procI];
}
char *allContents = new char [totalLength], *contents = new char [length];
for (int strI = 0, idx = 0; strI < s->GetNumberOfArrays(); strI++)
{
const char *arrayName = s->GetArrayName(strI);
contents[idx] = s->ArrayIsEnabled(arrayName);
const int len = static_cast<int>(strlen(arrayName)) + 1;
memmove(contents + idx + 1, arrayName, len);
idx += len + 1;
}
this->Controller->AllGatherV(contents, allContents, length, lengths, offsets);
delete [] contents;
delete [] lengths;
delete [] offsets;
// do not RemoveAllArray so that the previous arrays are preserved
// s->RemoveAllArrays();
for (int idx = 0; idx < totalLength; idx += static_cast<int>(strlen(allContents + idx + 1)) + 2)
{
const char *arrayName = allContents + idx + 1;
s->AddArray(arrayName);
if (allContents[idx] == 0)
{
s->DisableArray(arrayName);
}
else
{
s->EnableArray(arrayName);
}
}
delete [] allContents;
}