// -*- c++ -*- /*========================================================================= Program: Visualization Toolkit Module: vtkTemporalRanges.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. =========================================================================*/ /*---------------------------------------------------------------------------- Copyright (c) Sandia Corporation See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. ----------------------------------------------------------------------------*/ #include "vtkTemporalRanges.h" #include "vtkCellData.h" #include "vtkCompositeDataIterator.h" #include "vtkCompositeDataSet.h" #include "vtkDataArray.h" #include "vtkDataSet.h" #include "vtkDoubleArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStringArray.h" #include "vtkTable.h" #include "vtkTypeTraits.h" #include "vtkSmartPointer.h" #define VTK_CREATE(type, name) \ vtkSmartPointer name = vtkSmartPointer::New() #include #include #include #include //============================================================================= // This is not super portable. We really should be using vtkMath::IsNan. The // only reason we are not is so that we can copy this code to the 3.6 branch of // ParaView where that method does not yet exist. Once we move past that, this // section should go away and all instances of isnan should be replaced with // vtkMath::IsNan. #ifndef isnan // This is compiler specific not platform specific: MinGW doesn't need that. # if defined(_MSC_VER) || defined(__BORLANDC__) # include # define isnan(x) _isnan(x) # endif #endif //============================================================================= namespace vtkTemporalRangesNamespace{ const int AVERAGE_ROW = vtkTemporalRanges::AVERAGE_ROW; const int MINIMUM_ROW = vtkTemporalRanges::MINIMUM_ROW; const int MAXIMUM_ROW = vtkTemporalRanges::MAXIMUM_ROW; const int COUNT_ROW = vtkTemporalRanges::COUNT_ROW; const int NUMBER_OF_ROWS = vtkTemporalRanges::NUMBER_OF_ROWS; inline void InitializeColumn(vtkDoubleArray *column) { column->SetNumberOfComponents(1); column->SetNumberOfTuples(NUMBER_OF_ROWS); column->SetValue(AVERAGE_ROW, 0.0); column->SetValue(MINIMUM_ROW, vtkTypeTraits::Max()); column->SetValue(MAXIMUM_ROW, vtkTypeTraits::Min()); column->SetValue(COUNT_ROW, 0.0); } inline void AccumulateValue(double value, vtkDoubleArray *column) { if (!isnan(value)) { column->SetValue(AVERAGE_ROW, value + column->GetValue(AVERAGE_ROW)); column->SetValue(MINIMUM_ROW, std::min(column->GetValue(MINIMUM_ROW), value)); column->SetValue(MAXIMUM_ROW, std::max(column->GetValue(MAXIMUM_ROW), value)); column->SetValue(COUNT_ROW, column->GetValue(COUNT_ROW) + 1); } } inline void AccumulateColumn(vtkDoubleArray *source, vtkDoubleArray *target) { double targetCount = target->GetValue(COUNT_ROW); double sourceCount = source->GetValue(COUNT_ROW); double totalCount = targetCount + sourceCount; double targetTotal = targetCount*target->GetValue(AVERAGE_ROW); double sourceTotal = sourceCount*source->GetValue(AVERAGE_ROW); target->SetValue(AVERAGE_ROW, (targetTotal + sourceTotal)/totalCount); target->SetValue(MINIMUM_ROW, std::min(source->GetValue(MINIMUM_ROW), target->GetValue(MINIMUM_ROW))); target->SetValue(MAXIMUM_ROW, std::max(source->GetValue(MAXIMUM_ROW), target->GetValue(MAXIMUM_ROW))); target->SetValue(COUNT_ROW, totalCount); } }; using namespace vtkTemporalRangesNamespace; //============================================================================= vtkStandardNewMacro(vtkTemporalRanges); //----------------------------------------------------------------------------- vtkTemporalRanges::vtkTemporalRanges() { this->CurrentTimeIndex = 0; } vtkTemporalRanges::~vtkTemporalRanges() { } void vtkTemporalRanges::PrintSelf(ostream &os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //----------------------------------------------------------------------------- int vtkTemporalRanges::FillInputPortInformation(int port, vtkInformation *info) { if (port == 0) { info->Remove(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE()); info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkCompositeDataSet"); return 1; } return 0; } //----------------------------------------------------------------------------- int vtkTemporalRanges::RequestInformation( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { vtkInformation *outInfo = outputVector->GetInformationObject(0); // The output data of this filter has no time associated with it. It is the // result of computations that happen over all time. outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); return 1; } //----------------------------------------------------------------------------- int vtkTemporalRanges::RequestUpdateExtent( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *vtkNotUsed(outputVector)) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); // The RequestData method will tell the pipeline executive to iterate the // upstream pipeline to get each time step in order. The executive in turn // will call this method to get the extent request for each iteration (in this // case the time step). double *inTimes = inInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); if (inTimes) { inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), inTimes[this->CurrentTimeIndex]); } return 1; } //----------------------------------------------------------------------------- int vtkTemporalRanges::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkTable *output = vtkTable::GetData(outputVector); if (this->CurrentTimeIndex == 0) { // First execution. Initialize table. this->InitializeTable(output); } vtkCompositeDataSet *compositeInput = vtkCompositeDataSet::GetData(inInfo); vtkDataSet *dsInput = vtkDataSet::GetData(inInfo); if (compositeInput) { this->AccumulateCompositeData(compositeInput, output); } else if (dsInput) { this->AccumulateDataSet(dsInput, output); } else { vtkWarningMacro(<< "Unknown data type : " << vtkDataObject::GetData(inputVector[0])->GetClassName()); return 0; } this->CurrentTimeIndex++; if ( this->CurrentTimeIndex < inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) ) { // There is still more to do. request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); } else { // We are done. Finish up. request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); this->CurrentTimeIndex = 0; } return 1; } //----------------------------------------------------------------------------- void vtkTemporalRanges::InitializeTable(vtkTable *output) { output->Initialize(); VTK_CREATE(vtkStringArray, rangeName); rangeName->SetName("Range Name"); rangeName->SetNumberOfComponents(1); rangeName->SetNumberOfTuples(NUMBER_OF_ROWS); rangeName->SetValue(AVERAGE_ROW, "Average"); rangeName->SetValue(MINIMUM_ROW, "Minimum"); rangeName->SetValue(MAXIMUM_ROW, "Maximum"); rangeName->SetValue(COUNT_ROW, "Count"); output->AddColumn(rangeName); } //----------------------------------------------------------------------------- void vtkTemporalRanges::AccumulateCompositeData(vtkCompositeDataSet *input, vtkTable *output) { vtkSmartPointer iter; iter.TakeReference(input->NewIterator()); for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem()) { vtkDataObject *dataobj = iter->GetCurrentDataObject(); vtkDataSet *dataset = vtkDataSet::SafeDownCast(dataobj); if (dataset) { this->AccumulateDataSet(dataset, output); } else if (dataobj) { vtkWarningMacro(<< "Unknown data type : " << dataobj->GetClassName()); } } } //----------------------------------------------------------------------------- void vtkTemporalRanges::AccumulateDataSet(vtkDataSet *input, vtkTable *output) { this->AccumulateFields(input->GetPointData(), output); this->AccumulateFields(input->GetCellData(), output); this->AccumulateFields(input->GetFieldData(), output); } //----------------------------------------------------------------------------- void vtkTemporalRanges::AccumulateFields(vtkFieldData *fields, vtkTable *output) { for (int i = 0; i < fields->GetNumberOfArrays(); i++) { vtkDataArray *array = fields->GetArray(i); if (array) { this->AccumulateArray(array, output); } } } //----------------------------------------------------------------------------- void vtkTemporalRanges::AccumulateArray(vtkDataArray *field, vtkTable *output) { int numComponents = field->GetNumberOfComponents(); vtkIdType numTuples = field->GetNumberOfTuples(); vtkDoubleArray *magnitudeColumn = NULL; std::vector componentColumns(numComponents); VTK_CREATE(vtkDoubleArray, magnitudeAccumulate); std::vector > componentAccumulate(numComponents); if (numComponents > 1) { magnitudeColumn = this->GetColumn(output, field->GetName(), -1); InitializeColumn(magnitudeAccumulate); for (int i = 0; i < numComponents; i++) { componentColumns[i] = this->GetColumn(output, field->GetName(), i); componentAccumulate[i] = vtkSmartPointer::New(); InitializeColumn(componentAccumulate[i]); } } else { componentColumns[0] = this->GetColumn(output, field->GetName()); componentAccumulate[0] = vtkSmartPointer::New(); InitializeColumn(componentAccumulate[0]); } for (vtkIdType i = 0; i < numTuples; i++) { double mag = 0.0; for (int j = 0; j < numComponents; j++) { double value = field->GetComponent(i, j); mag += value*value; AccumulateValue(value, componentAccumulate[j]); } if (magnitudeColumn) { mag = sqrt(mag); AccumulateValue(mag, magnitudeAccumulate); } } for (int j = 0; j < numComponents; j++) { componentAccumulate[j]->SetValue(AVERAGE_ROW, ( componentAccumulate[j]->GetValue(AVERAGE_ROW) / componentAccumulate[j]->GetValue(COUNT_ROW) )); AccumulateColumn(componentAccumulate[j], componentColumns[j]); } if (magnitudeColumn) { magnitudeAccumulate->SetValue(AVERAGE_ROW, ( magnitudeAccumulate->GetValue(AVERAGE_ROW) / magnitudeAccumulate->GetValue(COUNT_ROW))); AccumulateColumn(magnitudeAccumulate, magnitudeColumn); } } //----------------------------------------------------------------------------- void vtkTemporalRanges::AccumulateTable(vtkTable *source, vtkTable *target) { for (vtkIdType c = 0; c < source->GetNumberOfColumns(); c++) { vtkDoubleArray *sourceColumn = vtkDoubleArray::SafeDownCast(source->GetColumn(c)); if (!sourceColumn) continue; vtkDoubleArray *targetColumn = this->GetColumn(target, sourceColumn->GetName()); AccumulateColumn(sourceColumn, targetColumn); } } //----------------------------------------------------------------------------- vtkDoubleArray *vtkTemporalRanges::GetColumn(vtkTable *table, const char *name, int component) { std::ostringstream fullname; fullname << name << "_"; if (component < 0) { fullname << "M"; } else { fullname << component; } std::string fullnamestring = fullname.str(); return this->GetColumn(table, fullnamestring.c_str()); } //----------------------------------------------------------------------------- vtkDoubleArray *vtkTemporalRanges::GetColumn(vtkTable *table, const char *name) { vtkAbstractArray *abstractArray = table->GetColumnByName(name); vtkDoubleArray *array = vtkDoubleArray::SafeDownCast(abstractArray); if (!array) { if (abstractArray) { table->RemoveColumnByName(name); } array = vtkDoubleArray::New(); array->SetName(name); InitializeColumn(array); table->AddColumn(array); array->Delete(); //Reference held by table. } return array; }