[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
This commit is contained in:
Uwe
2023-02-06 22:51:05 +01:00
parent bdfe5e764c
commit 2ffd650f20
2 changed files with 83 additions and 5 deletions

View File

@@ -37,6 +37,7 @@
# include <vtkCellArray.h>
# include <vtkCellData.h>
# include <vtkDoubleArray.h>
# include <vtkPointData.h>
# include <QApplication>
@@ -623,13 +624,24 @@ void ViewProviderFemPostObject::updateData(const App::Property* p) {
}
}
bool ViewProviderFemPostObject::setupPipeline() {
bool ViewProviderFemPostObject::setupPipeline()
{
vtkDataObject* data = static_cast<Fem::FemPostObject*>(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<vtkDataObject> 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<vtkDoubleArray> absoluteData = vtkSmartPointer<vtkDoubleArray>::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);
}
}
}
}