CFD Coupling
A one-dimensional model works in bulk quantities. Damage does not: it concentrates
wherever the local flow field departs from the bulk — bends, welds, restrictions,
headers, tube bundles. Screening models bridge that gap with generic textbook
multipliers.
This skill closes the gap properly. It takes whatever is known about a component
(P&ID, STID tag register, datasheets, plant data), takes the fluid from a NeqSim
flash, builds and runs an OpenFOAM case on the real geometry, and converts the
solved field back into the factor the one-dimensional model was guessing at. When
a CFD study already exists it qualifies that study instead of running a new one.
Every layer works on its own. NeqSim and OpenFOAM are both optional: without
NeqSim the fluid state is stated directly, and without OpenFOAM the case is still
written and can be transferred and run elsewhere.
When to Use
- A screening model needs a local enhancement factor and a generic multiplier is
currently being assumed.
- Pressure drop, velocity or wall shear is needed on real geometry rather than on
an equivalent-length correlation.
- Flow maldistribution across a bundle, manifold or header matters to the answer.
- Two phases share the line and the interface matters - stratified, slug or annular
flow, a free surface, or liquid accumulating in a low point.
- A CFD report, vendor flow analysis or CFD/FEM deliverable is attached to an
equipment tag and must be qualified before its numbers are used.
- A new CFD run must be specified and needs fluid properties, turbulence inlet
values and near-wall mesh sizing.
- A tonal noise or vibration observation needs a fail-closed readiness decision
before transient compressible CFD, acoustics, or structural coupling is scoped.
When Not to Use
- As a substitute for a qualified CFD engineer on a design decision. This is a
screening and coupling toolkit, not a verification-and-validation review.
- To extract a number from a CFD study that fails the quality gate.
- For droplet break-up statistics, separation efficiency or a dense dispersed
phase. The multiphase screening will say
lagrangian or euler_euler; those
cases are recommended with a reason but not generated here.
- For a temperature field. The generated cases solve momentum only, with the
fluid properties frozen at the inlet flash. A stagnant or dead-leg region, a
buoyancy-driven or thermally stratified region, or any wall-temperature
question needs a buoyant conjugate solver (
buoyantSimpleFoam,
buoyantPimpleFoam, chtMultiRegionFoam) that this skill does not write.
Use fem-coupling for the wall and near-wall temperature, and hand-build the
buoyant case if the fluid-side field itself is the deliverable.
- To diagnose a tonal aeroacoustic source with the generated steady RANS or
incompressible VOF cases. Call
assess_aeroacoustic_readiness first. A ready
case still requires a separately configured transient compressible LES/DES,
spectral pressure probes, acoustic propagation, and structural modal analysis
when vibration is in scope.
Inputs
| Stage |
Input |
Meaning |
build_design_basis |
tag, component_kind, sources |
Equipment or line identifier, the component class from the P&ID, and one entry per source with source, reference and values |
fluid_state_from_neqsim |
flashed NeqSim system, phase |
Density, viscosity, speed of sound and flow of the chosen phase |
derive_boundary_conditions |
FluidState, hydraulic_diameter_m, velocity or volumetric flow |
Optional turbulence_intensity, turbulence_length_scale_m, flow_area_m2 |
multiphase_state_from_neqsim |
flashed NeqSim system, optional continuous_phase / dispersed_phase |
Both phases plus the interfacial tension between them |
derive_multiphase_conditions |
MultiphaseState, hydraulic_diameter_m, optional flow_regime |
Superficial and mixture quantities, and the multiphase model screening |
MeshSpec |
kind (pipe, channel, external), dimensions, cell counts |
Optional first_cell_height_m to drive near-wall grading from a y+ target |
OpenFoamCase |
boundary conditions, mesh, flavour, wall_treatment |
flavour is org (OpenFOAM v11+, foamRun) or legacy (simpleFoam) |
assess_quality |
turbulence_model, wall_treatment, y_plus, mesh_levels, gci_percent |
Applies to a generated case or an existing report |
assess_aeroacoustic_readiness |
Verified topology, internal geometry, synchronized spectra, event operating state, acoustic boundaries, and optional structural/moving-part data |
Fails closed before tonal-source CFD or FSI is attempted |
evaluate_local_enhancement |
bulk and local peak velocity, and wall shear when available |
Bulk values come from the one-dimensional model |
Outputs
| Output |
Contents |
CfdDesignBasis |
Accepted values, per-field source and confidence, conflicts, missing fields, ready_for_meshing |
CfdBoundaryConditions |
Velocity, Reynolds, Mach, flow regime, compressibility class, k, epsilon, omega, recommended turbulence model and solver, warnings |
MultiphaseBoundaryConditions |
Superficial velocities, mixture velocity/density/viscosity, Reynolds, Weber, Froude, maximum stable droplet, Stokes number, recommended multiphase model with its rationale |
OpenFoamCase.write |
A complete case tree: system/, constant/, 0/, with function objects for wall shear, y+, patch fluxes and pressures |
VofOpenFoamCase.write |
A transient two-phase tree: alpha.<phase>, p_rgh, constant/g, per-phase properties, interfacial tension, setFieldsDict, Courant-limited control |
OpenFoamCase.mesh_warnings |
Near-wall grading that would over-stretch the mesh, with the cell count needed to avoid it |
RunOutcome |
completed, failed or not_executed, per-command output, and the commands needed to run the case elsewhere |
OpenFoamResults |
Continuity error, pressure drop, peak and mean wall shear, y+ min/mean/max, outlet dispersed fraction, peak-to-mean shear enhancement |
CfdQualityResult |
usable, usable_with_caution or not_usable with explicit findings |
AeroacousticReadinessResult |
not_ready, ready_for_transient_cfd, or ready_for_coupled_study, with missing inputs and the required solver sequence |
CfdEnhancementResult |
Velocity, shear and mass-transfer enhancement factors with their source |
Engineering Method
Design basis by precedence. Sources are ranked
measurement > mechanical_datasheet > process_datasheet > vendor > stid > plant_data > pid > estimate > assumption. A lower-ranked source never overwrites
a higher-ranked one; if it disagrees by more than 2 % it raises a conflict. The
component class determines which geometry fields are required, so an
under-specified case is reported rather than meshed.
Fluid to boundary condition. Density and viscosity come from the NeqSim phase
after initProperties(), because transport properties are otherwise zero.
Kinematic viscosity $\nu = \mu / \rho$ is what an incompressible solver consumes.
Inlet turbulence uses the fully developed correlations
$$I = 0.16,\mathrm{Re}^{-1/8}, \qquad \ell = 0.07,D_h$$
$$k = \tfrac{3}{2}(U I)^2, \qquad \varepsilon = C_\mu^{3/4}\frac{k^{3/2}}{\ell},
\qquad \omega = \frac{\varepsilon}{C_\mu k}$$
Mach number $U/c$ above 0.3 switches the recommended solver from
incompressibleFluid to compressibleFluid. Reynolds below 4000 disables the
turbulence model and says so.
Mesh. The O-grid round duct places one core block inside four ring blocks with
arc edges on the outer circle, which is what keeps cell skewness low near the
wall. Radial grading is solved from the requested first-cell height: the per-cell
geometric ratio $r$ satisfies $h_1(r^{n}-1)/(r-1) = t$, and simpleGrading takes
$r^{,n-1}$. That is how a y⁺ target derived from the NeqSim fluid reaches the
mesh. mesh_warnings() reports when that ratio exceeds 1.3, because the fix for a
too-thin first cell is more cells, not a stretched mesh. Any externally generated
mesh (Gmsh, Fluent, I-deas, CGNS) can be imported instead, so arbitrary geometry
is supported.
Numerics. Second-order linearUpwind on momentum, because first-order upwind
smears exactly the local peaks the coupling is trying to measure. checkMesh runs
before the solver. Function objects record wall shear stress, y⁺, patch fluxes and
patch-average pressures every write, which is what makes the result auditable.
Reading results back. Incompressible OpenFOAM reports kinematic pressure and
kinematic wall shear in m²/s²; both are multiplied by density to obtain Pa. Peak
and area-average wall shear on the wall patch give the peak-to-mean enhancement
directly. Mass-transfer enhancement follows the friction velocity
$u^{*} = \sqrt{\tau/\rho}$:
$$\text{mass transfer enhancement} = \sqrt{\text{shear enhancement}}$$
Quality gate. Three things decide whether a local CFD value means anything.
| Check |
Requirement |
| Wall treatment |
Wall functions need 30 ≤ y⁺ ≤ 300; a resolved low-Reynolds treatment needs y⁺ of order 1 |
| Mesh independence |
At least three mesh levels, or a grid-convergence index below about 5 % |
| Turbulence model |
RANS under-predicts local peaks in separated or unsteady flow; scale-resolving models (LES, DES, SAS) capture them |
Tonal aeroacoustic readiness. Overall dBA and a steady mean-flow field do not
identify a tonal source. Before meshing a diagnostic case, call
assess_aeroacoustic_readiness. It requires the as-built flow path and candidate
component to be verified, the actual internal geometry, synchronized narrow-band
pressure/acoustic/vibration spectra, the event operating state, and acoustic
lengths or termination impedances. Structural supports, clamps, damping, and
moving-part properties become mandatory when vibration or valve motion is in
scope. Missing evidence returns not_ready, never estimated incident geometry.
The minimum ready-case sequence is steady RANS initialization, transient
compressible LES/DES with spectral probes, acoustic propagation, and structural
modal analysis when required. The method is a readiness gate only; this skill
does not yet generate that transient compressible aeroacoustic solver chain.
Multiphase. One flash gives both phases and the interfacial tension, so the
superficial velocities follow from the phase volumetric flows and the mixture
quantities from the no-slip volume-fraction average. Three dimensionless groups
then decide the model:
$$\mathrm{We} = \frac{\rho_c U_m^2 D}{\sigma}, \qquad
\mathrm{Fr} = \frac{U_m}{\sqrt{gD}}, \qquad
\mathrm{St} = \frac{\rho_d d^2 U_m}{18 \mu_c D}$$
The maximum stable droplet follows Hinze turbulent break-up,
$d_{\max} = 0.725 (\sigma/\rho_c)^{3/5} \varepsilon^{-2/5}$, with the duct
dissipation rate $\varepsilon = f U_m^3 / 2D$. The screening then reports:
| Verdict |
Meaning |
Generated |
vof |
The interface is a large-scale, resolvable feature - stratified, slug, annular, free surface |
Yes, VofOpenFoamCase |
lagrangian |
Dilute dispersed phase that largely follows the carrier - mist, fine droplets |
Carrier solve only; the parcel cloud must be added |
euler_euler |
Dense dispersed phase with no resolvable interface |
No; specify with a CFD engineer |
VofOpenFoamCase refuses to build a case the screening did not recommend unless
allow_unrecommended_model=True is passed, so the wrong model is a deliberate,
recorded decision rather than an accident. The VOF case is transient by necessity
(an interface has no steady state), Courant-limited on both the flow and the phase
fraction, and uses a compressive vanLeer scheme on alpha so the interface stays
sharp. p_rgh carries the hydrostatic head separately, which is what makes gravity
driven separation behave.
Python Usage Pattern
Single-phase
from cfd_coupling import (
CfdCouplingModel, MeshSpec, OpenFoamCase, build_design_basis,
derive_boundary_conditions, fluid_state_from_neqsim, read_case_results,
)
# 1. Everything known about the component, from wherever it came from.
basis = build_design_basis(
tag="20-P-001",
component_kind="pipe",
sources=[
{"source": "pid", "reference": "P&ID 20-PID-001 rev C",
"values": {"nominal_size_inch": 12.0}},
{"source": "stid", "reference": "STID line 20-P-001",
"values": {"inside_diameter_m": 0.3048, "length_m": 6.0}},
{"source": "process_datasheet", "reference": "20-DS-014 rev 2",
"values": {"temperature_c": 45.0, "pressure_bara": 65.0,
"mass_flow_kg_per_h": 120_000.0}},
],
)
assert basis.ready_for_meshing, (basis.missing_fields, basis.conflicts)
# 2. Fluid from NeqSim, at the condition on the datasheet.
from neqsim.thermo import TPflash, fluid
gas = fluid("srk")
gas.addComponent("methane", 0.90)
gas.addComponent("ethane", 0.10)
gas.setMixingRule("classic")
gas.setTemperature(basis.value("temperature_c"), "C")
gas.setPressure(basis.value("pressure_bara"), "bara")
gas.setTotalFlowRate(basis.value("mass_flow_kg_per_h"), "kg/hr")
TPflash(gas)
state = fluid_state_from_neqsim(gas, phase="gas")
# 3. Boundary conditions, then a near-wall cell sized for the wall treatment.
boundary = derive_boundary_conditions(
state, hydraulic_diameter_m=basis.value("inside_diameter_m")
)
model = CfdCouplingModel()
plan = model.plan_wall_resolution(
density=state.density_kg_per_m3, viscosity=state.viscosity_pa_s,
velocity=boundary.velocity_m_per_s,
hydraulic_diameter=boundary.hydraulic_diameter_m, target_y_plus=50.0,
)
# 4. Write, run, read back.
case = OpenFoamCase(
boundary=boundary,
mesh=MeshSpec(kind="pipe", diameter_m=basis.value("inside_diameter_m"),
length_m=basis.value("length_m"),
first_cell_height_m=plan.first_cell_height_m),
name=basis.tag,
)
case.write("cases/20-P-001")
outcome = case.run("cases/20-P-001") # "not_executed" without OpenFOAM
results = read_case_results("cases/20-P-001",
density_kg_per_m3=state.density_kg_per_m3)
# 5. Gate before using any number, then convert to an engineering factor.
gate = model.assess_quality(
turbulence_model=boundary.recommended_turbulence_model,
wall_treatment="wall_function", y_plus=results.y_plus_mean, mesh_levels=1,
)
if gate.verdict != "not_usable" and results.wall_shear_enhancement:
factor = model.evaluate_local_enhancement(
location="20-P-001 wall", bulk_velocity=boundary.velocity_m_per_s,
local_peak_velocity=boundary.velocity_m_per_s,
bulk_wall_shear=results.mean_wall_shear_pa,
local_peak_wall_shear=results.peak_wall_shear_pa,
)
Multiphase
from cfd_coupling import (
MeshSpec, VofOpenFoamCase, derive_multiphase_conditions,
multiphase_state_from_neqsim, read_case_results,
)
TPflash(wellstream) # a flash that produces gas and liquid
state = multiphase_state_from_neqsim(wellstream) # both phases plus sigma
conditions = derive_multiphase_conditions(
state, hydraulic_diameter_m=0.2032, flow_regime="slug",
)
print(conditions.recommended_model, conditions.model_rationale)
if conditions.recommended_model == "vof":
case = VofOpenFoamCase(
boundary=conditions,
mesh=MeshSpec(kind="pipe", diameter_m=0.2032, length_m=4.0, axial_cells=120),
end_time=8.0,
gravity=(0.0, -9.80665, 0.0), # perpendicular to a horizontal pipe axis
)
case.write("cases/two-phase-line")
case.run("cases/two-phase-line")
results = read_case_results("cases/two-phase-line")
# results.outlet_dispersed_fraction vs state.dispersed_volume_fraction
Near-wall resolution: let the library solve it, and verify what you got
MeshSpec.first_cell_height_m exists so a y+ target from the fluid state reaches the
mesh. The grading is solved by _wall_grading, which brackets the root properly and
is reported through mesh_warnings(). Use it. Do not hand-roll the grading maths.
The arithmetic is easy to get wrong in a way that produces a valid-looking mesh.
Solving for a fixed last cell is ill-posed: if the cell count cannot span the
thickness there is no root, the bisection returns an endpoint, and the endpoint is
an expansion ratio of 1 — a perfectly clean uniform mesh. In one case that put the
first cell at y+ 27 instead of the requested 0.15, so a 10 um concentration boundary
layer sat inside a single 219 um cell and the wall gradient was meaningless. Posed
from the wall outwards the sum is monotonic in the expansion ratio and the bisection
is well conditioned.
Rules:
- Call
mesh_warnings() and print it, every case. Treat "no grading was applied
and the y+ target will not be met" as a stop, not a note.
- A mesh helper that cannot satisfy its target must raise, not silently degrade.
Guard both ends: expansion ratio above about 1.25, and a wall cell too coarse for
the layer being resolved.
- Verify the achieved resolution from the solution, not from the request. Write
the
yPlus field and read it back. A requested y+ and an achieved y+ are different
numbers, and only one of them is evidence.
- Where the answer depends on the near-wall layer, validate against a correlation on
the same mesh before quoting a local value — the developed run upstream of the
feature should reproduce the analytical wall shear, and for a scalar the textbook
Sherwood number. A validation that fails by two orders of magnitude is a good
validation; one that is never run lets a plausible wrong number through.
A point peak at a sharp corner is not a converged quantity
Run the mesh study on the quantity you intend to report, not on a convenient one.
A convex corner — a square-shouldered weld bead, a sharp step, an unrounded orifice
edge — is a singularity in shear and in mass transfer. The gradient there is limited
by the cell size, so the point peak grows with refinement instead of converging,
and no amount of refinement settles it.
Measured on a weld root protrusion, refining 80 → 110 radial cells gave:
| Quantity |
Change between levels |
| Developed reference |
+0.4 % |
| Point peak at the corner |
+24.5 % |
| Mean over the crest |
+1.3 % |
| Mean at reattachment |
+0.7 % |
Everything integral is converged; only the point value runs. Report the
area-averaged enhancement over a physically meaningful length and state the averaging
window. If a local peak is genuinely needed, put the real fillet or root radius into
the geometry first — that removes the singularity and makes a point value mean
something. Quoting the corner value would be the same error as reading a single-cell
maximum out of any CFD, which this skill already warns about; it is just harder to see
because the mesh study on the reference quantity looks perfect.
Running the case in a container
OpenFOAM is usually run from an image rather than a host install. Everything the
case writes lives inside the container filesystem unless it is on a bind mount, so
the case root must be mounted before the solver starts, not after it finishes.
docker run --rm \
-v "$TASK:/task" \
-v "$SKILL_SRC:/skill:ro" \
-v "$HOST_WORK:/work" \
-e PYTHONPATH=/skill:/task/step2_analysis \
<cfd-image> bash -lc "cd /task/step2_analysis && python3 my_case.py"
The third mount is the one that gets forgotten: it is the case root.
Rule: mount the case root, or drop --rm. --rm deletes the container
filesystem the moment the process exits. If CASE_ROOT (commonly /work/cases) is
not bind-mounted, then on exit you lose the mesh, the solved fields and every time
directory — leaving only whatever JSON was written to a mounted path. The summary
numbers survive; the fields do not, so any later step that samples the solution
(surface samples, section planes, figures, a mass-transfer post-solve) forces a full
re-solve. On a several-hundred-thousand-cell bend that is tens of minutes thrown away
for a missing -v.
Two practical consequences:
- Sample in the same container run that solves. Chain the solve and the sampling
in one
bash -lc "... && ..." so the fields are guaranteed to still exist, even when
the case root is mounted.
- Make the case subset selectable. Expose the geometry variants and mesh levels
through environment variables so one case can be re-solved for sampling without
repeating the whole matrix, and so the summary JSON can be written to a scratch path
rather than overwriting a good result.
Validation Checklist
Multiphase, additionally:
Common Mistakes
| Mistake |
Why it matters |
Reading properties without initProperties() |
Viscosity and thermal conductivity come back as zero, so the CFD case runs at an absurd Reynolds number |
| Using water tables for the CFD fluid |
Glycol, condensate and hydrocarbon mixtures differ substantially; take properties from a NeqSim flash |
| Quoting a model-wide maximum as a local value |
It is often a single-cell artefact. Use section-plane maxima or area-averaged values |
| Reading kinematic pressure as Pa |
Incompressible OpenFOAM reports p in m²/s²; multiply by density |
| Different cell counts between load cases read as a mesh study |
Meshes usually differ because geometry differs, not for convergence testing |
| A steady RANS peak used for a fatigue or erosion question |
Steady RANS smooths exactly the fluctuations those questions depend on |
| Ignoring the operating case |
Enhancement factors are case-specific. Maldistribution is usually worst at low flow, which is often the throttled control condition |
| Gas-side CFD applied to a liquid-side question |
Gas-side CFD constrains the heat-flux distribution, which sets the liquid-side film temperature; it does not give liquid-side velocities |
| A photograph treated as dimensional authority |
Only valid with a calibrated scale reference and perspective correction |
| Volume of fluid used on a dilute droplet mist |
The interface is far below cell size, so the solve is expensive and wrong. The screening says lagrangian for a reason |
| A single flash used along the whole geometry |
Phase split, density and interfacial tension change with pressure and temperature; the case fixes them at the inlet |
| A VOF result read before the interface develops |
The first residence times are start-up transient, not the flow pattern |
| A forced-convection film coefficient carried into a stagnant or dead-leg region |
With no through-flow the inside coefficient collapses from forced-convection to natural-convection values, so the same wall heat flux produces a film temperature rise one to two orders of magnitude larger. Solve it as a buoyancy problem, not by rescaling velocity |
docker run --rm with the case root inside the container |
The mesh and solved fields are destroyed on exit. Only files written to a bind mount survive, so sampling, section planes and figures all need a full re-solve. Mount the case root, or drop --rm |
| A geometry constant hard-coded under a block comment claiming document provenance |
The comment can be true for one constant and false for the next. A bend angle assumed as 90° where the drawings said 180° moved the computed geometry factor by 9 %. Source each geometry constant individually |
Hand-rolled near-wall grading instead of MeshSpec.first_cell_height_m |
Solved for a fixed last cell the problem has no root when the cell count cannot span the thickness, and the bisection returns an expansion ratio of 1 — a clean-looking uniform mesh that misses the y+ target by two orders of magnitude |
mesh_warnings() collected but not printed |
It already reports "no grading was applied and the y+ target will not be met". That is the one warning that invalidates every local value in the case |
| A requested y+ quoted as the achieved y+ |
Only the solved yPlus field is evidence. Write it and read it back |
| Wall shear converted to a mass-transfer coefficient at a separated feature |
k_m ~ sqrt(tau_w) holds for an attached boundary layer. At a weld root, orifice or sudden expansion the flow reattaches, and tau_w passes through zero where mass transfer peaks — so the shear map puts its minimum near the worst metal loss. Solve a passive scalar instead |
Limitations
Single-phase steady RANS and two-phase volume of fluid are what this skill
generates. Lagrangian parcel clouds and Euler-Euler dispersed models are
recommended with a reason but not written. Phase change, cavitation, combustion,
conjugate heat transfer and mass transfer across the interface are outside scope,
and the multiphase case fixes the phase properties at the inlet flash rather than
re-flashing along the geometry. The quality gate is a screening filter, not a
verification-and-validation review: a usable_with_caution verdict means any
derived factor must carry an explicit uncertainty band. Human review by a qualified
CFD engineer is required before a CFD-derived factor is used in a design decision.
The generated case targets OpenFOAM.org v11+ by default; the legacy flavour
covers simpleFoam/interFoam-era releases and the ESI fork, and neither is
tested against every intermediate version.
Related NeqSim Functionality
neqsim.thermodynamicoperations.ThermodynamicOperations#TPflash() and
neqsim.thermo.system.SystemInterface#initProperties() — the flash and the
property initialisation that supply density, viscosity and speed of sound.
Reached from Python as from neqsim.thermo import TPflash, fluid, or as
from neqsim import jneqsim for the full Java API.
neqsim.thermo.phase.PhaseInterface#getDensity, #getViscosity,
#getSoundSpeed, #getFlowRate — the per-phase accessors read by
fluid_state_from_neqsim.
neqsim.thermo.system.SystemInterface#getInterfacialTension(int, int) — the
interfacial tension between two phases, read by multiphase_state_from_neqsim
and written straight into the VOF sigma entry.
neqsim.process.equipment.stream.Stream — the process-model object a coupled
study normally starts from; pass stream.getThermoSystem() to
fluid_state_from_neqsim.
neqsim.process.equipment.pipeline.PipeBeggsAndBrills and
neqsim.process.equipment.pipeline.AdiabaticTwoPhasePipe — the one-dimensional
hydraulic models whose bulk results the CFD enhancement factors refine.
- This skill does not run any NeqSim calculation itself. It reads a fluid state
from a system NeqSim has already flashed, and hands enhancement factors back to
NeqSim-based screening models.
Related Skills
neqsim-fem-coupling - the solid-side companion. This skill resolves the fluid
and the boundary layer; that one consumes the resulting film coefficient and
resolves the temperature and stress field inside the wall. Hand it the film
coefficient and the near-wall heat-flux distribution; take back an effective
U-value, a U-multiplier and a metal temperature.- neqsim-flow-accelerated-corrosion — consumes the mass-transfer enhancement factor
neqsim-two-phase-flow-regime-screening,
neqsim-multiphase-flow-slug-screening — supply the flow_regime that drives
the multiphase model choice
neqsim-line-velocity-check, neqsim-pressure-drop-screening — the
one-dimensional models CFD refines
neqsim-flow-induced-vibration-screening,
neqsim-acoustic-induced-vibration-screening — pair with unsteady CFD
neqsim-pid-process-operations, neqsim-technical-document-reading — supply the
P&ID topology and the datasheet values that feed the design basis
References
- OpenFOAM Foundation, OpenFOAM User Guide, v11 and later —
foamRun,
incompressibleFluid, blockMesh, function objects.
- Menter, F. R. (1994). Two-equation eddy-viscosity turbulence models for
engineering applications. AIAA Journal, 32(8), 1598–1605.
- Roache, P. J. (1994). Perspective: a method for uniform reporting of grid
refinement studies. Journal of Fluids Engineering, 116(3), 405–413.
- ASME V&V 20-2009, Standard for Verification and Validation in Computational
Fluid Dynamics and Heat Transfer.
- Hirt, C. W., & Nichols, B. D. (1981). Volume of fluid (VOF) method for the
dynamics of free boundaries. Journal of Computational Physics, 39(1), 201-225.
- Hinze, J. O. (1955). Fundamentals of the hydrodynamic mechanism of splitting in
dispersion processes. AIChE Journal, 1(3), 289-295.
- Pope, S. B. (2000). Turbulent Flows. Cambridge University Press — wall
functions, friction velocity, near-wall scaling.
- Hirt, C. W., & Nichols, B. D. (1981). Volume of fluid (VOF) method for the
dynamics of free boundaries. Journal of Computational Physics, 39(1), 201–225.
- Hinze, J. O. (1955). Fundamentals of the hydrodynamic mechanism of splitting in
dispersion processes. AIChE Journal, 1(3), 289–295.
1---2name: neqsim-cfd-coupling3description: Link a NeqSim process simulation and engineering documents to a CFD study, single-phase or multiphase. Merges P&ID, STID, datasheet and plant-data inputs into a traceable design basis, converts a flashed NeqSim fluid into CFD boundary conditions, takes both phases and the interfacial tension from a multiphase flash and screens which multiphase model is defensible, writes and runs a complete OpenFOAM case (steady single-phase RANS or transient volume of fluid) for arbitrary geometry, reads the solved fields back, gates the study on wall treatment / mesh independence / turbulence model, and converts local-versus-bulk results into enhancement factors for one-dimensional models. Tonal-noise requests are first gated on source topology, internal geometry, synchronized spectra, event conditions, acoustic terminations, and structural boundaries; steady RANS is never presented as tonal-source diagnosis. USE WHEN: a task needs local flow detail a one-dimensional model cannot generate - velocity or shear peaks at bends,4---56# CFD Coupling78A one-dimensional model works in bulk quantities. Damage does not: it concentrates9wherever the local flow field departs from the bulk — bends, welds, restrictions,10headers, tube bundles. Screening models bridge that gap with generic textbook11multipliers.1213This skill closes the gap properly. It takes whatever is known about a component14(P&ID, STID tag register, datasheets, plant data), takes the fluid from a NeqSim15flash, builds and runs an OpenFOAM case on the real geometry, and converts the16solved field back into the factor the one-dimensional model was guessing at. When17a CFD study already exists it qualifies that study instead of running a new one.1819Every layer works on its own. NeqSim and OpenFOAM are both optional: without20NeqSim the fluid state is stated directly, and without OpenFOAM the case is still21written and can be transferred and run elsewhere.2223## When to Use2425- A screening model needs a local enhancement factor and a generic multiplier is26 currently being assumed.27- Pressure drop, velocity or wall shear is needed on real geometry rather than on28 an equivalent-length correlation.29- Flow maldistribution across a bundle, manifold or header matters to the answer.30- Two phases share the line and the interface matters - stratified, slug or annular31 flow, a free surface, or liquid accumulating in a low point.32- A CFD report, vendor flow analysis or CFD/FEM deliverable is attached to an33 equipment tag and must be qualified before its numbers are used.34- A new CFD run must be specified and needs fluid properties, turbulence inlet35 values and near-wall mesh sizing.36- A tonal noise or vibration observation needs a fail-closed readiness decision37 before transient compressible CFD, acoustics, or structural coupling is scoped.3839## When *Not* to Use4041- As a substitute for a qualified CFD engineer on a design decision. This is a42 screening and coupling toolkit, not a verification-and-validation review.43- To extract a number from a CFD study that fails the quality gate.44- For droplet break-up statistics, separation efficiency or a dense dispersed45 phase. The multiphase screening will say `lagrangian` or `euler_euler`; those46 cases are recommended with a reason but not generated here.47- For a temperature field. The generated cases solve momentum only, with the48 fluid properties frozen at the inlet flash. A stagnant or dead-leg region, a49 buoyancy-driven or thermally stratified region, or any wall-temperature50 question needs a buoyant conjugate solver (`buoyantSimpleFoam`,51 `buoyantPimpleFoam`, `chtMultiRegionFoam`) that this skill does not write.52 Use `fem-coupling` for the wall and near-wall temperature, and hand-build the53 buoyant case if the fluid-side field itself is the deliverable.54- To diagnose a tonal aeroacoustic source with the generated steady RANS or55 incompressible VOF cases. Call `assess_aeroacoustic_readiness` first. A ready56 case still requires a separately configured transient compressible LES/DES,57 spectral pressure probes, acoustic propagation, and structural modal analysis58 when vibration is in scope.5960## Inputs6162| Stage | Input | Meaning |63|---|---|---|64| `build_design_basis` | `tag`, `component_kind`, `sources` | Equipment or line identifier, the component class from the P&ID, and one entry per source with `source`, `reference` and `values` |65| `fluid_state_from_neqsim` | flashed NeqSim system, `phase` | Density, viscosity, speed of sound and flow of the chosen phase |66| `derive_boundary_conditions` | `FluidState`, `hydraulic_diameter_m`, velocity **or** volumetric flow | Optional `turbulence_intensity`, `turbulence_length_scale_m`, `flow_area_m2` |67| `multiphase_state_from_neqsim` | flashed NeqSim system, optional `continuous_phase` / `dispersed_phase` | Both phases plus the interfacial tension between them |68| `derive_multiphase_conditions` | `MultiphaseState`, `hydraulic_diameter_m`, optional `flow_regime` | Superficial and mixture quantities, and the multiphase model screening |69| `MeshSpec` | `kind` (`pipe`, `channel`, `external`), dimensions, cell counts | Optional `first_cell_height_m` to drive near-wall grading from a y+ target |70| `OpenFoamCase` | boundary conditions, mesh, `flavour`, `wall_treatment` | `flavour` is `org` (OpenFOAM v11+, `foamRun`) or `legacy` (`simpleFoam`) |71| `assess_quality` | `turbulence_model`, `wall_treatment`, `y_plus`, `mesh_levels`, `gci_percent` | Applies to a generated case or an existing report |72| `assess_aeroacoustic_readiness` | Verified topology, internal geometry, synchronized spectra, event operating state, acoustic boundaries, and optional structural/moving-part data | Fails closed before tonal-source CFD or FSI is attempted |73| `evaluate_local_enhancement` | bulk and local peak velocity, and wall shear when available | Bulk values come from the one-dimensional model |7475## Outputs7677| Output | Contents |78|---|---|79| `CfdDesignBasis` | Accepted values, per-field source and confidence, conflicts, missing fields, `ready_for_meshing` |80| `CfdBoundaryConditions` | Velocity, Reynolds, Mach, flow regime, compressibility class, `k`, `epsilon`, `omega`, recommended turbulence model and solver, warnings |81| `MultiphaseBoundaryConditions` | Superficial velocities, mixture velocity/density/viscosity, Reynolds, Weber, Froude, maximum stable droplet, Stokes number, recommended multiphase model with its rationale |82| `OpenFoamCase.write` | A complete case tree: `system/`, `constant/`, `0/`, with function objects for wall shear, y+, patch fluxes and pressures |83| `VofOpenFoamCase.write` | A transient two-phase tree: `alpha.<phase>`, `p_rgh`, `constant/g`, per-phase properties, interfacial tension, `setFieldsDict`, Courant-limited control |84| `OpenFoamCase.mesh_warnings` | Near-wall grading that would over-stretch the mesh, with the cell count needed to avoid it |85| `RunOutcome` | `completed`, `failed` or `not_executed`, per-command output, and the commands needed to run the case elsewhere |86| `OpenFoamResults` | Continuity error, pressure drop, peak and mean wall shear, y+ min/mean/max, outlet dispersed fraction, peak-to-mean shear enhancement |87| `CfdQualityResult` | `usable`, `usable_with_caution` or `not_usable` with explicit findings |88| `AeroacousticReadinessResult` | `not_ready`, `ready_for_transient_cfd`, or `ready_for_coupled_study`, with missing inputs and the required solver sequence |89| `CfdEnhancementResult` | Velocity, shear and mass-transfer enhancement factors with their source |9091## Engineering Method9293**Design basis by precedence.** Sources are ranked94`measurement > mechanical_datasheet > process_datasheet > vendor > stid >95plant_data > pid > estimate > assumption`. A lower-ranked source never overwrites96a higher-ranked one; if it disagrees by more than 2 % it raises a conflict. The97component class determines which geometry fields are required, so an98under-specified case is reported rather than meshed.99100**Fluid to boundary condition.** Density and viscosity come from the NeqSim phase101after `initProperties()`, because transport properties are otherwise zero.102Kinematic viscosity $\nu = \mu / \rho$ is what an incompressible solver consumes.103Inlet turbulence uses the fully developed correlations104105$$I = 0.16\,\mathrm{Re}^{-1/8}, \qquad \ell = 0.07\,D_h$$106107$$k = \tfrac{3}{2}(U I)^2, \qquad \varepsilon = C_\mu^{3/4}\frac{k^{3/2}}{\ell},108\qquad \omega = \frac{\varepsilon}{C_\mu k}$$109110Mach number $U/c$ above 0.3 switches the recommended solver from111`incompressibleFluid` to `compressibleFluid`. Reynolds below 4000 disables the112turbulence model and says so.113114**Mesh.** The O-grid round duct places one core block inside four ring blocks with115arc edges on the outer circle, which is what keeps cell skewness low near the116wall. Radial grading is solved from the requested first-cell height: the per-cell117geometric ratio $r$ satisfies $h_1(r^{n}-1)/(r-1) = t$, and `simpleGrading` takes118$r^{\,n-1}$. That is how a y⁺ target derived from the NeqSim fluid reaches the119mesh. `mesh_warnings()` reports when that ratio exceeds 1.3, because the fix for a120too-thin first cell is more cells, not a stretched mesh. Any externally generated121mesh (Gmsh, Fluent, I-deas, CGNS) can be imported instead, so arbitrary geometry122is supported.123124**Numerics.** Second-order `linearUpwind` on momentum, because first-order upwind125smears exactly the local peaks the coupling is trying to measure. `checkMesh` runs126before the solver. Function objects record wall shear stress, y⁺, patch fluxes and127patch-average pressures every write, which is what makes the result auditable.128129**Reading results back.** Incompressible OpenFOAM reports kinematic pressure and130kinematic wall shear in m²/s²; both are multiplied by density to obtain Pa. Peak131and area-average wall shear on the wall patch give the peak-to-mean enhancement132directly. Mass-transfer enhancement follows the friction velocity133$u^{*} = \sqrt{\tau/\rho}$:134135$$\text{mass transfer enhancement} = \sqrt{\text{shear enhancement}}$$136137**Quality gate.** Three things decide whether a local CFD value means anything.138139| Check | Requirement |140|---|---|141| Wall treatment | Wall functions need 30 ≤ y⁺ ≤ 300; a resolved low-Reynolds treatment needs y⁺ of order 1 |142| Mesh independence | At least three mesh levels, or a grid-convergence index below about 5 % |143| Turbulence model | RANS under-predicts local peaks in separated or unsteady flow; scale-resolving models (LES, DES, SAS) capture them |144145**Tonal aeroacoustic readiness.** Overall dBA and a steady mean-flow field do not146identify a tonal source. Before meshing a diagnostic case, call147`assess_aeroacoustic_readiness`. It requires the as-built flow path and candidate148component to be verified, the actual internal geometry, synchronized narrow-band149pressure/acoustic/vibration spectra, the event operating state, and acoustic150lengths or termination impedances. Structural supports, clamps, damping, and151moving-part properties become mandatory when vibration or valve motion is in152scope. Missing evidence returns `not_ready`, never estimated incident geometry.153The minimum ready-case sequence is steady RANS initialization, transient154compressible LES/DES with spectral probes, acoustic propagation, and structural155modal analysis when required. The method is a readiness gate only; this skill156does not yet generate that transient compressible aeroacoustic solver chain.157158**Multiphase.** One flash gives both phases and the interfacial tension, so the159superficial velocities follow from the phase volumetric flows and the mixture160quantities from the no-slip volume-fraction average. Three dimensionless groups161then decide the model:162163$$\mathrm{We} = \frac{\rho_c U_m^2 D}{\sigma}, \qquad164\mathrm{Fr} = \frac{U_m}{\sqrt{gD}}, \qquad165\mathrm{St} = \frac{\rho_d d^2 U_m}{18 \mu_c D}$$166167The maximum stable droplet follows Hinze turbulent break-up,168$d_{\max} = 0.725 (\sigma/\rho_c)^{3/5} \varepsilon^{-2/5}$, with the duct169dissipation rate $\varepsilon = f U_m^3 / 2D$. The screening then reports:170171| Verdict | Meaning | Generated |172|---|---|---|173| `vof` | The interface is a large-scale, resolvable feature - stratified, slug, annular, free surface | Yes, `VofOpenFoamCase` |174| `lagrangian` | Dilute dispersed phase that largely follows the carrier - mist, fine droplets | Carrier solve only; the parcel cloud must be added |175| `euler_euler` | Dense dispersed phase with no resolvable interface | No; specify with a CFD engineer |176177`VofOpenFoamCase` refuses to build a case the screening did not recommend unless178`allow_unrecommended_model=True` is passed, so the wrong model is a deliberate,179recorded decision rather than an accident. The VOF case is transient by necessity180(an interface has no steady state), Courant-limited on both the flow and the phase181fraction, and uses a compressive `vanLeer` scheme on `alpha` so the interface stays182sharp. `p_rgh` carries the hydrostatic head separately, which is what makes gravity183driven separation behave.184185## Python Usage Pattern186187### Single-phase188189```python190from cfd_coupling import (191 CfdCouplingModel, MeshSpec, OpenFoamCase, build_design_basis,192 derive_boundary_conditions, fluid_state_from_neqsim, read_case_results,193)194195# 1. Everything known about the component, from wherever it came from.196basis = build_design_basis(197 tag="20-P-001",198 component_kind="pipe",199 sources=[200 {"source": "pid", "reference": "P&ID 20-PID-001 rev C",201 "values": {"nominal_size_inch": 12.0}},202 {"source": "stid", "reference": "STID line 20-P-001",203 "values": {"inside_diameter_m": 0.3048, "length_m": 6.0}},204 {"source": "process_datasheet", "reference": "20-DS-014 rev 2",205 "values": {"temperature_c": 45.0, "pressure_bara": 65.0,206 "mass_flow_kg_per_h": 120_000.0}},207 ],208)209assert basis.ready_for_meshing, (basis.missing_fields, basis.conflicts)210211# 2. Fluid from NeqSim, at the condition on the datasheet.212from neqsim.thermo import TPflash, fluid213214gas = fluid("srk")215gas.addComponent("methane", 0.90)216gas.addComponent("ethane", 0.10)217gas.setMixingRule("classic")218gas.setTemperature(basis.value("temperature_c"), "C")219gas.setPressure(basis.value("pressure_bara"), "bara")220gas.setTotalFlowRate(basis.value("mass_flow_kg_per_h"), "kg/hr")221TPflash(gas)222state = fluid_state_from_neqsim(gas, phase="gas")223224# 3. Boundary conditions, then a near-wall cell sized for the wall treatment.225boundary = derive_boundary_conditions(226 state, hydraulic_diameter_m=basis.value("inside_diameter_m")227)228model = CfdCouplingModel()229plan = model.plan_wall_resolution(230 density=state.density_kg_per_m3, viscosity=state.viscosity_pa_s,231 velocity=boundary.velocity_m_per_s,232 hydraulic_diameter=boundary.hydraulic_diameter_m, target_y_plus=50.0,233)234235# 4. Write, run, read back.236case = OpenFoamCase(237 boundary=boundary,238 mesh=MeshSpec(kind="pipe", diameter_m=basis.value("inside_diameter_m"),239 length_m=basis.value("length_m"),240 first_cell_height_m=plan.first_cell_height_m),241 name=basis.tag,242)243case.write("cases/20-P-001")244outcome = case.run("cases/20-P-001") # "not_executed" without OpenFOAM245results = read_case_results("cases/20-P-001",246 density_kg_per_m3=state.density_kg_per_m3)247248# 5. Gate before using any number, then convert to an engineering factor.249gate = model.assess_quality(250 turbulence_model=boundary.recommended_turbulence_model,251 wall_treatment="wall_function", y_plus=results.y_plus_mean, mesh_levels=1,252)253if gate.verdict != "not_usable" and results.wall_shear_enhancement:254 factor = model.evaluate_local_enhancement(255 location="20-P-001 wall", bulk_velocity=boundary.velocity_m_per_s,256 local_peak_velocity=boundary.velocity_m_per_s,257 bulk_wall_shear=results.mean_wall_shear_pa,258 local_peak_wall_shear=results.peak_wall_shear_pa,259 )260```261262### Multiphase263264```python265from cfd_coupling import (266 MeshSpec, VofOpenFoamCase, derive_multiphase_conditions,267 multiphase_state_from_neqsim, read_case_results,268)269270TPflash(wellstream) # a flash that produces gas and liquid271state = multiphase_state_from_neqsim(wellstream) # both phases plus sigma272273conditions = derive_multiphase_conditions(274 state, hydraulic_diameter_m=0.2032, flow_regime="slug",275)276print(conditions.recommended_model, conditions.model_rationale)277278if conditions.recommended_model == "vof":279 case = VofOpenFoamCase(280 boundary=conditions,281 mesh=MeshSpec(kind="pipe", diameter_m=0.2032, length_m=4.0, axial_cells=120),282 end_time=8.0,283 gravity=(0.0, -9.80665, 0.0), # perpendicular to a horizontal pipe axis284 )285 case.write("cases/two-phase-line")286 case.run("cases/two-phase-line")287 results = read_case_results("cases/two-phase-line")288 # results.outlet_dispersed_fraction vs state.dispersed_volume_fraction289```290291## Near-wall resolution: let the library solve it, and verify what you got292293`MeshSpec.first_cell_height_m` exists so a y+ target from the fluid state reaches the294mesh. The grading is solved by `_wall_grading`, which brackets the root properly and295is reported through `mesh_warnings()`. **Use it. Do not hand-roll the grading maths.**296297The arithmetic is easy to get wrong in a way that produces a *valid-looking* mesh.298Solving for a fixed **last** cell is ill-posed: if the cell count cannot span the299thickness there is no root, the bisection returns an endpoint, and the endpoint is300an expansion ratio of 1 — a perfectly clean uniform mesh. In one case that put the301first cell at y+ 27 instead of the requested 0.15, so a 10 um concentration boundary302layer sat inside a single 219 um cell and the wall gradient was meaningless. Posed303from the wall outwards the sum is monotonic in the expansion ratio and the bisection304is well conditioned.305306**Rules:**307308- Call `mesh_warnings()` and **print it**, every case. Treat *"no grading was applied309and the y+ target will not be met"* as a stop, not a note.310- A mesh helper that cannot satisfy its target must **raise**, not silently degrade.311 Guard both ends: expansion ratio above about 1.25, and a wall cell too coarse for312 the layer being resolved.313- **Verify the achieved resolution from the solution, not from the request.** Write314 the `yPlus` field and read it back. A requested y+ and an achieved y+ are different315 numbers, and only one of them is evidence.316- Where the answer depends on the near-wall layer, **validate against a correlation on317 the same mesh before quoting a local value** — the developed run upstream of the318 feature should reproduce the analytical wall shear, and for a scalar the textbook319 Sherwood number. A validation that fails by two orders of magnitude is a good320 validation; one that is never run lets a plausible wrong number through.321322## A point peak at a sharp corner is not a converged quantity323324Run the mesh study on the quantity you intend to **report**, not on a convenient one.325A convex corner — a square-shouldered weld bead, a sharp step, an unrounded orifice326edge — is a singularity in shear and in mass transfer. The gradient there is limited327by the cell size, so the point peak **grows with refinement instead of converging**,328and no amount of refinement settles it.329330Measured on a weld root protrusion, refining 80 → 110 radial cells gave:331332| Quantity | Change between levels |333|---|---|334| Developed reference | +0.4 % |335| **Point peak at the corner** | **+24.5 %** |336| Mean over the crest | +1.3 % |337| Mean at reattachment | +0.7 % |338339Everything integral is converged; only the point value runs. **Report the340area-averaged enhancement over a physically meaningful length and state the averaging341window.** If a local peak is genuinely needed, put the real fillet or root radius into342the geometry first — that removes the singularity and makes a point value mean343something. Quoting the corner value would be the same error as reading a single-cell344maximum out of any CFD, which this skill already warns about; it is just harder to see345because the mesh study on the *reference* quantity looks perfect.346347## Running the case in a container348349OpenFOAM is usually run from an image rather than a host install. **Everything the350case writes lives inside the container filesystem unless it is on a bind mount**, so351the case root must be mounted before the solver starts, not after it finishes.352353```bash354docker run --rm \355 -v "$TASK:/task" \356 -v "$SKILL_SRC:/skill:ro" \357 -v "$HOST_WORK:/work" \358 -e PYTHONPATH=/skill:/task/step2_analysis \359 <cfd-image> bash -lc "cd /task/step2_analysis && python3 my_case.py"360```361362The third mount is the one that gets forgotten: it is the case root.363364**Rule: mount the case root, or drop `--rm`.** `--rm` deletes the container365filesystem the moment the process exits. If `CASE_ROOT` (commonly `/work/cases`) is366not bind-mounted, then on exit you lose the mesh, the solved fields and every time367directory — leaving only whatever JSON was written to a mounted path. The summary368numbers survive; **the fields do not**, so any later step that samples the solution369(surface samples, section planes, figures, a mass-transfer post-solve) forces a full370re-solve. On a several-hundred-thousand-cell bend that is tens of minutes thrown away371for a missing `-v`.372373Two practical consequences:374375- **Sample in the same container run that solves.** Chain the solve and the sampling376 in one `bash -lc "... && ..."` so the fields are guaranteed to still exist, even when377 the case root is mounted.378- **Make the case subset selectable.** Expose the geometry variants and mesh levels379 through environment variables so one case can be re-solved for sampling without380 repeating the whole matrix, and so the summary JSON can be written to a scratch path381 rather than overwriting a good result.382383## Validation Checklist384385- [ ] `basis.ready_for_meshing` is true386- [ ] `basis.ready_for_meshing` is true, or every missing field and conflict is387 resolved and recorded.388- [ ] `initProperties()` ran before properties were read; density and viscosity389 are non-zero and physical for the phase.390- [ ] Reynolds number is above 4000, or the laminar warning has been accepted.391- [ ] Mach number is below 0.3, or a compressible solver is used.392- [ ] `checkMesh` reported no failed mesh checks.393- [ ] `mesh_warnings()` is empty, or the near-wall expansion has been accepted.394- [ ] `mesh_warnings()` was printed, and it does not report that no grading was395 applied.396- [ ] The **achieved** y+ was read back from the solved `yPlus` field, not assumed397 from the requested first-cell height.398- [ ] Inlet and outlet volumetric flow agree to better than 1 %.399- [ ] y⁺ lies inside the band for the wall treatment actually used.400- [ ] At least two mesh levels were run before a local peak is quoted.401- [ ] Wall shear and pressure were converted from kinematic units to Pa.402- [ ] The case root is a bind mount, or the container is not run with `--rm`, so the403 solved fields survive for sampling and figures.404- [ ] The quality-gate verdict and all findings are carried into the receiving405 report's assumptions register.406407Multiphase, additionally:408409- [ ] The flash produced the phases expected at the inlet condition, and the410 continuous phase is the one that actually wets the wall.411- [ ] NeqSim returned a physical interfacial tension for the phase pair.412- [ ] The recommended model was used, or the override is recorded with a reason.413- [ ] A flow-regime screening was supplied rather than relying on volume fraction.414- [ ] The outlet dispersed fraction was compared with the inlet flash split.415- [ ] The case ran long enough for the interface to develop; a VOF result read at416 an arbitrary early time is a transient, not an answer.417418## Common Mistakes419420| Mistake | Why it matters |421|---|---|422| Reading properties without `initProperties()` | Viscosity and thermal conductivity come back as zero, so the CFD case runs at an absurd Reynolds number |423| Using water tables for the CFD fluid | Glycol, condensate and hydrocarbon mixtures differ substantially; take properties from a NeqSim flash |424| Quoting a model-wide maximum as a local value | It is often a single-cell artefact. Use section-plane maxima or area-averaged values |425| Reading kinematic pressure as Pa | Incompressible OpenFOAM reports `p` in m²/s²; multiply by density |426| Different cell counts between load cases read as a mesh study | Meshes usually differ because geometry differs, not for convergence testing |427| A steady RANS peak used for a fatigue or erosion question | Steady RANS smooths exactly the fluctuations those questions depend on |428| Ignoring the operating case | Enhancement factors are case-specific. Maldistribution is usually worst at low flow, which is often the throttled control condition |429| Gas-side CFD applied to a liquid-side question | Gas-side CFD constrains the heat-flux distribution, which sets the liquid-side film temperature; it does not give liquid-side velocities |430| A photograph treated as dimensional authority | Only valid with a calibrated scale reference and perspective correction |431| Volume of fluid used on a dilute droplet mist | The interface is far below cell size, so the solve is expensive and wrong. The screening says `lagrangian` for a reason |432| A single flash used along the whole geometry | Phase split, density and interfacial tension change with pressure and temperature; the case fixes them at the inlet |433| A VOF result read before the interface develops | The first residence times are start-up transient, not the flow pattern |434| A forced-convection film coefficient carried into a stagnant or dead-leg region | With no through-flow the inside coefficient collapses from forced-convection to natural-convection values, so the same wall heat flux produces a film temperature rise one to two orders of magnitude larger. Solve it as a buoyancy problem, not by rescaling velocity |435| `docker run --rm` with the case root inside the container | The mesh and solved fields are destroyed on exit. Only files written to a bind mount survive, so sampling, section planes and figures all need a full re-solve. Mount the case root, or drop `--rm` |436| A geometry constant hard-coded under a block comment claiming document provenance | The comment can be true for one constant and false for the next. A bend angle assumed as 90° where the drawings said 180° moved the computed geometry factor by 9 %. Source each geometry constant individually |437| Hand-rolled near-wall grading instead of `MeshSpec.first_cell_height_m` | Solved for a fixed last cell the problem has no root when the cell count cannot span the thickness, and the bisection returns an expansion ratio of 1 — a clean-looking uniform mesh that misses the y+ target by two orders of magnitude |438| `mesh_warnings()` collected but not printed | It already reports "no grading was applied and the y+ target will not be met". That is the one warning that invalidates every local value in the case |439| A requested y+ quoted as the achieved y+ | Only the solved `yPlus` field is evidence. Write it and read it back |440| Wall shear converted to a mass-transfer coefficient at a separated feature | `k_m ~ sqrt(tau_w)` holds for an attached boundary layer. At a weld root, orifice or sudden expansion the flow reattaches, and `tau_w` passes through zero where mass transfer peaks — so the shear map puts its minimum near the worst metal loss. Solve a passive scalar instead |441442## Limitations443444Single-phase steady RANS and two-phase volume of fluid are what this skill445generates. Lagrangian parcel clouds and Euler-Euler dispersed models are446recommended with a reason but not written. Phase change, cavitation, combustion,447conjugate heat transfer and mass transfer across the interface are outside scope,448and the multiphase case fixes the phase properties at the inlet flash rather than449re-flashing along the geometry. The quality gate is a screening filter, not a450verification-and-validation review: a `usable_with_caution` verdict means any451derived factor must carry an explicit uncertainty band. Human review by a qualified452CFD engineer is required before a CFD-derived factor is used in a design decision.453The generated case targets OpenFOAM.org v11+ by default; the `legacy` flavour454covers `simpleFoam`/`interFoam`-era releases and the ESI fork, and neither is455tested against every intermediate version.456457## Related NeqSim Functionality458459- `neqsim.thermodynamicoperations.ThermodynamicOperations#TPflash()` and460 `neqsim.thermo.system.SystemInterface#initProperties()` — the flash and the461 property initialisation that supply density, viscosity and speed of sound.462 Reached from Python as `from neqsim.thermo import TPflash, fluid`, or as463 `from neqsim import jneqsim` for the full Java API.464- `neqsim.thermo.phase.PhaseInterface#getDensity`, `#getViscosity`,465 `#getSoundSpeed`, `#getFlowRate` — the per-phase accessors read by466 `fluid_state_from_neqsim`.467- `neqsim.thermo.system.SystemInterface#getInterfacialTension(int, int)` — the468 interfacial tension between two phases, read by `multiphase_state_from_neqsim`469 and written straight into the VOF `sigma` entry.470- `neqsim.process.equipment.stream.Stream` — the process-model object a coupled471 study normally starts from; pass `stream.getThermoSystem()` to472 `fluid_state_from_neqsim`.473- `neqsim.process.equipment.pipeline.PipeBeggsAndBrills` and474 `neqsim.process.equipment.pipeline.AdiabaticTwoPhasePipe` — the one-dimensional475 hydraulic models whose bulk results the CFD enhancement factors refine.476- This skill does not run any NeqSim calculation itself. It reads a fluid state477 from a system NeqSim has already flashed, and hands enhancement factors back to478 NeqSim-based screening models.479480## Related Skills481- `neqsim-fem-coupling` - the solid-side companion. This skill resolves the fluid482 and the boundary layer; that one consumes the resulting film coefficient and483 resolves the temperature and stress field inside the wall. Hand it the film484 coefficient and the near-wall heat-flux distribution; take back an effective485 U-value, a U-multiplier and a metal temperature.- `neqsim-flow-accelerated-corrosion` — consumes the mass-transfer enhancement factor486- `neqsim-two-phase-flow-regime-screening`,487 `neqsim-multiphase-flow-slug-screening` — supply the `flow_regime` that drives488 the multiphase model choice489- `neqsim-line-velocity-check`, `neqsim-pressure-drop-screening` — the490 one-dimensional models CFD refines491- `neqsim-flow-induced-vibration-screening`,492 `neqsim-acoustic-induced-vibration-screening` — pair with unsteady CFD493- `neqsim-pid-process-operations`, `neqsim-technical-document-reading` — supply the494 P&ID topology and the datasheet values that feed the design basis495496## References497498- OpenFOAM Foundation, *OpenFOAM User Guide*, v11 and later — `foamRun`,499 `incompressibleFluid`, `blockMesh`, function objects.500- Menter, F. R. (1994). Two-equation eddy-viscosity turbulence models for501 engineering applications. *AIAA Journal*, 32(8), 1598–1605.502- Roache, P. J. (1994). Perspective: a method for uniform reporting of grid503 refinement studies. *Journal of Fluids Engineering*, 116(3), 405–413.504- ASME V&V 20-2009, *Standard for Verification and Validation in Computational505 Fluid Dynamics and Heat Transfer*.506- Hirt, C. W., & Nichols, B. D. (1981). Volume of fluid (VOF) method for the507 dynamics of free boundaries. *Journal of Computational Physics*, 39(1), 201-225.508- Hinze, J. O. (1955). Fundamentals of the hydrodynamic mechanism of splitting in509 dispersion processes. *AIChE Journal*, 1(3), 289-295.510- Pope, S. B. (2000). *Turbulent Flows*. Cambridge University Press — wall511 functions, friction velocity, near-wall scaling.512- Hirt, C. W., & Nichols, B. D. (1981). Volume of fluid (VOF) method for the513 dynamics of free boundaries. *Journal of Computational Physics*, 39(1), 201–225.514- Hinze, J. O. (1955). Fundamentals of the hydrodynamic mechanism of splitting in515 dispersion processes. *AIChE Journal*, 1(3), 289–295.