Operations averge, mass velocity and region multisphereRegion are added

This commit is contained in:
Hamidreza 2025-04-15 21:30:54 +03:30
parent 093160ba32
commit 35f10e5a94
6 changed files with 793 additions and 0 deletions

View File

@ -0,0 +1,20 @@
#include "PostprocessOperationAvMassVelocity.hpp"
pFlow::PostprocessOperationAvMassVelocity::PostprocessOperationAvMassVelocity
(
const dictionary &opDict,
const regionPoints &regPoints,
fieldsDataBase &fieldsDB
)
:
PostprocessOperationAverage
(
opDict,
opDict.getValOrSet<word>("velocityName", "velocity"),
opDict.getValOrSet<word>("massName", "mass"),
"all",
regPoints,
fieldsDB
)
{
}

View File

@ -0,0 +1,173 @@
/*------------------------------- phasicFlow ---------------------------------
O C enter of
O O E ngineering and
O O M ultiscale modeling of
OOOOOOO F luid flow
------------------------------------------------------------------------------
Copyright (C): www.cemf.ir
email: hamid.r.norouzi AT gmail.com
------------------------------------------------------------------------------
Licence:
This file is part of phasicFlow code. It is a free software for simulating
granular and multiphase flows. You can redistribute it and/or modify it under
the terms of GNU General Public License v3 or any other later versions.
phasicFlow is distributed to help others in their research in the field of
granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------------*/
#ifndef __PostprocessOperationAvMassVelocity_hpp__
#define __PostprocessOperationAvMassVelocity_hpp__
/*!
* @class PostprocessOperationAvMassVelocity
* @brief A class for averaging field values within specified regions during post-processing.
*
* @details
* The PostprocessOperationAvMassVelocity class is a specialized post-processing operation that
* calculates the average of field values within specified regions. It inherits from the
* postprocessOperation base class and implements a weighted averaging operation that
* can be applied to scalar (real), vector (realx3), and tensor (realx4) fields.
*
* The average operation follows the mathematical formula:
* \f[
* \text{result} = \frac{\sum_{j \in \text{includeMask}} w_j \cdot \phi_j \cdot \text{field}_j}
* {\sum_{i \in \text{processRegion}} w_i \cdot \phi_i}
* \f]
*
* Where:
* - \f$ i \f$ represents all particles within the specified processing region
* - \f$ j \f$ belongs to a subset of \f$ i \f$ based on an includeMask
* - \f$ w_i \f$ is the weight factor for particle \f$ i \f$
* - \f$ \phi_i \f$ is the value from the phi field for particle \f$ i \f$
* - \f$ \text{field}_j \f$ is the value from the target field for particle \f$ j \f$
*
* The calculation can optionally be divided by the region volume (when divideByVolume is set to yes),
* which allows calculating normalized averages:
* \f[
* \text{result} = \frac{1}{V_{\text{region}}} \frac{\sum_{j \in \text{includeMask}} w_j \cdot \phi_j \cdot \text{field}_j}
* {\sum_{i \in \text{processRegion}} w_i \cdot \phi_i}
* \f]
*
* The averaging can be further filtered using an includeMask to selectively include only
* specific particles that satisfy certain criteria.
*
* This class supports the following field types:
* - real (scalar values)
* - realx3 (vector values)
* - realx4 (tensor values)
*
* @section usage Usage Example
* Below is a sample dictionary showing how to configure and use this class:
*
* ```
* processMethod arithmetic; // method of performing the sum (arithmetic, uniformDistribution, GaussianDistribution)
* processRegion sphere; // type of region on which processing is performed
*
* sphereInfo
* {
* radius 0.01;
* center (-0.08 -0.08 0.015);
* }
*
* timeControl default;
*
* /// all the post process operations to be done
* operations
* (
* // computes the arithmetic mean of particle velocity
* averageVel
* {
* function average;
* field velocity;
* dividedByVolume no; // default is no
* threshold 3; // default is 1
* includeMask all; // include all particles in the calculation
* }
*
* // computes the fraction of par1 in the region
* par1Fraction
* {
* function average;
* field one; // the "one" field is special - all members have value 1.0
* phi one; // default is "one"
* dividedByVolume no;
* includeMask lessThan;
*
* // diameter of par1 is 0.003, so these settings
* // will select only particles of type par1
* lessThanInfo
* {
* field diameter;
* value 0.0031;
* }
* }
* );
* ```
*
* @section defaults Default Behavior
* - By default, `phi` is set to the field named "one" which contains value 1.0 for all entries
* - `dividedByVolume` is set to "no" by default
* - `threshold` is set to 1 by default
* - `includeMask` can be set to various filters, with "all" being the default to include all particles
*
* @section special Special Fields
* The field named "one" is a special field where all members have the value 1.0. This makes it
* particularly useful for calculating:
*
* 1. Volume or number fractions (as shown in the par1Fraction example)
* 2. Simple counts when used with an appropriate mask
* 3. Normalizing values by particle count
*
* @see postprocessOperation
* @see executeAverageOperation
*/
#include <variant>
#include <vector>
#include "postprocessOperation.hpp"
#include "regionField.hpp"
#include "includeMask.hpp"
namespace pFlow
{
class PostprocessOperationAvMassVelocity
:
public postprocessOperation
{
public:
TypeInfo("PostprocessOperation<avMassVelocity>");
/// @brief Constructs average operation processor
/// @param opDict Operation parameters dictionary
/// @param regPoints Region points data
/// @param fieldsDB Fields database
PostprocessOperationAvMassVelocity(
const dictionary& opDict,
const regionPoints& regPoints,
fieldsDataBase& fieldsDB);
/// destructor
~PostprocessOperationAvMassVelocity() override = default;
/// add this virtual constructor to the base class
add_vCtor
(
postprocessOperation,
PostprocessOperationAvMassVelocity,
dictionary
);
};
}
#endif //__PostprocessOperationAvMassVelocity_hpp__

