diff --git a/.github/scripts/sync-wiki.py b/.github/scripts/sync-wiki.py new file mode 100755 index 00000000..fe8a239e --- /dev/null +++ b/.github/scripts/sync-wiki.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +import os +import re +import yaml +import sys + +# Constants +REPO_URL = "https://github.com/PhasicFlow/phasicFlow" +REPO_PATH = os.path.join(os.environ.get("GITHUB_WORKSPACE", ""), "repo") +WIKI_PATH = os.path.join(os.environ.get("GITHUB_WORKSPACE", ""), "wiki") +MAPPING_FILE = os.path.join(REPO_PATH, ".github/workflows/markdownList.yml") + +def load_mapping(): + """Load the markdown to wiki page mapping file.""" + try: + with open(MAPPING_FILE, 'r') as f: + data = yaml.safe_load(f) + return data.get('mappings', []) + except Exception as e: + print(f"Error loading mapping file: {e}") + return [] + +def convert_relative_links(content, source_path): + """Convert relative links in markdown content to absolute URLs.""" + # Find markdown links with regex pattern [text](url) + md_pattern = r'\[([^\]]+)\]\(([^)]+)\)' + + # Find HTML img tags + img_pattern = r' {target_path}") + + try: + # Check if source exists + if not os.path.exists(source_path): + print(f"Source file not found: {source_path}") + return False + + # Read source content + with open(source_path, 'r') as f: + content = f.read() + + # Convert relative links + content = convert_relative_links(content, source_file) + + # Write to wiki page + with open(target_path, 'w') as f: + f.write(content) + + return True + + except Exception as e: + print(f"Error processing {source_file}: {e}") + return False + +def main(): + # Check if wiki directory exists + if not os.path.exists(WIKI_PATH): + print(f"Wiki path not found: {WIKI_PATH}") + sys.exit(1) + + # Load mapping + mappings = load_mapping() + if not mappings: + print("No mappings found in the mapping file") + sys.exit(1) + + print(f"Found {len(mappings)} mappings to process") + + # Process each mapping + success_count = 0 + for mapping in mappings: + source = mapping.get('source') + target = mapping.get('target') + + if not source or not target: + print(f"Invalid mapping: {mapping}") + continue + + if process_file(source, target): + success_count += 1 + + print(f"Successfully processed {success_count} of {len(mappings)} files") + + # Exit with error if any file failed + if success_count < len(mappings): + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/.github/workflows/markdownList.yml b/.github/workflows/markdownList.yml new file mode 100644 index 00000000..68b92ed5 --- /dev/null +++ b/.github/workflows/markdownList.yml @@ -0,0 +1,18 @@ +# This file maps source markdown files to their target wiki pages +# format: +# - source: path/to/markdown/file.md +# target: Wiki-Page-Name +mappings: + - source: benchmarks/readme.md + target: Performance-of-phasicFlow + - source: benchmarks/helicalMixer/readme.md + target: Helical-Mixer-Benchmark + - source: benchmarks/rotatingDrum/readme.md + target: Rotating-Drum-Benchmark + - source: doc/mdDocs/howToBuild-V1.0.md + target: How-to-build-PhasicFlow‐v‐1.0 + - source: tutorials/README.md + target: Tutorials + - source: doc/mdDocs/phasicFlowFeatures.md + target: Features-of-PhasicFlow + # Add more mappings as needed \ No newline at end of file diff --git a/.github/workflows/sync-wiki.yml b/.github/workflows/sync-wiki.yml new file mode 100644 index 00000000..f55d4c3c --- /dev/null +++ b/.github/workflows/sync-wiki.yml @@ -0,0 +1,60 @@ +name: Sync-Wiki + +on: + push: + branches: + - main + paths: + - "**/*.md" + - ".github/workflows/sync-wiki.yml" + - ".github/workflows/markdownList.yml" + - ".github/scripts/sync-wiki.py" + workflow_dispatch: + +jobs: + sync-wiki: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + path: repo + - name: Checkout Wiki + uses: actions/checkout@v3 + with: + repository: ${{ github.repository }}.wiki + path: wiki + continue-on-error: true + - name: Create Wiki Directory if Not Exists + run: | + if [ ! -d "wiki" ]; then + mkdir -p wiki + cd wiki + git init + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + git remote add origin "https://github.com/${{ github.repository }}.wiki.git" + fi + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Install dependencies + run: pip install pyyaml + - name: Sync markdown files to Wiki + run: | + python $GITHUB_WORKSPACE/repo/.github/scripts/sync-wiki.py + env: + GITHUB_REPOSITORY: ${{ github.repository }} + - name: Push changes to wiki + run: | + cd wiki + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + git add . + if git status --porcelain | grep .; then + git commit -m "Auto sync wiki from main repository" + git push --set-upstream https://${{ github.actor }}:${{ github.token }}@github.com/${{ github.repository }}.wiki.git master -f + else + echo "No changes to commit" + fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bdcde81..546725a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,30 +3,17 @@ cmake_minimum_required(VERSION 3.16 FATAL_ERROR) # set the project name and version project(phasicFlow VERSION 1.0 ) -set(CMAKE_CXX_STANDARD 17 CACHE STRING "" FORCE) +set(CMAKE_CXX_STANDARD 20 CACHE STRING "" FORCE) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_INSTALL_PREFIX ${phasicFlow_SOURCE_DIR} CACHE PATH "Install path of phasicFlow" FORCE) -set(CMAKE_BUILD_TYPE Release CACHE STRING "build type" FORCE) +set(CMAKE_BUILD_TYPE Release CACHE STRING "build type") set(BUILD_SHARED_LIBS ON CACHE BOOL "Build using shared libraries" FORCE) mark_as_advanced(FORCE var BUILD_SHARED_LIBS) -message(STATUS ${CMAKE_INSTALL_PREFIX}) +message(STATUS "Install prefix is:" ${CMAKE_INSTALL_PREFIX}) include(cmake/globals.cmake) -#Kokkos directory to be included -set(Kokkos_Source_DIR) - -if(DEFINED ENV{Kokkos_DIR}) - set(Kokkos_Source_DIR $ENV{Kokkos_DIR}) -else() - set(Kokkos_Source_DIR $ENV{HOME}/Kokkos/kokkos) -endif() -message(STATUS "Kokkos source directory is ${Kokkos_Source_DIR}") -add_subdirectory(${Kokkos_Source_DIR} ./kokkos) -Kokkos_cmake_settings() - - option(pFlow_STD_Parallel_Alg "Use TTB std parallel algorithms" ON) option(pFlow_Build_Serial "Build phasicFlow and backends for serial execution" OFF) option(pFlow_Build_OpenMP "Build phasicFlow and backends for OpenMP execution" OFF) @@ -34,6 +21,8 @@ option(pFlow_Build_Cuda "Build phasicFlow and backends for Cuda execution" OFF option(pFlow_Build_Double "Build phasicFlow with double precision floating-oint variables" ON) option(pFlow_Build_MPI "Build for MPI parallelization. This will enable multi-gpu run, CPU run on clusters (distributed memory machine). Use this combination Cuda+MPI, OpenMP + MPI or Serial+MPI " OFF) +#for installing the required packages +include(cmake/preReq.cmake) if(pFlow_Build_Serial) set(Kokkos_ENABLE_SERIAL ON CACHE BOOL "Serial execution" FORCE) @@ -46,7 +35,8 @@ elseif(pFlow_Build_OpenMP ) set(Kokkos_ENABLE_OPENMP ON CACHE BOOL "OpenMP execution" FORCE) set(Kokkos_ENABLE_CUDA OFF CACHE BOOL "Cuda execution" FORCE) set(Kokkos_ENABLE_CUDA_LAMBDA OFF CACHE BOOL "Cuda execution" FORCE) - set(Kokkos_DEFAULT_HOST_PARALLEL_EXECUTION_SPACE SERIAL CACHE STRING "" FORCE) + set(Kokkos_DEFAULT_HOST_PARALLEL_EXECUTION_SPACE Serial CACHE STRING "" FORCE) + set(Kokkos_DEFAULT_DEVICE_PARALLEL_EXECUTION_SPACE OpenMP CACHE STRING "" FORCE) set(Kokkos_ENABLE_CUDA_CONSTEXPR OFF CACHE BOOL "Enable constexpr on cuda code" FORCE) elseif(pFlow_Build_Cuda) set(Kokkos_ENABLE_SERIAL ON CACHE BOOL "Serial execution" FORCE) @@ -65,6 +55,7 @@ include(cmake/makeExecutableGlobals.cmake) configure_file(phasicFlowConfig.H.in phasicFlowConfig.H) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + #add a global include directory include_directories(src/setHelpers src/demComponent "${PROJECT_BINARY_DIR}") diff --git a/DEMSystems/DEMSystem/DEMSystem.hpp b/DEMSystems/DEMSystem/DEMSystem.hpp index 23814d3e..424af8ae 100644 --- a/DEMSystems/DEMSystem/DEMSystem.hpp +++ b/DEMSystems/DEMSystem/DEMSystem.hpp @@ -183,4 +183,4 @@ public: } // pFlow -#endif // __DEMSystem_hpp__ \ No newline at end of file +#endif // __DEMSystem_hpp__ diff --git a/README.md b/README.md index e1281936..ff041c6b 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,76 @@ -
- +
+ PhasicFlow Logo
+## **PhasicFlow: High-Performance Discrete Element Method Simulations** -**PhasicFlow** is a parallel C++ code for performing DEM simulations. It can run on shared-memory multi-core computational units such as multi-core CPUs or GPUs (for now it works on CUDA-enabled GPUs). The parallelization method mainly relies on loop-level parallelization on a shared-memory computational unit. You can build and run PhasicFlow in serial mode on regular PCs, in parallel mode for multi-core CPUs, or build it for a GPU device to off-load computations to a GPU. In its current statues you can simulate millions of particles (up to 80M particles tested) on a single desktop computer. You can see the [performance tests of PhasicFlow](https://github.com/PhasicFlow/phasicFlow/wiki/Performance-of-phasicFlow) in the wiki page. +PhasicFlow is a robust, open-source C++ framework designed for the efficient simulation of granular materials using the Discrete Element Method (DEM). Leveraging parallel computing paradigms, PhasicFlow is capable of executing simulations on shared-memory multi-core architectures, including CPUs and NVIDIA GPUs (CUDA-enabled). The core parallelization strategy focuses on loop-level parallelism, enabling significant performance gains on modern hardware. Users can seamlessly transition between serial execution on standard PCs, parallel execution on multi-core CPUs (OpenMP), and accelerated simulations on GPUs. Currently, PhasicFlow supports simulations involving up to 80 million particles on a single desktop workstation. Detailed performance benchmarks are available on the [PhasicFlow Wiki](https://github.com/PhasicFlow/phasicFlow/wiki/Performance-of-phasicFlow). -**MPI** parallelization with dynamic load balancing is under development. With this level of parallelization, PhasicFlow can leverage the computational power of **multi-gpu** workstations or clusters with distributed memory CPUs. -In summary PhasicFlow can have 6 execution modes: -1. Serial on a single CPU core, -2. Parallel on a multi-core computer/node (using OpenMP), -3. Parallel on an nvidia-GPU (using Cuda), -4. Parallel on distributed memory workstation (Using MPI) -5. Parallel on distributed memory workstations with multi-core nodes (using MPI+OpenMP) -6. Parallel on workstations with multiple GPUs (using MPI+Cuda). -## How to build? -You can build PhasicFlow for CPU and GPU executions. The latest release of PhasicFlow is v-0.1. [Here is a complete step-by-step procedure for building phasicFlow-v-0.1.](https://github.com/PhasicFlow/phasicFlow/wiki/How-to-Build-PhasicFlow). +**Scalable Parallelism: MPI Integration** -## Online code documentation -You can find a full documentation of the code, its features, and other related materials on [online documentation of the code](https://phasicflow.github.io/phasicFlow/) +Ongoing development includes the integration of MPI-based parallelization with dynamic load balancing. This enhancement will extend PhasicFlow's capabilities to distributed memory environments, such as multi-GPU workstations and high-performance computing clusters. Upon completion, PhasicFlow will offer six distinct execution modes: -## How to use PhasicFlow? -You can navigate into [tutorials folder](./tutorials) in the phasicFlow folder to see some simulation case setups. If you need more detailed discription, visit our [wiki page tutorials](https://github.com/PhasicFlow/phasicFlow/wiki/Tutorials). +1. **Serial Execution:** Single-core CPU. +2. **Shared-Memory Parallelism:** Multi-core CPU (OpenMP). +3. **GPU Acceleration:** NVIDIA GPU (CUDA). +4. **Distributed-Memory Parallelism:** MPI. +5. **Hybrid Parallelism:** MPI + OpenMP. +6. **Multi-GPU Parallelism:** MPI + CUDA. -## [PhasicFlowPlus](https://github.com/PhasicFlow/PhasicFlowPlus) -PhasicFlowPlus is and extension to PhasicFlow for simulating particle-fluid systems using resolved and unresolved CFD-DEM. [See the repository of this package.](https://github.com/PhasicFlow/PhasicFlowPlus) +## **Build and Installation** +PhasicFlow can be compiled for both CPU and GPU execution. -## Supporting packages -* [Kokkos](https://github.com/kokkos/kokkos) from National Technology & Engineering Solutions of Sandia, LLC (NTESS) -* [CLI11 1.8](https://github.com/CLIUtils/CLI11) from University of Cincinnati. +* **Current Development (v-1.0):** Comprehensive build instructions are available [here](https://github.com/PhasicFlow/phasicFlow/wiki/How-to-build-PhasicFlow%E2%80%90v%E2%80%901.0). +* **Latest Release (v-0.1):** Detailed build instructions are available [here](https://github.com/PhasicFlow/phasicFlow/wiki/How-to-Build-PhasicFlow). + +## **Comprehensive Documentation** + +In-depth documentation, including code structure, features, and usage guidelines, is accessible via the [online documentation portal](https://phasicflow.github.io/phasicFlow/). + +### **Tutorials and Examples** + +Practical examples and simulation setups are provided in the [tutorials directory](./tutorials). For detailed explanations and step-by-step guides, please refer to the [tutorial section on the PhasicFlow Wiki](https://github.com/PhasicFlow/phasicFlow/wiki/Tutorials). + +## Contributing to PhasicFlow +We welcome contributions to PhasicFlow! Whether you're a developer or a new user, there are many ways to get involved. Here's how you can help: +1. Bug Reports +2. Suggestions for better user experience +3. Feature request and algorithm improvements +4. Tutorials, Simulation Case Setups and documentation +5. Direct Code Contributions + +For more details on how you can contribute to PhasicFlow see [this page](https://github.com/PhasicFlow/phasicFlow/wiki/How-to-contribute-to-PhasicFlow). + +## **PhasicFlowPlus: Coupled CFD-DEM Simulations** + +PhasicFlowPlus is an extension of PhasicFlow that facilitates the simulation of particle-fluid systems using resolved and unresolved CFD-DEM methods. The repository for PhasicFlowPlus can be found [here](https://github.com/PhasicFlow/PhasicFlowPlus). + +## How to cite PhasicFlow? -## How to cite PhasicFlow If you are using PhasicFlow in your research or industrial work, cite the following [article](https://www.sciencedirect.com/science/article/pii/S0010465523001662): + ``` -@article{NOROUZI2023108821, -title = {PhasicFlow: A parallel, multi-architecture open-source code for DEM simulations}, -journal = {Computer Physics Communications}, -volume = {291}, -pages = {108821}, -year = {2023}, -issn = {0010-4655}, -doi = {https://doi.org/10.1016/j.cpc.2023.108821}, -url = {https://www.sciencedirect.com/science/article/pii/S0010465523001662}, -author = {H.R. Norouzi}, -keywords = {Discrete element method, Parallel computing, CUDA, GPU, OpenMP, Granular flow} +@article +{ + NOROUZI2023108821, + title = {PhasicFlow: A parallel, multi-architecture open-source code for DEM simulations}, + journal = {Computer Physics Communications}, + volume = {291}, + pages = {108821}, + year = {2023}, + issn = {0010-4655}, + doi = {https://doi.org/10.1016/j.cpc.2023.108821}, + url = {https://www.sciencedirect.com/science/article/pii/S0010465523001662}, + author = {H.R. Norouzi}, + keywords = {Discrete element method, Parallel computing, CUDA, GPU, OpenMP, Granular flow} } ``` + + +## **Dependencies** + +PhasicFlow relies on the following external libraries: + +* **Kokkos:** A community-led performance portability ecosystem within the Linux Foundation's High-Performance Software Foundation (HPSF). ([https://github.com/kokkos/kokkos](https://github.com/kokkos/kokkos)) +* **CLI11 1.8:** A command-line interface parser developed by the University of Cincinnati. ([https://github.com/CLIUtils/CLI11](https://github.com/CLIUtils/CLI11)) diff --git a/benchmarks/helicalMixer_4MParticles/caseSetup/interaction b/benchmarks/helicalMixer/caseSetup/interaction similarity index 100% rename from benchmarks/helicalMixer_4MParticles/caseSetup/interaction rename to benchmarks/helicalMixer/caseSetup/interaction diff --git a/benchmarks/helicalMixer_4MParticles/caseSetup/particleInsertion b/benchmarks/helicalMixer/caseSetup/particleInsertion similarity index 100% rename from benchmarks/helicalMixer_4MParticles/caseSetup/particleInsertion rename to benchmarks/helicalMixer/caseSetup/particleInsertion diff --git a/benchmarks/helicalMixer_4MParticles/caseSetup/sphereShape b/benchmarks/helicalMixer/caseSetup/sphereShape similarity index 100% rename from benchmarks/helicalMixer_4MParticles/caseSetup/sphereShape rename to benchmarks/helicalMixer/caseSetup/sphereShape diff --git a/benchmarks/helicalMixer_4MParticles/cleanThisCase b/benchmarks/helicalMixer/cleanThisCase similarity index 100% rename from benchmarks/helicalMixer_4MParticles/cleanThisCase rename to benchmarks/helicalMixer/cleanThisCase diff --git a/benchmarks/helicalMixer/readme.md b/benchmarks/helicalMixer/readme.md new file mode 100644 index 00000000..57bec363 --- /dev/null +++ b/benchmarks/helicalMixer/readme.md @@ -0,0 +1 @@ +# Helical Mixer Benchmark (phasicFlow v-1.0) diff --git a/benchmarks/helicalMixer_4MParticles/runThisCase b/benchmarks/helicalMixer/runThisCase similarity index 100% rename from benchmarks/helicalMixer_4MParticles/runThisCase rename to benchmarks/helicalMixer/runThisCase diff --git a/benchmarks/helicalMixer_4MParticles/settings/geometryDict b/benchmarks/helicalMixer/settings/geometryDict similarity index 100% rename from benchmarks/helicalMixer_4MParticles/settings/geometryDict rename to benchmarks/helicalMixer/settings/geometryDict diff --git a/benchmarks/helicalMixer_4MParticles/settings/particlesDict b/benchmarks/helicalMixer/settings/particlesDict similarity index 100% rename from benchmarks/helicalMixer_4MParticles/settings/particlesDict rename to benchmarks/helicalMixer/settings/particlesDict diff --git a/benchmarks/helicalMixer_4MParticles/settings/settingsDict b/benchmarks/helicalMixer/settings/settingsDict similarity index 100% rename from benchmarks/helicalMixer_4MParticles/settings/settingsDict rename to benchmarks/helicalMixer/settings/settingsDict diff --git a/benchmarks/readme.md b/benchmarks/readme.md new file mode 100644 index 00000000..888bab60 --- /dev/null +++ b/benchmarks/readme.md @@ -0,0 +1,7 @@ + +# Benchmarks + +Benchmakrs has been done on two different simulations: a simulation with simple geometry (rotating drum) and a simulation with complex geometry (helical mixer). + +- [rotating drum](./rotatingDrum/readme.md) +- [helical mixer](./helicalMixer/readme.md) \ No newline at end of file diff --git a/benchmarks/rotatingDrum/images/commericalDEMsnapshot.png b/benchmarks/rotatingDrum/images/commericalDEMsnapshot.png new file mode 100644 index 00000000..3dd8e08f Binary files /dev/null and b/benchmarks/rotatingDrum/images/commericalDEMsnapshot.png differ diff --git a/benchmarks/rotatingDrum/images/performance1.png b/benchmarks/rotatingDrum/images/performance1.png new file mode 100644 index 00000000..ce9828ff Binary files /dev/null and b/benchmarks/rotatingDrum/images/performance1.png differ diff --git a/benchmarks/rotatingDrum/images/phasicFlow_snapshot.png b/benchmarks/rotatingDrum/images/phasicFlow_snapshot.png new file mode 100644 index 00000000..33b2999d Binary files /dev/null and b/benchmarks/rotatingDrum/images/phasicFlow_snapshot.png differ diff --git a/benchmarks/rotatingDrum/readme.md b/benchmarks/rotatingDrum/readme.md new file mode 100644 index 00000000..ad3d8121 --- /dev/null +++ b/benchmarks/rotatingDrum/readme.md @@ -0,0 +1,96 @@ +# Rotating Drum Benchmark (phasicFlow v-1.0) + +## Overview + +This benchmark compares the performance of phasicFlow with a well-stablished commercial DEM software for simulating a rotating drum with varying particle counts (250k to 8M particles). The benchmark measures both computational efficiency and memory usage across different hardware configurations. + +## Simulation Setup + +
+ +
+

Figure 1. Commercial DEM simulation snapshot

+
+
+ +
+ +
+

Figure 2. phasicFlow simulation snapshot and visualized using Paraview

+
+
+ +### Hardware Specifications + +
+ Table 1. Hardware specifications used for benchmarking. +
+ +| System | CPU | GPU | Operating System | +| :---------: | :----------------------: | :--------------------------: | :--------------: | +| Laptop | Intel i9-13900HX 2.2 GHz | NVIDIA GeForce RTX 4050Ti 6G | Windows 11 24H2 | +| Workstation | Intel Xeon 4210 2.2 GHz | NVIDIA RTX A4000 16G | Ubuntu 22.04 | + +### Simulation Parameters + +
+ Table 2. Parameters for rotating drum simulations. +
+ +| Case | Particle Diameter | Particle Count | Drum Length | Drum Radius | +| :-------: | :---------------: | :--------------: | :------------------: | :------------------: | +| 250k | 6 mm | 250,000 | 0.8 m | 0.2 m | +| 500k | 5 mm | 500,000 | 0.8 m | 0.2 m | +| 1M | 4 mm | 1,000,000 | 0.8 m | 0.2 m | +| 2M | 3 mm | 2,000,000 | 1.2 m | 0.2 m | +| 4M | 3 mm | 4,000,000 | 1.6 m | 0.2 m | +| 8M | 2 mm | 8,000,000 | 1.6 m | 0.2 m | + +The time step for all simulations was set to 1.0e-5 seconds and the simulation ran for 4 seconds. + +## Performance Comparison + +### Execution Time + +
+ Table 3. Total calculation time (minutes) for different configurations. +
+ +| Software | 250k | 500k | 1M | 2M | 4M | 8M | +| :---------------: | :----: | :-----: | :-----: | :-----: | :-----: | :------: | +| phasicFlow-4050Ti | 54 min | 111 min | 216 min | 432 min | - | - | +| Commercial DEM-4050Ti | 68 min | 136 min | 275 min | 570 min | - | - | +| phasicFlow-A4000 | 38 min | 73 min | 146 min | 293 min | 589 min | 1188 min | + +The execution time scales linearly with particle count. phasicFlow demonstrates approximately: + +- 20% faster calculation than the well-established commercial DEM software on the same hardware +- 30% performance improvement when using the NVIDIA RTX A4000 compared to the RTX 4050Ti + +
+ +

