Merge pull request #212 from PhasicFlow/postprocessPhasicFlow

Postprocess phasic flow
This commit is contained in:
PhasicFlow 2025-04-25 09:29:02 +03:30 committed by GitHub
commit 59fbee9711
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 389 additions and 53 deletions

View File

@ -26,12 +26,6 @@ Licence:
#include "fieldFunctions.hpp"
#include "dictionary.hpp"
namespace pFlow::postprocessData
{
bool pointFieldGetType(const word& TYPENAME, word& fieldType, word& fieldSpace);
}
bool pFlow::postprocessData::fieldsDataBase::loadPointStructureToTime()
{
@ -898,7 +892,21 @@ pFlow::postprocessData::allPointFieldTypes pFlow::postprocessData::fieldsDataBas
}
}
bool pFlow::postprocessData::fieldsDataBase::pointFieldGetType
(
const word& TYPENAME,
word& fieldType,
word& fieldSpace
)
{
std::regex match("pointField\\<([A-Za-z1-9_]*)\\,([A-Za-z1-9_]*)\\>");
std::smatch search;
if(!std::regex_match(TYPENAME, search, match)) return false;
if(search.size()!= 3) return false;
fieldType = search[1];
fieldSpace = search[2];
return true;
}
pFlow::uniquePtr<pFlow::postprocessData::fieldsDataBase>
pFlow::postprocessData::fieldsDataBase::create
@ -941,19 +949,5 @@ pFlow::uniquePtr<pFlow::postprocessData::fieldsDataBase>
return nullptr;
}
bool pFlow::postprocessData::pointFieldGetType
(
const word& TYPENAME,
word& fieldType,
word& fieldSpace
)
{
std::regex match("pointField\\<([A-Za-z1-9_]*)\\,([A-Za-z1-9_]*)\\>");
std::smatch search;
if(!std::regex_match(TYPENAME, search, match)) return false;
if(search.size()!= 3) return false;
fieldType = search[1];
fieldSpace = search[2];
return true;
}

View File