View File

@ -0,0 +1,138 @@
#include "PostprocessOperationAverage.hpp"
#include "dictionary.hpp"
#include "fieldsDataBase.hpp"
#include "fieldFunctions.hpp"
/// Constructs average processor and initializes result field based on input field type
pFlow::PostprocessOperationAverage::PostprocessOperationAverage
(
const dictionary &opDict,
const regionPoints &regPoints,
fieldsDataBase &fieldsDB
)
:
postprocessOperation(opDict, regPoints, fieldsDB),
calculateFluctuation2_(opDict.getValOrSet<Logical>("fluctuation2", Logical(false)))
{
if( fieldType() == getTypeName<real>() )
{
processedRegFieldPtr_ = makeUnique<processedRegFieldType>(
regionField(processedFieldName(), regPoints, real(0)));
}
else if( fieldType() == getTypeName<realx3>() )
{
processedRegFieldPtr_ = makeUnique<processedRegFieldType>(
regionField(processedFieldName(), regPoints, realx3(0)));
}
else if( fieldType() == getTypeName<realx4>() )
{
processedRegFieldPtr_ = makeUnique<processedRegFieldType>(
regionField(processedFieldName(), regPoints, realx4(0)));
}
else
{
fatalErrorInFunction<<" in dictionary "<< opDict.globalName()
<< " field type is not supported for average operation"
<< " field type is "<< fieldType()
<< endl;
fatalExit;
}
}
pFlow::PostprocessOperationAverage::PostprocessOperationAverage
(
const dictionary &opDict,
const word &fieldName,
const word &phiName,
const word &includeName,
const regionPoints &regPoints,
fieldsDataBase &fieldsDB
)
:
postprocessOperation(opDict, fieldName, phiName, includeName, regPoints, fieldsDB),
calculateFluctuation2_(opDict.getValOrSet<Logical>("fluctuation2", Logical(false)))
{
if( fieldType() == getTypeName<real>() )
{
processedRegFieldPtr_ = makeUnique<processedRegFieldType>(
regionField(processedFieldName(), regPoints, real(0)));
}
else if( fieldType() == getTypeName<realx3>() )
{
processedRegFieldPtr_ = makeUnique<processedRegFieldType>(
regionField(processedFieldName(), regPoints, realx3(0)));
}
else if( fieldType() == getTypeName<realx4>() )
{
processedRegFieldPtr_ = makeUnique<processedRegFieldType>(
regionField(processedFieldName(), regPoints, realx4(0)));
}
else
{
fatalErrorInFunction<<" in dictionary "<< opDict.globalName()
<< " field type is not supported for average operation"
<< " field type is "<< fieldType()
<< endl;
fatalExit;
}
}
/// Performs weighted average of field values within each region
bool pFlow::PostprocessOperationAverage::execute
(
const std::vector<span<real>>& weights
)
{
auto allField = database().updateFieldAll(fieldName());
auto phi = database().updateFieldReal(
phiFieldName());
auto mask = getMask();
word procName = processedFieldName();
const auto& regP = regPoints();
bool dbVol = divideByVolume();
processedRegFieldPtr_ = makeUnique<processedRegFieldType>
(
std::visit([&](auto&& field)->processedRegFieldType
{
return executeAverageOperation(
procName,
field,
regP,
dbVol,
weights,
phi,
mask);
},
allField)
);
if(calculateFluctuation2_)
{
auto& processedRegField = processedRegFieldPtr_();
fluctuation2FieldPtr_ = makeUnique<processedRegFieldType>
(
std::visit([&](auto& field)->processedRegFieldType
{
using T = typename std::decay_t<std::remove_reference_t< decltype(field)>>::valueType;
if constexpr( std::is_same_v<T,real> ||
std::is_same_v<T,realx3>||
std::is_same_v<T,realx4>)
{
return executeFluctuation2Operation(
procName,
field,
std::get<regionField<T>>(processedRegField),
dbVol,
weights,
mask);
}
},
allField)
);
}
return true;
}