Figure 3. Calculation time comparison between phasicFlow and the well-established commercial DEM software.

+
+ +### Memory Usage + +
+ Table 4. Memory consumption for different configurations. +
+ +| Software | 250k | 500k | 1M | 2M | 4M | 8M | +| :---------------: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | +| phasicFlow-4050Ti | 252 MB | 412 MB | 710 MB | 1292 MB | - | - | +| Commercial DEM-4050Ti | 485 MB | 897 MB | 1525 MB | 2724 MB | - | - | +| phasicFlow-A4000 | 344 MB | 480 MB | 802 MB | 1386 MB | 2590 MB | 4966 MB | + +Memory efficiency comparison: + +- phasicFlow uses approximately 0.7 GB of memory per million particles +- Commercial DEM software uses approximately 1.2 GB of memory per million particles +- phasicFlow shows ~42% lower memory consumption compared to the commercial alternative +- The memory usage scales linearly with particle count in both software packages. But due to memory limitations on GPUs, it is possible to run larger simulation on GPUs with phasicFlow. + +## Run Your Own Benchmarks + +The simulation case setup files are available in this folder for users interested in performing similar benchmarks on their own hardware. These files can be used to reproduce the tests and compare performance across different systems. diff --git a/benchmarks/rotatingDrum/rotatingDrum_1mParticles/caseSetup/interaction b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/caseSetup/interaction new file mode 100644 index 00000000..4ef2c32f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/caseSetup/interaction @@ -0,0 +1,60 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName interaction; +objectType dictionary; +fileFormat ASCII; + +/*---------------------------------------------------------------------------*/ + +materials (glassMat wallMat); // a list of materials names + +densities (2500.0 2500); // density of materials [kg/m3] + +contactListType sortedContactList; + +contactSearch +{ + method NBS; + + updateInterval 20; + + sizeRatio 1.1; + + cellExtent 0.55; + + adjustableBox Yes; +} + +model +{ + contactForceModel nonLinearLimited; + + rollingFrictionModel normal; + + /* + Property (glassMat-glassMat glassMat-wallMat + wallMat-wallMat); + */ + + Yeff (1.0e6 1.0e6 + 1.0e6); // Young modulus [Pa] + + Geff (0.8e6 0.8e6 + 0.8e6); // Shear modulus [Pa] + + nu (0.25 0.25 + 0.25); // Poisson's ratio [-] + + en (0.97 0.85 + 1.00); // coefficient of normal restitution + + mu (0.65 0.65 + 0.65); // dynamic friction + + mur (0.1 0.1 + 0.1); // rolling friction +} + diff --git a/tutorials/sphereGranFlow/toteblender/caseSetup/particleInsertion b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/caseSetup/shapes similarity index 62% rename from tutorials/sphereGranFlow/toteblender/caseSetup/particleInsertion rename to benchmarks/rotatingDrum/rotatingDrum_1mParticles/caseSetup/shapes index cabe23da..c2302c64 100644 --- a/tutorials/sphereGranFlow/toteblender/caseSetup/particleInsertion +++ b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/caseSetup/shapes @@ -2,12 +2,14 @@ | phasicFlow File | | copyright: www.cemf.ir | \* ------------------------------------------------------------------------- */ -objectName particleInsertion; -objectType dicrionary; -fileFormat ASCII; + +objectName shapes; +objectType dictionary; +fileFormat ASCII; /*---------------------------------------------------------------------------*/ -active No; // is insertion active -> Yes or No -collisionCheck No; // is checked -> Yes or No +names (glassBead); // names of shapes +diameters (0.004); // diameter of shapes +materials (glassMat); // material names for shapes diff --git a/benchmarks/rotatingDrum_4MParticles/cleanThisCase b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/cleanThisCase similarity index 100% rename from benchmarks/rotatingDrum_4MParticles/cleanThisCase rename to benchmarks/rotatingDrum/rotatingDrum_1mParticles/cleanThisCase diff --git a/benchmarks/rotatingDrum_4MParticles/runThisCase b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/runThisCase similarity index 100% rename from benchmarks/rotatingDrum_4MParticles/runThisCase rename to benchmarks/rotatingDrum/rotatingDrum_1mParticles/runThisCase diff --git a/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/domainDict b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/domainDict new file mode 100644 index 00000000..ec704467 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/domainDict @@ -0,0 +1,50 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName domainDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +globalBox // Simulation domain: every particles that goes outside this domain will be deleted +{ + min (-0.2 -0.2 0.0); + max ( 0.2 0.2 0.8); +} + +boundaries +{ + neighborListUpdateInterval 200; + + updateInterval 20; + + left + { + type exit; // other options: periodic, reflective + } + + right + { + type exit; // other options: periodic, reflective + } + + bottom + { + type exit; // other options: periodic, reflective + } + + top + { + type exit; // other options: periodic, reflective + } + + rear + { + type exit; // other options: periodic, reflective + } + + front + { + type exit; // other options: periodic, reflective + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/geometryDict b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/geometryDict new file mode 100644 index 00000000..e2a0c797 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/geometryDict @@ -0,0 +1,86 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName geometryDict; +objectType dictionary; +fileFormat ASCII; + +motionModel rotatingAxis; // motion model: rotating object around an axis + +rotatingAxisInfo // information for rotatingAxisMotion motion model +{ + rotAxis + { + p1 (0.0 0.0 0.0); // first point for the axis of rotation + + p2 (0.0 0.0 1.0); // second point for the axis of rotation + + omega 1.256; // rotation speed (rad/s) => 12 rpm + } +} + +surfaces +{ + cylinder + { + type cylinderWall; // type of the wall + + p1 (0.0 0.0 0.0); // begin point of cylinder axis + + p2 (0.0 0.0 0.8); // end point of cylinder axis + + radius1 0.2; // radius at p1 + + radius2 0.2; // radius at p2 + + resolution 60; // number of divisions + + material wallMat; // material name of this wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the rear end of cylinder + */ + + wall1 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.0); // first point of the wall + + p2 ( 0.2 -0.2 0.0); // second point + + p3 ( 0.2 0.2 0.0); // third point + + p4 (-0.2 0.2 0.0); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the front end of cylinder + */ + + wall2 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.8); // first point of the wall + + p2 ( 0.2 -0.2 0.8); // second point + + p3 ( 0.2 0.2 0.8); // third point + + p4 (-0.2 0.2 0.8); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/particlesDict b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/particlesDict new file mode 100644 index 00000000..f395b571 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/particlesDict @@ -0,0 +1,47 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName particlesDict; +objectType dictionary; +fileFormat ASCII; + +setFields +{ + defaultValue + { + velocity realx3 (0 0 0); // linear velocity (m/s) + acceleration realx3 (0 0 0); // linear acceleration (m/s2) + rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) + shapeName word glassBead; // name of the particle shape + } + + selectors + {} +} + +positionParticles +{ + method ordered; + + orderedInfo + { + distance 0.004; // minimum space between centers of particles + + numPoints 1000000; // number of particles in the simulation + + axisOrder (z x y); // axis order for filling the space with particles + } + + regionType cylinder; // other options: box and sphere + + cylinderInfo // cylinder for positioning particles + { + p1 (0.0 0.0 0.01); // lower corner point of the box + + p2 (0.0 0.0 0.79); // upper corner point of the box + + radius 0.195; // radius of cylinder + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/settingsDict b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/settingsDict new file mode 100644 index 00000000..e98fa06a --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_1mParticles/settings/settingsDict @@ -0,0 +1,34 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName settingsDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +run rotatingDrum_1mParticles; + +dt 0.00001; // time step for integration (s) + +startTime 0; // start time for simulation + +endTime 4; // end time for simulation + +saveInterval 0.2; // time interval for saving the simulation + +timePrecision 5; // maximum number of digits for time folder + +g (0 -9.8 0); // gravity vector (m/s2) + +includeObjects (diameter); // save necessary (i.e., required) data on disk + +// exclude unnecessary data from saving on disk +excludeObjects (rVelocity.dy1 pStructPosition.dy1 pStructVelocity.dy1); + +integrationMethod AdamsBashforth2; // integration method + +writeFormat binary; // data writting format (ascii or binary) + +timersReport Yes; + +timersReportInterval 0.01; diff --git a/benchmarks/rotatingDrum/rotatingDrum_250kParticles/caseSetup/interaction b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/caseSetup/interaction new file mode 100644 index 00000000..4ef2c32f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/caseSetup/interaction @@ -0,0 +1,60 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName interaction; +objectType dictionary; +fileFormat ASCII; + +/*---------------------------------------------------------------------------*/ + +materials (glassMat wallMat); // a list of materials names + +densities (2500.0 2500); // density of materials [kg/m3] + +contactListType sortedContactList; + +contactSearch +{ + method NBS; + + updateInterval 20; + + sizeRatio 1.1; + + cellExtent 0.55; + + adjustableBox Yes; +} + +model +{ + contactForceModel nonLinearLimited; + + rollingFrictionModel normal; + + /* + Property (glassMat-glassMat glassMat-wallMat + wallMat-wallMat); + */ + + Yeff (1.0e6 1.0e6 + 1.0e6); // Young modulus [Pa] + + Geff (0.8e6 0.8e6 + 0.8e6); // Shear modulus [Pa] + + nu (0.25 0.25 + 0.25); // Poisson's ratio [-] + + en (0.97 0.85 + 1.00); // coefficient of normal restitution + + mu (0.65 0.65 + 0.65); // dynamic friction + + mur (0.1 0.1 + 0.1); // rolling friction +} + diff --git a/tutorials/sphereGranFlow/rotatingDrumSmall/caseSetup/particleInsertion b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/caseSetup/shapes old mode 100755 new mode 100644 similarity index 62% rename from tutorials/sphereGranFlow/rotatingDrumSmall/caseSetup/particleInsertion rename to benchmarks/rotatingDrum/rotatingDrum_250kParticles/caseSetup/shapes index cabe23da..b8aadc13 --- a/tutorials/sphereGranFlow/rotatingDrumSmall/caseSetup/particleInsertion +++ b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/caseSetup/shapes @@ -2,12 +2,14 @@ | phasicFlow File | | copyright: www.cemf.ir | \* ------------------------------------------------------------------------- */ -objectName particleInsertion; -objectType dicrionary; -fileFormat ASCII; + +objectName shapes; +objectType dictionary; +fileFormat ASCII; /*---------------------------------------------------------------------------*/ -active No; // is insertion active -> Yes or No -collisionCheck No; // is checked -> Yes or No +names (glassBead); // names of shapes +diameters (0.006); // diameter of shapes +materials (glassMat); // material names for shapes diff --git a/tutorials/sphereGranFlow/toteblender/cleanThisCase b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/cleanThisCase old mode 100644 new mode 100755 similarity index 100% rename from tutorials/sphereGranFlow/toteblender/cleanThisCase rename to benchmarks/rotatingDrum/rotatingDrum_250kParticles/cleanThisCase diff --git a/tutorials/sphereGranFlow/toteblender/runThisCase b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/runThisCase old mode 100644 new mode 100755 similarity index 100% rename from tutorials/sphereGranFlow/toteblender/runThisCase rename to benchmarks/rotatingDrum/rotatingDrum_250kParticles/runThisCase diff --git a/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/domainDict b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/domainDict new file mode 100644 index 00000000..ec704467 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/domainDict @@ -0,0 +1,50 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName domainDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +globalBox // Simulation domain: every particles that goes outside this domain will be deleted +{ + min (-0.2 -0.2 0.0); + max ( 0.2 0.2 0.8); +} + +boundaries +{ + neighborListUpdateInterval 200; + + updateInterval 20; + + left + { + type exit; // other options: periodic, reflective + } + + right + { + type exit; // other options: periodic, reflective + } + + bottom + { + type exit; // other options: periodic, reflective + } + + top + { + type exit; // other options: periodic, reflective + } + + rear + { + type exit; // other options: periodic, reflective + } + + front + { + type exit; // other options: periodic, reflective + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/geometryDict b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/geometryDict new file mode 100644 index 00000000..e2a0c797 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/geometryDict @@ -0,0 +1,86 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName geometryDict; +objectType dictionary; +fileFormat ASCII; + +motionModel rotatingAxis; // motion model: rotating object around an axis + +rotatingAxisInfo // information for rotatingAxisMotion motion model +{ + rotAxis + { + p1 (0.0 0.0 0.0); // first point for the axis of rotation + + p2 (0.0 0.0 1.0); // second point for the axis of rotation + + omega 1.256; // rotation speed (rad/s) => 12 rpm + } +} + +surfaces +{ + cylinder + { + type cylinderWall; // type of the wall + + p1 (0.0 0.0 0.0); // begin point of cylinder axis + + p2 (0.0 0.0 0.8); // end point of cylinder axis + + radius1 0.2; // radius at p1 + + radius2 0.2; // radius at p2 + + resolution 60; // number of divisions + + material wallMat; // material name of this wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the rear end of cylinder + */ + + wall1 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.0); // first point of the wall + + p2 ( 0.2 -0.2 0.0); // second point + + p3 ( 0.2 0.2 0.0); // third point + + p4 (-0.2 0.2 0.0); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the front end of cylinder + */ + + wall2 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.8); // first point of the wall + + p2 ( 0.2 -0.2 0.8); // second point + + p3 ( 0.2 0.2 0.8); // third point + + p4 (-0.2 0.2 0.8); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/particlesDict b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/particlesDict new file mode 100644 index 00000000..b096c0cc --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/particlesDict @@ -0,0 +1,47 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName particlesDict; +objectType dictionary; +fileFormat ASCII; + +setFields +{ + defaultValue + { + velocity realx3 (0 0 0); // linear velocity (m/s) + acceleration realx3 (0 0 0); // linear acceleration (m/s2) + rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) + shapeName word glassBead; // name of the particle shape + } + + selectors + {} +} + +positionParticles +{ + method ordered; + + orderedInfo + { + distance 0.006; // minimum space between centers of particles + + numPoints 250000; // number of particles in the simulation + + axisOrder (z x y); // axis order for filling the space with particles + } + + regionType cylinder; // other options: box and sphere + + cylinderInfo // cylinder for positioning particles + { + p1 (0.0 0.0 0.01); // lower corner point of the box + + p2 (0.0 0.0 0.79); // upper corner point of the box + + radius 0.195; // radius of cylinder + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/settingsDict b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/settingsDict new file mode 100644 index 00000000..6f971c6f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_250kParticles/settings/settingsDict @@ -0,0 +1,34 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName settingsDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +run rotatingDrum_250KParticles; + +dt 0.00001; // time step for integration (s) + +startTime 0; // start time for simulation + +endTime 4; // end time for simulation + +saveInterval 0.2; // time interval for saving the simulation + +timePrecision 5; // maximum number of digits for time folder + +g (0 -9.8 0); // gravity vector (m/s2) + +includeObjects (diameter); // save necessary (i.e., required) data on disk + +// exclude unnecessary data from saving on disk +excludeObjects (rVelocity.dy1 pStructPosition.dy1 pStructVelocity.dy1); + +integrationMethod AdamsBashforth2; // integration method + +writeFormat binary; // data writting format (ascii or binary) + +timersReport Yes; + +timersReportInterval 0.01; diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/caseSetup/interaction b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/caseSetup/interaction new file mode 100644 index 00000000..4ef2c32f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/caseSetup/interaction @@ -0,0 +1,60 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName interaction; +objectType dictionary; +fileFormat ASCII; + +/*---------------------------------------------------------------------------*/ + +materials (glassMat wallMat); // a list of materials names + +densities (2500.0 2500); // density of materials [kg/m3] + +contactListType sortedContactList; + +contactSearch +{ + method NBS; + + updateInterval 20; + + sizeRatio 1.1; + + cellExtent 0.55; + + adjustableBox Yes; +} + +model +{ + contactForceModel nonLinearLimited; + + rollingFrictionModel normal; + + /* + Property (glassMat-glassMat glassMat-wallMat + wallMat-wallMat); + */ + + Yeff (1.0e6 1.0e6 + 1.0e6); // Young modulus [Pa] + + Geff (0.8e6 0.8e6 + 0.8e6); // Shear modulus [Pa] + + nu (0.25 0.25 + 0.25); // Poisson's ratio [-] + + en (0.97 0.85 + 1.00); // coefficient of normal restitution + + mu (0.65 0.65 + 0.65); // dynamic friction + + mur (0.1 0.1 + 0.1); // rolling friction +} + diff --git a/tutorials/sphereGranFlow/rotatingDrumSmall/caseSetup/sphereShape b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/caseSetup/shapes old mode 100755 new mode 100644 similarity index 62% rename from tutorials/sphereGranFlow/rotatingDrumSmall/caseSetup/sphereShape rename to benchmarks/rotatingDrum/rotatingDrum_2mParticles/caseSetup/shapes index 7a87b7ad..d08fdf86 --- a/tutorials/sphereGranFlow/rotatingDrumSmall/caseSetup/sphereShape +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/caseSetup/shapes @@ -2,11 +2,14 @@ | phasicFlow File | | copyright: www.cemf.ir | \* ------------------------------------------------------------------------- */ -objectName sphereDict; -objectType sphereShape; -fileFormat ASCII; + +objectName shapes; +objectType dictionary; +fileFormat ASCII; /*---------------------------------------------------------------------------*/ -names (sphere1); // names of shapes -diameters (0.004); // diameter of shapes -materials (prop1); // material names for shapes +names (glassBead); // names of shapes + +diameters (0.003); // diameter of shapes + +materials (glassMat); // material names for shapes diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/cleanThisCase b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/cleanThisCase new file mode 100755 index 00000000..8a0ab919 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/cleanThisCase @@ -0,0 +1,7 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory + +ls | grep -P "^(([0-9]+\.?[0-9]*)|(\.[0-9]+))$" | xargs -d"\n" rm -rf +rm -rf VTK + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/runThisCase b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/runThisCase new file mode 100755 index 00000000..c48d71fe --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/runThisCase @@ -0,0 +1,21 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory +echo "\n<--------------------------------------------------------------------->" +echo "1) Creating particles" +echo "<--------------------------------------------------------------------->\n" +particlesPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "2) Creating geometry" +echo "<--------------------------------------------------------------------->\n" +geometryPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "3) Running the case" +echo "<--------------------------------------------------------------------->\n" +sphereGranFlow + + + + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/domainDict b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/domainDict new file mode 100644 index 00000000..1b4718fd --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/domainDict @@ -0,0 +1,50 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName domainDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +globalBox // Simulation domain: every particles that goes outside this domain will be deleted +{ + min (-0.2 -0.2 0.0); + max ( 0.2 0.2 1.2); +} + +boundaries +{ + neighborListUpdateInterval 200; + + updateInterval 20; + + left + { + type exit; // other options: periodic, reflective + } + + right + { + type exit; // other options: periodic, reflective + } + + bottom + { + type exit; // other options: periodic, reflective + } + + top + { + type exit; // other options: periodic, reflective + } + + rear + { + type exit; // other options: periodic, reflective + } + + front + { + type exit; // other options: periodic, reflective + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/geometryDict b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/geometryDict new file mode 100644 index 00000000..2b92233c --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/geometryDict @@ -0,0 +1,86 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName geometryDict; +objectType dictionary; +fileFormat ASCII; + +motionModel rotatingAxis; // motion model: rotating object around an axis + +rotatingAxisInfo // information for rotatingAxisMotion motion model +{ + rotAxis + { + p1 (0.0 0.0 0.0); // first point for the axis of rotation + + p2 (0.0 0.0 1.0); // second point for the axis of rotation + + omega 1.256; // rotation speed (rad/s) => 12 rpm + } +} + +surfaces +{ + cylinder + { + type cylinderWall; // type of the wall + + p1 (0.0 0.0 0.0); // begin point of cylinder axis + + p2 (0.0 0.0 1.2); // end point of cylinder axis + + radius1 0.2; // radius at p1 + + radius2 0.2; // radius at p2 + + resolution 60; // number of divisions + + material wallMat; // material name of this wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the rear end of cylinder + */ + + wall1 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.0); // first point of the wall + + p2 ( 0.2 -0.2 0.0); // second point + + p3 ( 0.2 0.2 0.0); // third point + + p4 (-0.2 0.2 0.0); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the front end of cylinder + */ + + wall2 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 1.2); // first point of the wall + + p2 ( 0.2 -0.2 1.2); // second point + + p3 ( 0.2 0.2 1.2); // third point + + p4 (-0.2 0.2 1.2); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/particlesDict b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/particlesDict new file mode 100644 index 00000000..ca61762a --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/particlesDict @@ -0,0 +1,47 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName particlesDict; +objectType dictionary; +fileFormat ASCII; + +setFields +{ + defaultValue + { + velocity realx3 (0 0 0); // linear velocity (m/s) + acceleration realx3 (0 0 0); // linear acceleration (m/s2) + rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) + shapeName word glassBead; // name of the particle shape + } + + selectors + {} +} + +positionParticles +{ + method ordered; + + orderedInfo + { + distance 0.003; // minimum space between centers of particles + + numPoints 2000000; // number of particles in the simulation + + axisOrder (z x y); // axis order for filling the space with particles + } + + regionType cylinder; // other options: box and sphere + + cylinderInfo // cylinder for positioning particles + { + p1 (0.0 0.0 0.01); // lower corner point of the box + + p2 (0.0 0.0 1.19); // upper corner point of the box + + radius 0.195; // radius of cylinder + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/settingsDict b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/settingsDict new file mode 100644 index 00000000..b53afca8 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_2mParticles/settings/settingsDict @@ -0,0 +1,34 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName settingsDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +run rotatingDrum_2mParticles; + +dt 0.00001; // time step for integration (s) + +startTime 0; // start time for simulation + +endTime 4; // end time for simulation + +saveInterval 0.2; // time interval for saving the simulation + +timePrecision 5; // maximum number of digits for time folder + +g (0 -9.8 0); // gravity vector (m/s2) + +includeObjects (diameter); // save necessary (i.e., required) data on disk + +// exclude unnecessary data from saving on disk +excludeObjects (rVelocity.dy1 pStructPosition.dy1 pStructVelocity.dy1); + +integrationMethod AdamsBashforth2; // integration method + +writeFormat binary; // data writting format (ascii or binary) + +timersReport Yes; + +timersReportInterval 0.01; diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/caseSetup/interaction b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/caseSetup/interaction new file mode 100644 index 00000000..4ef2c32f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/caseSetup/interaction @@ -0,0 +1,60 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName interaction; +objectType dictionary; +fileFormat ASCII; + +/*---------------------------------------------------------------------------*/ + +materials (glassMat wallMat); // a list of materials names + +densities (2500.0 2500); // density of materials [kg/m3] + +contactListType sortedContactList; + +contactSearch +{ + method NBS; + + updateInterval 20; + + sizeRatio 1.1; + + cellExtent 0.55; + + adjustableBox Yes; +} + +model +{ + contactForceModel nonLinearLimited; + + rollingFrictionModel normal; + + /* + Property (glassMat-glassMat glassMat-wallMat + wallMat-wallMat); + */ + + Yeff (1.0e6 1.0e6 + 1.0e6); // Young modulus [Pa] + + Geff (0.8e6 0.8e6 + 0.8e6); // Shear modulus [Pa] + + nu (0.25 0.25 + 0.25); // Poisson's ratio [-] + + en (0.97 0.85 + 1.00); // coefficient of normal restitution + + mu (0.65 0.65 + 0.65); // dynamic friction + + mur (0.1 0.1 + 0.1); // rolling friction +} + diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/caseSetup/shapes b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/caseSetup/shapes new file mode 100644 index 00000000..d08fdf86 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/caseSetup/shapes @@ -0,0 +1,15 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName shapes; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ + +names (glassBead); // names of shapes + +diameters (0.003); // diameter of shapes + +materials (glassMat); // material names for shapes diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/cleanThisCase b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/cleanThisCase new file mode 100755 index 00000000..8a0ab919 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/cleanThisCase @@ -0,0 +1,7 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory + +ls | grep -P "^(([0-9]+\.?[0-9]*)|(\.[0-9]+))$" | xargs -d"\n" rm -rf +rm -rf VTK + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/runThisCase b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/runThisCase new file mode 100755 index 00000000..c48d71fe --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/runThisCase @@ -0,0 +1,21 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory +echo "\n<--------------------------------------------------------------------->" +echo "1) Creating particles" +echo "<--------------------------------------------------------------------->\n" +particlesPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "2) Creating geometry" +echo "<--------------------------------------------------------------------->\n" +geometryPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "3) Running the case" +echo "<--------------------------------------------------------------------->\n" +sphereGranFlow + + + + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/domainDict b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/domainDict new file mode 100644 index 00000000..b92756a2 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/domainDict @@ -0,0 +1,50 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName domainDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +globalBox // Simulation domain: every particles that goes outside this domain will be deleted +{ + min (-0.2 -0.2 0.0); + max ( 0.2 0.2 1.6); +} + +boundaries +{ + neighborListUpdateInterval 200; + + updateInterval 20; + + left + { + type exit; // other options: periodic, reflective + } + + right + { + type exit; // other options: periodic, reflective + } + + bottom + { + type exit; // other options: periodic, reflective + } + + top + { + type exit; // other options: periodic, reflective + } + + rear + { + type exit; // other options: periodic, reflective + } + + front + { + type exit; // other options: periodic, reflective + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/geometryDict b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/geometryDict new file mode 100644 index 00000000..dae67a91 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/geometryDict @@ -0,0 +1,86 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName geometryDict; +objectType dictionary; +fileFormat ASCII; + +motionModel rotatingAxis; // motion model: rotating object around an axis + +rotatingAxisInfo // information for rotatingAxisMotion motion model +{ + rotAxis + { + p1 (0.0 0.0 0.0); // first point for the axis of rotation + + p2 (0.0 0.0 1.0); // second point for the axis of rotation + + omega 1.256; // rotation speed (rad/s) => 12 rpm + } +} + +surfaces +{ + cylinder + { + type cylinderWall; // type of the wall + + p1 (0.0 0.0 0.0); // begin point of cylinder axis + + p2 (0.0 0.0 1.6); // end point of cylinder axis + + radius1 0.2; // radius at p1 + + radius2 0.2; // radius at p2 + + resolution 60; // number of divisions + + material wallMat; // material name of this wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the rear end of cylinder + */ + + wall1 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.0); // first point of the wall + + p2 ( 0.2 -0.2 0.0); // second point + + p3 ( 0.2 0.2 0.0); // third point + + p4 (-0.2 0.2 0.0); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the front end of cylinder + */ + + wall2 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 1.6); // first point of the wall + + p2 ( 0.2 -0.2 1.6); // second point + + p3 ( 0.2 0.2 1.6); // third point + + p4 (-0.2 0.2 1.6); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/particlesDict b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/particlesDict new file mode 100644 index 00000000..fa4c3396 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/particlesDict @@ -0,0 +1,47 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName particlesDict; +objectType dictionary; +fileFormat ASCII; + +setFields +{ + defaultValue + { + velocity realx3 (0 0 0); // linear velocity (m/s) + acceleration realx3 (0 0 0); // linear acceleration (m/s2) + rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) + shapeName word glassBead; // name of the particle shape + } + + selectors + {} +} + +positionParticles +{ + method ordered; + + orderedInfo + { + distance 0.003; // minimum space between centers of particles + + numPoints 4000000; // number of particles in the simulation + + axisOrder (z x y); // axis order for filling the space with particles + } + + regionType cylinder; // other options: box and sphere + + cylinderInfo // cylinder for positioning particles + { + p1 (0.0 0.0 0.01); // lower corner point of the box + + p2 (0.0 0.0 1.59); // upper corner point of the box + + radius 0.195; // radius of cylinder + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/settingsDict b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/settingsDict new file mode 100644 index 00000000..67cbee31 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_4mParticles/settings/settingsDict @@ -0,0 +1,34 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName settingsDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +run rotatingDrum_4mParticles; + +dt 0.00001; // time step for integration (s) + +startTime 0; // start time for simulation + +endTime 4; // end time for simulation + +saveInterval 0.2; // time interval for saving the simulation + +timePrecision 5; // maximum number of digits for time folder + +g (0 -9.8 0); // gravity vector (m/s2) + +includeObjects (diameter); // save necessary (i.e., required) data on disk + +// exclude unnecessary data from saving on disk +excludeObjects (rVelocity.dy1 pStructPosition.dy1 pStructVelocity.dy1); + +integrationMethod AdamsBashforth2; // integration method + +writeFormat binary; // data writting format (ascii or binary) + +timersReport Yes; + +timersReportInterval 0.01; diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/caseSetup/interaction b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/caseSetup/interaction new file mode 100644 index 00000000..4ef2c32f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/caseSetup/interaction @@ -0,0 +1,60 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName interaction; +objectType dictionary; +fileFormat ASCII; + +/*---------------------------------------------------------------------------*/ + +materials (glassMat wallMat); // a list of materials names + +densities (2500.0 2500); // density of materials [kg/m3] + +contactListType sortedContactList; + +contactSearch +{ + method NBS; + + updateInterval 20; + + sizeRatio 1.1; + + cellExtent 0.55; + + adjustableBox Yes; +} + +model +{ + contactForceModel nonLinearLimited; + + rollingFrictionModel normal; + + /* + Property (glassMat-glassMat glassMat-wallMat + wallMat-wallMat); + */ + + Yeff (1.0e6 1.0e6 + 1.0e6); // Young modulus [Pa] + + Geff (0.8e6 0.8e6 + 0.8e6); // Shear modulus [Pa] + + nu (0.25 0.25 + 0.25); // Poisson's ratio [-] + + en (0.97 0.85 + 1.00); // coefficient of normal restitution + + mu (0.65 0.65 + 0.65); // dynamic friction + + mur (0.1 0.1 + 0.1); // rolling friction +} + diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/caseSetup/shapes b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/caseSetup/shapes new file mode 100644 index 00000000..962433e2 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/caseSetup/shapes @@ -0,0 +1,15 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName shapes; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ + +names (glassBead); // names of shapes + +diameters (0.005); // diameter of shapes + +materials (glassMat); // material names for shapes diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/cleanThisCase b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/cleanThisCase new file mode 100755 index 00000000..8a0ab919 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/cleanThisCase @@ -0,0 +1,7 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory + +ls | grep -P "^(([0-9]+\.?[0-9]*)|(\.[0-9]+))$" | xargs -d"\n" rm -rf +rm -rf VTK + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/runThisCase b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/runThisCase new file mode 100755 index 00000000..c48d71fe --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/runThisCase @@ -0,0 +1,21 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory +echo "\n<--------------------------------------------------------------------->" +echo "1) Creating particles" +echo "<--------------------------------------------------------------------->\n" +particlesPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "2) Creating geometry" +echo "<--------------------------------------------------------------------->\n" +geometryPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "3) Running the case" +echo "<--------------------------------------------------------------------->\n" +sphereGranFlow + + + + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/domainDict b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/domainDict new file mode 100644 index 00000000..ec704467 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/domainDict @@ -0,0 +1,50 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName domainDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +globalBox // Simulation domain: every particles that goes outside this domain will be deleted +{ + min (-0.2 -0.2 0.0); + max ( 0.2 0.2 0.8); +} + +boundaries +{ + neighborListUpdateInterval 200; + + updateInterval 20; + + left + { + type exit; // other options: periodic, reflective + } + + right + { + type exit; // other options: periodic, reflective + } + + bottom + { + type exit; // other options: periodic, reflective + } + + top + { + type exit; // other options: periodic, reflective + } + + rear + { + type exit; // other options: periodic, reflective + } + + front + { + type exit; // other options: periodic, reflective + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/geometryDict b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/geometryDict new file mode 100644 index 00000000..e2a0c797 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/geometryDict @@ -0,0 +1,86 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName geometryDict; +objectType dictionary; +fileFormat ASCII; + +motionModel rotatingAxis; // motion model: rotating object around an axis + +rotatingAxisInfo // information for rotatingAxisMotion motion model +{ + rotAxis + { + p1 (0.0 0.0 0.0); // first point for the axis of rotation + + p2 (0.0 0.0 1.0); // second point for the axis of rotation + + omega 1.256; // rotation speed (rad/s) => 12 rpm + } +} + +surfaces +{ + cylinder + { + type cylinderWall; // type of the wall + + p1 (0.0 0.0 0.0); // begin point of cylinder axis + + p2 (0.0 0.0 0.8); // end point of cylinder axis + + radius1 0.2; // radius at p1 + + radius2 0.2; // radius at p2 + + resolution 60; // number of divisions + + material wallMat; // material name of this wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the rear end of cylinder + */ + + wall1 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.0); // first point of the wall + + p2 ( 0.2 -0.2 0.0); // second point + + p3 ( 0.2 0.2 0.0); // third point + + p4 (-0.2 0.2 0.0); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the front end of cylinder + */ + + wall2 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.8); // first point of the wall + + p2 ( 0.2 -0.2 0.8); // second point + + p3 ( 0.2 0.2 0.8); // third point + + p4 (-0.2 0.2 0.8); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/particlesDict b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/particlesDict new file mode 100644 index 00000000..e0ef3e91 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/particlesDict @@ -0,0 +1,47 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName particlesDict; +objectType dictionary; +fileFormat ASCII; + +setFields +{ + defaultValue + { + velocity realx3 (0 0 0); // linear velocity (m/s) + acceleration realx3 (0 0 0); // linear acceleration (m/s2) + rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) + shapeName word glassBead; // name of the particle shape + } + + selectors + {} +} + +positionParticles +{ + method ordered; + + orderedInfo + { + distance 0.005; // minimum space between centers of particles + + numPoints 500000; // number of particles in the simulation + + axisOrder (z x y); // axis order for filling the space with particles + } + + regionType cylinder; // other options: box and sphere + + cylinderInfo // cylinder for positioning particles + { + p1 (0.0 0.0 0.01); // lower corner point of the box + + p2 (0.0 0.0 0.79); // upper corner point of the box + + radius 0.195; // radius of cylinder + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/settingsDict b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/settingsDict new file mode 100644 index 00000000..f42eacc5 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_500kParticles/settings/settingsDict @@ -0,0 +1,34 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName settingsDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +run rotatingDrum_500KParticles; + +dt 0.00001; // time step for integration (s) + +startTime 0; // start time for simulation + +endTime 4; // end time for simulation + +saveInterval 0.2; // time interval for saving the simulation + +timePrecision 5; // maximum number of digits for time folder + +g (0 -9.8 0); // gravity vector (m/s2) + +includeObjects (diameter); // save necessary (i.e., required) data on disk + +// exclude unnecessary data from saving on disk +excludeObjects (rVelocity.dy1 pStructPosition.dy1 pStructVelocity.dy1); + +integrationMethod AdamsBashforth2; // integration method + +writeFormat binary; // data writting format (ascii or binary) + +timersReport Yes; + +timersReportInterval 0.01; diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/caseSetup/interaction b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/caseSetup/interaction new file mode 100644 index 00000000..4ef2c32f --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/caseSetup/interaction @@ -0,0 +1,60 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName interaction; +objectType dictionary; +fileFormat ASCII; + +/*---------------------------------------------------------------------------*/ + +materials (glassMat wallMat); // a list of materials names + +densities (2500.0 2500); // density of materials [kg/m3] + +contactListType sortedContactList; + +contactSearch +{ + method NBS; + + updateInterval 20; + + sizeRatio 1.1; + + cellExtent 0.55; + + adjustableBox Yes; +} + +model +{ + contactForceModel nonLinearLimited; + + rollingFrictionModel normal; + + /* + Property (glassMat-glassMat glassMat-wallMat + wallMat-wallMat); + */ + + Yeff (1.0e6 1.0e6 + 1.0e6); // Young modulus [Pa] + + Geff (0.8e6 0.8e6 + 0.8e6); // Shear modulus [Pa] + + nu (0.25 0.25 + 0.25); // Poisson's ratio [-] + + en (0.97 0.85 + 1.00); // coefficient of normal restitution + + mu (0.65 0.65 + 0.65); // dynamic friction + + mur (0.1 0.1 + 0.1); // rolling friction +} + diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/caseSetup/shapes b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/caseSetup/shapes new file mode 100644 index 00000000..0c0b3443 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/caseSetup/shapes @@ -0,0 +1,15 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName shapes; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ + +names (glassBead); // names of shapes + +diameters (0.002); // diameter of shapes + +materials (glassMat); // material names for shapes diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/cleanThisCase b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/cleanThisCase new file mode 100755 index 00000000..8a0ab919 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/cleanThisCase @@ -0,0 +1,7 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory + +ls | grep -P "^(([0-9]+\.?[0-9]*)|(\.[0-9]+))$" | xargs -d"\n" rm -rf +rm -rf VTK + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/runThisCase b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/runThisCase new file mode 100755 index 00000000..c48d71fe --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/runThisCase @@ -0,0 +1,21 @@ +#!/bin/sh +cd ${0%/*} || exit 1 # Run from this directory +echo "\n<--------------------------------------------------------------------->" +echo "1) Creating particles" +echo "<--------------------------------------------------------------------->\n" +particlesPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "2) Creating geometry" +echo "<--------------------------------------------------------------------->\n" +geometryPhasicFlow + +echo "\n<--------------------------------------------------------------------->" +echo "3) Running the case" +echo "<--------------------------------------------------------------------->\n" +sphereGranFlow + + + + +#------------------------------------------------------------------------------ diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/domainDict b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/domainDict new file mode 100644 index 00000000..b92756a2 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/domainDict @@ -0,0 +1,50 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName domainDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +globalBox // Simulation domain: every particles that goes outside this domain will be deleted +{ + min (-0.2 -0.2 0.0); + max ( 0.2 0.2 1.6); +} + +boundaries +{ + neighborListUpdateInterval 200; + + updateInterval 20; + + left + { + type exit; // other options: periodic, reflective + } + + right + { + type exit; // other options: periodic, reflective + } + + bottom + { + type exit; // other options: periodic, reflective + } + + top + { + type exit; // other options: periodic, reflective + } + + rear + { + type exit; // other options: periodic, reflective + } + + front + { + type exit; // other options: periodic, reflective + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/geometryDict b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/geometryDict new file mode 100644 index 00000000..dae67a91 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/geometryDict @@ -0,0 +1,86 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName geometryDict; +objectType dictionary; +fileFormat ASCII; + +motionModel rotatingAxis; // motion model: rotating object around an axis + +rotatingAxisInfo // information for rotatingAxisMotion motion model +{ + rotAxis + { + p1 (0.0 0.0 0.0); // first point for the axis of rotation + + p2 (0.0 0.0 1.0); // second point for the axis of rotation + + omega 1.256; // rotation speed (rad/s) => 12 rpm + } +} + +surfaces +{ + cylinder + { + type cylinderWall; // type of the wall + + p1 (0.0 0.0 0.0); // begin point of cylinder axis + + p2 (0.0 0.0 1.6); // end point of cylinder axis + + radius1 0.2; // radius at p1 + + radius2 0.2; // radius at p2 + + resolution 60; // number of divisions + + material wallMat; // material name of this wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the rear end of cylinder + */ + + wall1 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 0.0); // first point of the wall + + p2 ( 0.2 -0.2 0.0); // second point + + p3 ( 0.2 0.2 0.0); // third point + + p4 (-0.2 0.2 0.0); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } + + /* + This is a plane wall at the front end of cylinder + */ + + wall2 + { + type planeWall; // type of the wall + + p1 (-0.2 -0.2 1.6); // first point of the wall + + p2 ( 0.2 -0.2 1.6); // second point + + p3 ( 0.2 0.2 1.6); // third point + + p4 (-0.2 0.2 1.6); // fourth point + + material wallMat; // material name of the wall + + motion rotAxis; // motion component name + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/particlesDict b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/particlesDict new file mode 100644 index 00000000..362efa72 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/particlesDict @@ -0,0 +1,47 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ + +objectName particlesDict; +objectType dictionary; +fileFormat ASCII; + +setFields +{ + defaultValue + { + velocity realx3 (0 0 0); // linear velocity (m/s) + acceleration realx3 (0 0 0); // linear acceleration (m/s2) + rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) + shapeName word glassBead; // name of the particle shape + } + + selectors + {} +} + +positionParticles +{ + method ordered; + + orderedInfo + { + distance 0.003; // minimum space between centers of particles + + numPoints 6000000; // number of particles in the simulation + + axisOrder (z x y); // axis order for filling the space with particles + } + + regionType cylinder; // other options: box and sphere + + cylinderInfo // cylinder for positioning particles + { + p1 (0.0 0.0 0.01); // lower corner point of the box + + p2 (0.0 0.0 1.59); // upper corner point of the box + + radius 0.195; // radius of cylinder + } +} diff --git a/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/settingsDict b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/settingsDict new file mode 100644 index 00000000..67cbee31 --- /dev/null +++ b/benchmarks/rotatingDrum/rotatingDrum_8mParticles/settings/settingsDict @@ -0,0 +1,34 @@ +/* -------------------------------*- C++ -*--------------------------------- *\ +| phasicFlow File | +| copyright: www.cemf.ir | +\* ------------------------------------------------------------------------- */ +objectName settingsDict; +objectType dictionary; +fileFormat ASCII; +/*---------------------------------------------------------------------------*/ +run rotatingDrum_4mParticles; + +dt 0.00001; // time step for integration (s) + +startTime 0; // start time for simulation + +endTime 4; // end time for simulation + +saveInterval 0.2; // time interval for saving the simulation + +timePrecision 5; // maximum number of digits for time folder + +g (0 -9.8 0); // gravity vector (m/s2) + +includeObjects (diameter); // save necessary (i.e., required) data on disk + +// exclude unnecessary data from saving on disk +excludeObjects (rVelocity.dy1 pStructPosition.dy1 pStructVelocity.dy1); + +integrationMethod AdamsBashforth2; // integration method + +writeFormat binary; // data writting format (ascii or binary) + +timersReport Yes; + +timersReportInterval 0.01; diff --git a/benchmarks/rotatingDrum_4MParticles/caseSetup/interaction b/benchmarks/rotatingDrum_4MParticles/caseSetup/interaction deleted file mode 100755 index 0477966f..00000000 --- a/benchmarks/rotatingDrum_4MParticles/caseSetup/interaction +++ /dev/null @@ -1,59 +0,0 @@ -/* -------------------------------*- C++ -*--------------------------------- *\ -| phasicFlow File | -| copyright: www.cemf.ir | -\* ------------------------------------------------------------------------- */ - -objectName interaction; -objectType dicrionary; - -materials (glassMat wallMat); // a list of materials names -densities (2500.0 2500); // density of materials [kg/m3] - -contactListType sortedContactList; - -model -{ - contactForceModel nonLinearLimited; - rollingFrictionModel normal; - - Yeff (1.0e6 1.0e6 // Young modulus [Pa] - 1.0e6); - - Geff (0.8e6 0.8e6 // Shear modulus [Pa] - 0.8e6); - - nu (0.25 0.25 // Poisson's ratio [-] - 0.25); - - en (0.97 0.85 // coefficient of normal restitution - 1.00); - - et (1.0 1.0 // coefficient of tangential restitution - 1.0); - - mu (0.65 0.65 // dynamic friction - 0.65); - - mur (0.1 0.1 // rolling friction - 0.1); - -} - -contactSearch -{ - method NBS; - wallMapping cellMapping; - - NBSInfo - { - updateFrequency 10; // each 20 timesteps, update neighbor list - sizeRatio 1.05; // bounding box size to particle diameter (max) - } - - cellMappingInfo - { - updateFrequency 10; // each 20 timesteps, update neighbor list - cellExtent 0.6; // bounding box for particle-wall search (> 0.5) - } - -} \ No newline at end of file diff --git a/benchmarks/rotatingDrum_4MParticles/caseSetup/particleInsertion b/benchmarks/rotatingDrum_4MParticles/caseSetup/particleInsertion deleted file mode 100755 index eec7b7f9..00000000 --- a/benchmarks/rotatingDrum_4MParticles/caseSetup/particleInsertion +++ /dev/null @@ -1,14 +0,0 @@ -/* -------------------------------*- C++ -*--------------------------------- *\ -| phasicFlow File | -| copyright: www.cemf.ir | -\* ------------------------------------------------------------------------- */ - -objectName particleInsertion; -objectType dicrionary; - - -active no; // is insertion active? - -collisionCheck No; // not implemented for yes - - diff --git a/benchmarks/rotatingDrum_4MParticles/caseSetup/sphereShape b/benchmarks/rotatingDrum_4MParticles/caseSetup/sphereShape deleted file mode 100755 index eab9b617..00000000 --- a/benchmarks/rotatingDrum_4MParticles/caseSetup/sphereShape +++ /dev/null @@ -1,11 +0,0 @@ -/* -------------------------------*- C++ -*--------------------------------- *\ -| phasicFlow File | -| copyright: www.cemf.ir | -\* ------------------------------------------------------------------------- */ - -objectName sphereDict; -objectType sphereShape; - -names (glassBead); // names of shapes -diameters (0.003); // diameter of shapes -materials (glassMat); // material names for shapes diff --git a/benchmarks/rotatingDrum_4MParticles/settings/geometryDict b/benchmarks/rotatingDrum_4MParticles/settings/geometryDict deleted file mode 100644 index 64702fd8..00000000 --- a/benchmarks/rotatingDrum_4MParticles/settings/geometryDict +++ /dev/null @@ -1,63 +0,0 @@ -/* -------------------------------*- C++ -*--------------------------------- *\ -| phasicFlow File | -| copyright: www.cemf.ir | -\* ------------------------------------------------------------------------- */ - -objectName geometryDict; -objectType dictionary; - -motionModel rotatingAxisMotion; - -surfaces -{ - - cylinder - { - type cylinderWall; - p1 (0.0 0.0 0.0); - p2 (0.0 0.0 1.6); - radius1 0.2; - radius2 0.2; - resolution 24; - material wallMat; - motion rotAxis; - } - - - wall1 - { - type planeWall; - p1 (-0.2 -0.2 0.0); - p2 ( 0.2 -0.2 0.0); - p3 ( 0.2 0.2 0.0); - p4 (-0.2 0.2 0.0); - material wallMat; - motion rotAxis; - } - - /* - This is a plane wall at the front end of cylinder - */ - wall2 - { - type planeWall; - p1 (-0.2 -0.2 1.6); - p2 ( 0.2 -0.2 1.6); - p3 ( 0.2 0.2 1.6); - p4 (-0.2 0.2 1.6); - material wallMat; - motion rotAxis; - } - -} - -// information for rotatingAxisMotion motion model -rotatingAxisMotionInfo -{ - rotAxis - { - p1 (0.0 0.0 0.0); - p2 (0.0 0.0 1.0); - omega 1.256; // rotation speed (rad/s) => 12 rpm - } -} \ No newline at end of file diff --git a/benchmarks/rotatingDrum_4MParticles/settings/particlesDict b/benchmarks/rotatingDrum_4MParticles/settings/particlesDict deleted file mode 100644 index 7ae00511..00000000 --- a/benchmarks/rotatingDrum_4MParticles/settings/particlesDict +++ /dev/null @@ -1,44 +0,0 @@ -/* -------------------------------*- C++ -*--------------------------------- *\ -| phasicFlow File | -| copyright: www.cemf.ir | -\* ------------------------------------------------------------------------- */ - -objectName particlesDict; -objectType dictionary; - -setFields -{ - - defaultValue - { - velocity realx3 (0 0 0); // linear velocity (m/s) - acceleration realx3 (0 0 0); // linear acceleration (m/s2) - rotVelocity realx3 (0 0 0); // rotational velocity (rad/s) - shapeName word glassBead; // name of the particle shape - } - - selectors - {} -} - -positionParticles -{ - method positionOrdered; - - maxNumberOfParticles 4000001; - mortonSorting Yes; - - cylinder // box for positioning particles - { - p1 ( 0.0 0.0 0.01); // lower corner point of the box - p2 ( 0.0 0.0 1.59); // upper corner point of the box - radius 0.195; - } - - positionOrderedInfo - { - diameter 0.003; // minimum space between centers of particles - numPoints 4000000; // number of particles in the simulation - axisOrder (z x y); // axis order for filling the space with particles - } -} diff --git a/benchmarks/rotatingDrum_4MParticles/settings/settingsDict b/benchmarks/rotatingDrum_4MParticles/settings/settingsDict deleted file mode 100644 index 8a881847..00000000 --- a/benchmarks/rotatingDrum_4MParticles/settings/settingsDict +++ /dev/null @@ -1,32 +0,0 @@ -/* -------------------------------*- C++ -*--------------------------------- *\ -| phasicFlow File | -| copyright: www.cemf.ir | -\* ------------------------------------------------------------------------- */ -objectName settingsDict; -objectType dictionary;; - -run rotatingDrum_1; - -dt 0.00001; // time step for integration (s) - -startTime 0; // start time for simulation - -endTime 10; // end time for simulation - -saveInterval 0.2; // time interval for saving the simulation - -timePrecision 5; // maximum number of digits for time folder - -g (0 -9.8 0); // gravity vector (m/s2) - -domain -{ - min (-0.2 -0.2 -0.0); - max ( 0.2 0.2 1.6); -} - -integrationMethod AdamsBashforth3; // integration method - -timersReport Yes; - -timersReportInterval 0.01; diff --git a/cmake/autoComplete b/cmake/autoComplete index 6c289ce5..babf3843 100644 --- a/cmake/autoComplete +++ b/cmake/autoComplete @@ -1,48 +1,89 @@ PF_cFlags="--description --help --version" AllTimeFolders= __getAllTime(){ - files=( $(ls) ) - deleteFiles=(settings caseSetup cleanThisCase VTK runThisCase stl postprocess postProcess) - declare -A delk - for del in "${deleteFiles[@]}" ; do delk[$del]=1 ; done - # Tag items to remove, based on - for k in "${!files[@]}" ; do - [ "${delk[${files[$k]}]-}" ] && unset 'files[k]' - done - # Compaction - COMPREPLY=("${files[@]}") - AllTimeFolders="${files[@]}" + # Initialize empty array for time folders + local time_folders=() + + # Loop through all directories in current folder + for dir in */; do + # Remove trailing slash + dir=${dir%/} + + # Check if directory name is a valid floating point number + # This pattern matches integers and floating point numbers + if [[ $dir =~ ^[0-9]+(\.[0-9]+)?$ ]]; then + time_folders+=("$dir") + fi + done + + # Set completion reply to the time folders + COMPREPLY=("${time_folders[@]}") + AllTimeFolders="${time_folders[@]}" } __getFields(){ - __getAllTime - local -A unique_files=() + __getAllTime + local -A unique_files=() + # Files to exclude from suggestions + local exclude_files=("shapeHash" "pStructure" "particleInsertion" "p" "alpha" "U" "Sp" "Su" "phi") + declare -A exclude_dict + + # Build exclude dictionary for faster lookups + for file in "${exclude_files[@]}"; do + exclude_dict["$file"]=1 + done - for dir in $AllTimeFolders; do - # Check if the directory exists - if [ ! -d "$dir" ]; then - continue # Skip to the next directory - fi - - files_in_dir=$(find "$dir" -maxdepth 1 -type f -printf '%f\n' | sort -u) - - # Add filenames to the associative array (duplicates will be overwritten) - while IFS= read -r filename; do - unique_files["$filename"]=1 # Just the key is important, value can be anything - done <<< "$files_in_dir" - - done - COMPREPLY=("${!unique_files[@]}") - AllTimeFolders= + for dir in $AllTimeFolders; do + # Skip if not a directory + [ ! -d "$dir" ] && continue + + # Find all files in this time directory + while IFS= read -r filename; do + # Skip empty lines and excluded files + [ -z "$filename" ] || [ "${exclude_dict[$filename]+exists}" ] && continue + + # Add to unique files + unique_files["$filename"]=1 + done < <(find "$dir" -maxdepth 1 -type f -printf '%f\n') + done + + # Set completion reply to the unique filenames + COMPREPLY=(${!unique_files[@]}) + + # Clear global variable + AllTimeFolders= } _pFlowToVTK(){ - if [ "$3" == "--time" ] ; then + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD-1]}" + + # Check if we're completing a field + local is_field=0 + for ((i=1; i bool pFlow::geometryMotion::findMotionIndex() { - if(motionComponentName().size() != numSurfaces() ) { fatalErrorInFunction<< diff --git a/src/Geometry/geometryMotion/geometryMotions.cpp b/src/Geometry/geometryMotion/geometryMotions.cpp index 6cdb4a3b..8636c1f7 100644 --- a/src/Geometry/geometryMotion/geometryMotions.cpp +++ b/src/Geometry/geometryMotion/geometryMotions.cpp @@ -28,4 +28,4 @@ template class pFlow::geometryMotion; template class pFlow::geometryMotion; -//template class pFlow::geometryMotion; +template class pFlow::geometryMotion; diff --git a/src/Geometry/geometryMotion/geometryMotions.hpp b/src/Geometry/geometryMotion/geometryMotions.hpp index 3b0a2867..4a916b6e 100644 --- a/src/Geometry/geometryMotion/geometryMotions.hpp +++ b/src/Geometry/geometryMotion/geometryMotions.hpp @@ -25,7 +25,7 @@ Licence: #include "stationaryWall.hpp" #include "rotatingAxisMotion.hpp" #include "conveyorBeltMotion.hpp" -//#include "multiRotatingAxisMotion.hpp" +#include "multiRotatingAxisMotion.hpp" #include "vibratingMotion.hpp" @@ -40,10 +40,7 @@ using stationaryGeometry = geometryMotion; using conveyorBeltMotionGeometry = geometryMotion; -//typedef geometryMotion multiRotationAxisMotionGeometry; - - - +using multiRotationAxisMotionGeometry = geometryMotion; } diff --git a/src/Integration/AdamsBashforth2/AdamsBashforth2.cpp b/src/Integration/AdamsBashforth2/AdamsBashforth2.cpp index 0eaa4bdb..9f457fe8 100644 --- a/src/Integration/AdamsBashforth2/AdamsBashforth2.cpp +++ b/src/Integration/AdamsBashforth2/AdamsBashforth2.cpp @@ -97,10 +97,11 @@ pFlow::AdamsBashforth2::AdamsBashforth2 const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField + const realx3Field_D& initialValField, + bool keepHistory ) : - integration(baseName, pStruct, method, initialValField), + integration(baseName, pStruct, method, initialValField, keepHistory), realx3PointField_D ( objectFile @@ -108,7 +109,7 @@ pFlow::AdamsBashforth2::AdamsBashforth2 groupNames(baseName,"dy1"), pStruct.time().integrationFolder(), objectFile::READ_IF_PRESENT, - objectFile::WRITE_ALWAYS + keepHistory?objectFile::WRITE_ALWAYS:objectFile::WRITE_NEVER ), pStruct, zero3, diff --git a/src/Integration/AdamsBashforth2/AdamsBashforth2.hpp b/src/Integration/AdamsBashforth2/AdamsBashforth2.hpp index a8218465..0241bb8e 100644 --- a/src/Integration/AdamsBashforth2/AdamsBashforth2.hpp +++ b/src/Integration/AdamsBashforth2/AdamsBashforth2.hpp @@ -81,7 +81,8 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField); + const realx3Field_D& initialValField, + bool keepHistory); /// Destructor ~AdamsBashforth2()override = default; diff --git a/src/Integration/AdamsBashforth3/AdamsBashforth3.cpp b/src/Integration/AdamsBashforth3/AdamsBashforth3.cpp index e728e533..c15b5ff2 100644 --- a/src/Integration/AdamsBashforth3/AdamsBashforth3.cpp +++ b/src/Integration/AdamsBashforth3/AdamsBashforth3.cpp @@ -109,10 +109,11 @@ pFlow::AdamsBashforth3::AdamsBashforth3 const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField + const realx3Field_D& initialValField, + bool keepHistory ) : - AdamsBashforth2(baseName, pStruct, method, initialValField), + AdamsBashforth2(baseName, pStruct, method, initialValField, keepHistory), dy2_ ( objectFile @@ -120,7 +121,7 @@ pFlow::AdamsBashforth3::AdamsBashforth3 groupNames(baseName,"dy2"), pStruct.time().integrationFolder(), objectFile::READ_IF_PRESENT, - objectFile::WRITE_ALWAYS + keepHistory ? objectFile::WRITE_ALWAYS : objectFile::WRITE_NEVER ), pStruct, zero3, diff --git a/src/Integration/AdamsBashforth3/AdamsBashforth3.hpp b/src/Integration/AdamsBashforth3/AdamsBashforth3.hpp index e71166ae..50a23c39 100644 --- a/src/Integration/AdamsBashforth3/AdamsBashforth3.hpp +++ b/src/Integration/AdamsBashforth3/AdamsBashforth3.hpp @@ -71,7 +71,8 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField); + const realx3Field_D& initialValField, + bool keepHistory); /// Destructor diff --git a/src/Integration/AdamsBashforth4/AdamsBashforth4.cpp b/src/Integration/AdamsBashforth4/AdamsBashforth4.cpp index a0d5c4a1..24461282 100644 --- a/src/Integration/AdamsBashforth4/AdamsBashforth4.cpp +++ b/src/Integration/AdamsBashforth4/AdamsBashforth4.cpp @@ -115,10 +115,11 @@ pFlow::AdamsBashforth4::AdamsBashforth4 const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField + const realx3Field_D& initialValField, + bool keepHistory ) : - AdamsBashforth3(baseName, pStruct, method, initialValField), + AdamsBashforth3(baseName, pStruct, method, initialValField, keepHistory), dy3_ ( objectFile @@ -126,7 +127,7 @@ pFlow::AdamsBashforth4::AdamsBashforth4 groupNames(baseName,"dy3"), pStruct.time().integrationFolder(), objectFile::READ_IF_PRESENT, - objectFile::WRITE_ALWAYS + keepHistory?objectFile::WRITE_ALWAYS:objectFile::WRITE_NEVER ), pStruct, zero3, diff --git a/src/Integration/AdamsBashforth4/AdamsBashforth4.hpp b/src/Integration/AdamsBashforth4/AdamsBashforth4.hpp index fc2b913b..a9bb9a43 100644 --- a/src/Integration/AdamsBashforth4/AdamsBashforth4.hpp +++ b/src/Integration/AdamsBashforth4/AdamsBashforth4.hpp @@ -69,7 +69,8 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField); + const realx3Field_D& initialValField, + bool keepHistory); diff --git a/src/Integration/AdamsBashforth5/AdamsBashforth5.cpp b/src/Integration/AdamsBashforth5/AdamsBashforth5.cpp index 3fde7276..dd1503e2 100644 --- a/src/Integration/AdamsBashforth5/AdamsBashforth5.cpp +++ b/src/Integration/AdamsBashforth5/AdamsBashforth5.cpp @@ -123,10 +123,11 @@ pFlow::AdamsBashforth5::AdamsBashforth5 const word &baseName, pointStructure &pStruct, const word &method, - const realx3Field_D &initialValField + const realx3Field_D &initialValField, + bool keepHistory ) : - AdamsBashforth4(baseName, pStruct, method, initialValField), + AdamsBashforth4(baseName, pStruct, method, initialValField, keepHistory), dy4_ ( objectFile @@ -134,7 +135,7 @@ pFlow::AdamsBashforth5::AdamsBashforth5 groupNames(baseName,"dy4"), pStruct.time().integrationFolder(), objectFile::READ_IF_PRESENT, - objectFile::WRITE_ALWAYS + keepHistory?objectFile::WRITE_ALWAYS:objectFile::WRITE_NEVER ), pStruct, zero3, diff --git a/src/Integration/AdamsBashforth5/AdamsBashforth5.hpp b/src/Integration/AdamsBashforth5/AdamsBashforth5.hpp index ed16d99c..939f96a3 100644 --- a/src/Integration/AdamsBashforth5/AdamsBashforth5.hpp +++ b/src/Integration/AdamsBashforth5/AdamsBashforth5.hpp @@ -68,7 +68,8 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField); + const realx3Field_D& initialValField, + bool keepHistory); diff --git a/src/Integration/integration/integration.cpp b/src/Integration/integration/integration.cpp index d9fc8ba8..710df9ad 100644 --- a/src/Integration/integration/integration.cpp +++ b/src/Integration/integration/integration.cpp @@ -51,10 +51,12 @@ pFlow::integration::integration( const word &baseName, pointStructure &pStruct, const word &, - const realx3Field_D &) + const realx3Field_D &, + bool keepHistory) : owner_(*pStruct.owner()), pStruct_(pStruct), - baseName_(baseName) + baseName_(baseName), + keepHistory_(keepHistory) {} @@ -64,12 +66,13 @@ pFlow::uniquePtr const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField + const realx3Field_D& initialValField, + bool keepHistory ) { if( wordvCtorSelector_.search(method) ) { - return wordvCtorSelector_[method] (baseName, pStruct, method, initialValField); + return wordvCtorSelector_[method] (baseName, pStruct, method, initialValField, keepHistory); } else { diff --git a/src/Integration/integration/integration.hpp b/src/Integration/integration/integration.hpp index fb0d84df..1161bd1e 100644 --- a/src/Integration/integration/integration.hpp +++ b/src/Integration/integration/integration.hpp @@ -24,6 +24,7 @@ Licence: #include "virtualConstructor.hpp" #include "pointFields.hpp" +#include "Logical.hpp" namespace pFlow @@ -63,6 +64,8 @@ private: /// The base name for integration const word baseName_; + bool keepHistory_; + protected: bool insertValues( @@ -83,7 +86,8 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField); + const realx3Field_D& initialValField, + bool keepHistory); /// Copy constructor integration(const integration&) = default; @@ -109,9 +113,10 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField + const realx3Field_D& initialValField, + bool keepHistory ), - (baseName, pStruct, method, initialValField) + (baseName, pStruct, method, initialValField, keepHistory) ); @@ -138,6 +143,11 @@ public: return owner_; } + bool keepHistory()const + { + return keepHistory_; + } + virtual void updateBoundariesSlaveToMasterIfRequested() = 0; /// return integration method @@ -164,7 +174,8 @@ public: const word& baseName, pointStructure& pStruct, const word& method, - const realx3Field_D& initialValField); + const realx3Field_D& initialValField, + bool keepHistory); }; // integration diff --git a/src/Interaction/contactLists/sortedContactList.hpp b/src/Interaction/contactLists/sortedContactList.hpp index 4f41caac..aee1767e 100644 --- a/src/Interaction/contactLists/sortedContactList.hpp +++ b/src/Interaction/contactLists/sortedContactList.hpp @@ -80,13 +80,17 @@ public: TypeInfoNV("sortedContactList"); - - explicit sortedContactList(uint32 initialSize =1) + sortedContactList(uint32 initialSize =1) : - SortedPairs(initialSize), - values_("values", SortedPairs::capacity()), - sortedPairs0_("sortedPairs0", SortedPairs::capacity()), - values0_("values0", SortedPairs::capacity()) + sortedContactList("sortedContactList", initialSize) + {} + + sortedContactList(const word& name, uint32 initialSize =1) + : + SortedPairs(name, initialSize), + values_(groupNames(name, "values"), SortedPairs::capacity()), + sortedPairs0_(groupNames(name, "sortedPairs0"), SortedPairs::capacity()), + values0_(groupNames(name, "values0"), SortedPairs::capacity()) {} bool beforeBroadSearch() diff --git a/src/Interaction/contactLists/sortedPairs.hpp b/src/Interaction/contactLists/sortedPairs.hpp index 12593810..4a91718a 100644 --- a/src/Interaction/contactLists/sortedPairs.hpp +++ b/src/Interaction/contactLists/sortedPairs.hpp @@ -110,11 +110,11 @@ public: // constructors - explicit sortedPairs(uint32 initialSize =1) + explicit sortedPairs(const word& name, uint32 initialSize =1) : UnsortedPairs(initialSize), - flags_("flags_",UnsortedPairs::capacity()+1), - sortedPairs_("sortedPairs_",UnsortedPairs::capacity()) + flags_( groupNames(name, "flags_"), UnsortedPairs::capacity()+1), + sortedPairs_(groupNames(name, "sortedPairs_"), UnsortedPairs::capacity()) {} @@ -193,7 +193,7 @@ public: if( capacity+1 > flags_.size() ) { - reallocNoInit(flags_, capacity+1); + reallocInit(flags_, capacity+1); } // fill the flags @@ -219,7 +219,7 @@ public: { // get more space to prevent reallocations in next iterations uint32 len = size_*1.1+1; - reallocNoInit(sortedPairs_, len); + reallocInit(sortedPairs_, len); } Kokkos::parallel_for( @@ -231,6 +231,7 @@ public: // - sort paris based on the first and second sort(sortedPairs_, 0, size_ ); + } diff --git a/src/Interaction/contactLists/unsortedContactList.hpp b/src/Interaction/contactLists/unsortedContactList.hpp index 7aa98237..202b08ec 100644 --- a/src/Interaction/contactLists/unsortedContactList.hpp +++ b/src/Interaction/contactLists/unsortedContactList.hpp @@ -82,11 +82,16 @@ public: TypeInfoNV("unsortedContactList"); explicit unsortedContactList(uint32 capacity=1) + : + unsortedContactList("unsortedContactList", capacity) + {} + + unsortedContactList(const word& name, uint32 capacity=1) : UnsortedPairs(capacity), - values_("values", UnsortedPairs::capacity()), + values_(groupNames(name, "values"), UnsortedPairs::capacity()), container0_(capacity), - values0_("values0",container0_.capacity()) + values0_(groupNames(name, "values0"),container0_.capacity()) {} diff --git a/src/Interaction/contactLists/unsortedPairs.hpp b/src/Interaction/contactLists/unsortedPairs.hpp index fb622bdb..32898964 100644 --- a/src/Interaction/contactLists/unsortedPairs.hpp +++ b/src/Interaction/contactLists/unsortedPairs.hpp @@ -194,7 +194,9 @@ public: { uint newCap = container_.capacity()+len; this->clear(); + //output<<"----------------before "<::createGrainInteraction() geometryMotion_, timers()); - ppContactList_ = makeUnique(nPrtcl+1); + ppContactList_ = makeUnique("Grain-Grain",nPrtcl+1); - pwContactList_ = makeUnique(nPrtcl/5+1); + pwContactList_ = makeUnique("Grain-wall",nPrtcl/5+1); return true; } diff --git a/src/Interaction/sphereInteraction/sphereInteraction/sphereInteraction.cpp b/src/Interaction/sphereInteraction/sphereInteraction/sphereInteraction.cpp index cd362c66..fe907354 100644 --- a/src/Interaction/sphereInteraction/sphereInteraction/sphereInteraction.cpp +++ b/src/Interaction/sphereInteraction/sphereInteraction/sphereInteraction.cpp @@ -41,9 +41,9 @@ bool pFlow::sphereInteraction::createSphereInteraction() geometryMotion_, timers()); - ppContactList_ = makeUnique(nPrtcl+1); + ppContactList_ = makeUnique("sphere-sphere",nPrtcl+1); - pwContactList_ = makeUnique(nPrtcl/5+1); + pwContactList_ = makeUnique("sphere-wall",nPrtcl/5+1); return true; } diff --git a/src/Interaction/sphereInteraction/sphereInteractionsNonLinearModModels.cpp b/src/Interaction/sphereInteraction/sphereInteractionsNonLinearModModels.cpp index d7f79ff7..fd277432 100644 --- a/src/Interaction/sphereInteraction/sphereInteractionsNonLinearModModels.cpp +++ b/src/Interaction/sphereInteraction/sphereInteractionsNonLinearModModels.cpp @@ -58,5 +58,5 @@ createInteraction(pFlow::cfModels::limitedNonLinearModNormalRolling, pFlow::conv createInteraction(pFlow::cfModels::nonLimitedNonLinearModNormalRolling,pFlow::conveyorBeltMotionGeometry); // multiRotationAxisMotionGeometry -//createInteraction(pFlow::cfModels::limitedNonLinearModNormalRolling, pFlow::multiRotationAxisMotionGeometry); -//createInteraction(pFlow::cfModels::nonLimitedNonLinearModNormalRolling,pFlow::multiRotationAxisMotionGeometry); +createInteraction(pFlow::cfModels::limitedNonLinearModNormalRolling, pFlow::multiRotationAxisMotionGeometry); +createInteraction(pFlow::cfModels::nonLimitedNonLinearModNormalRolling,pFlow::multiRotationAxisMotionGeometry); diff --git a/src/MotionModel/CMakeLists.txt b/src/MotionModel/CMakeLists.txt index 1e92a989..d28af4f5 100644 --- a/src/MotionModel/CMakeLists.txt +++ b/src/MotionModel/CMakeLists.txt @@ -14,8 +14,8 @@ entities/stationary/stationary.cpp conveyorBeltMotion/conveyorBeltMotion.cpp entities/conveyorBelt/conveyorBelt.cpp -#entities/multiRotatingAxis/multiRotatingAxis.cpp -#multiRotatingAxisMotion/multiRotatingAxisMotion.cpp +entities/multiRotatingAxis/multiRotatingAxis.cpp +multiRotatingAxisMotion/multiRotatingAxisMotion.cpp ) diff --git a/src/MotionModel/MotionModel/MotionModel.cpp b/src/MotionModel/MotionModel/MotionModel.cpp index 6a530eaa..426b0218 100644 --- a/src/MotionModel/MotionModel/MotionModel.cpp +++ b/src/MotionModel/MotionModel/MotionModel.cpp @@ -32,7 +32,6 @@ bool pFlow::MotionModel::impl_nameToIndex(const word& name, ui indx = static_cast(i); return true; } - } template diff --git a/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.cpp b/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.cpp index 62733216..10e70aa7 100644 --- a/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.cpp +++ b/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.cpp @@ -22,31 +22,32 @@ Licence: #include "multiRotatingAxisMotion.hpp" #include "dictionary.hpp" +/// Construct from dictionary FUNCTION_H -pFlow::multiRotatingAxis::multiRotatingAxis -( - multiRotatingAxisMotion* axisMotion -) -{ - //axisList_ = axisMotion->getAxisListPtr(); -} +pFlow::multiRotatingAxis::multiRotatingAxis(const dictionary& dict) +: + rotatingAxis(dict) +{} + FUNCTION_H pFlow::multiRotatingAxis::multiRotatingAxis ( - multiRotatingAxisMotion* axisMotion, + multiRotatingAxis* axisListPtr, + const wordList& componentsNames, const dictionary& dict ) +: + rotatingAxis(dict), + axisList_(axisListPtr) { - if(!read(axisMotion, dict)) + if(!read(dict, componentsNames)) { fatalErrorInFunction<< " error in reading rotatingAxis from dictionary "<< dict.globalName()<getAxisListPtr(); } @@ -54,22 +55,29 @@ pFlow::multiRotatingAxis::multiRotatingAxis FUNCTION_H bool pFlow::multiRotatingAxis::read ( - multiRotatingAxisMotion* axisMotion, - const dictionary& dict + const dictionary& dict, + const wordList& componentNames ) { - - if(!rotatingAxis::read(dict))return false; word rotAxis = dict.getValOrSet("rotationAxis", "none"); if(rotAxis == "none") { - parentAxisIndex_ = -1; + parentAxisIndex_ = static_cast(-1); } else { - parentAxisIndex_ = axisMotion-> nameToIndex(rotAxis); + if( auto i = componentNames.findi(rotAxis); i != -1 ) + { + parentAxisIndex_ = i; + } + else + { + fatalErrorInFunction<<"crotationAxis "<< rotAxis<<" in dictionary "<< + dict.globalName()<<" is not found in list of axis names "<< componentNames<indexToName(parentAxisIndex_); - dict.add("rotationAxis", rotAxis); + dict.add("rotationAxis", componentNames[parentAxisIndex_]); } return true; } - diff --git a/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.hpp b/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.hpp index c79e87c8..d39c6dbd 100644 --- a/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.hpp +++ b/src/MotionModel/entities/multiRotatingAxis/multiRotatingAxis.hpp @@ -24,7 +24,7 @@ Licence: #include "rotatingAxis.hpp" #include "KokkosTypes.hpp" - +#include "List.hpp" namespace pFlow { @@ -79,26 +79,31 @@ class multiRotatingAxis protected: /// This is device pointer to all axes - multiRotatingAxis* axisList_; + multiRotatingAxis* axisList_ = nullptr; /// Index of parent axis - int32 parentAxisIndex_ = -1; + uint32 parentAxisIndex_ = static_cast(-1); public: + TypeInfoNV("multiRotatingAxis"); + // - Constructors /// Empty Constructor - INLINE_FUNCTION_HD - multiRotatingAxis(){} + FUNCTION_HD + multiRotatingAxis() = default; - /// Empty with list of axes + /// Construct from dictionary FUNCTION_H - multiRotatingAxis(multiRotatingAxisMotion* axisMotion); + explicit multiRotatingAxis(const dictionary& dict); /// Construct from dictionary and list of axes FUNCTION_H - multiRotatingAxis(multiRotatingAxisMotion* axisMotion, const dictionary& dict); + multiRotatingAxis( + multiRotatingAxis* axisListPtr, + const wordList& componentsNames, + const dictionary& dict); /// Copy constructor FUNCTION_HD @@ -123,11 +128,11 @@ public: while(parIndex != -1) { auto& ax = axisList_[parIndex]; - parentVel += ax.linTangentialVelocityPoint(p); + parentVel += ax.linVelocityPoint(p); parIndex = ax.parentAxisIndex(); } - return parentVel + rotatingAxis::linTangentialVelocityPoint(p); + return parentVel + rotatingAxis::linVelocityPoint(p); } /// Translate point p for dt seconds based on the axis information @@ -143,7 +148,7 @@ public: } auto parIndex = parentAxisIndex_; - while(parIndex != -1) + while(parIndex != static_cast(-1)) { auto& ax = axisList_[parIndex]; newP = pFlow::rotate(newP, ax, dt); @@ -157,12 +162,12 @@ public: INLINE_FUNCTION_HD bool hasParent()const { - return parentAxisIndex_ > -1; + return parentAxisIndex_ != static_cast(-1); } /// Return the index of parent axis INLINE_FUNCTION_HD - int32 parentAxisIndex()const + uint32 parentAxisIndex()const { return parentAxisIndex_; } @@ -182,6 +187,7 @@ public: * It is assumed that the axis with deepest level (with more parrents) is * moved first and then the axis with lower levels. */ + INLINE_FUNCTION_HD void move(real dt) { @@ -201,11 +207,12 @@ public: /// Read from dictionary FUNCTION_H - bool read(multiRotatingAxisMotion* axisMotion, const dictionary& dict); + bool read(const dictionary& dict, const wordList& componentNames); /// Write to dictionary FUNCTION_H - bool write(const multiRotatingAxisMotion* axisMotion, dictionary& dict) const; + bool write(dictionary& dict, const wordList& componentNames) const; + }; diff --git a/src/MotionModel/multiRotatingAxisMotion/multiRotatingAxisMotion.cpp b/src/MotionModel/multiRotatingAxisMotion/multiRotatingAxisMotion.cpp index 360f1ee0..feed07a8 100644 --- a/src/MotionModel/multiRotatingAxisMotion/multiRotatingAxisMotion.cpp +++ b/src/MotionModel/multiRotatingAxisMotion/multiRotatingAxisMotion.cpp @@ -19,40 +19,63 @@ Licence: -----------------------------------------------------------------------------*/ #include "multiRotatingAxisMotion.hpp" -#include "dictionary.hpp" -#include "vocabs.hpp" - -bool pFlow::multiRotatingAxisMotion::readDictionary +void pFlow::multiRotatingAxisMotion::impl_setTime ( - const dictionary& dict -) + uint32 iter, + real t, + real dt +)const { + auto motion = motionComponents_.deviceViewAll(); + Kokkos::parallel_for( + "multiRotatingAxisMotion::impl_setTime", + deviceRPolicyStatic(0, numComponents_), + LAMBDA_D(uint32 i){ + motion[i].setTime(t); + }); + Kokkos::fence(); +} - auto motionModel = dict.getVal("motionModel"); +bool pFlow::multiRotatingAxisMotion::impl_move(uint32 iter, real t , real dt ) const +{ + auto motion = motionComponents_.deviceViewAll(); + Kokkos::parallel_for( + "multiRotatingAxisMotion::impl_move", + deviceRPolicyStatic(0, numComponents_), + LAMBDA_D(uint32 i){ + motion[i].move(dt); + }); + Kokkos::fence(); + return true; +} - if(motionModel != "multiRotatingAxisMotion") +bool pFlow::multiRotatingAxisMotion::impl_readDictionary(const dictionary &dict) +{ + auto modelName = dict.getVal("motionModel"); + + if(modelName != getTypeName()) { fatalErrorInFunction<< - " motionModel should be multiRotatingAxisMotion, but found " - << motionModel <())<< + ", but found "<< Yellow_Text(modelName)<(axDict); axPtr) { - rotationAxis.push_back( + rotationAxisNames.push_back( axDict.getValOrSet("rotationAxis", "none")); } else @@ -63,26 +86,26 @@ bool pFlow::multiRotatingAxisMotion::readDictionary } } - if( !axisNames.search("none") ) + if( !compNames.search("none") ) { - axisNames.push_back("none"); - rotationAxis.push_back("none"); + compNames.push_back("none"); + rotationAxisNames.push_back("none"); } using intPair = std::pair; std::vector numRotAxis; - for(size_t i=0; i< axisNames.size(); i++) + for(size_t i=0; i< compNames.size(); i++) { - word rotAxis = rotationAxis[i]; + word rotAxis = rotationAxisNames[i]; int32 n=0; while(rotAxis != "none") { n++; - if(int32 iAxis = axisNames.findi(rotAxis) ; iAxis != -1) + if(int32 iAxis = compNames.findi(rotAxis) ; iAxis != -1) { - rotAxis = rotationAxis[iAxis]; + rotAxis = rotationAxisNames[iAxis]; }else { fatalErrorInFunction<< @@ -98,60 +121,73 @@ bool pFlow::multiRotatingAxisMotion::readDictionary auto compareFunc = [](const intPair& a, const intPair& b) { return a.first > b.first; }; - algorithms::STD::sort(numRotAxis.data(), numRotAxis.size(), compareFunc); + std::sort(numRotAxis.begin(), numRotAxis.end(), compareFunc); + Vector sortedIndex; + componentNames_.clear(); - sortedIndex_.clear(); - axisName_.clear(); + output< components("Read::modelComponent", + compNames.size()+1, + 0, + RESERVE()); + + + for(auto& compName: componentNames_) { - if(aName != "none") + + if(compName != "none") { - auto& axDict = motionInfo.subDict(aName); - axis_.push_back( - multiRotatingAxis(this, axDict)); + auto& compDict = motionInfo.subDict(compName); + components.emplace_back( + motionComponents_.data(), + componentNames_, + compDict); } else { - axis_.push_back( - multiRotatingAxis(this)); + components.emplace_back(impl_noneComponent()); } } - return true; + motionComponents_.assign(components); + return true; } -bool pFlow::multiRotatingAxisMotion::writeDictionary + +bool pFlow::multiRotatingAxisMotion::impl_writeDictionary ( dictionary& dict )const { - dict.add("motionModel", "multiRotatingAxisMotion"); + word modelName = "multiRotatingAxis"; - auto& motionInfo = dict.subDictOrCreate("multiRotatingAxisMotionInfo"); - - ForAll(i, axis_) + dict.add("motionModel", modelName ); + + auto modelDictName = modelName+"Info"; + + auto& motionInfo = dict.subDictOrCreate(modelDictName); + auto hostComponents = motionComponents_.hostView(); + + ForAll(i, motionComponents_) { - auto& axDict = motionInfo.subDictOrCreate(axisName_[i]); - if( !axis_.hostVectorAll()[i].write(this,axDict)) + auto& axDict = motionInfo.subDictOrCreate(componentNames_[i]); + if( !hostComponents[i].write(axDict, componentNames_)) { fatalErrorInFunction<< - " error in writing axis "<< axisName_[i] << " to dicrionary " + " error in writing axis "<< componentNames_[i] << " to dicrionary " << motionInfo.globalName()< { -public: - - /** Motion model class to be passed to computational units/kernels for - * transfing points and returning velocities at various positions - */ - class Model - { - protected: - - deviceViewType1D axis_; - int32 numAxis_=0; - - public: - - INLINE_FUNCTION_HD - Model(deviceViewType1D axis, int32 numAxis): - axis_(axis), - numAxis_(numAxis) - {} - - INLINE_FUNCTION_HD - Model(const Model&) = default; - - - INLINE_FUNCTION_HD - Model& operator=(const Model&) = default; - - - INLINE_FUNCTION_HD - realx3 pointVelocity(int32 n, const realx3& p)const - { - return axis_[n].pointTangentialVel(p); - } - - INLINE_FUNCTION_HD - realx3 operator()(int32 n, const realx3& p)const - { - return pointVelocity(n,p); - } - - INLINE_FUNCTION_HD - realx3 transferPoint(int32 n, const realx3 p, real dt)const - { - return axis_[n].transferPoint(p, dt); - } - - INLINE_FUNCTION_HD int32 numComponents()const - { - return numAxis_; - } - }; - protected: - using axisVector_HD = VectorDual; + VectorSingle sortedIndex_; - /// Vector of multiRotaingAxis axes - axisVector_HD axis_; - - /// Sorted index based on number of parrents each axis ha - VectorDual sortedIndex_; + friend MotionModel; - /// List of axes names - wordList axisName_; + /// is the geometry attached to this component moving + bool impl_isMoving()const + { + return true; + } - /// Number of axes - label numAxis_= 0; - /// Read from a dictionary - bool readDictionary(const dictionary& dict); - /// Write to a dictionary - bool writeDictionary(dictionary& dict)const; + /// Read from dictionary + bool impl_readDictionary(const dictionary& dict); + + bool impl_writeDictionary(dictionary& dict)const; public: - /// Type info - TypeInfoNV("multiRotatingAxisMotion"); + TypeInfo("multiRotatingAxisMotion"); - // - Constructor + multiRotatingAxisMotion(const objectFile& objf, repository* owner); - /// Empty constructor - FUNCTION_H - multiRotatingAxisMotion(); + multiRotatingAxisMotion( + const objectFile& objf, + const dictionary& dict, + repository* owner); - /// Construct with dictionary - FUNCTION_H - multiRotatingAxisMotion(const dictionary& dict); + using fileDictionary::write; - /// Copy constructor - FUNCTION_H - multiRotatingAxisMotion(const multiRotatingAxisMotion&) = default; + bool write(iOstream& os, const IOPattern& iop)const override; - /// No Move - multiRotatingAxisMotion(multiRotatingAxisMotion&&) = delete; + static + multiRotatingAxis noneComponent() + { + return multiRotatingAxis(); + } - /// Copy assignment - FUNCTION_H - multiRotatingAxisMotion& operator=(const multiRotatingAxisMotion&) = default; + // TODO: make this method protected + void impl_setTime(uint32 iter, real t, real dt)const; - /// No move assignment - multiRotatingAxisMotion& operator=(multiRotatingAxisMotion&&) = delete; - - /// Destructor - FUNCTION_H - ~multiRotatingAxisMotion() = default; - - // - Methods - - /// Retrun motion model at time t - Model getModel(real t) - { - for(int32 i= 0; isubDictOrCreate("stationaryInfo"); if(!impl_readDictionary(*this) ) { fatalErrorInFunction; @@ -46,6 +46,8 @@ pFlow::stationaryWall::stationaryWall : fileDictionary(objf, dict, owner) { + const auto& dummy = this->subDictOrCreate("stationaryInfo"); + if(!impl_readDictionary(*this) ) { fatalErrorInFunction; diff --git a/src/Particles/GrainParticles/grainParticles/grainParticles.cpp b/src/Particles/GrainParticles/grainParticles/grainParticles.cpp index 1e6cc065..d4d5bf05 100644 --- a/src/Particles/GrainParticles/grainParticles/grainParticles.cpp +++ b/src/Particles/GrainParticles/grainParticles/grainParticles.cpp @@ -248,7 +248,8 @@ pFlow::grainParticles::grainParticles( "rVelocity", dynPointStruct(), intMethod, - rAcceleration_.field() + rAcceleration_.field(), + control.keepIntegrationHistory() ); if( !rVelIntegration_ ) diff --git a/src/Particles/GrainParticles/grainShape/grainShape.cpp b/src/Particles/GrainParticles/grainShape/grainShape.cpp index 4558940b..246b5be8 100644 --- a/src/Particles/GrainParticles/grainShape/grainShape.cpp +++ b/src/Particles/GrainParticles/grainShape/grainShape.cpp @@ -73,6 +73,18 @@ pFlow::grainShape::grainShape } } +pFlow::grainShape::grainShape +( + const word &shapeType, + const word &fileName, + repository *owner, + const property &prop +) +: + grainShape(fileName, owner, prop) +{ +} + pFlow::real pFlow::grainShape::maxBoundingSphere() const { return max(grainDiameters_); @@ -99,9 +111,12 @@ pFlow::real pFlow::grainShape::boundingDiameter(uint32 index) const { return grainDiameters_[index]; } - fatalErrorInFunction<<"Invalid index for diameter "<< - index< pFlow::shape::create +( + const word &shapeType, + const word &fileName, + repository *owner, + const property &prop +) +{ + word type = angleBracketsNames("shape", shapeType); + + if( wordvCtorSelector_.search(type) ) + { + auto objPtr = + wordvCtorSelector_[type] + (shapeType, fileName, owner, prop); + return objPtr; + } + else + { + printKeys + ( + fatalError << "Ctor Selector "<< + type << " dose not exist. \n" + <<"Avaiable ones are: \n\n" + , + wordvCtorSelector_ + ); + fatalExit; + return nullptr; + } + +} diff --git a/src/Particles/particles/shape/shape.hpp b/src/Particles/particles/shape/shape.hpp index 5a4007aa..4c7d74e9 100644 --- a/src/Particles/particles/shape/shape.hpp +++ b/src/Particles/particles/shape/shape.hpp @@ -60,9 +60,28 @@ public: const word& fileName, repository* owner, const property& prop); + + shape( + const word& shapeType, + const word& fileName, + repository* owner, + const property& prop); ~shape() override=default; + create_vCtor + ( + shape, + word, + ( + const word& shapeType, + const word& fileName, + repository* owner, + const property& prop + ), + (shapeType, fileName, owner, prop) + ); + inline const auto& properties()const { @@ -148,6 +167,9 @@ public: virtual realVector boundingDiameter()const = 0; + virtual + realVector volume()const = 0; + virtual bool mass(uint32 index, real& m)const = 0; @@ -187,6 +209,13 @@ public: virtual real Inertial_zz(uint32 index)const = 0; + static + uniquePtr create( + const word& shapeType, + const word& fileName, + repository* owner, + const property& prop); + }; } diff --git a/src/PostprocessData/CMakeLists.txt b/src/PostprocessData/CMakeLists.txt new file mode 100644 index 00000000..a68a6d75 --- /dev/null +++ b/src/PostprocessData/CMakeLists.txt @@ -0,0 +1,35 @@ +set(SourceFiles + # Main postprocess data + postprocessData/postprocessData.cpp + + # Fields database + fieldsDataBase/fieldsDataBase.cpp + fieldsDataBase/simulationFieldsDataBase.cpp + + # Regions + region/regionPoints/regionPoints/regionPoints.cpp + region/regionPoints/sphereRegionPoints/sphereRegionPoints.cpp + region/regionPoints/lineRegionPoints/lineRegionPoints.cpp + region/regionPoints/centerPointsRegionPoints/centerPointsRegionPoints.cpp + region/regionPoints/multipleSpheresRegionPoints/multipleSpheresRegionPoints.cpp + + # Postprocess components + postprocessComponent/postprocessComponent/postprocessComponent.cpp + postprocessComponent/particleProbePostprocessComponent/particleProbePostprocessComponent.cpp + postprocessComponent/PostprocessComponent/PostprocessComponents.cpp + + # Operations + operation/postprocessOperation/postprocessOperation.cpp + operation/PostprocessOperation/PostprocessOperationSum.cpp + operation/PostprocessOperation/PostprocessOperationAverage.cpp + operation/PostprocessOperation/PostprocessOperationAvMassVelocity.cpp + + operation/includeMask/includeMask.cpp + operation/includeMask/IncludeMasks.cpp + + +) + +set(link_libs Kokkos::kokkos phasicFlow Particles) + +pFlow_add_library_install(PostprocessData SourceFiles link_libs) \ No newline at end of file diff --git a/src/PostprocessData/fieldsDataBase/fieldFunctions.hpp b/src/PostprocessData/fieldsDataBase/fieldFunctions.hpp new file mode 100644 index 00000000..7454188d --- /dev/null +++ b/src/PostprocessData/fieldsDataBase/fieldFunctions.hpp @@ -0,0 +1,165 @@ +/*------------------------------- 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 __fieldFunctions_hpp__ +#define __fieldFunctions_hpp__ + +#include "types.hpp" +#include "span.hpp" + +namespace pFlow::postprocessData +{ + +template +inline +void funcCast(span src, span dst) +{ + for(uint32 i=0; i(src[i]); + } +} + +template +inline +void funcAbs(span src, span dst) +{ + for(uint32 i=0; i +inline +void funcSquare(span src, span dst) +{ + for( uint32 i=0; i(src[i]),2); + } +} + +template +inline +void funcCube(span src, span dst) +{ + for( uint32 i=0; i(src[i]),3); + } +} + +template +inline +void funcSquareRoot(span src, span dst) +{ + for( uint32 i=0; i(src[i])); + } +} + +template +inline +void funcMagnitude(span src, span dst) +{ + for( uint32 i=0; i +inline +void funcMagnitudeSquare(span src, span dst) +{ + for( uint32 i=0; i +inline +void funcMagnitudeCube(span src, span dst) +{ + for( uint32 i=0; i +inline +void funcMagnitudeSquareRoot(span src, span dst) +{ + for( uint32 i=0; i src, span dst, char component) +{ + for( uint32 i=0; i src, span dst, char component) +{ + for( uint32 i=0; i + +#include "vocabs.hpp" +#include "systemControl.hpp" +#include "fieldsDataBase.hpp" +#include "fieldFunctions.hpp" +#include "dictionary.hpp" + + +bool pFlow::postprocessData::fieldsDataBase::loadPointStructureToTime() +{ + return false; +} + + +bool pFlow::postprocessData::fieldsDataBase::checkForUpdate +( + const word &compoundName, + bool forceUpdate +) +{ + auto t = currentTime(); + bool shouldUpdate = false; + + if(auto [iter, found]= captureTime_.findIf(compoundName); found) + { + shouldUpdate = iter->second < t || forceUpdate; + iter->second = t; + } + else + { + shouldUpdate = true; + captureTime_.insertIf(compoundName, t); + } + + return shouldUpdate; +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::createOrGetRealField +( + const word &name +) +{ + + bool shouldUpdate = checkForUpdate(name); + + if(shouldUpdate) + { + allFields_.emplaceBackOrReplace> + ( + name, + FieldTypeHost + ( + name, + "value", + pointFieldSize() + ) + ); + } + + auto& field = allFields_.getObject>(name); + return span( + field.data(), + field.size()); +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::createOrGetVolume +( + bool forceUpdate +) +{ + const word fName = "volume"; + bool shouldUpdate = checkForUpdate(fName, forceUpdate); + + if(shouldUpdate) + { + const auto index = updateFieldUint32("shapeIndex", true); + auto vols = getShape().volume(); + + FieldTypeHost volField + ( + fName, + "value", + pointFieldSize() + ); + + for(uint32 i=0; i< volField.size(); i++) + { + volField[i] = vols[index[i]]; + } + + allFields_.emplaceBackOrReplace> + ( + fName, + std::move(volField) + ); + } + + auto& field = allFields_.getObject>(fName); + return span( + field.data(), + field.size()); + +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::createOrGetDensity(bool forceUpdate) +{ + const word fName = "density"; + + bool shouldUpdate = checkForUpdate(fName, forceUpdate); + + if(shouldUpdate) + { + const auto index = updateFieldUint32("shapeIndex", true); + const auto dens = getShape().density(); + + FieldTypeHost denFeild + ( + fName, + "value", + pointFieldSize() + ); + + for(uint32 i=0; i< denFeild.size(); i++) + { + denFeild[i] = dens[index[i]]; + } + + allFields_.emplaceBackOrReplace> + ( + fName, + std::move(denFeild) + ); + } + + auto& field = allFields_.getObject>(fName); + return span( + field.data(), + field.size()); +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::createOrGetOne(bool forceUpdate) +{ + const word fName = "one"; + + bool shouldUpdate = checkForUpdate(fName, forceUpdate); + + if(shouldUpdate) + { + allFields_.emplaceBackOrReplace> + ( + fName, + FieldTypeHost + ( + fName, + "value", + pointFieldSize(), + 1.0 + ) + ); + } + + auto& field = allFields_.getObject>(fName); + return span( + field.data(), + field.size()); +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::createOrGetMass(bool forceUpdate) +{ + const word fName = "mass"; + + bool shouldUpdate = checkForUpdate(fName, forceUpdate); + + if(shouldUpdate) + { + const auto index = updateFieldUint32("shapeIndex", true); + const auto ms = getShape().mass(); + + FieldTypeHost massField + ( + fName, + "value", + pointFieldSize() + ); + + for(uint32 i=0; i< massField.size(); i++) + { + massField[i] = ms[index[i]]; + } + + allFields_.emplaceBackOrReplace> + ( + fName, + std::move(massField) + ); + } + + auto& field = allFields_.getObject>(fName); + return span( + field.data(), + field.size()); +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::createOrGetI(bool forceUpdate) +{ + const word fName = "I"; + + bool shouldUpdate = checkForUpdate(fName, forceUpdate); + + if(shouldUpdate) + { + const auto index = updateFieldUint32("shapeIndex", true); + const auto Is = getShape().Inertia(); + + FieldTypeHost IField + ( + fName, + "value", + pointFieldSize() + ); + + for(uint32 i=0; i< IField.size(); i++) + { + IField[i] = Is[index[i]]; + } + + allFields_.emplaceBackOrReplace> + ( + fName, + std::move(IField) + ); + } + + auto& field = allFields_.getObject>(fName); + return span( + field.data(), + field.size()); +} + +bool pFlow::postprocessData::fieldsDataBase::findFunction( + const word &compoundFieldName, + word &fieldName, + fieldsDataBase::Functions &func) +{ + + std::regex pattern(R"((\w+)?\((\w+)(?:,([xyzw]))?\)|(\w+))"); + std::smatch match; + + if (std::regex_match(compoundFieldName, match, pattern)) + { + if (match[1].matched) // Function is present + { + word functionName = match[1].str(); + fieldName = match[2].str(); + + // Map the function name to the enum value + if(functionName=="component") + { + if (!match[3].matched) // Component is not present + { + fatalErrorInFunction << + "Component (x, y, z, or w) is not specified in the function component: " << compoundFieldName << + " the format is component(u,x), where u is the vector field name and x is the compoenent." << endl; + return false; + } + + switch (match[3].str()[0]) + { + case 'x': func = fieldsDataBase::Functions::ComponentX; break; + case 'y': func = fieldsDataBase::Functions::ComponentY; break; + case 'z': func = fieldsDataBase::Functions::ComponentZ; break; + case 'w': func = fieldsDataBase::Functions::ComponentW; break; + default: + fatalErrorInFunction << + "Invalid component specified: " << match[3].str() << endl; + return false; + } + return true; + } + else if (functionName == "abs") + { + func = fieldsDataBase::Functions::Abs; + } + else if (functionName == "square") + { + func = fieldsDataBase::Functions::Square; + } + else if (functionName == "cube") + { + func = fieldsDataBase::Functions::Cube; + } + else if (functionName == "sqrt") + { + func = fieldsDataBase::Functions::SqureRoot; + } + else if (functionName == "mag") + { + func = fieldsDataBase::Functions::Magnitude; + } + else if (functionName == "magSquare") + { + func = fieldsDataBase::Functions::MagnitudeSquare; + } + else if (functionName == "magCube") + { + func = fieldsDataBase::Functions::MagnitudeCube; + } + else if (functionName == "magSqrt") + { + func = fieldsDataBase::Functions::MagnitudeSquareRoot; + } + else + { + fatalErrorInFunction << + "Unknown function specified: " << functionName<< + " in: "<() || + inputType == getTypeName() ) + { + outputType = getTypeName(); + return true; + } + else + { + fatalErrorInFunction<<"Wrong function: component(u,comp), for input field type: "<() ) + { + outputType = getTypeName(); + return true; + } + else + { + fatalErrorInFunction<<"Wrong function: component(u,w), for input field type: "<() || + inputType == getTypeName() || + inputType == getTypeName() || + inputType == getTypeName() ) + { + outputType = getTypeName(); + return true; + } + else + { + fatalErrorInFunction<<"Wrong input field type for functions abs, squqre, cube, and sqrt."<< + " field type is "<< inputType<() || + inputType == getTypeName() ) + { + outputType = getTypeName(); + return true; + } + else + { + fatalErrorInFunction<<"Wroing input field type for functions mag, magSquare, magCube, magSqrt. "<< + " Input field type is "<< inputType<() || + inputType == getTypeName() || + inputType == getTypeName()) + { + outputType = inputType; + return true; + } + else if( inputType == getTypeName() || + inputType == getTypeName() ) + { + outputType = getTypeName(); + return true; + } + else + { + fatalErrorInFunction<< "Wroing input field type "<< inputType<("shapeType", ""); + + if(shapeType_.empty()) + { + WARNING + << "shapeType is not set in dictionary: " + << postDict.globalName() + << " and you may need to set for some postprocess operations"<second; + } + else + { + // the name is in the Time object + if(pointFieldNameExists(pointFieldName)) + { + originalType = getPointFieldType(pointFieldName); + } + else + { + fatalErrorInFunction + << "The field name: "<< pointFieldName + << " is not in the Time object.\n" + <<" Avaiable ones are: \n"<< time().objectNames()< pFlow::postprocessData::fieldsDataBase::updatePoints(bool forceUpdate) +{ + const word fName = "position"; + bool shouldUpdate = checkForUpdate(fName, forceUpdate); + + if(shouldUpdate) + { + // load pointStructure + if(!loadPointStructureToTime()) + { + fatalErrorInFunction<< "Error in loading pointStructure to Time object."< + ( + fName, + pstruct.activePointsHost() + ); + } + + auto& points = allFields_.getObject(fName); + + return span( + points.data(), + points.size()); + +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::updateFieldRealx3 +( + const word &compoundName, + bool forceUpdate +) +{ + word originalType, typeAfterFunction, fieldName; + Functions func; + + if( !getFieldTypeNameFunction( + compoundName, + fieldName, + originalType, + typeAfterFunction, + func) ) + { + fatalErrorInFunction<< "Error in getting the type name of field: "<< + compoundName<<", with type name: "<< originalType <(nullptr, 0); + } + + if( originalType == getTypeName() && func == Functions::None ) + { + return updateField(fieldName, forceUpdate); + } + else + { + fatalErrorInFunction<< "Error in getting the type name of field: "<< + compoundName<<", with type name: "<< originalType <(nullptr, 0); + } + +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::updateFieldRealx4 +( + const word &compoundName, + bool forceUpdate +) +{ + word originalType, typeAfterFunction, fieldName; + Functions func; + + if( !getFieldTypeNameFunction( + compoundName, + fieldName, + originalType, + typeAfterFunction, + func)) + { + fatalErrorInFunction<< "Error in getting the type name of field: "<< + compoundName<<", with type name: "<< originalType <(nullptr, 0); + } + + if( originalType == getTypeName() && func == Functions::None ) + { + return updateField(fieldName, forceUpdate); + } + else + { + fatalErrorInFunction<< "Error in getting the type name of field: "<< + compoundName<<", with type name: "<< originalType <(nullptr, 0); + } + +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::updateFieldReal +( + const word &compoundName, + bool forceUpdate +) +{ + word originalType, typeAfterFunction, fieldName; + Functions func; + + if( !getFieldTypeNameFunction( + compoundName, + fieldName, + originalType, + typeAfterFunction, + func) ) + { + fatalErrorInFunction<< "Error in getting the type name of field: "<< + compoundName<<", with type name: "<< originalType <(nullptr, 0); + } + + // if the output type is not real, then it is not supported yet + if(typeAfterFunction != getTypeName()) + { + fatalErrorInFunction<< "The output type of field "<< compoundName<< + " is not real, it is: "<< typeAfterFunction<(nullptr, 0); + } + + // if the orginal type is real and no function, then it is a normal field + if( originalType == getTypeName() && func == Functions::None ) + { + return updateField(fieldName, forceUpdate); + } + + // if the original type is uint32, and no funciton, cast to real + if( originalType == getTypeName()) + { + if(func == Functions::None) + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(fieldName+".real"); + funcCast(sp, spReal); + return spReal; + } + else + { + fatalErrorInFunction<<"No function can be applied to field of type uint32. "<< + " The field is: "<< compoundName<(nullptr, 0); + fatalExit; + } + } + + if( originalType == getTypeName() ) + { + switch(func) + { + case Functions::Abs: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcAbs(sp, spReal); + return spReal; + } + case Functions::Square: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcSquare(sp, spReal); + return spReal; + } + case Functions::Cube: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcCube(sp, spReal); + return spReal; + } + case Functions::SqureRoot: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName+".sqrt"); + funcSquareRoot(sp, spReal); + return spReal; + } + default: + { + fatalErrorInFunction<< "Wrong function for field type real in :"<< + compoundName<(nullptr, 0); + } + } + } + + if( originalType == getTypeName()) + { + switch(func) + { + case Functions::Magnitude: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcMagnitude(sp, spReal); + return spReal; + } + case Functions::MagnitudeSquare: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcMagnitudeSquare(sp, spReal); + return spReal; + } + case Functions::MagnitudeCube: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcMagnitudeCube(sp, spReal); + return spReal; + } + case Functions::MagnitudeSquareRoot: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcMagnitudeSquareRoot(sp, spReal); + return spReal; + } + case Functions::ComponentX: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcComponent(sp, spReal, 'x'); + return spReal; + } + case Functions::ComponentY: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcComponent(sp, spReal, 'y'); + return spReal; + } + case Functions::ComponentZ: + { + auto sp = updateField(fieldName, forceUpdate); + auto spReal = createOrGetRealField(compoundName); + funcComponent(sp, spReal, 'z'); + return spReal; + } + default: + { + fatalErrorInFunction<< "Wrong function for field type realx3 in :"<< + compoundName<(nullptr, 0); + } + } + } + + fatalErrorInFunction<<"NOT SUPPORTED "<(nullptr, 0); +} + +pFlow::span pFlow::postprocessData::fieldsDataBase::updateFieldUint32 +( + const word& name, + bool forceUpdate +) +{ + return updateField(name, forceUpdate); +} + +pFlow::postprocessData::allPointFieldTypes pFlow::postprocessData::fieldsDataBase::updateFieldAll +( + const word &compoundName, + bool forceUpdate +) +{ + word typeAfterFunction, originalType; + + if( !getFieldType(compoundName, originalType, typeAfterFunction)) + { + fatalErrorInFunction<< "Error in getting the type name of field: "<< + compoundName<<", with type name: "<< originalType <(nullptr, 0); + } + + if( typeAfterFunction == getTypeName() ) + { + return updateFieldRealx3(compoundName, forceUpdate); + } + else if( typeAfterFunction == getTypeName() ) + { + return updateFieldRealx4(compoundName, forceUpdate); + } + else if( typeAfterFunction == getTypeName() ) + { + return updateFieldReal(compoundName, forceUpdate); + } + else + { + fatalErrorInFunction<< "Invalid feild "<< compoundName<(nullptr, 0); + } +} + +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::create +( + systemControl& control, + const dictionary& postDict, + bool inSimulation, + timeValue startTime +) +{ + word dbType; + if(inSimulation) + { + dbType = "fieldsDataBase"; + } + else + { + dbType = "fieldsDataBase"; + } + + if( boolvCtorSelector_.search(dbType) ) + { + auto objPtr = + boolvCtorSelector_[dbType](control, postDict, inSimulation, startTime); + return objPtr; + } + else + { + printKeys + ( + fatalError << "Ctor Selector "<< + dbType << " does not exist. \n" + <<"Available ones are: \n\n" + , + boolvCtorSelector_ + ); + fatalExit; + } + + return nullptr; +} + + + diff --git a/src/PostprocessData/fieldsDataBase/fieldsDataBase.hpp b/src/PostprocessData/fieldsDataBase/fieldsDataBase.hpp new file mode 100644 index 00000000..fb707b1e --- /dev/null +++ b/src/PostprocessData/fieldsDataBase/fieldsDataBase.hpp @@ -0,0 +1,326 @@ +/*------------------------------- 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 __fieldsDataBase_hpp__ +#define __fieldsDataBase_hpp__ + +#include "fieldsDataBaseDclr.hpp" + +#include "pointStructure.hpp" +#include "pointFields.hpp" +#include "anyList.hpp" +#include "Map.hpp" +#include "shape.hpp" + +namespace pFlow +{ + class dictionary; + class systemControl; + class Time; +} + +namespace pFlow::postprocessData +{ + + +class fieldsDataBase +{ +private: + + // - Typedefs + + /// Point position data type + using PointsTypeHost = typename pointStructure::PointsTypeHost; + + /// Point field data type + template + using FieldTypeHost = typename internalField::FieldTypeHost; + + /// @brief Enumeration of functions that can be applied to point fields. + enum class Functions + { + None, /// no function + ComponentX, /// component(u,x) + ComponentY, /// component(u,y) + ComponentZ, /// component(u,z) + ComponentW, /// component(u,w) + Abs, /// abs(s) + Square, /// square(s) + Cube, /// cube(s) + SqureRoot, /// sqrt(s) + Magnitude, /// mag(u) + MagnitudeSquare, /// magSquare(u) + MagnitudeCube, /// magCube(u) + MagnitudeSquareRoot /// magSqrt(u) + }; + + + // - Member variables + + /// List to store all the point fields + anyList allFields_; + + /// Map to store the last capture time of each field + wordMap captureTime_; + + /// Reference to the Time object + Time& time_; + + /// Flag indicating if we're in simulation mode + bool inSimulation_ = false; + + word shapeType_; + +protected: + + /// check if pointField name exists in Time or time folder + virtual + bool pointFieldNameExists(const word& name)const = 0; + + /// Loads a pointField with a given name to the Time object + virtual + bool loadPointFieldToTime(const word& name)= 0; + + virtual + bool loadPointStructureToTime()=0; + + virtual + const shape& getShape() const= 0; + + const word& shapeTypeName()const + { + return shapeType_; + } + + /// get the type name of the pointField in the Time object + virtual + word getPointFieldType(const word& name)const = 0; + + /// Checks if a field needs to be updated based on capture time + bool checkForUpdate(const word& compoundName, bool forceUpdate = false); + + /// @brief return the size of pointStructure + uint32 pointFieldSize() + { + auto s = updatePoints(); + return s.size(); + } + + template + span updateField(const word& name, bool forceUpdate = false); + + template + span updateReservedField(const word& name, bool forceUpdate = false); + + span createOrGetRealField(const word& name); + + span createOrGetVolume(bool forceUpdate=false); + + span createOrGetDensity(bool forceUpdate=false); + + span createOrGetOne(bool forceUpdate=false); + + span createOrGetMass(bool forceUpdate=false); + + span createOrGetI(bool forceUpdate=false); + + /// Map of reserved field names with their corresponding types + static const inline std::map reservedFieldNames_ + { + {"position", "realx3"}, + {"one", "real"}, + {"volume", "real"}, + {"density", "real"}, + {"mass", "real"}, + {"I", "real"} + }; + + static + bool findFunction( + const word& compoundFieldName, + word& fieldName, + fieldsDataBase::Functions& func ); + + static + bool inputOutputType( + fieldsDataBase::Functions func, + const word& inputType, + word& outputType); + + + +public: + + // - Type info + + TypeInfo("fieldsDataBase"); + + // - constructors + + fieldsDataBase( + systemControl& control, + const dictionary& postDict, + bool inSimulation, + timeValue startTime); + + /// no copy constructor + fieldsDataBase(const fieldsDataBase&) = delete; + + /// no move constructor + fieldsDataBase(fieldsDataBase&&) = delete; + + /// no copy assignment + fieldsDataBase& operator=(const fieldsDataBase&) = delete; + + /// no move assignment + fieldsDataBase& operator=(fieldsDataBase&&) = delete; + + /// destructor + virtual ~fieldsDataBase() = default; + + create_vCtor + ( + fieldsDataBase, + bool, + ( + systemControl& control, + const dictionary& postDict, + bool inSimulation, + timeValue startTime + ), + (control, postDict, inSimulation, startTime) + ); + + + // - Public Access Functions + /// returns the current time + timeValue currentTime()const; + + /// const ref to object Time + const Time& time()const + { + return time_; + } + + Time& time() + { + return time_; + } + + // - Public Member Functions + + bool getFieldTypeNameFunction + ( + const word& compoundName, + word& pointFieldName, + word& originalType, + word& typeAfterFunction, + Functions& func + )const; + + + bool getFieldType + ( + const word& compoundName, + word& originalType, + word& typeAfterFunction + ) const; + + bool getFieldType + ( + const word& compoundName, + word& typeAfterFunction + ) const; + + + /// update pointStructure if necessary + span updatePoints(bool forceUpdate = false); + + /// update a field with realx3 type + span updateFieldRealx3( + const word& compoundName, + bool forceUpdate = false); + + span updateFieldRealx4( + const word& compoundName, + bool forceUpdate = false); + + span updateFieldReal( + const word& compoundName, + bool forceUpdate = false); + + span updateFieldUint32( + const word& name, + bool forceUpdate = false); + + /// Updates and retrieves a point field of any type from the database. + /// It returns types real, realx3 and realx4 only. + allPointFieldTypes updateFieldAll( + const word& compoundName, + bool forceUpdate = false); + + virtual + const pointStructure& pStruct()const = 0; + + /// Get the next avaiable time folder after the current time folder + /// This is only used for post-simulation processing + virtual + timeValue getNextTimeFolder()const + { + return -1.0; + } + + /// Sets the current folder to the next time folder. + /// This is used only for post-simulation processing + /// @returns the time value of the next folder. + virtual + timeValue setToNextTimeFolder() + { + return -1.0; + } + + /// Skips the next time folder. + /// This is used only for post-simulation processing + /// @returns the time value of the skipped folder + virtual + timeValue skipNextTimeFolder() + { + return -1.0; + } + + static + bool pointFieldGetType( + const word& TYPENAME, + word& fieldType, + word& fieldSpace); + + static + uniquePtr create( + systemControl& control, + const dictionary& postDict, + bool inSimulation, + timeValue startTime); +}; + +} // namespace pFlow::postprocessData + +#include "fieldsDataBaseTemplates.cpp" + +#endif //__fieldsDataBased_hpp__ diff --git a/src/PostprocessData/fieldsDataBase/fieldsDataBaseDclr.hpp b/src/PostprocessData/fieldsDataBase/fieldsDataBaseDclr.hpp new file mode 100644 index 00000000..e5d483c0 --- /dev/null +++ b/src/PostprocessData/fieldsDataBase/fieldsDataBaseDclr.hpp @@ -0,0 +1,45 @@ + +#ifndef __fieldsDataBaseDclr_hpp__ +#define __fieldsDataBaseDclr_hpp__ + +#include +#include +#include + +#include "types.hpp" +#include "span.hpp" + +namespace pFlow::postprocessData +{ + + +template +concept ValidFieldType = + std::same_as || + std::same_as || + std::same_as || + std::same_as; + +template +concept VectorType = + std::same_as || + std::same_as; + +template +concept ScalarType = + std::same_as; + + +template +concept ValidRegionFieldType = + std::same_as || + std::same_as || + std::same_as ; + + +using allPointFieldTypes = std::variant, span, span>; + + +} // namespace pFlow + +#endif //__fieldsDataBaseDclr_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/fieldsDataBase/fieldsDataBaseTemplates.cpp b/src/PostprocessData/fieldsDataBase/fieldsDataBaseTemplates.cpp new file mode 100644 index 00000000..33cb0d87 --- /dev/null +++ b/src/PostprocessData/fieldsDataBase/fieldsDataBaseTemplates.cpp @@ -0,0 +1,171 @@ +/*------------------------------- 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 __fieldsDataBaseTemplates_hpp__ +#define __fieldsDataBaseTemplates_hpp__ + +#include "fieldsDataBase.hpp" + +template +inline +pFlow::span pFlow::postprocessData::fieldsDataBase::updateField(const word& name, bool forceUpdate) +{ + + bool shouldUpdate = checkForUpdate(name, forceUpdate); + + if(shouldUpdate) + { + if(reservedFieldNames_.contains(name)) + { + return updateReservedField(name, true); + } + else + { + if( loadPointFieldToTime(name) ) + { + const auto& pField = time_.template lookupObject>(name); + allFields_.template emplaceBackOrReplace>( + name, + pField.activeValuesHost()); + } + else + { + fatalErrorInFunction<<"Error in loading the pointField "<>(name); + + return span( + field.data(), + field.size()); + +} + + +template +inline +pFlow::span pFlow::postprocessData::fieldsDataBase::updateReservedField +( + const word& name, + bool forceUpdate +) +{ + if(name == "one") + { + if constexpr( std::same_as) + { + return createOrGetOne(forceUpdate); + } + else + { + fatalErrorInFunction + << "This type: " + << getTypeName() + <<" is not supported for field one."<) + { + return createOrGetVolume(forceUpdate); + } + else + { + fatalErrorInFunction + << "This type: " + << getTypeName() + <<" is not supported for field volume."<) + { + return createOrGetDensity(forceUpdate); + } + else + { + fatalErrorInFunction + << "This type: " + << getTypeName() + <<" is not supported for field density."<) + { + return createOrGetMass(forceUpdate); + } + else + { + fatalErrorInFunction + << "This type: " + << getTypeName() + <<" is not supported for field mass."<) + { + return createOrGetI(forceUpdate); + } + else + { + fatalErrorInFunction + << "This type: " + << getTypeName() + <<" is not supported for field I."<) + { + return updatePoints(forceUpdate); + } + else + { + fatalErrorInFunction + << "This type: " + << getTypeName() + <<" is not supported for field position."<(nullptr, 0); + +} + +#endif //__fieldsDataBaseTemplates_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/fieldsDataBase/simulationFieldsDataBase.cpp b/src/PostprocessData/fieldsDataBase/simulationFieldsDataBase.cpp new file mode 100644 index 00000000..b4e19f6a --- /dev/null +++ b/src/PostprocessData/fieldsDataBase/simulationFieldsDataBase.cpp @@ -0,0 +1,71 @@ +#include "Time.hpp" +#include "simulationFieldsDataBase.hpp" +#include "dynamicPointStructure.hpp" +#include "vocabs.hpp" + + + +bool pFlow::postprocessData::simulationFieldsDataBase::pointFieldNameExists(const word &name) const +{ + return time().lookupObjectName(name); +} + +bool pFlow::postprocessData::simulationFieldsDataBase::loadPointFieldToTime(const word &name) +{ + return time().lookupObjectName(name); +} + +bool pFlow::postprocessData::simulationFieldsDataBase::loadPointStructureToTime() +{ + // it is already in the Time object + return time().lookupObjectName(pointStructureFile__); +} + + +const pFlow::shape& pFlow::postprocessData::simulationFieldsDataBase::getShape() const +{ + return shape_; +} + +pFlow::word pFlow::postprocessData::simulationFieldsDataBase::getPointFieldType +( + const word &name +) const +{ + word pfType = time().lookupObjectTypeName(name); + word type, space; + if(!fieldsDataBase::pointFieldGetType(pfType, type, space)) + { + fatalErrorInFunction + <<"Error in retriving the type of pointField " + << pfType<(*control.caseSetup().lookupObjectPtr(shapeFile__)) + ) +{ +} + +const pFlow::pointStructure &pFlow::postprocessData::simulationFieldsDataBase::pStruct() const +{ + return + static_cast + ( + time().lookupObject(pointStructureFile__) + ); +} + diff --git a/src/PostprocessData/fieldsDataBase/simulationFieldsDataBase.hpp b/src/PostprocessData/fieldsDataBase/simulationFieldsDataBase.hpp new file mode 100644 index 00000000..298a4957 --- /dev/null +++ b/src/PostprocessData/fieldsDataBase/simulationFieldsDataBase.hpp @@ -0,0 +1,82 @@ +/*------------------------------- 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 __simulationFieldsDataBase_hpp__ +#define __simulationFieldsDataBase_hpp__ + +#include "fieldsDataBase.hpp" + +namespace pFlow::postprocessData +{ + +class simulationFieldsDataBase +: + public fieldsDataBase +{ +private: + + const shape& shape_; + +protected: + + /// check if pointField name exists in Time or time folder + bool pointFieldNameExists(const word& name)const override; + + + /// Loads a pointField with a given name to the Time object. + /// For simulation, it just checks if the name exists + bool loadPointFieldToTime(const word& name) override; + + /// Loads pointStructure to the Time object + /// For simulation, it just checks if the name exists + bool loadPointStructureToTime() override; + + const shape& getShape() const override; + + word getPointFieldType(const word& name)const override; + +public: + + TypeInfo("fieldsDataBase"); + + simulationFieldsDataBase( + systemControl& control, + const dictionary& postDict, + bool inSimulation, + timeValue startTime); + + ~simulationFieldsDataBase() override = default; + + add_vCtor + ( + fieldsDataBase, + simulationFieldsDataBase, + bool + ); + + const pointStructure& pStruct()const override; + +}; + + +} + + +#endif //__simulationFieldsDataBase_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAvMassVelocity.cpp b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAvMassVelocity.cpp new file mode 100644 index 00000000..b64ba902 --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAvMassVelocity.cpp @@ -0,0 +1,25 @@ +#include "PostprocessOperationAvMassVelocity.hpp" + +namespace pFlow::postprocessData +{ + +PostprocessOperationAvMassVelocity::PostprocessOperationAvMassVelocity +( + const dictionary &opDict, + const regionPoints ®Points, + fieldsDataBase &fieldsDB +) +: + PostprocessOperationAverage + ( + opDict, + opDict.getValOrSet("velocityName", "velocity"), + opDict.getValOrSet("massName", "mass"), + "all", + regPoints, + fieldsDB + ) +{ +} + +} \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAvMassVelocity.hpp b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAvMassVelocity.hpp new file mode 100644 index 00000000..4cbdf5a2 --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAvMassVelocity.hpp @@ -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 +#include + +#include "PostprocessOperationAverage.hpp" +#include "regionField.hpp" +#include "includeMask.hpp" + +namespace pFlow::postprocessData +{ + + +class PostprocessOperationAvMassVelocity +: + public PostprocessOperationAverage +{ + +public: + + TypeInfo("PostprocessOperation"); + + /// @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 + ); + +}; + + +} // namespace pFlow::postprocessData + +#endif //__PostprocessOperationAvMassVelocity_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAverage.cpp b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAverage.cpp new file mode 100644 index 00000000..07a4411e --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAverage.cpp @@ -0,0 +1,181 @@ +#include "PostprocessOperationAverage.hpp" +#include "dictionary.hpp" +#include "fieldsDataBase.hpp" +#include "operationFunctions.hpp" + +namespace pFlow::postprocessData +{ + +/// Constructs average processor and initializes result field based on input field type +PostprocessOperationAverage::PostprocessOperationAverage +( + const dictionary &opDict, + const regionPoints ®Points, + fieldsDataBase &fieldsDB +) +: + postprocessOperation(opDict, regPoints, fieldsDB), + calculateFluctuation2_(opDict.getValOrSet("fluctuation2", Logical(false))) +{ + if( fieldType() == getTypeName() ) + { + processedRegFieldPtr_ = makeUnique( + regionField(processedFieldName(), regPoints, real(0))); + } + else if( fieldType() == getTypeName() ) + { + processedRegFieldPtr_ = makeUnique( + regionField(processedFieldName(), regPoints, realx3(0))); + } + else if( fieldType() == getTypeName() ) + { + processedRegFieldPtr_ = makeUnique( + 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; + } +} + +PostprocessOperationAverage::PostprocessOperationAverage +( + const dictionary &opDict, + const word &fieldName, + const word &phiName, + const word &includeName, + const regionPoints ®Points, + fieldsDataBase &fieldsDB +) +: + postprocessOperation(opDict, fieldName, phiName, includeName, regPoints, fieldsDB), + calculateFluctuation2_(opDict.getValOrSet("fluctuation2", Logical(false))) +{ + if( fieldType() == getTypeName() ) + { + processedRegFieldPtr_ = makeUnique( + regionField(processedFieldName(), regPoints, real(0))); + } + else if( fieldType() == getTypeName() ) + { + processedRegFieldPtr_ = makeUnique( + regionField(processedFieldName(), regPoints, realx3(0))); + } + else if( fieldType() == getTypeName() ) + { + processedRegFieldPtr_ = makeUnique( + 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 PostprocessOperationAverage::execute +( + const std::vector>& weights, + const regionField& volFactor +) +{ + 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 + ( + std::visit([&](auto&& field)->processedRegFieldType + { + return executeAverageOperation( + procName, + field, + volFactor, + dbVol, + weights, + phi, + mask); + }, + allField) + ); + + if(calculateFluctuation2_()) + { + auto& processedRegField = processedRegFieldPtr_(); + fluctuation2FieldPtr_ = makeUnique + ( + std::visit([&](auto& field)->processedRegFieldType + { + using T = typename std::decay_t>::valueType; + if constexpr( std::is_same_v || + std::is_same_v|| + std::is_same_v) + { + return executeFluctuation2Operation( + procName, + field, + std::get>(processedRegField), + volFactor, + dbVol, + weights, + mask); + } + }, + allField) + ); + } + + + return true; +} + +bool PostprocessOperationAverage::write(const fileSystem &parDir) const +{ + if(! postprocessOperation::write(parDir)) + { + return false; + } + if(!calculateFluctuation2_()) + { + return true; + } + + auto ti = time().TimeInfo(); + + if(!os2Ptr_) + { + fileSystem path = parDir+( + processedFieldName()+"_prime2" + ".Start_" + ti.timeName()); + os2Ptr_ = makeUnique(path); + + regPoints().write(os2Ptr_()); + } + + + std::visit + ( + [&](auto&& arg)->bool + { + return writeField(os2Ptr_(), ti.t(), arg, threshold()); + }, + fluctuation2FieldPtr_() + ); + + return true; +} + +} // namespace pFlow::postprocessData \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAverage.hpp b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAverage.hpp new file mode 100644 index 00000000..1840c0c4 --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationAverage.hpp @@ -0,0 +1,211 @@ +/*------------------------------- 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 +#include + +#include "postprocessOperation.hpp" +#include "regionField.hpp" +#include "includeMask.hpp" + +namespace pFlow::postprocessData +{ + +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 processedRegFieldPtr_ = nullptr; + + uniquePtr fluctuation2FieldPtr_ = nullptr; + + /// Pointer to the output stream for writing fluctuation2 results + mutable uniquePtr os2Ptr_ = nullptr; + +public: + + TypeInfo("PostprocessOperation"); + + /// @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_(); + } + + /// write to os stream + bool write(const fileSystem &parDir)const override; + + + /// @brief Execute average operation on field values + /// @param weights Weight factors for particles + /// @return True if successful + bool execute( + const std::vector>& weights, + const regionField& volFactor) override; + +}; + + +} // namespace pFlow::postprocessData + +#endif //__PostprocessOperationAverage_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationSum.cpp b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationSum.cpp new file mode 100644 index 00000000..1eec581f --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationSum.cpp @@ -0,0 +1,80 @@ +#include "PostprocessOperationSum.hpp" +#include "dictionary.hpp" +#include "fieldsDataBase.hpp" +#include "operationFunctions.hpp" + +namespace pFlow::postprocessData +{ + +/// Constructs sum processor and initializes result field based on input field type +PostprocessOperationSum::PostprocessOperationSum +( + const dictionary &opDict, + const regionPoints ®Points, + fieldsDataBase &fieldsDB +) +: + postprocessOperation(opDict, regPoints, fieldsDB) +{ + if( fieldType() == getTypeName() ) + { + processedRegField_ = makeUnique( + regionField(processedFieldName(), regPoints, real(0))); + } + else if( fieldType() == getTypeName() ) + { + processedRegField_ = makeUnique( + regionField(processedFieldName(), regPoints, realx3(0))); + } + else if( fieldType() == getTypeName() ) + { + processedRegField_ = makeUnique( + regionField(processedFieldName(), regPoints, realx4(0))); + } + else + { + fatalErrorInFunction<<" in dictionary "<< opDict.globalName() + << " field type is not supported for sum operation" + << " field type is "<< fieldType() + << endl; + fatalExit; + } +} + +/// Performs weighted sum of field values within each region +bool PostprocessOperationSum::execute +( + const std::vector>& weights, + const regionField& volFactor +) +{ + auto allField = database().updateFieldAll(fieldName()); + auto phi = database().updateFieldReal( + phiFieldName()); + + auto mask = getMask(); + word procName = processedFieldName(); + const auto& regP = regPoints(); + bool dbVol = divideByVolume(); + + processedRegField_ = makeUnique + ( + std::visit([&](auto&& field)->processedRegFieldType + { + return executeSumOperation( + procName, + field, + volFactor, + dbVol, + weights, + phi, + mask); + }, + allField) + ); + + return true; +} + + +} \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationSum.hpp b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationSum.hpp new file mode 100644 index 00000000..4452be0e --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/PostprocessOperationSum.hpp @@ -0,0 +1,187 @@ +/*------------------------------- 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 __PostprocessOperationSum_hpp__ +#define __PostprocessOperationSum_hpp__ + +/*! + * @class PostprocessOperationSum + * @brief A class for summing field values within specified regions during post-processing. + * + * @details + * The PostprocessOperationSum class is a specialized post-processing operation that + * calculates the sum of field values within specified regions. It inherits from the + * postprocessOperation base class and implements a weighted summation operation that + * can be applied to scalar (real), vector (realx3), and tensor (realx4) fields. + * + * The sum operation follows the mathematical formula: + * \f[ + * \text{result} = \sum_{i \in \text{processRegion}} w_i \cdot \phi_i \cdot \text{field}_i + * \f] + * + * Where: + * - \f$ i \f$ represents particles within the specified processing region + * - \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}_i \f$ is the value from the target field for particle \f$ i \f$ + * + * The calculation can optionally be divided by the region volume (when divideByVolume is set to yes), + * which allows calculating density-like quantities: + * \f[ + * \text{result} = \frac{1}{V_{\text{region}}} \sum_{i \in \text{processRegion}} w_i \cdot \phi_i \cdot \text{field}_i + * \f] + * + * The summation 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 + * + * To use the PostprocessOperationSum class in a postprocessDataDict file, the following + * parameters can be specified: + * + * - function: Must be set to "sum" to use this operation + * - field: The name of the field to process (e.g., "velocity", "diameter", "one") + * - Special fields like "one" (constant value 1) are also supported + * - Expressions like "cube(diameter)" can be used for mathematical operations + * - dividedByVolume: Whether to divide the sum by the region volume (yes/no, default: no) + * - includeMask: Optional mask to filter which particles to include in the calculation + * + * @section example Example Configuration + * + * Here is an example configuration in the postprocessDataDict file: + * + * @code + * { + * processMethod arithmetic; + * processRegion line; + * + * // the time interval for executing the post-processing + * // other options: timeStep, default, and settings + * timeControl simulationTime; + * 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); + * numPoints 10; + * radius 0.01; + * } + * + * operations + * ( + * // computes the number density (particles per unit volume) + * numberDensity + * { + * function sum; + * field one; // constant field with value 1.0 + * dividedByVolume yes; // divide by region volume + * } + * + * // computes an approximation of volume fraction + * volumeDensity + * { + * function sum; + * field cube(diameter); // d^3, although it differs by pi/6 + * dividedByVolume yes; + * } + * ); + * } + * @endcode + * + * In this example: + * - numberDensity: Calculates the number of particles per unit volume + * - volumeDensity: Calculates an approximation of the volume fraction using d³ + * + * @see postprocessOperation + * @see executeSumOperation + */ + +#include +#include + +#include "postprocessOperation.hpp" +#include "regionField.hpp" +#include "includeMask.hpp" + +namespace pFlow::postprocessData +{ + + +class PostprocessOperationSum +: + public postprocessOperation +{ +private: + /// Result field containing sums for each region (real, realx3, or realx4) + uniquePtr processedRegField_ = nullptr; + +public: + + TypeInfo("PostprocessOperation"); + + /// @brief Constructs sum operation processor + /// @param opDict Operation parameters dictionary + /// @param regPoints Region points data + /// @param fieldsDB Fields database + PostprocessOperationSum( + const dictionary& opDict, + const regionPoints& regPoints, + fieldsDataBase& fieldsDB); + + /// destructor + ~PostprocessOperationSum() override = default; + + /// add this virtual constructor to the base class + add_vCtor + ( + postprocessOperation, + PostprocessOperationSum, + dictionary + ); + + /// @brief Get the processed field containing regional sums + /// @return Const reference to sum results + const processedRegFieldType& processedField()const override + { + return processedRegField_(); + } + + /// @brief Execute sum operation on field values + /// @param weights Weight factors for particles + /// @return True if successful + bool execute( + const std::vector>& weights, + const regionField& volFactor) override; + +}; + + +} // namespace pFlow::postprocessData + +#endif //__PostprocessOperationSum_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/operation/PostprocessOperation/operationFunctions.hpp b/src/PostprocessData/operation/PostprocessOperation/operationFunctions.hpp new file mode 100644 index 00000000..d9c23552 --- /dev/null +++ b/src/PostprocessData/operation/PostprocessOperation/operationFunctions.hpp @@ -0,0 +1,195 @@ +/*------------------------------- 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 __operationFunctions_hpp__ +#define __operationFunctions_hpp__ + +#include + +#include "span.hpp" +#include "regionPoints.hpp" +#include "regionField.hpp" +#include "includeMask.hpp" + +namespace pFlow::postprocessData +{ + +template +regionField executeSumOperation +( + const word& regFieldName, + const span& field, + const regionField& volFactor, + const bool devideByVol, + const std::vector>& weights, + const span& phi, + const includeMask::Mask& mask +) +{ + const auto& regPoints = volFactor.regPoints(); + regionField processedField(regFieldName, regPoints, T{}); + auto vols = regPoints.volumes(); + + for(uint32 reg =0; reg +regionField executeAverageOperation +( + const word& regFieldName, + const span& field, + const regionField& volFactor, + const bool devideByVol, + const std::vector>& weights, + const span& phi, + const includeMask::Mask& mask +) +{ + + const auto& regPoints = volFactor.regPoints(); + regionField processedField(regFieldName, regPoints, T{}); + auto vols = regPoints.volumes(); + + for(uint32 reg =0; reg +regionField executeFluctuation2Operation +( + const word& regFieldName, + const span& field, + const regionField& fieldAvg, + const regionField& volFactor, + const bool devideByVol, + const std::vector>& weights, + const includeMask::Mask& mask +) +{ + const auto& regPoints = fieldAvg.regPoints(); + regionField processedField(regFieldName, regPoints, T{}); + auto vols = regPoints.volumes(); + + for(uint32 reg =0; reg(2)); + } + sumDen += w[n]; + } + n++; + } + + if(devideByVol) + { + processedField[reg] = sumNum / max(sumDen, smallValue) / vol; + } + else + { + processedField[reg] = sumNum / max(sumDen, smallValue); + } + + } + + return processedField; +} + +} // namespace pFlow::postprocessData + +#endif //__operationFunctions_hpp__ diff --git a/src/PostprocessData/operation/includeMask/IncludeMask.hpp b/src/PostprocessData/operation/includeMask/IncludeMask.hpp new file mode 100644 index 00000000..3689f22c --- /dev/null +++ b/src/PostprocessData/operation/includeMask/IncludeMask.hpp @@ -0,0 +1,277 @@ +/*------------------------------- 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. + +-----------------------------------------------------------------------------*/ + +/** + * @brief A template class implementing includeMask for filtering data based on field values + * + * The IncludeMask class creates boolean masks that identify which elements from a field + * satisfy a given condition. It applies an operator to each element of a field and + * generates a mask (vector of booleans) where true means the element satisfies the + * condition and should be included. + * + * @tparam T The data type of the field (real, realx3, realx4) + * @tparam Operator The operation class that defines the condition (e.g., greaterThanOp) + * + * The class has a specialized implementation for allOp operator which includes all elements. + * + * Usage example in postprocessDataDict: + * ``` + * // Create a dictionary with the required configuration for filtering + * + * { + * includeMask lessThan; + * + * // Diameter of par1 is 0.003, so these settings + * // will select only particles of type par1 + * lessThanInfo + * { + * field diameter; + * value 0.0031; + * } + * + * } + * + * ``` + */ + +#ifndef __IncludeMask_hpp__ +#define __IncludeMask_hpp__ + +#include "dictionary.hpp" +#include "includeMask.hpp" +#include "fieldsDataBase.hpp" +#include "maskOperations.hpp" +#include "Time.hpp" + + +namespace pFlow::postprocessData +{ + +template +class IncludeMask +: + public includeMask +{ +public: + + /// Type alias for the mask container returned by getMask() + using Mask = typename includeMask::Mask; + +private: + + /// Boolean vector the filtering status of each element (true = include) + std::vector mask_; + + /// Comparison operator instance that evaluates the filtering condition + Operator operator_; + + /// Name of the field to apply filtering on + word fieldName_; + + /// Timestamp when mask was last updated (-1 indicates never updated) + timeValue lastUpdated_ = -1; + + /// Updates the mask based on current field values if needed, returns true if successful + bool updateMask() + { + timeValue t = database().currentTime(); + + if( equal( t, lastUpdated_)) return true; + + span s; + if constexpr (std::is_same_v) + { + s = database().updateFieldReal(fieldName_); + } + else if constexpr ( std::is_same_v) + { + s = database().updateFieldRealx3(fieldName_); + } + else if constexpr( std::is_same_v) + { + s = database().updateFieldRealx4(fieldName_); + } + else + { + fatalErrorInFunction<<"Type "<< getTypeName() + <<" is not supported for IncludeMask for field " + << fieldName_ << endl; + return false; + } + + + mask_.resize(s.size()); + + for(uint32 i=0; i("field")) + {} + + IncludeMask( + const word& type, + const dictionary& dict, + fieldsDataBase& feildsDB) + : + includeMask(type, dict, feildsDB), + operator_(dict.subDict(operatorName()+"Info")), + fieldName_( + dict.subDict + ( + operatorName()+"Info" + ).getVal("field")) + {} + + /// Add virtual constructor pattern for creating instances + add_vCtor + ( + includeMask, + IncludeMask, + dictionary + ); + + add_vCtor + ( + includeMask, + IncludeMask, + word + ); + + /// Returns the mask for filtering elements (updates the mask if necessary) + Mask getMask() override + { + updateMask(); + return Mask(mask_); + } + +}; + + +template +class IncludeMask> +: + public includeMask +{ +public: + + using Mask = typename includeMask::Mask; + +private: + + std::vector mask_; + + timeValue lastUpdated_ = -1; + + bool updateMask() + { + timeValue t = database().currentTime(); + + if( equal( t, lastUpdated_)) return true; + + span s = database().updatePoints(); + mask_.resize(s.size(), true); + + lastUpdated_ = t ; + + return true; + } + +public: + + TypeInfoTemplate12("IncludeMask", T, allOp); + + IncludeMask( + const dictionary& opDict, + fieldsDataBase& feildsDB) + : + includeMask(opDict, feildsDB) + { + span s = database().updatePoints(); + mask_.resize(s.size(), true); + } + + IncludeMask( + const word& type, + const dictionary& opDict, + fieldsDataBase& feildsDB) + : + includeMask(type, opDict, feildsDB) + { + span s = database().updatePoints(); + mask_.resize(s.size(), true); + } + + add_vCtor + ( + includeMask, + IncludeMask, + dictionary + ); + + add_vCtor + ( + includeMask, + IncludeMask, + word + ); + + Mask getMask()override + { + updateMask(); + return Mask(mask_); + } + +}; + + +} // pFlow::postprocessData + +#endif //__IncludeMask_hpp__ + + diff --git a/src/PostprocessData/operation/includeMask/IncludeMasks.cpp b/src/PostprocessData/operation/includeMask/IncludeMasks.cpp new file mode 100644 index 00000000..7e8e687c --- /dev/null +++ b/src/PostprocessData/operation/includeMask/IncludeMasks.cpp @@ -0,0 +1,53 @@ +/*------------------------------- 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. + +-----------------------------------------------------------------------------*/ + +#include "IncludeMask.hpp" + +namespace pFlow::postprocessData +{ + +// real +template class IncludeMask >; +template class IncludeMask >; + +template class IncludeMask >; +template class IncludeMask >; + +template class IncludeMask >; + +template class IncludeMask >; +template class IncludeMask >; + +template class IncludeMask>; + +// realx3 +template class IncludeMask >; +template class IncludeMask >; + +template class IncludeMask >; +template class IncludeMask >; + +template class IncludeMask >; + +template class IncludeMask >; +template class IncludeMask >; + + +} // postprocessData diff --git a/src/PostprocessData/operation/includeMask/includeMask.cpp b/src/PostprocessData/operation/includeMask/includeMask.cpp new file mode 100644 index 00000000..6ba84aa8 --- /dev/null +++ b/src/PostprocessData/operation/includeMask/includeMask.cpp @@ -0,0 +1,156 @@ +/*------------------------------- 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. + +-----------------------------------------------------------------------------*/ + + +#include "includeMask.hpp" +#include "dictionary.hpp" +#include "fieldsDataBase.hpp" + + +namespace pFlow::postprocessData +{ + +includeMask::includeMask +( + const dictionary& dict, + fieldsDataBase& fieldDB +) +: + database_(fieldDB) +{} + +includeMask::includeMask +( + const word &type, + const dictionary &opDict, + fieldsDataBase &fieldsDB +) +: + database_(fieldsDB) +{ +} + +uniquePtr includeMask::create +( + const dictionary& opDict, + fieldsDataBase& fieldsDB +) +{ + word mask = opDict.getValOrSet("includeMask", "all"); + word fieldType; + if( mask != "all") + { + auto& maskDict = opDict.subDict(mask+"Info"); + word maskField = maskDict.getVal("field"); + + if( !fieldsDB.getFieldType(maskField, fieldType) ) + { + fatalErrorInFunction<<"Error in retriving the type of field" + << maskField <<" from dictionary " + << maskDict.globalName() + << endl; + fatalExit; + return nullptr; + } + } + else + { + fieldType = getTypeName(); + } + + word method = angleBracketsNames2("IncludeMask", fieldType, mask); + + if( dictionaryvCtorSelector_.search(method) ) + { + auto objPtr = + dictionaryvCtorSelector_[method] + (opDict, fieldsDB); + return objPtr; + } + else + { + printKeys + ( + fatalError << "Ctor Selector "<< + method << " dose not exist. \n" + <<"Avaiable ones are: \n\n" + , + dictionaryvCtorSelector_ + ); + fatalExit; + return nullptr; + } + return nullptr; +} + +uniquePtr includeMask::create +( + const word &type, + const dictionary &opDict, + fieldsDataBase &fieldsDB +) +{ + word fieldType; + if( type != "all") + { + auto& maskDict = opDict.subDict(type+"Info"); + word maskField = maskDict.getVal("field"); + + if( !fieldsDB.getFieldType(maskField, fieldType) ) + { + fatalErrorInFunction<<"Error in retriving the type of field" + << maskField <<" from dictionary " + << maskDict.globalName() + << endl; + fatalExit; + return nullptr; + } + } + else + { + fieldType = getTypeName(); + } + + word method = angleBracketsNames2("IncludeMask", fieldType, type); + + if( wordvCtorSelector_.search(method) ) + { + auto objPtr = + wordvCtorSelector_[method] + (type, opDict, fieldsDB); + return objPtr; + } + else + { + printKeys + ( + fatalError << "Ctor Selector "<< + method << " dose not exist. \n" + <<"Avaiable ones are: \n\n" + , + wordvCtorSelector_ + ); + fatalExit; + return nullptr; + } + return nullptr; +} + +} \ No newline at end of file diff --git a/src/PostprocessData/operation/includeMask/includeMask.hpp b/src/PostprocessData/operation/includeMask/includeMask.hpp new file mode 100644 index 00000000..1f58a31a --- /dev/null +++ b/src/PostprocessData/operation/includeMask/includeMask.hpp @@ -0,0 +1,199 @@ +/*------------------------------- 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 includeMask +* @brief Base class for creating inclusion masks for data filtering +* + * includeMask is an abstract base class for creating masks that filter data + * from a fieldsDataBase. Derived classes implement specific filtering criteria + * through the getMask() method which returns a Mask object - a wrapper around + * a vector of booleans that indicates which elements to include/exclude. + * + * This class follows a factory pattern with create() methods that instantiate + * the appropriate derived mask type based on dictionary settings. + * + * Derived classes can implement various filtering strategies such as: + * - Filtering by field values + * - Filtering by spatial regions + * - Filtering by predefined criteria + * + * The Mask objects returned by getMask() can be used in postprocessing operations + * to include only the data points that match the specified criteria. + */ + +#ifndef __includeMask_hpp__ +#define __includeMask_hpp__ + +#include + +#include "virtualConstructor.hpp" + +namespace pFlow +{ + class dictionary; +} + +namespace pFlow::postprocessData +{ + +// forward declaration +class fieldsDataBase; + + +class includeMask +{ +public: + + /// @brief Wrapper around a boolean vector that represents elements to include/exclude + /// Provides a functional interface to access the underlying mask vector + /// where true indicates inclusion and false indicates exclusion. + class Mask + { + /// @brief Reference to the underlying boolean vector + const std::vector& mask_; + + public: + + /// @brief Constructor from a boolean vector + /// @param msk Boolean vector where true means include, false means exclude + Mask(const std::vector& msk) + : + mask_(msk) + {} + + /// @brief Copy constructor + Mask(const Mask&) = default; + + /// @brief Move constructor + Mask(Mask&&) = default; + + /// @brief Destructor + ~Mask()=default; + + /// @brief Get the size of the mask + auto size()const + { + return mask_.size(); + } + + /// @brief Check if element at index i should be included + /// @param i Index to check + bool operator()(uint32 i)const + { + return mask_[i]; + } + }; + +private: + + /// @brief Reference to the database containing fields to be filtered + fieldsDataBase& database_; + +public: + + TypeInfo("includeMask"); + + /// @brief Constructor + /// @param opDict Dictionary containing operation settings + /// @param feildsDB Database of fields + includeMask(const dictionary& opDict, fieldsDataBase& feildsDB); + + /// @brief Constructor with explicit type + /// @param type Type of mask to create + /// @param opDict Dictionary containing operation settings + /// @param feildsDB Database of fields + includeMask(const word& type, const dictionary& opDict, fieldsDataBase& feildsDB); + + /// @brief Virtual destructor + virtual ~includeMask() = default; + + /// @brief Virtual constructor pattern implementation using dictionary + create_vCtor + ( + includeMask, + dictionary, + ( + const dictionary& opDict, fieldsDataBase& feildsDB + ), + (opDict, feildsDB) + ); + + /// @brief Virtual constructor pattern implementation using type and dictionary + create_vCtor + ( + includeMask, + word, + ( + const word& type, + const dictionary& opDict, + fieldsDataBase& feildsDB + ), + (type, opDict, feildsDB) + ); + + /// @brief Get const access to the database + /// @return Const reference to the fields database + const fieldsDataBase& database()const + { + return database_; + } + + /// @brief Get non-const access to the database + /// @return Reference to the fields database + fieldsDataBase& database() + { + return database_; + } + + /// @brief Get the mask for filtering elements + /// @return Mask object indicating which elements to include + virtual + Mask getMask()= 0; + + /// @brief Factory method to create appropriate mask type from dictionary + /// @param opDict Dictionary with mask settings including type + /// @param feildsDB Database of fields to filter + /// @return Unique pointer to created mask instance + static + uniquePtr create( + const dictionary& opDict, + fieldsDataBase& feildsDB); + + /// @brief Factory method to create mask with explicit type + /// @param type Type of mask to create + /// @param opDict Dictionary with mask settings + /// @param feildsDB Database of fields to filter + /// @return Unique pointer to created mask instance + static + uniquePtr create( + const word& type, + const dictionary& opDict, + fieldsDataBase& feildsDB); + +}; + + + +} // pFlow::postprocessData + +#endif //__IncludeMask_hpp__ + + diff --git a/utilities/postprocessPhasicFlow/IncludeMask.hpp b/src/PostprocessData/operation/includeMask/maskOperations.hpp similarity index 72% rename from utilities/postprocessPhasicFlow/IncludeMask.hpp rename to src/PostprocessData/operation/includeMask/maskOperations.hpp index c56001de..054ea240 100644 --- a/utilities/postprocessPhasicFlow/IncludeMask.hpp +++ b/src/PostprocessData/operation/includeMask/maskOperations.hpp @@ -18,16 +18,15 @@ Licence: -----------------------------------------------------------------------------*/ -#ifndef __IncludeMask_hpp__ -#define __IncludeMask_hpp__ +#ifndef __maskOperation_hpp__ +#define __maskOperation_hpp__ +#include "types.hpp" +#include "dictionary.hpp" -#include "includeMask.hpp" - -namespace pFlow +namespace pFlow::postprocessData { - template struct greaterThanOp { @@ -177,87 +176,6 @@ public: } }; -template -class IncludeMask -: - public includeMask -{ -protected: - - Operator operator_; - - uniquePtr> fieldPtr_; - - hostViewType1D field_; -public: - - TypeInfoTemplate12("IncludeMask", T, Operator); - - IncludeMask( - const dictionary& dict, - const word& opType, - readFromTimeFolder& timeFolder) - : - includeMask(dict, opType, timeFolder), - operator_(dict), - fieldPtr_(timeFolder.readPointField_H(this->fieldName())), - field_(fieldPtr_().hostView()) - { - } - - add_vCtor( - includeMask, - IncludeMask, - dictionary); - - bool isIncluded(int32 n)const override - { - return operator_(field_[n]); - } - - uint32 size()const override - { - return field_.size(); - } - -}; - - -template -class IncludeMask> -: - public includeMask -{ -public: - TypeInfoTemplate12("IncludeMask", T, allOp); - - IncludeMask( - const dictionary& dict, - const word& opType, - readFromTimeFolder& timeFolder) - : - includeMask(dict, opType, timeFolder) - {} - - add_vCtor( - includeMask, - IncludeMask, - dictionary); - - bool isIncluded(int32 n)const override - { - return true; - } - - uint32 size()const override - { - return 0; - } -}; - - -} // pFlow - -#endif //__IncludeMask_hpp__ - +} // namespace pFlow::postprocessData +#endif //__maskOperation_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/operation/postprocessOperation/postprocessOperation.cpp b/src/PostprocessData/operation/postprocessOperation/postprocessOperation.cpp new file mode 100644 index 00000000..b123f0af --- /dev/null +++ b/src/PostprocessData/operation/postprocessOperation/postprocessOperation.cpp @@ -0,0 +1,159 @@ +/*------------------------------- 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. + +-----------------------------------------------------------------------------*/ + +#include "Time.hpp" +#include "postprocessOperation.hpp" +#include "regionPoints.hpp" +#include "fieldsDataBase.hpp" + + +namespace pFlow::postprocessData +{ + +postprocessOperation::postprocessOperation +( + const dictionary &opDict, + const regionPoints& regPoints, + fieldsDataBase &fieldsDB +) +: + postprocessOperation + ( + opDict, + opDict.getVal("field"), + opDict.getValOrSet("phi", "one"), + opDict.getValOrSet("includeMask", "all"), + regPoints, + fieldsDB + ) +{} + +postprocessOperation::postprocessOperation +( + const dictionary &opDict, + const word &fieldName, + const word &phiName, + const word& includeName, + const regionPoints ®Points, + fieldsDataBase &fieldsDB +) +: + operationDict_(opDict), + threshold_ + ( + opDict.getValOrSet("threshold", 1) + ), + divideByVolume_ + ( + opDict.getValOrSet("divideByVolume", Logical(false)) + ), + regionPoints_ + ( + regPoints + ), + database_ + ( + fieldsDB + ), + fieldName_ + ( + fieldName + ), + phiFieldName_ + ( + phiName + ), + includeMask_ + ( + includeMask::create(includeName, opDict, fieldsDB) + ) +{ + + if(!fieldsDB.getFieldType(fieldName_, fieldType_)) + { + fatalErrorInFunction; + fatalExit; + } +} +const Time& postprocessOperation::time() const +{ + return database_.time(); +} + +bool postprocessOperation::write(const fileSystem &parDir) const +{ + auto ti = time().TimeInfo(); + + if(!osPtr_) + { + fileSystem path = parDir+( + processedFieldName() + ".Start_" + ti.timeName()); + osPtr_ = makeUnique(path); + + regPoints().write(osPtr_()); + } + + const auto& field = processedField(); + + std::visit + ( + [&](auto&& arg)->bool + { + return writeField(osPtr_(), ti.t(), arg, threshold_); + }, + field + ); + + return true; +} + +uniquePtr postprocessOperation::create +( + const dictionary &opDict, + const regionPoints ®Points, + fieldsDataBase &fieldsDB +) +{ + word func = opDict.getVal("function"); + word method = angleBracketsNames("PostprocessOperation", func); + if( dictionaryvCtorSelector_.search(method) ) + { + REPORT(3)<<"Operation "<< Green_Text(opDict.name())<<" with function "<< Green_Text(func)< + +#include "virtualConstructor.hpp" +#include "Logical.hpp" +#include "dictionary.hpp" +#include "span.hpp" +#include "oFstream.hpp" +#include "regionField.hpp" +#include "includeMask.hpp" +#include "postprocessOperationFunctions.hpp" + +namespace pFlow +{ + class Time; +} + +namespace pFlow::postprocessData +{ + +/// - forward declaration +class fieldsDataBase; + + +class postprocessOperation +{ +public: + + using Mask = typename includeMask::Mask; + +private: + + /// Dictionary containing operation-specific parameters. + pFlow::dictionary operationDict_; + + /// This Threshold is used to exclude the regions which contain + /// fewer than this value. + uint32 threshold_; + + /// Logical flag to determine if the result is divided by volume. + Logical divideByVolume_; + + /// Reference to the region points used in the operation. + const regionPoints& regionPoints_; + + /// Reference to the fields database containing field data. + fieldsDataBase& database_; + + /// Name of the field to be processed. + word fieldName_; + + /// Type of the field to be processed. + word fieldType_; + + /// Name of the phi field to be processed. + word phiFieldName_; + + /// Pointer to the include mask used for masking operations. + uniquePtr includeMask_ = nullptr; + + mutable uniquePtr osPtr_ = nullptr; + +public: + + /// Type info + TypeInfo("postprocessOperation"); + + /// Constructor + /// @param opDict Dictionary containing operation-specific parameters. + /// @param regPoints Reference to the region points used in the operation. + /// @param fieldsDB Reference to the fields database containing field data. + postprocessOperation( + const dictionary& opDict, + const regionPoints& regPoints, + fieldsDataBase& fieldsDB ); + + postprocessOperation( + const dictionary& opDict, + const word& fieldName, + const word& phiName, + const word& includeName, + const regionPoints& regPoints, + fieldsDataBase& fieldsDB + ); + + /// destructor + virtual ~postprocessOperation()=default; + + /// Active the virtual constructor for creating derived classes. + create_vCtor( + postprocessOperation, + dictionary, + ( + const dictionary& opDict, + const regionPoints& regPoints, + fieldsDataBase& fieldsDB + ), + (opDict, regPoints, fieldsDB)); + + /// Access to regionPoints instance + const regionPoints& regPoints()const + { + return regionPoints_; + } + + /// Access to fields database instance + const fieldsDataBase& database()const + { + return database_; + } + + /// Access to fields database instance + fieldsDataBase& database() + { + return database_; + } + + /// Access to the time instance + const Time& time()const; + + /// Return the name of the processed field. + word processedFieldName()const + { + return operationDict_.name(); + } + + /// return the name of the field to be processed. + const word& fieldName()const + { + return fieldName_; + } + + /// return the type name of the field to be processed. + const word& fieldType()const + { + return fieldType_; + } + + /// return the name of the phi field to be processed. + const word& phiFieldName()const + { + return phiFieldName_; + } + + /// Access to the operation dictionary + const dictionary& operationDict()const + { + return operationDict_; + } + + /// return threshold value + /// which is used to exclude the regions which contain + /// particles fewer than this value. + const uint32 threshold()const + { + return threshold_; + } + + /// whether the result is divided by volume of the region + bool divideByVolume()const + { + return divideByVolume_(); + } + + /// return the include mask + Mask getMask() + { + return includeMask_().getMask(); + } + + /// return the processed field + virtual + const processedRegFieldType& processedField()const=0; + + /// execute the operation + /// @param weights Vector of weights for the operation. + /// @param volFactor a factor to be multiplied by the volume of the region + virtual bool execute( + const std::vector>& weights, + const regionField& volFactor) = 0; + + /// write the result to a file + /// @param parDir Parent directory for the output file. + virtual + bool write(const fileSystem &parDir)const; + + /// write the result to output stream (possibly a file) + /// @param os Output stream to write the result. + virtual + bool write(iOstream& os)const {return true;} + + /// Create the polymorphic object using the virtual constructor. + /// @param opDict Dictionary containing operation-specific parameters. + /// @param regPoints Reference to the region points used in the operation. + /// @param fieldsDB Reference to the fields database containing field data. + static + uniquePtr create( + const dictionary& opDict, + const regionPoints& regPoints, + fieldsDataBase& fieldsDB); + +}; + +} // namespace pFlow::postprocessData + +#endif //__postprocessOperation_hpp__ \ No newline at end of file diff --git a/src/PostprocessData/operation/postprocessOperation/postprocessOperationFunctions.hpp b/src/PostprocessData/operation/postprocessOperation/postprocessOperationFunctions.hpp new file mode 100644 index 00000000..5356cf84 --- /dev/null +++ b/src/PostprocessData/operation/postprocessOperation/postprocessOperationFunctions.hpp @@ -0,0 +1,100 @@ +/*------------------------------- 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 __postprocessOperationFunctions_hpp__ +#define __postprocessOperationFunctions_hpp__ + +#include + +#include "types.hpp" +#include "iOstream.hpp" +#include "regionField.hpp" + +namespace pFlow::postprocessData +{ + +/// Type alias for processed region field types. +/// Only regionField, regionField, and regionField are supported +/// in the postprocessOperation class. +using processedRegFieldType = std::variant +< + regionField, + regionField, + regionField +>; + + +template +inline +bool writeField +( + iOstream& os, + timeValue t, + const regionField field, + uint32 threshold, + const T& defValue=T{} +) +{ + const auto& regPoints = field.regPoints(); + const uint32 n = field.size(); + os<= threshold) + { + if constexpr(std::is_same_v) + { + os<) + { + os << field[i].x() << ' ' << field[i].y() << ' ' << field[i].z() << ' ' << field[i].w() << tab; + } + else + { + os<) + { + os<) + { + os << defValue.x() << ' ' << defValue.y() << ' ' << defValue.z() << ' ' << defValue.w() << tab; + } + else + { + os< +pFlow::postprocessData::PostprocessComponent::PostprocessComponent +( + const dictionary& dict, + fieldsDataBase& fieldsDB, + const baseTimeControl& defaultTimeControl +) +: + postprocessComponent(dict, fieldsDB, defaultTimeControl), + regionPointsPtr_ + ( + makeUnique(dict, fieldsDB) + ), + regionsProcessMethod_ + ( + regionPointsPtr_().size() + ), + volumeFactor_ + ( + "volumeFactor", + regionPointsPtr_(), + 1.0 + ), + operationDicts_(readDictList("operations", dict)) +{ + + for(auto& opDict:operationDicts_) + { + operatios_.push_back + ( + postprocessOperation::create + ( + opDict, + regionPointsPtr_(), + this->database() + ) + ); + } +} + + +template +bool pFlow::postprocessData::PostprocessComponent::execute +( + const timeInfo &ti, + bool forceUpdate +) +{ + if( !forceUpdate && !timeControl().eventTime(ti)) + { + executed_ = false; + return true; + } + + REPORT(1)<<"Executing postprocess component (" + <regPoints(); + + if(!regPoints.update()) + { + fatalErrorInFunction + << "regionPoints update failed for " + << operationDicts_.globalName() + << endl; + return false; + } + + auto centers = regPoints.centers(); + const uint32 n = centers.size(); + auto points = this->database().updatePoints(); + + for(uint32 i=0; i> weights(n); + + for(uint32 i=0; iexecute(weights, volumeFactor_) ) + { + fatalErrorInFunction + <<"error occured in executing operatoin defined in dict " + << op->operationDict() + < +inline +bool pFlow::postprocessData::PostprocessComponent::write +( + const fileSystem &parDir +) const +{ + if(!executed_) return true; + + if(regionPointsPtr_().writeToSameTimeFile()) + { + for(auto& operation:operatios_) + { + if(!operation->write(parDir)) + { + fatalErrorInFunction + <<"Error occurred in writing operation defined in dict " + << operation->operationDict() + < + +#include "ListPtr.hpp" +#include "List.hpp" +#include "postprocessComponent.hpp" +#include "postprocessOperation.hpp" +#include "dictionaryList.hpp" +#include "fieldsDataBase.hpp" +#include "regionPoints.hpp" +#include "regionField.hpp" + +namespace pFlow::postprocessData +{ + +template +class PostprocessComponent +: + public postprocessComponent +{ +private: + + + ListPtr operatios_; + + /// Region type for selecting a subset of particles for processing + uniquePtr regionPointsPtr_; + + /// Method for processing the selected particles data + std::vector regionsProcessMethod_; + + regionField volumeFactor_; + + bool executed_{false}; + + dictionaryList operationDicts_; + +protected: + + std::vector& regionProecessMethod() + { + return regionsProcessMethod_; + } + + regionField& volumeFactor() + { + return volumeFactor_; + } + + const regionField& volumeFactor()const + { + return volumeFactor_; + } + +public: + + // type info + TypeInfoTemplate12( + "PostprocessComponent", + RegionType, + ProcessMethodType); + + PostprocessComponent( + const dictionary& dict, + fieldsDataBase& fieldsDB, + const baseTimeControl& defaultTimeControl); + + ~PostprocessComponent() override = default; + + // add the virtual constructor + add_vCtor( + postprocessComponent, + PostprocessComponent, + dictionary + ); + + word name()const override + { + return operationDicts_.parrent().name(); + } + + regionPoints& regPoints() override + { + return static_cast(regionPointsPtr_()); + } + + const regionPoints& regPoints()const override + { + return static_cast(regionPointsPtr_()); + } + + bool execute(const timeInfo& ti, bool forceUpdate = false) override; + + bool executed()const override + { + return executed_; + } + + bool write(const fileSystem& parDir)const override; + +}; + + + +} + +#include "PostprocessComponent.cpp" + +#endif \ No newline at end of file diff --git a/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentArithmetic.hpp b/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentArithmetic.hpp new file mode 100644 index 00000000..aa335dd6 --- /dev/null +++ b/src/PostprocessData/postprocessComponent/PostprocessComponent/PostprocessComponentArithmetic.hpp @@ -0,0 +1,75 @@ +/*------------------------------- 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 __PostprocessComponentArithmetic_hpp__ +#define __PostprocessComponentArithmetic_hpp__ + +#include "PostprocessComponent.hpp" +#include "arithmetic.hpp" + +namespace pFlow::postprocessData +{ + +template +class PostprocessComponentArithmetic +: + public PostprocessComponent +{ +public: + + /// type info + TypeInfoTemplate12("PostprocessComponent", RegionType, arithmetic); + + PostprocessComponentArithmetic + ( + const dictionary& dict, + fieldsDataBase& fieldsDB, + const baseTimeControl& defaultTimeControl + ) + : + PostprocessComponent(dict, fieldsDB, defaultTimeControl) + { + /// initializes the arithmetic distribution for all elements of region + //const uint32 n = this->regPoints().size(); + auto d = this->regPoints().eqDiameters(); + auto c = this->regPoints().centers(); + auto& regs = this->regionProecessMethod(); + auto& volFactor = this->volumeFactor(); + const uint32 n = d.size(); + for(uint32 i=0; i +class PostprocessComponentGaussian +: + public PostprocessComponent +{ +public: + + /// type info + TypeInfoTemplate12("PostprocessComponent", RegionType, GaussianDistribution); + + PostprocessComponentGaussian + ( + const dictionary& dict, + fieldsDataBase& fieldsDB, + const baseTimeControl& defaultTimeControl + ) + : + PostprocessComponent(dict, fieldsDB, defaultTimeControl) + { + /// initializes the Gaussian distribution for all elements of region + //const uint32 n = this->regPoints().size(); + auto d = this->regPoints().eqDiameters(); + auto c = this->regPoints().centers(); + auto& regs = this->regionProecessMethod(); + auto& volFactor = this->volumeFactor(); + + const uint32 n = d.size(); + for(uint32 i=0; i +class PostprocessComponentUniform +: + public PostprocessComponent +{ +public: + + /// type info + TypeInfoTemplate12("PostprocessComponent", RegionType, uniformDistribution); + + PostprocessComponentUniform + ( + const dictionary& dict, + fieldsDataBase& fieldsDB, + const baseTimeControl& defaultTimeControl + ) + : + PostprocessComponent(dict, fieldsDB, defaultTimeControl) + { + /// initializes the Uniform distribution for all elements of region + //const uint32 n = this->regPoints().size(); + auto d = this->regPoints().eqDiameters(); + auto c = this->regPoints().centers(); + auto& regs = this->regionProecessMethod(); + auto& volFactor = this->volumeFactor(); + const uint32 n = d.size(); + for(uint32 i=0; i -void -insertSetElementH( - ViewType1D& view, - hostViewType1D