From d0c76e2fc4b78f42cbb05910bf098968cb5f8217 Mon Sep 17 00:00:00 2001 From: Hamidreza Date: Thu, 3 Jul 2025 01:22:55 +0330 Subject: [PATCH] updates for rectMesh in postprocess --- .../PostprocessComponentGaussian.hpp | 2 +- src/PostprocessData/readme.md | 186 +++++++++++++++--- .../rectMeshRegionPoints.cpp | 15 +- .../rectMeshRegionPoints.hpp | 16 +- .../regionPoints/regionPoints.hpp | 17 +- .../sampleDictionary/postprocessDataDict | 58 +++++- 6 files changed, 239 insertions(+), 55 deletions(-) diff --git a/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentGaussian.hpp b/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentGaussian.hpp index ac8b33fa..3e0b6812 100644 --- a/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentGaussian.hpp +++ b/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentGaussian.hpp @@ -48,7 +48,7 @@ public: PostprocessComponent(dict, fieldsDB, defaultTimeControl) { - this->regPoints().setRegionExtension(2); + this->regPoints().applyRegionExtension(); auto d = this->regPoints().eqDiameters(); auto c = this->regPoints().centers(); auto& regs = this->regionProecessMethod(); diff --git a/src/PostprocessData/readme.md b/src/PostprocessData/readme.md index 88d42232..8f0d5659 100644 --- a/src/PostprocessData/readme.md +++ b/src/PostprocessData/readme.md @@ -2,17 +2,16 @@ The `PostprocessData` module in phasicFlow provides powerful tools for analyzing particle-based simulations both during runtime (in-simulation) and after simulation completion (post-simulation). This document explains how to configure and use the postprocessing features through the dictionary-based input system. -- in-simulation: this is postprocessing that is active during simulation. When running a solver, it allows for real-time data analysis and adjustments based on the simulation's current state. See below to see how you can activate in-simulation postprocessing. -- post-simulation: this is postprocessing that is done after the simulation is completed. It allows for detailed analysis of the simulation results, including data extraction and visualization based on the results that are stored in time-folders. If you want to use post-simulation, you need to run utility `postprocessPhasicFlow` in terminal (in the simulation case setup folder) to run the postprocessing. This utility reads the `postprocessDataDict` file and performs the specified operations on the simulation data. - +- **In-simulation**: This is postprocessing that is active during simulation. When running a solver, it allows for real-time data analysis and adjustments based on the simulation's current state. See below to learn how you can activate in-simulation postprocessing. +- **Post-simulation**: This is postprocessing that is done after the simulation is completed. It allows for detailed analysis of the simulation results, including data extraction and visualization based on the results stored in time folders. If you want to use post-simulation, you need to run the utility `postprocessPhasicFlow` in the terminal (in the simulation case setup folder) to execute the postprocessing. This utility reads the `postprocessDataDict` file and performs the specified operations on the simulation data. ### Important Notes -* **NOTE 1:** -postprocessing for in-simulation, is not implemented for MPI execution. So, do not use it when using MPI execution. For post-simulation postprocessing, you can use the `postprocessPhasicFlow` utility without MPI, even though the actual simulation has been done using MPI. +* **NOTE 1:** +Postprocessing for in-simulation is not implemented for MPI execution. So, do not use it when using MPI execution. For post-simulation postprocessing, you can use the `postprocessPhasicFlow` utility without MPI, even though the actual simulation has been done using MPI. -* **NOTE 2:** -In post-simulation mode, all timeControl settings are ignored. The postprocessing will be done for all the time folders that are available in the case directory or if you specify the time range in the command line, the postprocessing will be done for the time folders that are in the specified range of command line. +* **NOTE 2:** +In post-simulation mode, all `timeControl` settings are ignored. The postprocessing will be done for all the time folders that are available in the case directory, or if you specify the time range in the command line, the postprocessing will be done for the time folders within the specified range. ## Table of Contents @@ -32,12 +31,14 @@ In post-simulation mode, all timeControl settings are ignored. The postprocessin - [7.1. Example 1: Probing Individual Particles](#71-example-1-probing-individual-particles) - [7.2. Example 2: Processing in a Spherical Region](#72-example-2-processing-in-a-spherical-region) - [7.3. Example 3: Processing Along a Line](#73-example-3-processing-along-a-line) + - [7.4. Example 4: Processing in a Rectangular Mesh](#74-example-4-processing-in-a-rectangular-mesh) + - [7.5. Example 5: Tracking particles](#75-example-5-tracking-particles) - [8. Advanced Features](#8-advanced-features) - - [8.1. Special functions applied on fields](#81-special-functions-applied-on-fields) - - [8.2. Particle Filtering with includeMask](#82-particle-filtering-with-includemask) + - [8.1. Special Functions Applied on Fields](#81-special-functions-applied-on-fields) + - [8.2. Particle Filtering with IncludeMask](#82-particle-filtering-with-includemask) - [8.3. Implementation Notes](#83-implementation-notes) - [9. Mathematical Formulations](#9-mathematical-formulations) -- [10. A complete dictionary file (postprocessDataDict)](#10-a-complete-dictionary-file-postprocessdatadict) +- [10. A Complete Dictionary File (postprocessDataDict)](#10-a-complete-dictionary-file-postprocessdatadict) ## 1. Overview @@ -46,12 +47,12 @@ Postprocessing in phasicFlow allows you to: - Extract information about particles in specific regions of the domain - Calculate statistical properties such as averages and sums of particle attributes - Track specific particles throughout the simulation -- Apply different weighing methods when calculating statistics +- Apply different weighting methods when calculating statistics - Perform postprocessing at specific time intervals ## 2. Setting Up Postprocessing -Postprocessing is configured through a dictionary file named `postprocessDataDict` which should be placed in the `settings` directory. Below is a detailed explanation of the configuration options. +Postprocessing is configured through a dictionary file named `postprocessDataDict`, which should be placed in the `settings` directory. Below is a detailed explanation of the configuration options. ### 2.1. Basic Configuration @@ -60,7 +61,6 @@ The input dictionary, **settings/postprocessDataDict**, may look like this: ```cpp // PostprocessData dictionary - // Enable/disable postprocessing during simulation runTimeActive yes; // Options: yes, no @@ -70,7 +70,7 @@ shapeType sphere; // Options depend on the simulation type: sphere, grain, etc // Default time control for postprocessing components defaultTimeControl { - timeControl timeStep; // Options: timeStep, simulationTime, settings + timeControl timeStep; // Options: timeStep, simulationTime, settingsDict startTime 0; // Start time for postprocessing endTime 1000; // End time for postprocessing executionInterval 150; // How frequently to run postprocessing @@ -83,7 +83,6 @@ components ); ``` - If you want to activate in-simulation postprocessing, you need to add these lines to the `settings/settingsDict` file: ```cpp @@ -92,7 +91,7 @@ libs ("libPostprocessData.so"); auxFunctions postprocessData; ``` -This will link the postprocessing library to your simulation, allowing you to use its features. Note that, anytime you want to deactivate the in-simulation postprocessing, you can simply change the `runTimeActive` option to `no` in `postprocessDataDict` file. +This will link the postprocessing library to your simulation, allowing you to use its features. Note that anytime you want to deactivate the in-simulation postprocessing, you can simply change the `runTimeActive` option to `no` in the `postprocessDataDict` file. ## 3. Time Control Options @@ -102,8 +101,8 @@ Each postprocessing component can either use the default time control settings o |--------|-------------|---------------------| | `timeStep` | Controls execution based on simulation time steps | `startTime`, `endTime`, `executionInterval` | | `simulationTime` | Controls execution based on simulation time | `startTime`, `endTime`, `executionInterval` | -| `settings` | Uses parameters from settingsDict file | None (defined elsewhere) | -| `default` | Uses the default time control settings (uses `defaultTimeControl` settings)| None (uses default) | +| `settingsDict` | Uses parameters from settingsDict file | None (defined elsewhere) | +| `default` | Uses the default time control settings (uses `defaultTimeControl` settings) | None (uses default) | If no time control is specified, the `default` option is used automatically. @@ -111,14 +110,14 @@ If no time control is specified, the `default` option is used automatically. The postprocessing module provides several methods for processing particle data. They are categorized into two main groups: bulk and individual methods. -- **Bulk Methods**: Operate on all particles that are located in a specified locations/regions (cells, spheres, etc.). +- **Bulk Methods**: Operate on all particles that are located in specified locations/regions (cells, spheres, etc.). - **Individual Methods**: Operate on specific particles, allowing for targeted particle property extraction. -| Method | Property type | Description | Formula | -|--------|------------------|-------------|---------| +| Method | Property Type | Description | Formula | +|--------|---------------|-------------|---------| | `arithmetic` | bulk | Simple arithmetic mean/sum with equal weights | Each particle contributes equally | | `uniformDistribution` | bulk | Each particle contributes inversely proportional to the total number of particles | $w_i = 1/n$ where $n$ is the number of particles | -| `GaussianDistribution` | bulk | Weight contribution based on distance from center with Gaussian falloff | $w_i = \exp(-\|x_i - c\|^2/(2\sigma^2))/\sqrt{2\pi\sigma^2}$ | +| `GaussianDistribution` | bulk | Weight contribution based on distance from the center with Gaussian falloff | $w_i = \exp(-\|x_i - c\|^2/(2\sigma^2))/\sqrt{2\pi\sigma^2}$ | | `particleProbe` | individual | Extracts values from specific particles | Direct access to particle properties | ## 5. Region Types @@ -131,11 +130,13 @@ Regions define where in the domain the postprocessing operations are applied: | `multipleSpheres` | Multiple spherical regions | `centers`, `radii` defined in `multiplSpheresInfo` dict | bulk | | `line` | Spheres along a line with specified radius | `p1`, `p2`, `nSpheres`, `radius` defined in `lineInfo` dict| bulk | | `box`| A cuboid region | `min`, `max` defined in `boxInfo` dict | bulk | -| `centerPoints`* | Specific particles selected by ID | `ids` | individual | -| `centerPoints`* | Specific particles selected by center points located in a box | `boxInfo` | individual | -| `centerPoints`* | Specific particles selected by center points located in a sphere | `sphereInfo` | individual | -| `centerPoints`* | Specific particles selected by center points located in a cylinder | `cylinderInfo` | individual | -| \* Particles selection is done when simulation reaches the time that is specified by `startTime` of the post-process component and this selection remains intact up to the end of simulation. This is very good for particle tracking purposes or when you want to analyze specific particles behavior over time. | +| `rectMesh`** | creates a rectangular mesh and each direction is divided into equal spaces| corner points of mesh, and `nx`, `ny`, `nz`: number of divisions in each direction | bulk | +| `centerPoints`* | if `selector` is set to `id`, particles selected by ID list | `ids`: a list of particle ids | individual | +| `centerPoints`* | if `selector` is set to `box`, particles are selected by center points located in a box | corner points of the box are given in `boxInfo` sub-dict | individual | +| `centerPoints`* | if `selector` is set to `sphere`, particles are selected by center points located in a sphere | center and radius of a sphere given in `sphereInfo` sub-dict | individual | +| `centerPoints`* | if `selector` is set to `cylinder`, particles are selected by center points located in a cylinder | axis info and radius of cylinder at end points that are given in `cylinderInfo` sub-dict | individual | +| \* Particles selection is done when simulation reaches the time that is specified by `startTime` of the post-process component and this selection remains intact up to the end of simulation. This is very good for particle tracking purposes or when you want to analyze specific particles behavior over time. | +| \** This region creates a rectangular mesh and particles are located into cells according to their center points. When using `GaussianDistribution` as `processMethod`, a larger neighbor radius is considered for each cell and particles inside this neighbor radius are included in the calculations. | ## 6. Processing Operations for Bulk Properties @@ -166,7 +167,7 @@ where: ### 6.2. About fluctuation2 in average function -Fluctuation2 is an optional parameter that can be used to account for fluctuations in the particle field values with respect to mean value of the field. +`fluctuation2` is an optional parameter that can be used to account for fluctuations in the particle field values with respect to mean value of the field. It is used in the `average` function to calculate the fluctuation of the field values around the mean. The formula for fluctuation2 is: $$\text{fluctuation}^2 = \frac{\sum_j w_j \cdot \phi_j \cdot (\text{field}_j - \text{mean})^2}{\sum_i w_i \cdot \phi_i}$$ @@ -349,6 +350,90 @@ along_a_line This example creates 10 spherical regions along a line from (0,0,0) to (0,0.15,0.15) and calculates the bulk density and volume density in each region. +### 7.4 Example 4: Processing in a Rectangular Mesh + +In this example, a rectangular mesh is defined. The `rectMeshInfo` section specifies the minimum and maximum corner points of the box, the number of divisions in each direction, and an optional cell extension factor which is effective for GaussianDistribution only. In the `operations` section, two operations are defined: one for calculating the average velocity and another for calculating the solid volume fraction. + +```cpp +on_a_rectMesh +{ + processMethod GaussianDistribution; + processRegion rectMesh; + + timeControl settingsDict; // uses settings from settingsDict file + + rectMeshInfo + { + min (-0.12 -0.12 0.00); // lower corner point of the box + max (0.12 0.12 0.11); // upper corner point of the box + + nx 30; // number of divisions in x direction + ny 30; // number of divisions in y direction + nz 15; // number of divisions in z direction + + // optional (default is 2.0) + // for each cell, a neighbor radius is considered. This neighbor radius is equal to + // cellExtension * equivalent diameter of the cell. + // cell extension is only effective when using GaussianDistribution as processMethod. + cellExtension 3; + } + + operations + ( + avVelocity + { + function average; + field velocity; + fluctuation2 yes; + threshold 4; + phi mass; + } + + solidVolumeFraction + { + function sum; + field volume; + divideByVolume yes; + } + ); +} +``` + +### 7.5 Example 5: Tracking particles + +Suppose we want to mark and track the position of particles that are located inside a box region at t = 1 s. All particles that are inside the box at t = 1 s will be marked/selected and then the position of them are recorded along the simulation time. The following example shows how to do this. Note that marking/selecting of particles is done at the instance that is defined by `startTime`. + +```C++ +particlesTrack +{ + processMethod particleProbe; + + processRegion centerPoints; + + // all particles whose ceters are located inside this box + // are selected. Selection occurs at startTime: particles + // that are inside the box at t = startTime. + selector box; + boxInfo + { + min (0 0 0); + max (0.1 0.05 0.05); + } + + // center position of selected particles are processed + field position; + + timeControl simulationTime; + // execution starts at 1.0 s + startTime 1.0; + // execution ends at 100 s + endTime 100; + // execution interval of this compoenent + executionInterval 0.02; + +} +``` + ## 8. Advanced Features ### 8.1. Special functions applied on fields @@ -464,7 +549,7 @@ components field component(velocity,y); ids (0 10 100); timeControl default; // other options are settings, timeStep, simulationTime - // settings: uses parameters from settingsDict file + // settingsDict: uses parameters from settingsDict file // timeStep: uses the time step of the simulation controlling the execution of postprocessing // simulationTime: uses the simulation time of the simulation controlling the execution of postprocessing // default: uses the default time control (defined in defaultTimeControl). @@ -499,6 +584,49 @@ components executionInterval 0.02; } + + on_a_rectMesh + { + processMethod GaussianDistribution; + processRegion rectMesh; + + timeControl settingsDict; // uses settings from settingsDict file + + rectMeshInfo + { + min (-0.12 -0.12 0.00); // lower corner point of the box + max (0.12 0.12 0.11); // upper corner point of the box + + nx 30; // number of divisions in x direction + ny 30; // number of divisions in y direction + nz 15; // number of divisions in z direction + + // optional (default is 2.0) + // for each cell, a neighbor radius is considered. This neighbor radius is equal to + // cellExtension * equivalent diameter of the cell. + // cell extension is only effective when using GaussianDistribution as processMethod. + cellExtension 3; + } + + operations + ( + avVelocity + { + function average; + field velocity; + fluctuation2 yes; + threshold 4; + phi mass; + } + + solidVolumeFraction + { + function sum; + field volume; + divideByVolume yes; + } + ); + } on_single_sphere { diff --git a/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.cpp b/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.cpp index 28589484..64f88810 100644 --- a/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.cpp +++ b/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.cpp @@ -85,9 +85,12 @@ pFlow::postprocessData::rectMeshRegionPoints::rectMeshRegionPoints : regionPoints(dict, fieldsDataBase), boxRegion_(dict.subDict("rectMeshInfo")), + cellExtension_(dict.subDict("rectMeshInfo").getValOrSet("cellExtension", 2.0)), pointsOnCells_("selectedPoints"), selectedPoints_(pointsOnCells_) { + cellExtension_ = max(cellExtension_, one); + const auto& rectMeshInfo = dict.subDict("rectMeshInfo"); auto nx = rectMeshInfo.getValMax("nx", 1); @@ -124,10 +127,12 @@ pFlow::postprocessData::rectMeshRegionPoints::rectMeshRegionPoints } } -void pFlow::postprocessData::rectMeshRegionPoints::setRegionExtension(real ext) +void pFlow::postprocessData::rectMeshRegionPoints::applyRegionExtension() { - regionExtension_ = max(one, ext); - real vf = pow(regionExtension_, 3); + // it cannot be lower than 1 + cellExtension_ = max(one, cellExtension_); + + real vf = pow(cellExtension_, 3); for(auto& v:volumes_) { v *= vf; @@ -135,7 +140,7 @@ void pFlow::postprocessData::rectMeshRegionPoints::setRegionExtension(real ext) for(auto& d:diameter_) { - d *= regionExtension_; + d *= cellExtension_; } } @@ -163,7 +168,7 @@ bool pFlow::postprocessData::rectMeshRegionPoints::update() } // search beyound cells is not required - if( equal(regionExtension_,one)) + if( equal(cellExtension_,one)) { selectedPoints_ = pointsOnCells_; return true; diff --git a/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.hpp b/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.hpp index ee5c96da..b1f50ee3 100644 --- a/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.hpp +++ b/src/PostprocessData/region/regionPoints/rectMeshRegionPoints/rectMeshRegionPoints.hpp @@ -50,7 +50,7 @@ class rectMeshRegionPoints private: /// box object defining the region for point selection - box boxRegion_; + box boxRegion_; /// store the cells that are inside the box region cellMapper mapper_; @@ -59,10 +59,12 @@ private: realx3Vector centerPoints_; /// Volume of each cell in the rectMesh region - realVector volumes_; + realVector volumes_; /// Diameter of each cell in the rectMesh region - realVector diameter_; + realVector diameter_; + + real cellExtension_; Vector pointsOnCells_; @@ -121,7 +123,13 @@ public: return volumes_.empty(); } - void setRegionExtension(real ext) override; + void applyRegionExtension() override; + + + real regionExtensionRatio()const override + { + return cellExtension_; + } /** * @brief Get the volume of the rectMesh region diff --git a/src/PostprocessData/region/regionPoints/regionPoints/regionPoints.hpp b/src/PostprocessData/region/regionPoints/regionPoints/regionPoints.hpp index 1e8874bb..1656b82d 100644 --- a/src/PostprocessData/region/regionPoints/regionPoints/regionPoints.hpp +++ b/src/PostprocessData/region/regionPoints/regionPoints/regionPoints.hpp @@ -49,15 +49,10 @@ class fieldsDataBase; */ class regionPoints { - using PointsTypeHost = typename pointStructure::PointsTypeHost; + using PointsTypeHost = typename pointStructure::PointsTypeHost; /// Reference to the fields database containing simulation data - fieldsDataBase& fieldsDataBase_; - -protected: - - /// extends the search radius to a distance farther than the region - real regionExtension_ = 1.0; + fieldsDataBase& fieldsDataBase_; public: @@ -97,9 +92,15 @@ public: /// 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) + virtual void applyRegionExtension() {} + virtual + real regionExtensionRatio()const + { + return 1.0; + } + /// @brief volume of elements /// @return sapn for accessing the volume of elements virtual diff --git a/src/PostprocessData/sampleDictionary/postprocessDataDict b/src/PostprocessData/sampleDictionary/postprocessDataDict index ca715179..7beaaeab 100755 --- a/src/PostprocessData/sampleDictionary/postprocessDataDict +++ b/src/PostprocessData/sampleDictionary/postprocessDataDict @@ -39,7 +39,7 @@ components field component(velocity,y); ids (0 10 100); timeControl default; // other options are settings, timeStep, simulationTime - // settings: uses parameters from settingsDict file + // settingsDict: uses parameters from settingsDict file // timeStep: uses the time step of the simulation controlling the execution of postprocessing // simulationTime: uses the simulation time of the simulation controlling the execution of postprocessing // default: uses the default time control (defined in defaultTimeControl). @@ -74,6 +74,49 @@ components executionInterval 0.02; } + + on_a_rectMesh + { + processMethod GaussianDistribution; + processRegion rectMesh; + + timeControl settingsDict; // uses settings from settingsDict file + + rectMeshInfo + { + min (-0.12 -0.12 0.00); // lower corner point of the box + max (0.12 0.12 0.11); // upper corner point of the box + + nx 30; // number of divisions in x direction + ny 30; // number of divisions in y direction + nz 15; // number of divisions in z direction + + // optional (default is 2.0) + // for each cell, a neighbor radius is considered. This neighbor radius is equal to + // cellExtension * equivalent diameter of the cell. + // cell extension is only effective when using GaussianDistribution as processMethod. + cellExtension 3; + } + + operations + ( + avVelocity + { + function average; + field velocity; + fluctuation2 yes; + threshold 4; + phi mass; + } + + solidVolumeFraction + { + function sum; + field volume; + divideByVolume yes; + } + ); + } on_single_sphere { @@ -134,7 +177,7 @@ components { function sum; field one; - phi one; + phi one; divideByVolume yes; } @@ -153,15 +196,14 @@ components startTime 1.0; endTime 3.0; executionInterval 0.1; - - + // 10 spheres with radius 0.01 along the straight line defined by p1 and p2 lineInfo { - p1 (0 0 0); - p2 (0 0.15 0.15); - nSpheres 10; - radius 0.01; + p1 (0 0 0); + p2 (0 0.15 0.15); + nSpheres 10; + radius 0.01; } operations