You have a converged steady incompressible field and you want to release a set of particles from known positions and trace their paths. You set transient false and coupled false in your cloud properties, patchInjection runs fine, but manualInjection dies with "the manualInjection injection model is not compatible with steady state solution". This is not a bug and it is not your case. It is a design limitation that tells you something real about how steady particle tracking works, and there is a clean way to get exactly what you want.
Verified against the OpenFOAM 13 (Foundation, openfoam.org) source, and it holds for the ESI fork (openfoam.com) too: the injection model design is shared. The one fork difference is the dedicated tracking tool, covered in section 4, where the function object is named particles in the Foundation fork and icoUncoupledKinematicCloud in the ESI fork.
The message comes from the base injection model when it sets up in steady cloud mode. With transient false, the cloud does not advance physical time the way a transient run does. Injection is interpreted as a rate that gets integrated over the steady solution, so every steady-compatible injector has to supply a massFlowRate. If it cannot, you get:
--> FOAM FATAL ERROR:
The manualInjection injection model is not compatible with steady state solution
So the solver is not refusing the file or your positions. It is telling you that this type of injector has no steady-state meaning.
The two injectors describe fundamentally different things.
manualInjection is a one-shot injector. It reads your positionsFile and releases every parcel at a single instant (the start of injection, SOI) with a fixed total mass. There is no rate and no duration in its definition.patchInjection is a rate-based injector. It is defined by a rate over a duration: parcelsPerSecond together with a massFlowRate. That is a continuous stream, which has a clean meaning in a steady solution.Steady cloud mode needs a rate to integrate. A continuous stream gives it one; a fixed list of parcels dumped at one instant does not. That is the whole reason one is accepted and the other is rejected. The limitation is consistent, not arbitrary.
Here is the part that solves your actual problem. You do not need steady cloud mode to get steady-state trajectories. A particle path depends only on the velocity field it moves through. If that field is frozen and converged, a cloud released into it traces exactly the steady pathlines you are after.
So run the cloud transient on top of your converged field:
solution
{
active true;
// transient cloud, no feedback to the flow
transient true;
coupled false;
cellValueSourceCorrection off;
interpolationSchemes
{
U cellPoint;
}
integrationSchemes
{
U Euler;
}
}
With transient true, manualInjection is allowed and your parcels are released from the exact positions in your positionsFile. One point to be clear about: coupled false only stops the parcels feeding momentum back to the flow, it does not by itself stop a solver from re-solving the carrier each step. To keep the field genuinely frozen you advect the cloud without solving the flow equations again. That is exactly what an uncoupled cloud does, which is the next section. Read U from your converged time, do not re-solve it, and because the field never changes the trajectories are the steady-state pathlines you wanted in the first place.
Rather than freezing the field by hand, the purpose-built way to do this is a function object that advects parcels through a specified velocity field with strictly one-way coupling, so the flow is never affected.
particles function object. Its own description says it "tracks a particle cloud in the specified velocity field of an incompressible flow" and "tracks the particles or parcels without affecting the flow-field", usable with any transient incompressible solver or solver module such as incompressibleFluid. Point it at your converged field and it evolves the cloud while the flow stays put.icoUncoupledKinematicCloud function object, which tracks an uncoupled kinematic cloud in a given incompressible velocity field.Both run the cloud in transient mode, which is exactly why manualInjection is accepted there: the parcels are released from your positionsFile at SOI and tracked through the fixed field, with no feedback to the flow.
You can, but only with a rate-based injector: patchInjection, patchFlowRateInjection, or coneInjection with a massFlowRate. These define a continuous stream entering at a patch or nozzle. The catch is that they throw away the one thing manualInjection gave you: precise, user-specified release points. If your release positions matter, steady mode is the wrong place and the transient cloud is the answer.
Write the cloud positions over time and load them in ParaView as a particle track. Because the carrier field is steady, parcels released from the same point at different times should follow the same path. If two parcels from the same release point diverge, your field is not actually frozen, so check that the carrier solver is not still updating U between cloud steps.
CFDpilot reads your OpenFOAM case in the terminal, explains errors like this one, and tells you the fix and the reasoning behind it. No upload, it runs where your case lives.
Diagnose my case →It is a one-shot injector: it reads a positionsFile and releases every parcel at a single instant (SOI) with a fixed total mass, with no rate. Steady cloud mode interprets injection as a massFlowRate integrated over the steady solution, so it needs a rate to integrate. manualInjection has none, so it is rejected by design.
patchInjection is rate-based (parcelsPerSecond, massFlowRate, duration), which describes a continuous stream and has a clean steady-state meaning. manualInjection is a fixed list of positions injected at one instant, which has no rate. Steady mode needs a rate, so the rate-based injector is accepted and the one-shot one is not.
Run the cloud transient (transient true, coupled false) over the frozen converged field, using an uncoupled cloud so the flow is not re-solved. Note that coupled false only removes the feedback to the flow, it does not freeze it on its own; an uncoupled cloud advects parcels through the existing field without solving the carrier again. The trajectories are then the steady pathlines you want, and manualInjection works because transient mode is where it belongs.
A cloud that advects parcels through a specified velocity field with one-way coupling, never feeding back to the flow. In the Foundation fork (incl. OpenFOAM 13) it is the particles function object, which tracks a cloud in a given incompressible velocity field without affecting the flow. In the ESI fork the equivalent is the icoUncoupledKinematicCloud function object. Both run transient, so manualInjection is allowed.
No. Steady mode only accepts rate-based injectors (patchInjection, patchFlowRateInjection, coneInjection with a massFlowRate). Those define a continuous stream, not a fixed list of positions. Exact release points require a transient cloud.
No, as long as the carrier field is frozen and converged. A trajectory depends only on the velocity field the parcel moves through. If that field is steady, a transient cloud traces the same pathlines, with the bonus that manualInjection lets you place parcels exactly where you want them.