@ -304,6 +304,12 @@ public:
{
return -1.0;
}
static
bool pointFieldGetType(
const word& TYPENAME,
word& fieldType,
word& fieldSpace);
static
uniquePtr<fieldsDataBase> create(

View File

@ -3,10 +3,7 @@
#include "dynamicPointStructure.hpp"
#include "vocabs.hpp"
namespace pFlow
{
bool pointFieldGetType(const word& TYPENAME, word& fieldType, word& fieldSpace);
}
bool pFlow::postprocessData::simulationFieldsDataBase::pointFieldNameExists(const word &name) const
{
@ -37,7 +34,7 @@ pFlow::word pFlow::postprocessData::simulationFieldsDataBase::getPointFieldType
{
word pfType = time().lookupObjectTypeName(name);
word type, space;
if(!pointFieldGetType(pfType, type, space))
if(!fieldsDataBase::pointFieldGetType(pfType, type, space))
{
fatalErrorInFunction
<<"Error in retriving the type of pointField "

View File

@ -0,0 +1,110 @@
# pFlowToVTK Utility
## Overview
pFlowToVTK is a utility for converting phasicFlow simulation data into VTK (Visualization Toolkit) file format. This enables visualization of simulation results in applications like ParaView. The utility handles two primary types of data:
1. **Particle Data** (pointField) - Converts particle properties such as position, velocity, forces, etc.
2. **Geometry Data** (triSurfaceField) - Converts surface geometries and their properties
## Basic Usage
```bash
pFlowToVTK [OPTIONS]
```
After simulation is complete, run this command from the case directory to convert all simulation data to VTK format, which will be stored in the `./VTK/` folder.
## Command Line Options
| Option | Description |
|--------|-------------|
| `--no-geometry` | Skip conversion of geometry data to VTK format |
| `--no-particles` | Skip conversion of particle data to VTK format |
| `-b, --binary` | Write VTK files in binary format (default is ASCII). Using binary format accelerates conversion (5-10x) and visualization in ParaView |
| `-o, --out-folder <path>` | Specify the output directory path (default: `./VTK/`) |
| `-s, --separate-surfaces` | Create separate files for each sub-surface in geometry |
| `-f, --fields <field1> <field2>...` | Specify which particle fields to convert (space-separated list). If not specified, all fields are converted |
| `-t, --time <times>` | Process only specific time folders. Accepts multiple formats: <br> - Space-separated list of times (e.g., `0.1 0.2 0.3`) <br> - Strided range with format `<begin>:<stride>:<end>` (e.g., `0.1:0.1:0.5`) <br> - Interval with format `<begin>:<end>` (e.g., `0.1:0.5`) |
| `-h, --help` | Display help message with all available options |
## Examples
Convert all data with default settings:
```bash
pFlowToVTK
```
Convert only geometry data:
```bash
pFlowToVTK --no-particles
```
Convert only particle data in binary format:
```bash
pFlowToVTK --no-geometry --binary
```
Convert specific fields for particles:
```bash
pFlowToVTK -f velocity diameter contactForce
```
Convert data for specific time steps:
```bash
pFlowToVTK -t 0.1 0.2 0.3
```
Convert data for a range of time steps:
```bash
pFlowToVTK -t 0.1:0.1:1.0
```
Write output to a custom directory:
```bash
pFlowToVTK -o /path/to/custom/output
```
## Output Structure
The utility creates the following directory structure:
```
simulationCase/
├── 0/ # Contains the initial time step data
├── 0.1/ # time-folder for simulation data at 0.1 s
├── 0.2/ # time-folder for simulation data at 0.2 s
├── caseSetup/ # Contains the case setup files
├── settings/ # Contains the settings files
└── VTK/
├── geometry/ # Contains VTK files for geometry
│ └── surface-*.vtk # Geometry at different time steps
└── particles/ # Contains VTK files for particles
└── particles-*.vtk # Particle data at different time steps
```
Additionally, the utility generates `.vtk.series` files in the VTK root folder, which can be used by ParaView for loading time series data automatically:
```
VTK/
├── particles.vtk.series
└── surface.vtk.series # (and possibly other surface names if --separate-surfaces is used)
```
## Recommendations
- Use binary format (`-b` flag) for large simulations to significantly improve conversion speed and reduce file size
- For complex geometries with multiple sub-surfaces, consider using `-s` flag to keep surfaces in separate files for better visualization
- When working with large datasets, use the `-t` option to convert only the time steps you need to visualize
## See Also
## Related Utilities
- [`tutorials`](../../tutorials): Contains example cases and step-by-step guides for using phasicFlow
- [`particlesPhasicFlow`](../particlesPhasicFlow): Creates the initial fields for particles
- [`geometryPhasicFlow`](../geometryPhasicFlow): Creates the geometry
- [`postprocessPhasicFlow`](../postprocessPhasicFlow): Tool for performing various cell-based averaging on fields

View File

@ -1,26 +1,19 @@
#include "postSimulationFieldsDataBase.hpp"
#include "vocabs.hpp"
namespace pFlow
namespace pFlow::postprocessData
{
bool pointFieldGetType
(
const word& objectType,
word& fieldType,
word& fieldSpace
);
}
bool pFlow::postSimulationFieldsDataBase::pointFieldNameExists(const word& name) const
bool postSimulationFieldsDataBase::pointFieldNameExists(const word& name) const
{
if(currentFileFields_.contains(name)) return true;
if(time().lookupObjectName(name)) return true;
return false;
}
bool pFlow::postSimulationFieldsDataBase::loadPointFieldToTime(const word &name)
bool postSimulationFieldsDataBase::loadPointFieldToTime(const word &name)
{
if(time().lookupObjectName(name)) return true;
if(auto [iter, success]=currentFileFields_.findIf(name); success)
@ -116,7 +109,7 @@ bool pFlow::postSimulationFieldsDataBase::loadPointFieldToTime(const word &name)
return true;
}
bool pFlow::postSimulationFieldsDataBase::loadPointStructureToTime()
bool postSimulationFieldsDataBase::loadPointStructureToTime()
{
if(!pStructPtr_)
{
@ -126,7 +119,7 @@ bool pFlow::postSimulationFieldsDataBase::loadPointStructureToTime()
return true;
}
const pFlow::shape &pFlow::postSimulationFieldsDataBase::getShape() const
const shape &postSimulationFieldsDataBase::getShape() const
{
if(!shapePtr_)
{
@ -143,7 +136,7 @@ const pFlow::shape &pFlow::postSimulationFieldsDataBase::getShape() const
return shapePtr_();
}
pFlow::word pFlow::postSimulationFieldsDataBase::getPointFieldType(const word &name) const
word postSimulationFieldsDataBase::getPointFieldType(const word &name) const
{
if(auto [iter, success]=currentFileFields_.findIf(name); success)
{
@ -159,7 +152,7 @@ pFlow::word pFlow::postSimulationFieldsDataBase::getPointFieldType(const word &n
return "";
}
bool pFlow::postSimulationFieldsDataBase::setToCurrentFolder()
bool postSimulationFieldsDataBase::setToCurrentFolder()
{
allPointFields_.clear();
pStructPtr_.reset(nullptr);
@ -184,7 +177,7 @@ bool pFlow::postSimulationFieldsDataBase::setToCurrentFolder()
word type, space;
for(auto& [name, objectType]: files)
{
if(pointFieldGetType(objectType, type, space))
if(fieldsDataBase::pointFieldGetType(objectType, type, space))
{
if(name == pointStructureFile__) continue;
currentFileFields_.insertIf(name, type);
@ -194,7 +187,7 @@ bool pFlow::postSimulationFieldsDataBase::setToCurrentFolder()
return true;
}
pFlow::postSimulationFieldsDataBase::postSimulationFieldsDataBase
postSimulationFieldsDataBase::postSimulationFieldsDataBase
(
systemControl &control,
const dictionary& postDict,
@ -233,17 +226,17 @@ pFlow::postSimulationFieldsDataBase::postSimulationFieldsDataBase
}
}
const pFlow::pointStructure& pFlow::postSimulationFieldsDataBase::pStruct()const
const pointStructure& postSimulationFieldsDataBase::pStruct()const
{
return pStructPtr_();
}
pFlow::timeValue pFlow::postSimulationFieldsDataBase::getNextTimeFolder() const
timeValue postSimulationFieldsDataBase::getNextTimeFolder() const
{
return allValidFolders_.nextTime();
}
pFlow::timeValue pFlow::postSimulationFieldsDataBase::setToNextTimeFolder()
timeValue postSimulationFieldsDataBase::setToNextTimeFolder()
{
timeValue nextTime = allValidFolders_.nextTime();
if(nextTime < 0.0) return nextTime;
@ -261,7 +254,7 @@ pFlow::timeValue pFlow::postSimulationFieldsDataBase::setToNextTimeFolder()
return nextTime;
}
pFlow::timeValue pFlow::postSimulationFieldsDataBase::skipNextTimeFolder()
timeValue postSimulationFieldsDataBase::skipNextTimeFolder()
{
timeValue nextTime = allValidFolders_.nextTime();
if(nextTime < 0.0) return nextTime;
@ -269,3 +262,5 @@ pFlow::timeValue pFlow::postSimulationFieldsDataBase::skipNextTimeFolder()
allValidFolders_++;
return nextTime;
}
} // namespace pFlow::postprocessData

View File

@ -27,12 +27,12 @@ Licence:
#include "ListPtr.hpp"
#include "property.hpp"
namespace pFlow
namespace pFlow::postprocessData
{
class postSimulationFieldsDataBase
:
public fieldsDataBase
public postprocessData::fieldsDataBase
{
systemControl& control_;

View File

@ -30,7 +30,7 @@ Licence:
int main(int argc, char** argv )
{
pFlow::word outFolder = (pFlow::CWD()/pFlow::postProcessGlobals::defaultRelDir__).wordPath();
pFlow::word outFolder = (pFlow::CWD()/pFlow::postprocessData::defaultRelDir__).wordPath();
pFlow::commandLine cmds(
"postprocessPhasicFlow",
@ -40,7 +40,7 @@ int main(int argc, char** argv )
pFlow::wordVector times;
pFlow::word description = "path to output folder of postprocess data: ./"
+ pFlow::postProcessGlobals::defaultRelDir__;
+ pFlow::postprocessData::defaultRelDir__;
cmds.addOption("-o,--out-folder",
outFolder,
@ -50,7 +50,7 @@ int main(int argc, char** argv )
cmds.addOption(
"-t,--time",
times.vectorField(),
"a SPACE separated lits of time folders, "
"a SPACE separated list of time folders, "
"or a strided range <begin>:<stride>:<end>, or an interval <begin>:<end>",
" ");
@ -99,7 +99,7 @@ int main(int argc, char** argv )
fatalExit;
}
pFlow::postprocessData postprocess(Control, nextTime);
pFlow::postprocessData::postprocessData postprocess(Control, nextTime);
postprocess.setOutputDirectory(pFlow::fileSystem(outFolder+"/").absolute());
bool folderSkipped = false;

View File

@ -0,0 +1,234 @@
# postprocessPhasicFlow Utility
This is a documentation for the `postprocessPhasicFlow` utility. This utility is designed to perform post-simulation processing on completed simulation data.
## Table of Contents
- [1. Overview](#1-overview)
- [2. When to Use postprocessPhasicFlow](#2-when-to-use-postprocessphasicflow)
- [3. Basic Usage](#3-basic-usage)
- [4. Command Line Options](#4-command-line-options)
- [4.1. Available Options](#41-available-options)
- [4.2. Examples](#42-examples)
- [5. Configuration](#5-configuration)
- [5.1. Important Configuration Parameters for Post-Simulation Processing](#51-important-configuration-parameters-for-post-simulation-processing)
- [6. Difference Between In-Simulation and Post-Simulation Processing](#6-difference-between-in-simulation-and-post-simulation-processing)
- [7. File Structure](#7-file-structure)
- [8. Advanced Features](#8-advanced-features)
- [9. Example Configuration](#9-example-configuration)
- [10. Troubleshooting](#10-troubleshooting)
- [11. See Also](#11-see-also)
## 1. Overview
`postprocessPhasicFlow` is a utility for performing postprocessing analysis on completed simulation data. It allows you to extract statistical information, track specific particles, and analyze regional particle behavior without needing to re-run your simulations. This utility leverages the functionality provided by phasicFlow's `PostprocessData` module to analyze data stored in time folders.
## 2. When to Use postprocessPhasicFlow
You should use this utility when:
1. Your simulation has completed and you want to analyze the results
2. You want to try different postprocessing configurations on the same simulation data
3. You need to extract additional information that wasn't included in real-time processing
4. You want to focus on specific time periods or regions of your simulation domain
## 3. Basic Usage
To use the `postprocessPhasicFlow` utility, navigate to your simulation case directory and run:
```bash
postprocessPhasicFlow
```
This will read the `postprocessDataDict` file from your case's `settings` directory and perform the configured postprocessing operations on all available time folders.
## 4. Command Line Options
The `postprocessPhasicFlow` utility supports several command line options that allow you to customize its behavior:
```bash
postprocessPhasicFlow [OPTIONS]
```
### 4.1. Available Options
| Option | Description |
|--------|-------------|
| `-o, --out-folder <path>` | Specify the output directory path where postprocessing results will be written. Default is `./postprocessData/` |
| `-t, --time <times>` | Process only specific time folders. Accepts multiple formats: <br> - Space-separated list of times (e.g., `0.1 0.2 0.3`) <br> - Strided range with format `<begin>:<stride>:<end>` (e.g., `0.1:0.1:0.5`) <br> - Interval with format `<begin>:<end>` (e.g., `0.1:0.5`) |
| `-z, --zeroFolder` | Include the zero folder (initial state) in the processing. By default, the zero folder is not processed. |
| `-h, --help` | Display help message with all available options |
### 4.2. Examples
Process all available time folders (except zero folder):
```bash
postprocessPhasicFlow
```
Process only specific time steps:
```bash
postprocessPhasicFlow -t 0.1 0.2 0.5
```
Process a range of time steps from 0.1 to 1.0 with 0.1 increments:
```bash
postprocessPhasicFlow -t 0.1:0.1:1.0
```
Process all time steps including the initial state (zero folder):
```bash
postprocessPhasicFlow -z
```
Write output to a custom directory:
```bash
postprocessPhasicFlow -o /path/to/custom/output
```
## 5. Configuration
The `postprocessPhasicFlow` utility is configured through the same `postprocessDataDict` file used for in-simulation postprocessing. This file should be placed in the `settings` directory of your case.
### 5.1. Important Configuration Parameters for Post-Simulation Processing
When using `postprocessPhasicFlow` for post-simulation processing, pay special attention to these settings:
```cpp
// For post-simulation, runTimeActive should be set to "no"
// This indicates that you're doing post-simulation processing
runTimeActive no;
// Specify the correct shape type used in your simulation
// This is essential for post-simulation processing
shapeType sphere; // Options: sphere, grain, etc.
```
The `shapeType` parameter is particularly crucial for post-simulation processing as it tells the utility what kind of particles were used in the simulation, allowing it to correctly interpret the stored data.
## 6. Difference Between In-Simulation and Post-Simulation Processing
| Feature | In-Simulation Processing | Post-Simulation Processing with postprocessPhasicFlow |
|---------|--------------------------|--------------------------------------------------------|
| When it runs | During simulation execution | After simulation is complete |
| How to activate | Set `runTimeActive yes` in postprocessDataDict, set `auxFunctions postprocessData` in settingsDict and add library | Run the `postprocessPhasicFlow` utility |
| Data access | Direct access to simulation data in memory | Reads data from time folders |
| Performance impact | May slow down simulation | No impact on simulation performance |
| Iterations | Can only run once per simulation step | Can be run multiple times with different settings |
## 7. File Structure
The results of the postprocessing will be written to files in your case directory (by default, under `postprocessData` folder), with timestamps and naming that matches your configured components and operations. These files can then be used for further analysis or visualization.
## 8. Advanced Features
`postprocessPhasicFlow` supports all the features of the PostprocessData module, including:
- Different processing methods (arithmetic, uniformDistribution, GaussianDistribution)
- Various region types (sphere, multipleSpheres, line, centerPoints)
- Multiple operation types (average, sum, avMassVelocity)
- Special field functions (component, abs, square, magnitude, etc.)
- Particle filtering with includeMask
but it disables/ignores the effect of all `timeControl` settings in postprocess components.
For detailed information about these features, refer to the [PostprocessData module documentation](../../src/PostprocessData/readme.md).
## 9. Example Configuration
Here's a simple example of a `postprocessDataDict` file configured for post-simulation processing:
```cpp
/* -------------------------------*- C++ -*--------------------------------- *\
| phasicFlow File |
| copyright: www.cemf.ir |
\* ------------------------------------------------------------------------- */
objectName postprocessDataDict;
objectType dictionary;;
fileFormat ASCII;
/*---------------------------------------------------------------------------*/
// Set to "no" for post-simulation processing
runTimeActive no;
// Required for post-simulation processing - specify the shape type used in the simulation
shapeType sphere;
// Default time control settings
defaultTimeControl
{
timeControl timeStep;
startTime 0;
endTime 1000;
executionInterval 20;
}
// List of postprocessing components
components
(
// Track specific particles by ID
particleTracker
{
processMethod particleProbe;
processRegion centerPoints;
selector id;
field velocity;
ids (10 42 87);
timeControl default;
}
// Analyze particle behavior in a spherical region
centerRegionAnalysis
{
processMethod arithmetic;
processRegion sphere;
sphereInfo
{
radius 0.05;
center (0 0 0.1);
}
timeControl default;
operations
(
velocityMagnitude
{
function average;
field mag(velocity);
threshold 5;
divideByVolume no;
fluctuation2 yes;
}
particleDensity
{
function sum;
field mass;
divideByVolume yes;
}
);
}
);
```
## 10. Troubleshooting
If you encounter issues with the `postprocessPhasicFlow` utility, check the following:
1. Make sure your `postprocessDataDict` file specifies the correct `shapeType`
2. Verify that the time folders contain all the required field data
3. Check that field names referenced in your configuration exist in the simulation data
4. Ensure that the simulation case structure is intact and not modified
## 11. See Also
- [PostprocessData module documentation](../../src/PostprocessData/readme.md)
- [phasicFlow simulation tutorials](../../tutorials/)