rectMesh postProcess revisited

This commit is contained in:
Hamidreza
2025-07-01 18:18:53 +03:30
parent b7f051e099
commit c90f775156
14 changed files with 399 additions and 55 deletions

View File

@ -178,4 +178,26 @@ bool PostprocessOperationAverage::write(const fileSystem &parDir) const
return true; return true;
} }
bool PostprocessOperationAverage::write(iOstream &os) const
{
if(! postprocessOperation::write(os))
{
return false;
}
if(!calculateFluctuation2_())
{
return true;
}
return
std::visit
(
[&](auto&& arg)->bool
{
return arg.writeFieldToVtk(os);
},
fluctuation2FieldPtr_()
);
}
} // namespace pFlow::postprocessData } // namespace pFlow::postprocessData

View File

@ -195,6 +195,8 @@ public:
/// write to os stream /// write to os stream
bool write(const fileSystem &parDir)const override; bool write(const fileSystem &parDir)const override;
bool write(iOstream& os)const override;
/// @brief Execute average operation on field values /// @brief Execute average operation on field values
/// @param weights Weight factors for particles /// @param weights Weight factors for particles

View File

@ -142,7 +142,7 @@ regionField<T> executeFluctuation2Operation
) )
{ {
const auto& regPoints = fieldAvg.regPoints(); const auto& regPoints = fieldAvg.regPoints();
regionField<T> processedField(regFieldName, regPoints, T{}); regionField<T> processedField(regFieldName+"_fluctuation2", regPoints, T{});
auto vols = regPoints.volumes(); auto vols = regPoints.volumes();
for(uint32 reg =0; reg<regPoints.size(); reg++) for(uint32 reg =0; reg<regPoints.size(); reg++)

View File

@ -124,6 +124,25 @@ bool postprocessOperation::write(const fileSystem &parDir) const
return true; return true;
} }
bool postprocessOperation::write(iOstream& os)const
{
if(!regPoints().writeToSameTimeFile())
{
const auto& field = processedField();
return
std::visit
(
[&](auto&& arg)->bool
{
return arg.writeFieldToVtk(os);
},
field
);
}
return false;
}
uniquePtr<postprocessOperation> postprocessOperation::create uniquePtr<postprocessOperation> postprocessOperation::create
( (
const dictionary &opDict, const dictionary &opDict,

View File

@ -99,7 +99,7 @@ public:
private: private:
/// Dictionary containing operation-specific parameters. /// Dictionary containing operation-specific parameters.
pFlow::dictionary operationDict_; pFlow::dictionary operationDict_;
/// This Threshold is used to exclude the regions which contain /// This Threshold is used to exclude the regions which contain
/// fewer than this value. /// fewer than this value.
@ -255,7 +255,7 @@ public:
/// write the result to output stream (possibly a file) /// write the result to output stream (possibly a file)
/// @param os Output stream to write the result. /// @param os Output stream to write the result.
virtual virtual
bool write(iOstream& os)const {return true;} bool write(iOstream& os)const;
/// Create the polymorphic object using the virtual constructor. /// Create the polymorphic object using the virtual constructor.
/// @param opDict Dictionary containing operation-specific parameters. /// @param opDict Dictionary containing operation-specific parameters.

View File

@ -152,11 +152,25 @@ bool pFlow::postprocessData::PostprocessComponent<RegionType, ProcessMethodType>
} }
else else
{ {
notImplementedFunction; word chNum = real2FixedStripZeros(database().time().currentTime() *1000000, 0);
return false; fileSystem file = parDir + (name() +"-"+chNum+".vtk");
}
auto osPtr = makeUnique<oFstream>(file);
regPoints().write(osPtr());
for(auto& operation:operatios_)
{
if(!operation->write(osPtr()))
{
fatalErrorInFunction
<<"Error occurred in writing operation defined in dict "
<< operation->operationDict()
<<endl;
return false;
}
}
}
return true; return true;
} }