View File

@ -0,0 +1,203 @@
/*------------------------------- phasicFlow ---------------------------------
O C enter of
O O E ngineering and
O O M ultiscale modeling of
OOOOOOO F luid flow
------------------------------------------------------------------------------
Copyright (C): www.cemf.ir
email: hamid.r.norouzi AT gmail.com
------------------------------------------------------------------------------
Licence:
This file is part of phasicFlow code. It is a free software for simulating
granular and multiphase flows. You can redistribute it and/or modify it under
the terms of GNU General Public License v3 or any other later versions.
phasicFlow is distributed to help others in their research in the field of
granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------------*/
#ifndef __PostprocessOperationAverage_hpp__
#define __PostprocessOperationAverage_hpp__
/*!
* @class PostprocessOperationAverage
* @brief A class for averaging field values within specified regions during post-processing.
*
* @details
* The PostprocessOperationAverage class is a specialized post-processing operation that
* calculates the average of field values within specified regions. It inherits from the
* postprocessOperation base class and implements a weighted averaging operation that
* can be applied to scalar (real), vector (realx3), and tensor (realx4) fields.
*
* The average operation follows the mathematical formula:
* \f[
* \text{result} = \frac{\sum_{j \in \text{includeMask}} w_j \cdot \phi_j \cdot \text{field}_j}
* {\sum_{i \in \text{processRegion}} w_i \cdot \phi_i}
* \f]
*
* Where:
* - \f$ i \f$ represents all particles within the specified processing region
* - \f$ j \f$ belongs to a subset of \f$ i \f$ based on an includeMask
* - \f$ w_i \f$ is the weight factor for particle \f$ i \f$
* - \f$ \phi_i \f$ is the value from the phi field for particle \f$ i \f$
* - \f$ \text{field}_j \f$ is the value from the target field for particle \f$ j \f$
*
* The calculation can optionally be divided by the region volume (when divideByVolume is set to yes),
* which allows calculating normalized averages:
* \f[
* \text{result} = \frac{1}{V_{\text{region}}} \frac{\sum_{j \in \text{includeMask}} w_j \cdot \phi_j \cdot \text{field}_j}
* {\sum_{i \in \text{processRegion}} w_i \cdot \phi_i}
* \f]
*
* The averaging can be further filtered using an includeMask to selectively include only
* specific particles that satisfy certain criteria.
*
* This class supports the following field types:
* - real (scalar values)
* - realx3 (vector values)
* - realx4 (tensor values)
*
* @section usage Usage Example
* Below is a sample dictionary showing how to configure and use this class:
*
* ```
* processMethod arithmetic; // method of performing the sum (arithmetic, uniformDistribution, GaussianDistribution)
* processRegion sphere; // type of region on which processing is performed
*
* sphereInfo
* {
* radius 0.01;
* center (-0.08 -0.08 0.015);
* }
*
* timeControl default;
*
* /// all the post process operations to be done
* operations
* (
* // computes the arithmetic mean of particle velocity
* averageVel
* {
* function average;
* field velocity;
* dividedByVolume no; // default is no
* threshold 3; // default is 1
* includeMask all; // include all particles in the calculation
* }
*
* // computes the fraction of par1 in the region
* par1Fraction
* {
* function average;
* field one; // the "one" field is special - all members have value 1.0
* phi one; // default is "one"
* dividedByVolume no;
* includeMask lessThan;
*
* // diameter of par1 is 0.003, so these settings
* // will select only particles of type par1
* lessThanInfo
* {
* field diameter;
* value 0.0031;
* }
* }
* );
* ```
*
* @section defaults Default Behavior
* - By default, `phi` is set to the field named "one" which contains value 1.0 for all entries
* - `dividedByVolume` is set to "no" by default
* - `threshold` is set to 1 by default
* - `includeMask` can be set to various filters, with "all" being the default to include all particles
*
* @section special Special Fields
* The field named "one" is a special field where all members have the value 1.0. This makes it
* particularly useful for calculating:
*
* 1. Volume or number fractions (as shown in the par1Fraction example)
* 2. Simple counts when used with an appropriate mask
* 3. Normalizing values by particle count
*
* @see postprocessOperation
* @see executeAverageOperation
*/
#include <variant>
#include <vector>
#include "postprocessOperation.hpp"
#include "regionField.hpp"
#include "includeMask.hpp"
namespace pFlow
{
class PostprocessOperationAverage
:
public postprocessOperation
{
private:
///< Flag to calculate fluctuation powered by 2
Logical calculateFluctuation2_;
/// Result field containing averages for each region (real, realx3, or realx4)
uniquePtr<processedRegFieldType> processedRegFieldPtr_ = nullptr;
uniquePtr<processedRegFieldType> fluctuation2FieldPtr_ = nullptr;
public:
TypeInfo("PostprocessOperation<average>");
/// @brief Constructs average operation processor
/// @param opDict Operation parameters dictionary
/// @param regPoints Region points data
/// @param fieldsDB Fields database
PostprocessOperationAverage(
const dictionary& opDict,
const regionPoints& regPoints,
fieldsDataBase& fieldsDB);
PostprocessOperationAverage(
const dictionary& opDict,
const word& fieldName,
const word& phiName,
const word& includeName,
const regionPoints& regPoints,
fieldsDataBase& fieldsDB);
/// destructor
~PostprocessOperationAverage() override = default;
/// add this virtual constructor to the base class
add_vCtor
(
postprocessOperation,
PostprocessOperationAverage,
dictionary
);
/// @brief Get the processed field containing regional averages
/// @return Const reference to average results
const processedRegFieldType& processedField()const override
{
return processedRegFieldPtr_();
}
/// @brief Execute average operation on field values
/// @param weights Weight factors for particles
/// @return True if successful
bool execute(const std::vector<span<real>>& weights) override;
};
}
#endif //__PostprocessOperationAverage_hpp__

