From c59a10be7765ae45bb17a23eb0a4e40c2e9ac1c3 Mon Sep 17 00:00:00 2001 From: Uwe Date: Mon, 6 Feb 2023 22:51:05 +0100 Subject: [PATCH] [FEM] add support to show absolute value result fields - for harmonically driven forces, the results of course also have an imaginary part. Elmer outputs the real and the imaginary parts as separate result field. However, for several applications one needs the absolute (sqrt(Re^2+Im^2) - therefore offer also absolute field if there are real/imaginary results --- src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp | 85 ++++++++++++++++++- src/Mod/Fem/Gui/ViewProviderFemPostObject.h | 3 +- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp index 86506dd53f..79dd39ac29 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.cpp @@ -37,6 +37,7 @@ # include # include +# include # include # include @@ -623,13 +624,24 @@ void ViewProviderFemPostObject::updateData(const App::Property* p) { } } -bool ViewProviderFemPostObject::setupPipeline() { - +bool ViewProviderFemPostObject::setupPipeline() +{ vtkDataObject* data = static_cast(getObject())->Data.getValue(); if (!data) return false; + // check all fields if there is a real/imaginary one and if so + // add a field with an absolute value + vtkSmartPointer SPdata = data; + vtkDataSet* dset = vtkDataSet::SafeDownCast(SPdata); + std::string FieldName; + auto numFields = dset->GetPointData()->GetNumberOfArrays(); + for (int i = 0; i < numFields; ++i) { + FieldName = std::string(dset->GetPointData()->GetArrayName(i)); + addAbsoluteField(dset, FieldName); + } + m_outline->SetInputData(data); m_surface->SetInputData(data); m_wireframe->SetInputData(data); @@ -638,7 +650,6 @@ bool ViewProviderFemPostObject::setupPipeline() { return true; } - void ViewProviderFemPostObject::onChanged(const App::Property* prop) { if (m_blockPropertyChanges) @@ -685,7 +696,6 @@ bool ViewProviderFemPostObject::doubleClicked() { return true; } - bool ViewProviderFemPostObject::setEdit(int ModNum) { if (ModNum == ViewProvider::Default || ModNum == 1) { @@ -842,3 +852,70 @@ void ViewProviderFemPostObject::onSelectionChanged(const Gui::SelectionChanges & updateMaterial(); } } + +// if there is a real and an imaginary field, an absolute field is added +void ViewProviderFemPostObject::addAbsoluteField(vtkDataSet* dset, std::string FieldName) +{ + // real field names have the suffix " re", given by Elmer + // if the field does not have this suffix, we can return + auto suffix = FieldName.substr(FieldName.size() - 3, FieldName.size() - 1); + if (strcmp(suffix.c_str(), " re") != 0) + return; + + // absolute fields might have already been created, then do nothing + auto strAbsoluteFieldName = FieldName.substr(0, FieldName.size() - 2) + "abs"; + vtkDataArray* testArray = dset->GetPointData()->GetArray(strAbsoluteFieldName.c_str()); + if (testArray) + return; + + // safety check + vtkDataArray* realDdata = dset->GetPointData()->GetArray(FieldName.c_str()); + if (!realDdata) + return; + + // now check if the imaginary counterpart exists + auto strImaginaryFieldName = FieldName.substr(0, FieldName.size() - 2) + "im"; + vtkDataArray* imagDdata = dset->GetPointData()->GetArray(strImaginaryFieldName.c_str()); + if (!imagDdata) + return; + + // create a new array and copy over the real data + // since one cannot directly access the values of a vtkDataSet + // we need to copy them over in a loop + vtkSmartPointer absoluteData = vtkSmartPointer::New(); + absoluteData->SetNumberOfComponents(realDdata->GetNumberOfComponents()); + auto numTuples = realDdata->GetNumberOfTuples(); + absoluteData->SetNumberOfTuples(numTuples); + double tuple[] = {0, 0, 0}; + for (vtkIdType i = 0; i < numTuples; ++i) { + absoluteData->SetTuple(i, tuple); + } + // name the array + auto strAbsFieldName = FieldName.substr(0, FieldName.size() - 2) + "abs"; + absoluteData->SetName(strAbsFieldName.c_str()); + + // add array to data set + dset->GetPointData()->AddArray(absoluteData); + + // step through all mesh points and calculate them + double realValue = 0; + double imaginaryValue = 0; + double absoluteValue = 0; + for (int i = 0; i < dset->GetNumberOfPoints(); ++i) { + if (absoluteData->GetNumberOfComponents() == 1) { + realValue = realDdata->GetComponent(i, 0); + imaginaryValue = imagDdata->GetComponent(i, 0); + absoluteValue = sqrt(pow(realValue, 2) + pow(imaginaryValue, 2)); + absoluteData->SetComponent(i, 0, absoluteValue); + } + // if field is a vector + else { + for (int j = 0; j < absoluteData->GetNumberOfComponents(); ++j) { + realValue = realDdata->GetComponent(i, j); + imaginaryValue = imagDdata->GetComponent(i, j); + absoluteValue = sqrt(pow(realValue, 2) + pow(imaginaryValue, 2)); + absoluteData->SetComponent(i, j, absoluteValue); + } + } + } +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemPostObject.h b/src/Mod/Fem/Gui/ViewProviderFemPostObject.h index c573ebd7c2..15b56fce5d 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemPostObject.h +++ b/src/Mod/Fem/Gui/ViewProviderFemPostObject.h @@ -103,7 +103,7 @@ public: // handling when object is deleted bool onDelete(const std::vector&) override; bool canDelete(App::DocumentObject* obj) const override; - virtual void onSelectionChanged(const Gui::SelectionChanges &sel); + virtual void onSelectionChanged(const Gui::SelectionChanges& sel); /** @name Selection handling * This group of methods do the selection handling. @@ -156,6 +156,7 @@ private: vtkDataArray *tcoords); void WriteColorData(bool ResetColorBarRange); void WriteTransparency(); + void addAbsoluteField(vtkDataSet* dset, std::string FieldName); App::Enumeration m_coloringEnum, m_vectorEnum; bool m_blockPropertyChanges;