# cgnstofoam **Repository Path**: yiestudio/cgnstofoam ## Basic Information - **Project Name**: cgnstofoam - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-08 - **Last Updated**: 2026-08-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # cgnsToFoam — CGNS to OpenFOAM Mesh Converter An OpenFOAM utility that reads CGNS (CFD General Notation System) unstructured mesh files and converts them to OpenFOAM's native `polyMesh` format. ## Features ### Element Types - **Standard cells**: TETRA_4, HEXA_8, PENTA_6 (prism), PYRA_5 (pyramid) - **Structured zones**: Multi-block structured grids (converted to hex cells) - **Mixed sections**: CGNS `MIXED` element type (heterogeneous topologies) - **Polyhedral cells**: Full NGON_n / NFACE_n support for arbitrary polyhedra - **High-order elements**: Automatically reduced to linear (e.g. TETRA_10 → TETRA_4, HEXA_27 → HEXA_8) ### Boundary Conditions Maps CGNS BC types to OpenFOAM patch types: - `BCWall*` → `wall` - `BCSymmetryPlane` → `symmetryPlane` - `BCInflow` / `BCOutflow` / `BCFarfield` → `patch` - `BCDegenerate*` → `empty` ### Other - **Multi-zone**: Merges multiple unstructured zones with automatic point deduplication at zone interfaces - **Coordinate scaling**: Optional `-scale` factor (e.g. mm → m) - **Auto-detection**: Automatically selects the structured, element-based, or NGON/NFACE code path per zone based on zone type and element sections ## Compatibility ### Tested Configurations | OpenFOAM | CGNS Library | Status | |----------|-------------|--------| | ESI v2512 | CGNS 4.5.1 | Compiled and tested | | ESI v2406+ | CGNS 4.x | Expected to work | | ESI v2012+ | CGNS 3.4+ | Expected to work (3.4+ required for NGON/NFACE offsets API) | The source uses the ESI OpenFOAM v2512 API conventions: - `args.getOrDefault()` (not the deprecated `optionLookupOrDefault`) - `forAllConstIters` / `forAllIters` (range-based iteration macros) - `Hash` with `unsigned operator()(const T&, unsigned seed=0) const` - `mesh.boundaryMesh()` for patch construction (no `polyBoundaryMesh::null()`) If compiling against an older ESI version (pre-v1912) or the Foundation fork, minor API adjustments may be needed — see the Troubleshooting section. ## Prerequisites 1. **OpenFOAM** (ESI v2512 recommended) — sourced in your shell 2. **CGNS library** (libcgns) — version 4.x recommended for full NGON/NFACE polyhedral support; minimum 3.4 for the offsets-based element read API ### Installing CGNS **Ubuntu/Debian:** ```bash sudo apt-get install libcgns-dev export CGNS_DIR=/usr ``` **From source (recommended for NGON/NFACE and HDF5 support):** ```bash git clone https://github.com/CGNS/CGNS.git cd CGNS git checkout v4.5.1 # or latest release tag mkdir build && cd build cmake -DCMAKE_INSTALL_PREFIX=$HOME/cgns \ -DCGNS_ENABLE_HDF5=ON \ -DCGNS_BUILD_SHARED=ON \ -DHDF5_ROOT=/path/to/your/hdf5 \ -DCMAKE_BUILD_TYPE=Release .. make -j$(nproc) && make install export CGNS_DIR=$HOME/cgns ``` If HDF5 is not found automatically, pass `-DHDF5_ROOT=/path/to/hdf5`. On systems with parallel HDF5 (common on clusters), you may also need `-DHDF5_NEED_MPI=ON`. **macOS (Homebrew):** ```bash brew install cgns export CGNS_DIR=$(brew --prefix cgns) ``` ## Building ```bash # 1. Source your OpenFOAM environment source /opt/openfoam/etc/bashrc # adjust to your installation path # 2. Set CGNS installation path export CGNS_DIR=$HOME/cgns # or /usr if installed via package manager # 3. Build cd cgnsToFoam wmake ``` The binary is placed in `$FOAM_USER_APPBIN/cgnsToFoam`. **Runtime library path:** If you built CGNS as a shared library from source, ensure the loader can find it: ```bash export LD_LIBRARY_PATH=$CGNS_DIR/lib:$LD_LIBRARY_PATH ``` You can add this to your `~/.bashrc` or to the OpenFOAM `prefs.sh` customisation file so it persists across sessions. ## Usage ```bash # Basic usage (run from an OpenFOAM case directory) cgnsToFoam mesh.cgns # With coordinate scaling (e.g. mm to m) cgnsToFoam mesh.cgns -scale 0.001 # The mesh is written to constant/polyMesh/ # Verify with: checkMesh ``` ### Typical Workflow ```bash # 1. Create a case directory mkdir -p myCase/constant myCase/system cd myCase # 2. Create minimal system files cat > system/controlDict << 'EOF' FoamFile { version 2.0; format ascii; class dictionary; object controlDict; } application simpleFoam; startFrom latestTime; stopAt endTime; endTime 1000; deltaT 1; writeControl timeStep; writeInterval 1000; EOF cat > system/fvSchemes << 'EOF' FoamFile { version 2.0; format ascii; class dictionary; object fvSchemes; } ddtSchemes { default steadyState; } gradSchemes { default Gauss linear; } divSchemes { default none; } laplacianSchemes { default Gauss linear corrected; } interpolationSchemes { default linear; } snGradSchemes { default corrected; } EOF cat > system/fvSolution << 'EOF' FoamFile { version 2.0; format ascii; class dictionary; object fvSolution; } solvers {} EOF # 3. Convert the CGNS mesh cgnsToFoam /path/to/mesh.cgns # 4. Check mesh quality checkMesh # 5. View in ParaView paraFoam ``` ## How It Works The converter auto-detects the zone type and element representation used in each CGNS zone and selects the appropriate code path. ### Path S: Structured Zones Used for zones with `ZoneType_t = Structured`. These are multi-block structured grids where the topology is implicit in the IJK indexing. 1. Read the IJK zone dimensions (NI × NJ × NK vertices) 2. Read coordinate arrays (stored in IJK order) 3. Generate (NI-1)×(NJ-1)×(NK-1) hexahedral cells from the implicit connectivity — cell (ci,cj,ck) uses the 8 surrounding vertices 4. Read structured BCs: each BC specifies a `PointRange` of two IJK triplets defining a face on a constant-index plane (i=const, j=const, or k=const). Generate the quad boundary faces on that plane and register them with the patch name. The generated hex cells feed into the same element-based face decomposition used by Path B, so multi-zone meshes with mixed structured and unstructured zones are handled correctly. ### Path A: NGON_n / NFACE_n (Polyhedral) Used when a zone contains both `NGON_n` and `NFACE_n` element sections. This is the representation used by polyhedral meshes (Fluent Poly, STAR-CCM+, etc.) and is increasingly common in modern CGNS files. **CGNS data model:** - `NGON_n` section: every face in the mesh (internal + boundary), each defined as a variable-length polygon via node connectivity. Read with `cg_poly_elements_read`, which returns a packed connectivity array and an offsets array. - `NFACE_n` section: every cell, defined as a list of signed face references. The sign encodes face orientation relative to the cell: - **Positive index**: face normal points outward from the cell - **Negative index**: face normal points inward into the cell **Conversion algorithm:** 1. Read all NGON_n face-to-node connectivity → `ngonFaceNodes[]` 2. Read all NFACE_n cell-to-face connectivity 3. Walk cells: for each face a cell references, assign it as owner (first claim) or neighbour (second claim). Enforce `owner < neighbour`. 4. Use the CGNS sign convention to orient faces correctly: the face normal must point from owner to neighbour (OpenFOAM convention). If the owner referenced the face with a negative sign, the stored node order is reversed. 5. Faces with no neighbour are boundary faces. Map them to patches via the CGNS BC element indices. This path feeds directly into OpenFOAM's face/owner/neighbour arrays without the intermediate cell decomposition step — making it both more natural for polyhedra and more efficient for large meshes. ### Path B: Standard Elements Used when a zone contains traditional typed element sections (TETRA_4, HEXA_8, PENTA_6, PYRA_5, MIXED) without NGON_n/NFACE_n. 1. Read cell-to-node connectivity from each volume element section 2. Decompose each cell into faces using CGNS-standard node ordering 3. Hash each face by its sorted node set. Faces appearing twice → internal; once → boundary. 4. Match boundary faces to CGNS BC definitions via element index lookup. ### Shared Post-Processing Both paths feed into the same final assembly: - Merge duplicate points across zones (tolerance-based) - Sort internal faces by (owner, neighbour) — required by OpenFOAM - Group boundary faces by patch - Create `polyMesh`, add patches, and write ## CGNS File Requirements The converter expects: - **Structured zones**: IJK-ordered coordinate arrays with BCs defined via `PointRange` (IJK triplets) - **Unstructured zones** (`ZoneType_t = Unstructured`): element sections for volume and boundary elements, or NGON_n/NFACE_n polyhedral sections - **Boundary conditions** defined as `BC_t` nodes using `PointRange`, `ElementRange`, `PointList`, or `ElementList` Mixed meshes (some structured zones, some unstructured) are supported — zones are processed independently and merged via point deduplication. ## Designed for Meshes From - **Pointwise**: Exports NGON_n/NFACE_n for polyhedral meshes - **STAR-CCM+**: Polyhedral export uses NGON_n/NFACE_n - **Fluent**: Both standard element and poly exports - **ICEM CFD**: Standard element sections - **Gmsh**: CGNS export (standard elements) - **CGNS utilities** (`cgnsconvert`, `adf2hdf`, etc.) ## Limitations - CGNS solution data (flow fields) is not converted — only the mesh - Periodic/connectivity interfaces between zones are merged by point matching (tolerance-based), not by CGNS `GridConnectivity` - One `NGON_n` and one `NFACE_n` section per zone is expected; multiple `NGON_n` sections in the same zone are not handled - Foundation OpenFOAM (openfoam.org) may require minor API changes (see below) ## Troubleshooting ### Build Errors | Error | Cause | Fix | |-------|-------|-----| | `cgnslib.h: No such file` | CGNS headers not found | Set `CGNS_DIR` to the CGNS installation prefix | | `-lcgns` not found | CGNS library not in linker path | Check `$CGNS_DIR/lib` has `libcgns.so` or `libcgns.a` | | `'getOrDefault' not found` | OpenFOAM version older than v1912 | Replace with `lookupOrDefault` | | `'forAllConstIters' undeclared` | OpenFOAM version older than v1806 | Replace with `forAllConstIter(TypeDef, container, iter)` using a typedef to avoid template commas in the macro | | `Hash` errors | Foundation OpenFOAM has a different `Hash` API | Adjust the `operator()` signature to match your version's `Hash.H` | | `'addPatches' not found` | Foundation OpenFOAM API difference | Check `polyMesh.H` for the correct method name in your version | ### Runtime Errors | Error | Cause | Fix | |-------|-------|-----| | `libcgns.so: cannot open shared object` | Runtime linker can't find CGNS library | `export LD_LIBRARY_PATH=$CGNS_DIR/lib:$LD_LIBRARY_PATH` | | Duplicate points warning | Normal for multi-zone meshes | Points are merged automatically; this is informational | | Faces in `defaultPatch` | CGNS BCs don't cover all boundary faces | Check BC definitions in your CGNS file with `cgnscheck` | | `checkMesh` errors | Poor element quality in source mesh | Inspect the original mesh in the generating tool | | `NFACE_n references face element X not in NGON_n` | Inconsistent element numbering | Validate CGNS file with `cgnscheck` or re-export | | `Face element X referenced by >2 cells` | Non-manifold mesh topology | Fix the source mesh | ### Porting to Foundation OpenFOAM The code targets ESI OpenFOAM (openfoam.com). For the Foundation fork (openfoam.org), the main changes needed are: - `args.getOrDefault(...)` → `args.lookupOrDefault(...)` - `forAllConstIters(container, iter)` → `forAllConstIter(ContainerType, container, iter)` (3-argument macro; use a typedef if the container type contains template commas) - `iter.val()` → `iter()` for HashTable iterators - `forAllIters(container, iter)` → `forAllIter(ContainerType, container, iter)` - The `Hash` specialisation signature may differ — check `$FOAM_SRC/OpenFOAM/primitives/hashes/Hash/Hash.H` - `polyPatch::New(...)` argument order may differ ## Extending To add **solution field conversion**, read `FlowSolution_t` nodes after mesh creation and write corresponding `volScalarField` / `volVectorField` files. The CGNS mid-level API provides `cg_nsols`, `cg_sol_info`, and `cg_field_read` for this purpose. Match the CGNS solution location (`Vertex` vs `CellCenter`) to the appropriate OpenFOAM field registration.