View File

@ -53,7 +53,7 @@ private:
regionField<real> volumeFactor_; regionField<real> volumeFactor_;
bool executed_{false}; bool executed_{false};
dictionaryList operationDicts_; dictionaryList operationDicts_;
@ -122,8 +122,6 @@ public:
}; };
} }
#include "PostprocessComponent.cpp" #include "PostprocessComponent.cpp"

View File

@ -47,8 +47,8 @@ public:
: :
PostprocessComponent<RegionType,GaussianDistribution>(dict, fieldsDB, defaultTimeControl) PostprocessComponent<RegionType,GaussianDistribution>(dict, fieldsDB, defaultTimeControl)
{ {
/// initializes the Gaussian distribution for all elements of region
//const uint32 n = this->regPoints().size(); this->regPoints().setRegionExtension(2);
auto d = this->regPoints().eqDiameters(); auto d = this->regPoints().eqDiameters();
auto c = this->regPoints().centers(); auto c = this->regPoints().centers();
auto& regs = this->regionProecessMethod(); auto& regs = this->regionProecessMethod();

View File

@ -24,6 +24,7 @@ Licence:
#include "types.hpp" #include "types.hpp"
#include "regionPoints.hpp" #include "regionPoints.hpp"
#include "Field.hpp" #include "Field.hpp"
#include "cellMapper.hpp"
namespace pFlow::postprocessData namespace pFlow::postprocessData
{ {
@ -101,6 +102,11 @@ public:
return field_.size(); return field_.size();
} }
uint32x3 shape()const
{
return regionPoints_.shape();
}
bool empty()const bool empty()const
{ {
return field_.empty(); return field_.empty();

View File

@ -1,3 +1,6 @@
namespace pFlow::postprocessData namespace pFlow::postprocessData
{ {
@ -9,6 +12,86 @@ regionField<T>::regionField(
: :
field_(name, "regionFieldValue", rPoints.size(), rPoints.size(), defaultVal), field_(name, "regionFieldValue", rPoints.size(), rPoints.size(), defaultVal),
regionPoints_(rPoints) regionPoints_(rPoints)
{} {}
template<typename T>
inline
bool regionField<T>::writeFieldToVtk(iOstream& os)const
{
fatalErrorInFunction<< "This type is not supported for vtk conversion:"<<
field_.typeName()<<endl;
fatalExit;
return false;
}
template<>
inline
bool regionField<real>::writeFieldToVtk(iOstream& os)const
{
os<<"FIELD FieldData 1 " << field_.name() << " 1 "<< field_.size() << " float\n";
const auto mapper = cellMapper{shape()};
for(uint32 k=0; k<mapper.nz(); k++)
{
for(uint32 j=0; j<mapper.ny(); j++)
{
for(uint32 i=0; i<mapper.nx(); i++)
{
os<< field_[ mapper(i,j,k) ]<<'\n';
}
}
}
os<<endl;
return true;
}
template<>
inline
bool regionField<realx3>::writeFieldToVtk(iOstream& os)const
{
os<<"FIELD FieldData 1 " << field_.name() << " 3 "<< field_.size() << " float\n";
const auto mapper = cellMapper{shape()};
for(uint32 k=0; k<mapper.nz(); k++)
{
for(uint32 j=0; j<mapper.ny(); j++)
{
for(uint32 i=0; i<mapper.nx(); i++)
{
os<<field_[mapper(i,j,k)].x()<<' '<<field_[mapper(i,j,k)].y()<<' '<<field_[mapper(i,j,k)].z()<<'\n';
}
}
}
os<<endl;
return true;
}
template<>
inline
bool regionField<uint32>::writeFieldToVtk(iOstream& os)const
{
os<<"FIELD FieldData 1 " << field_.name() << " 1 "<< field_.size() << " int\n";
const auto mapper = cellMapper{shape()} ;
for(uint32 k=0; k<mapper.nz(); k++)
{
for(uint32 j=0; j<mapper.ny(); j++)
{
for(uint32 i=0; i<mapper.nx(); i++)
{
os<< field_[ mapper(i,j,k) ]<<'\n';
}
}
}
os<<endl;
return true;
}
} // End namespace pFlow::postprocessData } // End namespace pFlow::postprocessData

View File

@ -0,0 +1,56 @@
#ifndef __cellMapper_hpp__
#define __cellMapper_hpp__
#include "types.hpp"
namespace pFlow::postprocessData
{
struct cellMapper
{
uint32x3 cells_;
cellMapper()
:
cells_()
{}
explicit cellMapper(uint32x3 cells)
:
cells_(cells)
{}
cellMapper(const cellMapper&) = default;
cellMapper(cellMapper&&) = default;
cellMapper& operator=(const cellMapper&) = default;
cellMapper& operator=(cellMapper&&) = default;
~cellMapper() = default;
inline
uint32 operator()(uint32 i, uint32 j, uint32 k)const
{
return (k*(cells_.y()*cells_.x()))+j*cells_.x() + i;
}
uint32 nx()const
{
return cells_.x();
}
uint32 ny()const
{
return cells_.y();
}
uint32 nz()const
{
return cells_.z();
}
};
} //pFlow::postprocessData
#endif //__cellMapper_hpp__

View File

@ -2,6 +2,80 @@
#include "fieldsDataBase.hpp" #include "fieldsDataBase.hpp"
#include "numericConstants.hpp" #include "numericConstants.hpp"
void pFlow::postprocessData::rectMeshRegionPoints::findPointsBeyoundCells()
{
// check if pointsBeyoundCells_ is initialized
if(!pointsBeyoundCells_)
{
pointsBeyoundCells_ = makeUnique<decltype(pointsOnCells_)>
(
"selectedPoints2",
this->size()
);
}
// get the reference to pointsBeyoundCells_ and clear it
auto& selectedPoints = pointsBeyoundCells_();
// point positions are obtained from the database
const auto points = database().updatePoints();
// iterate through all cells to find points that are within the search radius
for(int32 i=0; i<mapper_.nx(); i++)
{
for(int32 j=0; j<mapper_.ny(); j++)
{
for(int32 k=0; k<mapper_.nz(); k++)
{
uint32 cellIndex = mapper_(i,j,k);
// copy the points in the center cell
auto& cellIndices = selectedPoints[cellIndex];
cellIndices.clear();
if(pointsOnCells_[cellIndex].empty())
continue;
const auto cellCenter = centerPoints_[cellIndex];
const auto rad = 0.5*diameter_[cellIndex];
for(int32 ii=-2; ii <= 2; ++ii)
{
for(int32 jj=-2; jj <= 2; ++jj)
{
for(int32 kk=-2; kk <= 2; ++kk)
{
int32 ni = i + ii;
int32 nj = j + jj;
int32 nk = k + kk;
if(ni < 0 || nj < 0 || nk < 0)
continue;
if(ni >= mapper_.nx() || nj >= mapper_.ny() || nk >= mapper_.nz())
continue;
uint32 neighborIndex = mapper_(ni, nj, nk);
const auto& neighborPoints = pointsOnCells_[neighborIndex];
for(auto nIndx : neighborPoints)
{
if( (points[nIndx]-cellCenter).length() < rad )
{
cellIndices.push_back(nIndx);
}
}
}
}
}
}
}
}
}
pFlow::postprocessData::rectMeshRegionPoints::rectMeshRegionPoints pFlow::postprocessData::rectMeshRegionPoints::rectMeshRegionPoints
( (
@ -9,23 +83,28 @@ pFlow::postprocessData::rectMeshRegionPoints::rectMeshRegionPoints
fieldsDataBase &fieldsDataBase fieldsDataBase &fieldsDataBase
) )
: :
regionPoints(dict, fieldsDataBase) regionPoints(dict, fieldsDataBase),
boxRegion_(dict.subDict("rectMeshInfo")),
pointsOnCells_("selectedPoints"),
selectedPoints_(pointsOnCells_)
{ {
const auto& rectMeshInfo = dict.subDict("rectMeshInfo"); const auto& rectMeshInfo = dict.subDict("rectMeshInfo");
boxRegion_ = box(rectMeshInfo.subDict("boxInfo"));
nx = rectMeshInfo.getValMax<uint32>("nx", 1);
ny = rectMeshInfo.getValMax<uint32>("ny", 1);
nz = rectMeshInfo.getValMax<uint32>("nz", 1);
// boxRegion_ = box(minP, maxP); auto nx = rectMeshInfo.getValMax<uint32>("nx", 1);
cells_ = uint32x3(nx, ny, nz); auto ny = rectMeshInfo.getValMax<uint32>("ny", 1);
uint32 nCells = nx * ny * nz; auto nz = rectMeshInfo.getValMax<uint32>("nz", 1);
volumes_.resize(nCells, boxRegion_.volume() / nCells); mapper_ = cellMapper(uint32x3(nx, ny, nz));
diameter_.resize(nCells, 2 * pow(3 * boxRegion_.volume() / nCells / 4.0 / Pi, 1.0 / 3.0)); uint32 nCells = mapper_.nx() * mapper_.ny() * mapper_.nz();
selectedPoints_.resize(nCells); real vol = boxRegion_.volume() / nCells;
volumes_.resize(nCells, vol);
diameter_.resize(nCells, 2 * pow(3 * vol / 4.0 / Pi, 0.3333333));
pointsOnCells_.resize(nCells);
centerPoints_.resize(nCells); centerPoints_.resize(nCells);
real dx = (boxRegion_.maxPoint().x() - boxRegion_.minPoint().x()) / mapper_.nx();
real dy = (boxRegion_.maxPoint().y() - boxRegion_.minPoint().y()) / mapper_.ny();
real dz = (boxRegion_.maxPoint().z() - boxRegion_.minPoint().z()) / mapper_.nz();
for(uint32 i = 0; i < nx; ++i) for(uint32 i = 0; i < nx; ++i)
{ {
@ -33,57 +112,86 @@ pFlow::postprocessData::rectMeshRegionPoints::rectMeshRegionPoints
{ {
for(uint32 k = 0; k < nz; ++k) for(uint32 k = 0; k < nz; ++k)
{ {
// calculate the center point of each cell
uint32 index = (i * ny + j) * nz + k;
realx3 center = boxRegion_.minPoint() + realx3 center = boxRegion_.minPoint() +
realx3( realx3(
(i + 0.5) * (boxRegion_.maxPoint().x() - boxRegion_.minPoint().x()) / nx, ( static_cast<real>(i) + 0.5) * dx,
(j + 0.5) * (boxRegion_.maxPoint().y() - boxRegion_.minPoint().y()) / ny, ( static_cast<real>(j) + 0.5) * dy,
(k + 0.5) * (boxRegion_.maxPoint().z() - boxRegion_.minPoint().z()) / nz ( static_cast<real>(k) + 0.5) * dz
); );
centerPoints_[index] = center; centerPoints_[mapper_(i, j, k)] = center;
} }
} }
} }
} }
void pFlow::postprocessData::rectMeshRegionPoints::setRegionExtension(real ext)
{
regionExtension_ = max(one, ext);
real vf = pow(regionExtension_, 3);
for(auto& v:volumes_)
{
v *= vf;
}
for(auto& d:diameter_)
{
d *= regionExtension_;
}
}
bool pFlow::postprocessData::rectMeshRegionPoints::update() bool pFlow::postprocessData::rectMeshRegionPoints::update()
{ {
const auto points = database().updatePoints(); const auto points = database().updatePoints();
for (auto& elem : selectedPoints_) for (auto& elem : pointsOnCells_)
{ {
elem.clear(); elem.clear();
} }
real dx = (boxRegion_.maxPoint().x() - boxRegion_.minPoint().x()) / cells_.x(); real dx = (boxRegion_.maxPoint().x() - boxRegion_.minPoint().x()) / mapper_.nx();
real dy = (boxRegion_.maxPoint().y() - boxRegion_.minPoint().y()) / cells_.y(); real dy = (boxRegion_.maxPoint().y() - boxRegion_.minPoint().y()) / mapper_.ny();
real dz = (boxRegion_.maxPoint().z() - boxRegion_.minPoint().z()) / cells_.z(); real dz = (boxRegion_.maxPoint().z() - boxRegion_.minPoint().z()) / mapper_.nz();
for (uint32 i = 0; i < points.size(); ++i) for (uint32 i = 0; i < points.size(); ++i)
{ {
if(boxRegion_.isInside(points[i])) if(boxRegion_.isInside(points[i]))
{ {
uint indexX = (points[i] - boxRegion_.minPoint()).x() / dx; uint32 indexX = (points[i] - boxRegion_.minPoint()).x() / dx;
uint indexY = (points[i] - boxRegion_.minPoint()).y() / dy; uint32 indexY = (points[i] - boxRegion_.minPoint()).y() / dy;
uint indexZ = (points[i] - boxRegion_.minPoint()).z() / dz; uint32 indexZ = (points[i] - boxRegion_.minPoint()).z() / dz;
uint cellIndex = (indexX * cells_.y() + indexY) * cells_.z() + indexZ; pointsOnCells_[mapper_(indexX, indexY, indexZ)].push_back(i);
selectedPoints_[cellIndex].push_back(i);
} }
} }
// search beyound cells is not required
if( equal(regionExtension_,one))
{
selectedPoints_ = pointsOnCells_;
return true;
}
// search beyound cells is required
findPointsBeyoundCells();
selectedPoints_ = pointsBeyoundCells_();
return true; return true;
} }
bool pFlow::postprocessData::rectMeshRegionPoints::write(iOstream &os) const bool pFlow::postprocessData::rectMeshRegionPoints::write(iOstream &os) const
{ {
auto [x, y , z] = boxRegion_.minPoint();
auto [nx, ny, nz] = mapper_.cells_;
real dx = (boxRegion_.maxPoint().x() - boxRegion_.minPoint().x()) / mapper_.nx();
real dy = (boxRegion_.maxPoint().y() - boxRegion_.minPoint().y()) / mapper_.ny();
real dz = (boxRegion_.maxPoint().z() - boxRegion_.minPoint().z()) / mapper_.nz();
os << "# vtk DataFile Version 3.0" << endl; os << "# vtk DataFile Version 3.0" << endl;
os << "postProcessData" << endl; os << "postProcessData" << endl;
os << "ASCII" << endl; os << "ASCII" << endl;
os << "DATASET RECTILINEAR_GRID" << endl; os << "DATASET RECTILINEAR_GRID" << endl;
os << "DIMENSIONS " << nx + 1 << " " << ny + 1 << " " << nz + 1 << endl; os << "DIMENSIONS " << nx + 1 << " " << ny + 1 << " " << nz + 1 << endl;
auto [x, y , z] = boxRegion_.minPoint();
auto [dx, dy, dz] = (boxRegion_.maxPoint() - boxRegion_.minPoint()) / realx3(nx, ny, nz);
os << "X_COORDINATES " << nx + 1 << " float\n"; os << "X_COORDINATES " << nx + 1 << " float\n";
for(int32 i = 0; i < nx + 1; i++) for(int32 i = 0; i < nx + 1; i++)
{ {

View File

@ -27,7 +27,6 @@ Licence:
* It inherits from regionPoints and implements all required virtual methods. * It inherits from regionPoints and implements all required virtual methods.
* *
* @see regionPoints * @see regionPoints
* @see rectMesh
* @see fieldsDataBase * @see fieldsDataBase
*/ */
@ -37,11 +36,13 @@ Licence:
#include "regionPoints.hpp" #include "regionPoints.hpp"
#include "box.hpp" #include "box.hpp"
#include "Vectors.hpp" #include "Vectors.hpp"
#include "cells.hpp" #include "cellMapper.hpp"
namespace pFlow::postprocessData namespace pFlow::postprocessData
{ {
class rectMeshRegionPoints class rectMeshRegionPoints
: :
public regionPoints public regionPoints
@ -51,11 +52,8 @@ private:
/// box object defining the region for point selection /// box object defining the region for point selection
box boxRegion_; box boxRegion_;
/// Number of cells in each direction
uint32 nx, ny, nz;
/// store the cells that are inside the box region /// store the cells that are inside the box region
uint32x3 cells_; cellMapper mapper_;
/// Center points of each cell in the rectMesh region /// Center points of each cell in the rectMesh region
realx3Vector centerPoints_; realx3Vector centerPoints_;
@ -66,8 +64,15 @@ private:
/// Diameter of each cell in the rectMesh region /// Diameter of each cell in the rectMesh region
realVector diameter_; realVector diameter_;
Vector<uint32Vector> pointsOnCells_;
uniquePtr<Vector<uint32Vector>> pointsBeyoundCells_;
/// Indices of points that are selected by this region /// Indices of points that are selected by this region
Vector<uint32Vector> selectedPoints_; Vector<uint32Vector>& selectedPoints_;
void findPointsBeyoundCells();
public: public:
@ -95,14 +100,29 @@ public:
} }
/** /**
* @brief Check if the region is empty * return the shape of the field
* @return Always returns false */
uint32x3 shape()const override
{
return mapper_.cells_;
}
const cellMapper& mapper()const
{
return mapper_;
}
/**
* @brief Update the points selected by this region
* @return True if update was successful
*/ */
bool empty()const override bool empty()const override
{ {
return volumes_.empty(); return volumes_.empty();
} }
void setRegionExtension(real ext) override;
/** /**
* @brief Get the volume of the rectMesh region * @brief Get the volume of the rectMesh region
* @return A span containing the volume of the region * @return A span containing the volume of the region
@ -163,7 +183,7 @@ public:
fatalExit; fatalExit;
} }
return span<uint32>(selectedPoints_[elem].data(), selectedPoints_[elem].size()); return span<uint32>(selectedPoints_[elem].data(), selectedPoints_[elem].size());
} }
/** /**
@ -174,11 +194,10 @@ public:
/** /**
* @brief Determine if data should be written to the same time file * @brief Determine if data should be written to the same time file
* @return Always returns true
*/ */
bool writeToSameTimeFile()const override bool writeToSameTimeFile()const override
{ {
return true; return false;
} }
/** /**

View File

@ -54,6 +54,11 @@ class regionPoints
/// Reference to the fields database containing simulation data /// Reference to the fields database containing simulation data
fieldsDataBase& fieldsDataBase_; fieldsDataBase& fieldsDataBase_;
protected:
/// extends the search radius to a distance farther than the region
real regionExtension_ = 1.0;
public: public:
TypeInfo("regionPoints"); TypeInfo("regionPoints");
@ -78,11 +83,23 @@ public:
/// @brief size of elements /// @brief size of elements
virtual virtual
uint32 size()const = 0; uint32 size()const = 0;
virtual
uint32x3 shape()const
{
return uint32x3(size(), 1u, 1u);
}
/// @brief check if the region is empty /// @brief check if the region is empty
virtual virtual
bool empty()const = 0; bool empty()const = 0;
/// by default it does nothing
/// But, it can be used for the methods that needs to search for
/// particles which are beyound the region
virtual void setRegionExtension(real ext)
{}
/// @brief volume of elements /// @brief volume of elements
/// @return sapn for accessing the volume of elements /// @return sapn for accessing the volume of elements
virtual virtual