View File

@ -0,0 +1,98 @@
#include "multipleSpheresRegionPoints.hpp"
#include "fieldsDataBase.hpp"
pFlow::multipleSpheresRegionPoints::multipleSpheresRegionPoints
(
const dictionary &dict,
fieldsDataBase &fieldsDataBase
)
:
regionPoints(dict, fieldsDataBase)
{
const auto& multiSphereInfo = dict.subDict("multipleSphereInfo");
// Read centers and radii lists
auto centers = multiSphereInfo.getVal<List<realx3>>("centers");
auto radii = multiSphereInfo.getVal<List<real>>("radii");
// Check if lists have the same length
if(centers.size() != radii.size())
{
fatalErrorInFunction
<< "The number of centers (" << centers.size()
<< ") does not match the number of radii (" << radii.size() << ")"
<< endl;
fatalExit;
}
uint32 nSpheres = centers.size();
// Initialize data structures
sphereRegions_.resize(nSpheres, sphere(realx3(0.0, 0.0, 0.0), 1.0));
centerPoints_.resize(nSpheres);
diameters_.resize(nSpheres);
volumes_.resize(nSpheres);
selectedPoints_.resize(nSpheres);
// Setup each sphere
for (uint32 i = 0; i < nSpheres; ++i)
{
real diameter = 2.0 * radii[i]; // Convert radius to diameter
sphereRegions_[i] = pFlow::sphere(centers[i], radii[i]);
centerPoints_[i] = centers[i];
diameters_[i] = diameter;
volumes_[i] = sphereRegions_[i].volume();
}
}
pFlow::span<const pFlow::uint32> pFlow::multipleSpheresRegionPoints::indices(uint32 elem) const
{
if (elem >= size())
{
fatalErrorInFunction
<< "The element index is out of range. elem: " << elem
<< " size: " << size() << endl;
fatalExit;
}
return span<const uint32>(selectedPoints_[elem].data(), selectedPoints_[elem].size());
}
bool pFlow::multipleSpheresRegionPoints::update()
{
const auto points = database().updatePoints();
for (auto& elem : selectedPoints_)
{
elem.clear();
}
for (uint32 i = 0; i < points.size(); ++i)
{
for (uint32 j = 0; j < sphereRegions_.size(); ++j)
{
if (sphereRegions_[j].isInside(points[i]))
{
selectedPoints_[j].push_back(i);
}
}
}
return true;
}
bool pFlow::multipleSpheresRegionPoints::write(iOstream &os) const
{
os << "# Multiple spheres region points\n";
os << "# No." << tab << "centerPoint" << tab << "diameter" << endl;
for (uint32 i = 0; i < sphereRegions_.size(); ++i)
{
os << "# " << i << tab << sphereRegions_[i].center() << tab << diameters_[i] << '\n';
}
os << "time/No. ";
for (uint32 i = 0; i < sphereRegions_.size(); ++i)
{
os << i << " ";
}
os << endl;
return true;
}

