@@ -130,6 +130,7 @@ SET(libengrid_HEADERS
operation.h
optimisation.h
optimisenormalvector.h
+ padsurface.h
physicalboundarycondition.h
plywriter.h
pointfinder.h
@@ -329,6 +330,7 @@ SET(libengrid_SOURCES
operation.cpp
optimisation.cpp
optimisenormalvector.cpp
+ padsurface.cpp
physicalboundarycondition.cpp
plywriter.cpp
pointfinder.cpp
@@ -170,8 +170,8 @@ void BlenderReader::operate()
makeCopy(new_grid, m_Grid);
}
- UpdateNodeIndex(m_Grid);
- UpdateCellIndex(m_Grid);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
// check and set the boundary names if required
int update_required = true;
@@ -368,8 +368,8 @@ void CreateCadTesselation::operate()
GuiMainWindow::pointer()->resetProgress(text, m_Ni*m_Nj + m_Ni*m_Nk + m_Nj*m_Nk);
scan(true, interlaces);
- UpdateNodeIndex(m_Grid);
- UpdateCellIndex(m_Grid);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
GuiMainWindow::pointer()->resetXmlDoc();
GuiMainWindow::pointer()->clearBCs();
GuiMainWindow::pointer()->setBC(1, BoundaryCondition("imported", "patch", 1));
@@ -313,6 +313,6 @@ void CreateHexCore::operate()
EG_VTKSP(vtkUnstructuredGrid, otgrid);
transferOctreeGrid();
createBoundaryFaces();
- UpdateCellIndex(m_Grid);
+ updateCellIndex(m_Grid);
GuiMainWindow::pointer()->updateBoundaryCodes(true);
}
@@ -31,7 +31,7 @@ void DeleteVolumeGrid::operate()
allocateGrid(sgrid, scells.size(), snodes.size());
makeCopy(m_Grid, sgrid, scells);
makeCopy(sgrid, m_Grid);
- UpdateCellIndex(m_Grid);
+ updateCellIndex(m_Grid);
GuiMainWindow::pointer()->updateBoundaryCodes(true);
}
#include "drnumwriter.h"
#include "guimainwindow.h"
#include "vtkEgNormalExtrusion.h"
+#include "padsurface.h"
DrNumWriter::DrNumWriter()
{
+ m_BackupGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
}
QList<BoundaryCondition> DrNumWriter::getBcsOfType(QString type)
@@ -53,6 +55,34 @@ void DrNumWriter::readSettings()
}
}
+double DrNumWriter::edgeLength(QString bc_name)
+{
+ QString rules_txt = GuiMainWindow::pointer()->getXmlSection("engrid/surface/rules");
+ rules_txt = rules_txt.replace("\n", " ");
+ rules_txt = rules_txt.trimmed();
+ QStringList rules = rules_txt.split(";", QString::SkipEmptyParts);
+ double h_min = EG_LARGE_REAL;
+ foreach (QString rule, rules) {
+ QStringList parts = rule.split("=");
+ if (parts.size() > 1) {
+ QString left = parts[0].trimmed();
+ double h = parts[1].trimmed().toDouble();
+ QStringList or_parts = left.split("<OR>");
+ foreach (QString or_part, or_parts) {
+ or_part = or_part.trimmed();
+ QStringList and_parts = or_part.split("<AND>");
+ if (and_parts.size() == 1) {
+ QString and_part = and_parts[0].trimmed();
+ if (and_part == bc_name) {
+ h_min = min(h, h_min);
+ }
+ }
+ }
+ }
+ }
+ return h_min;
+}
+
void DrNumWriter::prepareLevelSets(QList<BoundaryCondition> bcs, double distance)
{
bool extrude = distance > 1e-3;
@@ -61,6 +91,11 @@ void DrNumWriter::prepareLevelSets(QList<BoundaryCondition> bcs, double distance
BoundaryCondition tmp_bc = GuiMainWindow::pointer()->getBC(BoundaryCondition(bc.getName(), "auxilary"));
MeshPartition part(m_Grid);
part.setBC(bc.getCode());
+ if (!part.isPlanar()) {
+ PhysicalBoundaryCondition pbc = GuiMainWindow::pointer()->getPhysicalBoundaryCondition(bc.getType());
+ QString msg = "only planar surfaces allowed for boundaries of type \"" + pbc.getType() + "\"";
+ EG_ERR_RETURN(msg);
+ }
double A, P, Dh;
vec3_t x, n;
part.calcPlanarSurfaceMetrics(Dh, A, P, x, n);
@@ -73,8 +108,19 @@ void DrNumWriter::prepareLevelSets(QList<BoundaryCondition> bcs, double distance
}
part.duplicate();
part.resetBC(new_bc.getName(), new_bc.getType());
+
+ //part.setBC(new_bc.getCode());
+ //part.scale((Dh + 10*m_MaximalEdgeLength)/Dh, x);
+
+ PadSurface pad;
+ pad.setGrid(m_Grid);
+ pad.addBC(new_bc.getCode());
+ pad.relativeOff();
+ pad.setDistance(10*m_MaximalEdgeLength);
+ pad.setNewBC(new_bc.getCode());
+ pad();
part.setBC(new_bc.getCode());
- part.scale((Dh + 10*m_MaximalEdgeLength)/Dh, x);
+
if (extrude) {
part.translate(-10*m_MaximalEdgeLength*n);
}
@@ -97,6 +143,10 @@ void DrNumWriter::prepareLevelSets(QList<BoundaryCondition> bcs, double distance
for (int i = 0; i < pbc.getNumVars(); ++i) {
info << pbc.getVarType(i).leftJustified(7) << pbc.getVarName(i).leftJustified(max_size) << " = " << pbc.getVarValueAsString(i) << ";\n";
}
+ double h = edgeLength(bc.getName());
+ if (h < m_MaximalEdgeLength) {
+ info << "real " + QString("h").leftJustified(max_size) << " = " << h << ";\n";
+ }
}
}
@@ -119,14 +169,58 @@ void DrNumWriter::prepareWallLevelSets(QList<BoundaryCondition> bcs)
for (int i = 0; i < pbc.getNumVars(); ++i) {
info << pbc.getVarType(i).leftJustified(7) << pbc.getVarName(i).leftJustified(max_size) << " = " << pbc.getVarValueAsString(i) << ";\n";
}
+ double h = edgeLength(bc.getName());
+ if (h < m_MaximalEdgeLength) {
+ info << "real " + QString("h").leftJustified(max_size) << " = " << h << ";\n";
+ }
+ }
+}
+
+void DrNumWriter::computeBBox()
+{
+ m_X1 = vec3_t(EG_LARGE_REAL, EG_LARGE_REAL, EG_LARGE_REAL);
+ m_X2 = -1*m_X1;
+ for (vtkIdType id_node = 0; id_node < m_Grid->GetNumberOfPoints(); ++id_node) {
+ vec3_t x;
+ m_Grid->GetPoint(id_node, x.data());
+ for (int i = 0; i < 3; ++i) {
+ m_X1[i] = min(m_X1[i], x[i]);
+ m_X2[i] = max(m_X2[i], x[i]);
+ }
}
}
+void DrNumWriter::writeGlobals()
+{
+ QFile info_file(getFileName() + "/engrid/global.dnc");
+ info_file.open(QIODevice::WriteOnly);
+ QTextStream info(&info_file);
+
+ info << "string name = global;\n";
+ info << "real h_max = " << m_MaximalEdgeLength << ";\n";
+ info << "real gf = " << m_GrowthFactor << ";\n";
+ info << "vector x1 = (" << m_X1[0] << ", " << m_X1[1] << ", " << m_X1[2] << ");\n";
+ info << "vector x2 = (" << m_X2[0] << ", " << m_X2[1] << ", " << m_X2[2] << ");\n";
+}
+
+void DrNumWriter::backup()
+{
+ makeCopy(m_Grid, m_BackupGrid);
+}
+
+void DrNumWriter::restore()
+{
+ makeCopy(m_BackupGrid, m_Grid);
+ GuiMainWindow::pointer()->updateBoundaryCodes(true);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
+}
void DrNumWriter::operate()
{
- readOutputDirectory();
+ readOutputDirectory();
if (isValid()) {
+ backup();
readSettings();
QList<BoundaryCondition> turb_duct_in_bcs = getBcsOfType("turbulent-duct-inlet");
@@ -164,6 +258,9 @@ void DrNumWriter::operate()
prepareWallLevelSets(lam_wall_bcs);
prepareWallLevelSets(slip_wall_bcs);
+ computeBBox();
+ writeGlobals();
writeSolverParameters(getFileName());
+ restore();
}
}
@@ -40,10 +40,13 @@ protected: // data types
protected: // attributes
- double m_MaximalEdgeLength;
- double m_MinimalEdgeLength;
- double m_GrowthFactor;
+ double m_MaximalEdgeLength;
+ double m_MinimalEdgeLength;
+ double m_GrowthFactor;
+ vec3_t m_X1;
+ vec3_t m_X2;
+ vtkSmartPointer<vtkUnstructuredGrid> m_BackupGrid;
protected: // methods
@@ -51,6 +54,11 @@ protected: // methods
void prepareLevelSets(QList<BoundaryCondition> bc, double distance);
void prepareWallLevelSets(QList<BoundaryCondition> bc);
void readSettings();
+ double edgeLength(QString bc_name);
+ void computeBBox();
+ void writeGlobals();
+ void backup();
+ void restore();
virtual void operate();
@@ -629,7 +629,7 @@ bool EgVtkObject::isSurface(vtkIdType id_cell, vtkUnstructuredGrid *grid)
return isSurf;
}
-void EgVtkObject::UpdateCellIndex(vtkUnstructuredGrid *grid)
+void EgVtkObject::updateCellIndex(vtkUnstructuredGrid *grid)
{
if (!grid->GetCellData()->GetArray("cell_index")) {
EG_VTKSP(vtkLongArray_t, cell_index);
@@ -643,7 +643,7 @@ void EgVtkObject::UpdateCellIndex(vtkUnstructuredGrid *grid)
}
}
-void EgVtkObject::UpdateNodeIndex(vtkUnstructuredGrid *grid)
+void EgVtkObject::updateNodeIndex(vtkUnstructuredGrid *grid)
{
if (!grid->GetPointData()->GetArray("node_index")) {
EG_VTKSP(vtkLongArray_t, node_index);
@@ -664,8 +664,8 @@ void EgVtkObject::addToPolyData
vtkUnstructuredGrid *grid
)
{
- UpdateCellIndex(grid);
- UpdateNodeIndex(grid);
+ updateCellIndex(grid);
+ updateNodeIndex(grid);
QVector<vtkIdType> nodes;
QVector<int> _nodes;
getNodesFromCells(cells, nodes, grid);
@@ -126,12 +126,12 @@ protected: // methods
/**
* Update the cell index array.
*/
- void UpdateCellIndex(vtkUnstructuredGrid *grid);
+ void updateCellIndex(vtkUnstructuredGrid *grid);
/**
* Update the point index array.
*/
- void UpdateNodeIndex(vtkUnstructuredGrid *grid);
+ void updateNodeIndex(vtkUnstructuredGrid *grid);
/**
* Compute normal vectors on nodes and cells of a subset of a grid.
#include <QtDebug>
#include <QString>
#include <QDate>
+#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkLongArray.h>
@@ -68,6 +69,7 @@ typedef vtkLongLongArray vtkLongArray_t;
Error err; \
err.setText(txt); \
err.setType(Error::ExitOperation); \
+ QApplication::restoreOverrideCursor(); \
throw err; \
};
<file>resources/solvers/openfoam-2.1/simpleFoam/standard/system/decomposeParDict</file>
<file>resources/solvers/openfoam-2.1/simpleFoam/standard/machines</file>
<file>resources/solvers/DrNUM-1.0/drnumLowSpeed/standard/control/main.dnc</file>
+ <file>resources/solvers/DrNUM-1.0/drnumLowSpeed/standard/preprocess.py</file>
</qresource>
</RCC>
@@ -203,7 +203,7 @@ void FoamReader::operate()
}
makeCopy(ug, m_Grid);
createBasicFields(m_Grid, m_Grid->GetNumberOfCells(), m_Grid->GetNumberOfPoints());
- UpdateCellIndex(m_Grid);
+ updateCellIndex(m_Grid);
}
} catch (Error err) {
err.display();
@@ -229,7 +229,7 @@ void GmshReader::operate()
readAscii2(m_Grid);
}
createBasicFields(m_Grid, m_Grid->GetNumberOfCells(), m_Grid->GetNumberOfPoints());
- UpdateCellIndex(m_Grid);
+ updateCellIndex(m_Grid);
CorrectSurfaceOrientation corr_surf;
corr_surf.setGrid(m_Grid);
corr_surf();
<addaction name="actionFoamWriter"/>
<addaction name="actionFoamCaseWriter"/>
</widget>
+ <addaction name="actionExportDrNum"/>
<addaction name="menuGmsh"/>
<addaction name="actionExportNeutral"/>
<addaction name="actionExportAsciiStl"/>
<addaction name="actionExportAsciiPly"/>
<addaction name="actionExportBinaryPly"/>
<addaction name="menuOpenFOAM"/>
- <addaction name="actionExportDrNum"/>
<addaction name="actionExportDolfyn"/>
<addaction name="actionExportSu2"/>
<addaction name="actionExportTau"/>
@@ -709,6 +709,25 @@ void MeshPartition::calcPlanarSurfaceMetrics(double &Dh, double &A, double &P, v
Dh = 4*A/P;
}
+bool MeshPartition::isPlanar(double tolerance_angle)
+{
+ foreach (vtkIdType id_cell, m_Cells) {
+ if (!isSurface(id_cell, m_Grid)) {
+ return false;
+ }
+ }
+ double Dh, A, P;
+ vec3_t x, n0;
+ calcPlanarSurfaceMetrics(Dh, A, P, n0, x);
+ foreach (vtkIdType id_cell, m_Cells) {
+ vec3_t n = cellNormal(m_Grid, id_cell);
+ if (angle(n, n0) > tolerance_angle) {
+ return false;
+ }
+ }
+ return true;
+}
+
void MeshPartition::setBC(int bc)
{
QList<vtkIdType> cls;
@@ -393,6 +393,13 @@ public: // methods
*/
void writeSTL(QString file_name);
+ /**
+ * @brief Check if the mesh partition represents a planar surface.
+ * @param tolerance_angle the maximally allowed angle between a face normal and the mean normal
+ * @return true if it is planar
+ */
+ bool isPlanar(double tolerance_angle = 0.0017453);
+
};
--- /dev/null
+// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// + +
+// + This file is part of enGrid. +
+// + +
+// + Copyright 2008-2016 enGits GmbH +
+// + +
+// + enGrid is free software: you can redistribute it and/or modify +
+// + it under the terms of the GNU General Public License as published by +
+// + the Free Software Foundation, either version 3 of the License, or +
+// + (at your option) any later version. +
+// + +
+// + enGrid is distributed in the hope that it will be useful, +
+// + but WITHOUT ANY WARRANTY; without even the implied warranty of +
+// + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
+// + GNU General Public License for more details. +
+// + +
+// + You should have received a copy of the GNU General Public License +
+// + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
+// + +
+// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+#include "padsurface.h"
+#include "meshpartition.h"
+#include "geometrytools.h"
+
+PadSurface::PadSurface()
+{
+ m_Relative = true;
+ m_Distance = 1.0;
+ m_NewBC = 99;
+}
+
+void PadSurface::operate()
+{
+ MeshPartition part(m_Grid);
+ part.setBCs(m_BCs);
+ QList<QVector<vec3_t> > quads;
+ foreach (vtkIdType id_cell, part.getCells()) {
+ vec3_t n = GeometryTools::cellNormal(m_Grid, id_cell);
+ n.normalise();
+ EG_GET_CELL(id_cell, m_Grid);
+ QVector<vec3_t> x(num_pts + 1);
+ for (int i = 0; i < num_pts; ++i) {
+ m_Grid->GetPoint(pts[i], x[i].data());
+ }
+ x[num_pts] = x[0];
+ for (int i = 0; i < num_pts; ++i) {
+ if (part.c2cGG(id_cell, i) < 0) {
+ vec3_t b = x[i+1] - x[i];
+ double L = m_Distance;
+ if (m_Relative) {
+ L = b.abs();
+ }
+ b.normalise();
+ vec3_t a = b.cross(n);
+ QVector<vec3_t> xn(4);
+ xn[0] = x[i] - L*b;
+ xn[1] = x[i] - L*b + L*a;
+ xn[2] = x[i+1] + L*b + L*a;
+ xn[3] = x[i+1] + L*b;
+ quads << xn;
+ }
+ }
+ }
+ EG_VTKSP(vtkUnstructuredGrid, grid);
+ allocateGrid(grid, quads.size(), 4*quads.size());
+ vtkIdType start_id = 0;
+ vtkIdType pts[4];
+ EG_VTKDCC(vtkIntArray, cell_code, grid, "cell_code");
+ foreach (QVector<vec3_t> quad, quads) {
+ for (int i = 0; i < 4; ++i) {
+ grid->GetPoints()->SetPoint(start_id + i, quad[i].data());
+ pts[i] = start_id + i;
+ }
+ vtkIdType id_cell = grid->InsertNextCell(VTK_QUAD, 4, pts);
+ cell_code->SetValue(id_cell, m_NewBC);
+ start_id += 4;
+ }
+ MeshPartition new_part(grid, true);
+ part.concatenatePartition(new_part);
+}
// + +
// + This file is part of enGrid. +
// + +
-// + Copyright 2008-2014 enGits GmbH +
+// + Copyright 2008-2016 enGits GmbH +
// + +
// + enGrid is free software: you can redistribute it and/or modify +
// + it under the terms of the GNU General Public License as published by +
// + +
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-#include "deletevolumegrid.h"
-#include "guimainwindow.h"
+#ifndef PADSURFACE_H
+#define PADSURFACE_H
-void DeleteVolumeGrid::operate()
+#include "operation.h"
+
+class PadSurface : public Operation
{
- EG_VTKSP(vtkUnstructuredGrid, sgrid);
- QVector<vtkIdType> scells, snodes;
- getAllSurfaceCells(scells, m_Grid);
- getNodesFromCells(scells, snodes, m_Grid);
- allocateGrid(sgrid, scells.size(), snodes.size());
- makeCopy(m_Grid, sgrid, scells);
- makeCopy(sgrid, m_Grid);
- UpdateCellIndex(m_Grid);
- GuiMainWindow::pointer()->updateBoundaryCodes(true);
-}
+protected: // attributes
+
+ QSet<int> m_BCs;
+ int m_NewBC;
+ bool m_Relative;
+ double m_Distance;
+
+
+protected: // methods
+
+ virtual void operate();
+
+
+public:
+
+ PadSurface();
+ void addBC(int bc) { m_BCs.insert(bc); }
+ void addBC(BoundaryCondition bc) { m_BCs.insert(bc.getCode()); }
+ void setNewBC(int bc) { m_NewBC = bc; }
+ void setDistance(double d) { m_Distance = d; }
+ void relativeOn() { m_Relative = true; }
+ void relativeOff() { m_Relative = false; }
+
+};
+
+#endif // PADSURFACE_H
@@ -44,8 +44,8 @@ void PolyDataReader::operate()
pd2ug->Update();
m_Grid->DeepCopy(pd2ug->GetOutput());
createBasicFields(m_Grid, m_Grid->GetNumberOfCells(), m_Grid->GetNumberOfPoints());
- UpdateNodeIndex(m_Grid);
- UpdateCellIndex(m_Grid);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
EG_VTKDCC(vtkIntArray, bc, m_Grid, "cell_code");
for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfPoints(); ++id_cell) {
bc->SetValue(id_cell,99);
@@ -288,8 +288,8 @@ void ReducedPolyDataReader::operate()
makeCopy(poly2ug->GetOutput(), m_Grid);
createBasicFields(m_Grid, m_Grid->GetNumberOfCells(), m_Grid->GetNumberOfPoints());
- UpdateNodeIndex(m_Grid);
- UpdateCellIndex(m_Grid);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
EG_VTKDCC(vtkIntArray, bc, m_Grid, "cell_code");
for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
bc->SetValue(id_cell, 0);
@@ -2,6 +2,7 @@ title : standard drnumLowSpeed 1.0;
section : DrNUM-1.0/drnumLowSpeed/standard;
binary : drnumLowSpeed;
files:
+ preprocess.py;
control/main.dnc;
=
title : standard simpleFoam 1.5;
@@ -89,6 +89,6 @@ void RestrictToAvailableVolumeCells::operate()
}
makeCopy(new_grid2, m_Grid);
GuiMainWindow::pointer()->setBC(bc_new, BoundaryCondition("ami_blayer", "cyclic_AMI", bc_new));
- UpdateCellIndex(m_Grid);
+ updateCellIndex(m_Grid);
GuiMainWindow::pointer()->updateBoundaryCodes(true);
}
@@ -463,7 +463,7 @@ void SeedSimplePrismaticLayer::operate()
// writeGrid(new_grid, "pre-createBoundaryElements");
createBoundaryElements(new_grid);
- UpdateCellIndex(new_grid);
+ updateCellIndex(new_grid);
m_Grid->DeepCopy(new_grid);
cout << "done." << endl;
}
@@ -81,8 +81,8 @@ void SeligAirfoilReader::operate()
poly2ug->SetInputConnection(tri->GetOutputPort());
poly2ug->Update();
makeCopy(poly2ug->GetOutput(), m_Grid);
- UpdateNodeIndex(m_Grid);
- UpdateCellIndex(m_Grid);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
}
} catch (Error err) {
err.display();
@@ -195,6 +195,6 @@ void vtkEgEliminateShortEdges::ExecuteEg()
allocateGrid(m_Output, N_new_cells, N_new_points);
CopyPoints();
CopyCells();
- UpdateCellIndex(m_Output);
+ updateCellIndex(m_Output);
N_eliminated = N;
};
@@ -508,7 +508,7 @@ void vtkEgNormalExtrusion::ExecuteEg()
}
}
- UpdateCellIndex(m_Output);
+ updateCellIndex(m_Output);
}
void vtkEgNormalExtrusion::SetLayers(const QVector<double> &y)
@@ -88,8 +88,8 @@ void VtkReader::operate()
makeCopy(vtk->GetOutput(), m_Grid);
createBoundaryFaces();
createBasicFields(m_Grid, m_Grid->GetNumberOfCells(), m_Grid->GetNumberOfPoints());
- UpdateNodeIndex(m_Grid);
- UpdateCellIndex(m_Grid);
+ updateNodeIndex(m_Grid);
+ updateCellIndex(m_Grid);
}
} catch (Error err) {
err.display();