View File

@ -0,0 +1,161 @@
/*------------------------------- phasicFlow ---------------------------------
O C enter of
O O E ngineering and
O O M ultiscale modeling of
OOOOOOO F luid flow
------------------------------------------------------------------------------
Copyright (C): www.cemf.ir
email: hamid.r.norouzi AT gmail.com
------------------------------------------------------------------------------
Licence:
This file is part of phasicFlow code. It is a free software for simulating
granular and multiphase flows. You can redistribute it and/or modify it under
the terms of GNU General Public License v3 or any other later versions.
phasicFlow is distributed to help others in their research in the field of
granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------------*/
/**
* @class multipleSpheresRegionPoints
* @brief A class to select and track particles contained within multiple
* spherical regions
* @details This class defines multiple spherical regions in the simulation
* domain and identifies which particles are contained within each
* sphere at each time step. It inherits from the regionPoints base
* class and specializes it for handling multiple spherical regions
* simultaneously.
*
* The class reads a list of center points and radii from a dictionary,
* creates sphere objects for each, and provides methods to:
* - Track which particles are inside each spherical region
* - Return volumetric information about the regions
* - Access center points and size information for each sphere
*
*
* @note Used in post-processing workflows to analyze particle behavior
* in specific regions of interest within the simulation domain.
*
* @see regionPoints Base class for all region-based point selection
* @see sphere Geometric primitive used to define spherical regions
* @see postprocessPhasicFlow Utility for post-processing simulation data
* @see fieldsDataBase Database containing simulation field data
*/
#ifndef __multipleSpheresRegionPoints_hpp__
#define __multipleSpheresRegionPoints_hpp__
#include "regionPoints.hpp"
#include "sphere.hpp"
#include "Vectors.hpp"
namespace pFlow
{
class multipleSpheresRegionPoints
:
public regionPoints
{
private:
/// Vector containing all spherical regions used for particle selection
Vector<sphere> sphereRegions_;
/// Center coordinates of all spherical regions
realx3Vector centerPoints_;
/// Diameters of all spherical regions
realVector diameters_;
/// Volumes of all spherical regions
realVector volumes_;
/// Vectors of point indices for particles contained in each spherical region
/// Each element corresponds to a particular sphere region
Vector<uint32Vector> selectedPoints_;
public:
/// Type identification for run-time type information
TypeInfo("multipleSpheres");
/// Constructor
/// @param dict Dictionary containing multipleSpheresInfo for the regions
/// @param fieldsDataBase Reference to the database containing field data
multipleSpheresRegionPoints(
const dictionary& dict,
fieldsDataBase& fieldsDataBase);
/// Virtual destructor for proper inheritance cleanup
~multipleSpheresRegionPoints() override = default;
/// Returns the number of spherical regions
/// @return Number of spherical regions
uint32 size()const override
{
return sphereRegions_.size();
}
/// Checks if there are any spherical regions defined
/// @return True if no regions exist, false otherwise
bool empty()const override
{
return sphereRegions_.empty();
}
/// Returns the volumes of all spherical regions
/// @return Span containing the volumes of all regions
span<const real> volumes()const override
{
return span<const real>(volumes_.data(), volumes_.size());
}
/// Returns the diameters of all spherical regions
/// @return Span containing the diameters of all regions
span<const real> diameters()const
{
return span<const real>(diameters_.data(), diameters_.size());
}
/// Returns the equivalent diameters of all spherical regions
/// @return Span containing the equivalent diameters (same as diameters)
span<const real> eqDiameters()const
{
return diameters();
}
/// Returns the center coordinates of all spherical regions
/// @return Span containing the center points of all regions
span<const realx3> centers()const override
{
return span<const realx3>(centerPoints_.data(), centerPoints_.size());
}
/// Returns the indices of particles contained in a specific spherical region
/// @param elem Index of the spherical region to query
/// @return Span containing indices of particles within the specified region
span<const uint32> indices(uint32 elem)const override;
/// Updates the selection of particles within each spherical region
/// @return True if update was successful, false otherwise
bool update() override;
/// Determines if data should be written to the same time file
/// @return True to indicate regions should be written to the same time file
bool writeToSameTimeFile()const override
{
return true;
}
/// Writes region data to the output stream
/// @param os Output stream to write data to
/// @return True if write operation was successful, false otherwise
bool write(iOstream& os) const override;
};
}
#endif // __multipleSpheresRegionPoints_hpp__