diff --git a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.C b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.C
index 107fcf30a5c1c0da2bf9c34b0a8d35ac9e01c687..9ce82de75203774db7dbae7bd59c4d8a3a278916 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.C
+++ b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,6 +28,19 @@ License
 
 #include "fanFvPatchField.H"
 
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+template<class Type>
+const Foam::Enum<typename Foam::fanFvPatchField<Type>::operatingMode>
+Foam::fanFvPatchField<Type>::operatingModeNames_
+({
+    { operatingMode::VELOCITY, "velocity" },
+    { operatingMode::UNIFORM_VELOCITY, "uniformVelocity" },
+    { operatingMode::VOL_FLOW_RATE, "volumeFlowRate" },
+    { operatingMode::NON_DIMENSIONAL, "nonDimensional" },
+});
+
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 template<class Type>
@@ -50,10 +63,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
 )
 :
     uniformJumpFvPatchField<Type>(p, iF),
+    operatingMode_(operatingMode::VELOCITY),
     phiName_("phi"),
     rhoName_("rho"),
-    uniformJump_(false),
-    nonDimensional_(false),
     rpm_(nullptr),
     dm_(nullptr)
 {}
@@ -68,15 +80,36 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
 )
 :
     uniformJumpFvPatchField<Type>(p, iF, dict, false),  // needValue = false
+    operatingMode_
+    (
+        operatingModeNames_.getOrDefault("mode", dict, operatingMode::VELOCITY)
+    ),
     phiName_(dict.getOrDefault<word>("phi", "phi")),
     rhoName_(dict.getOrDefault<word>("rho", "rho")),
-    uniformJump_(dict.getOrDefault("uniformJump", false)),
-    nonDimensional_(dict.getOrDefault("nonDimensional", false)),
     rpm_(nullptr),
     dm_(nullptr)
 {
+    // Backwards compatibility
+    if (operatingMode_ == operatingMode::VELOCITY)
+    {
+        bool nonDimCompat = dict.getOrDefault("nonDimensional", false);
+        if (nonDimCompat)
+        {
+            // Warn?
+            operatingMode_ = operatingMode::NON_DIMENSIONAL;
+        }
+
+        bool uniformCompat = dict.getOrDefault("uniformJump", false);
+        if (uniformCompat)
+        {
+            // Warn?
+            operatingMode_ = operatingMode::UNIFORM_VELOCITY;
+        }
+    }
+
+
     // Note that we've not read jumpTable_ etc
-    if (nonDimensional_)
+    if (operatingMode_ == operatingMode::NON_DIMENSIONAL)
     {
         rpm_.reset(Function1<scalar>::New("rpm", dict, &this->db()));
         dm_.reset(Function1<scalar>::New("dm", dict, &this->db()));
@@ -104,10 +137,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
 )
 :
     uniformJumpFvPatchField<Type>(rhs, p, iF, mapper),
+    operatingMode_(rhs.operatingMode_),
     phiName_(rhs.phiName_),
     rhoName_(rhs.rhoName_),
-    uniformJump_(rhs.uniformJump_),
-    nonDimensional_(rhs.nonDimensional_),
     rpm_(rhs.rpm_.clone()),
     dm_(rhs.dm_.clone())
 {}
@@ -120,10 +152,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
 )
 :
     uniformJumpFvPatchField<Type>(rhs),
+    operatingMode_(rhs.operatingMode_),
     phiName_(rhs.phiName_),
     rhoName_(rhs.rhoName_),
-    uniformJump_(rhs.uniformJump_),
-    nonDimensional_(rhs.nonDimensional_),
     rpm_(rhs.rpm_.clone()),
     dm_(rhs.dm_.clone())
 {}
@@ -137,10 +168,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
 )
 :
     uniformJumpFvPatchField<Type>(rhs, iF),
+    operatingMode_(rhs.operatingMode_),
     phiName_(rhs.phiName_),
     rhoName_(rhs.rhoName_),
-    uniformJump_(rhs.uniformJump_),
-    nonDimensional_(rhs.nonDimensional_),
     rpm_(rhs.rpm_.clone()),
     dm_(rhs.dm_.clone())
 {}
@@ -170,14 +200,10 @@ void Foam::fanFvPatchField<Type>::write(Ostream& os) const
     os.writeEntryIfDifferent<word>("phi", "phi", phiName_);
     os.writeEntryIfDifferent<word>("rho", "rho", rhoName_);
 
-    if (uniformJump_)
-    {
-        os.writeEntry("uniformJump", "true");
-    }
+    os.writeEntry("mode", operatingModeNames_[operatingMode_]);
 
-    if (nonDimensional_)
+    if (operatingMode_ == operatingMode::NON_DIMENSIONAL)
     {
-        os.writeEntry("nonDimensional", "true");
         rpm_->writeData(os);
         dm_->writeData(os);
     }
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.H b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.H
index 4a0fb21631e316e001b403ea4de5063aa394c20a..fb37abc4af5f2fe05c15fb118275921d31cf4485 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchField.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2019 OpenCFD Ltd.
+    Copyright (C) 2017-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,14 +37,21 @@ Description
     The jump is specified as a \c Function1 type, to enable the use of, e.g.
     constant, polynomial, table values.
 
-    The switch nonDimensional can be used for a non-dimensional table,
-    in combination with uniformJump = true.
+    The basis of the table is specified according to the \c mode:
+
+    - velocity: deltap = F(velocity per face) \[DEFAULT\]
+    - uniformVelocity: deltap = F(patch area-averaged velocity)
+    - volumeFlowRate:  deltap = F(patch volume flow rate)
+    - nonDimensional:  non-dim deltap = F(non-dim volume flow rate)
+
+    Non-dimensional operation:
+
     As inputs it needs the fan RPM (rpm) and the mean diameter (dm).
 
     The non-dimensional U for the table is calculated as follows:
 
     \verbatim
-        phi = 120*Un/(PI^3*dm*rpm)
+        phi = 120*Un/(PI^3*dm^3*rpm)
         where:
             dm is the mean diameter.
             rpm is the RPM of the fan.
@@ -64,11 +71,10 @@ Usage
     \table
         Property    | Description                           | Required | Default
         patchType   | underlying patch type should be \c cyclic | yes |
+        mode        | jump table operating mode (see above) | no | velocity
         jumpTable   | jump data, e.g. \c csvFile            | yes |
         phi         | flux field name                       | no  | phi
         rho         | density field name                    | no  | rho
-        uniformJump | apply uniform pressure based on avg velocity | no | false
-        nonDimensional | use non-dimensional table          | no | false
         rpm         | fan rpm (non-dimensional table)       | no |
         dm          | mean diameter (non-dimensional table) | no |
     \endtable
@@ -80,6 +86,7 @@ Usage
         type            fan;
         patchType       cyclic;
         jumpTable       csvFile;
+        mode            velocity;
 
         jumpTableCoeffs
         {
@@ -107,15 +114,15 @@ SourceFiles
     fanFvPatchField.C
     fanFvPatchFields.H
     fanFvPatchFields.C
-    fanFvPatchFieldsFwd.H
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef fanFvPatchField_H
-#define fanFvPatchField_H
+#ifndef foam_fanFvPatchField_H
+#define foam_fanFvPatchField_H
 
 #include "uniformJumpFvPatchField.H"
 #include "Function1.H"
+#include "Enum.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -131,20 +138,36 @@ class fanFvPatchField
 :
     public uniformJumpFvPatchField<Type>
 {
+public:
+
+    // Public Data Types
+
+        //- Enumeration defining the operating modes
+        enum class operatingMode
+        {
+            VELOCITY,           //!< velocity-based lookup
+            UNIFORM_VELOCITY,   //!< uniform velocity-based lookup
+            VOL_FLOW_RATE,      //!< volume-flow-rate-based lookup
+            NON_DIMENSIONAL     //!< non-dimensional-based lookup
+        };
+
+        //- Names for the operating modes
+        static const Enum<operatingMode> operatingModeNames_;
+
+
+private:
+
     // Private Data
 
+        //- Operating mode
+        operatingMode operatingMode_;
+
         //- Name of the flux transporting the field
         word phiName_;
 
         //- Name of the density field for normalising the mass flux if necessary
         word rhoName_;
 
-        //- Apply uniform pressure drop
-        bool uniformJump_;
-
-        //- Use non-dimensional curve
-        bool nonDimensional_;
-
         //- Fan rpm (for non-dimensional curve)
         autoPtr<Function1<scalar>> rpm_;
 
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.C b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.C
index e3e0b3a4817afb46047d0015b7fc6b075c5773be..2bb5c4b2ba6a98f55d6313503040d489b621e8b1 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.C
+++ b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -44,69 +44,120 @@ namespace Foam
 template<>
 void Foam::fanFvPatchField<Foam::scalar>::calcFanJump()
 {
-    if (this->cyclicPatch().owner())
+    if (!this->cyclicPatch().owner())
     {
-        const auto& phip =
-            patch().lookupPatchField<surfaceScalarField>(phiName_);
+        return;
+    }
+
+    const auto& phip = patch().lookupPatchField<surfaceScalarField>(phiName_);
+
+    scalarField volFlowRate(max(phip, scalar(0)));
 
-        scalarField Un(max(phip/patch().magSf(), scalar(0)));
+    if (phip.internalField().dimensions() == dimVolume/dimTime)
+    {
+        // No conversion of volFlowRate required
+    }
+    else if (phip.internalField().dimensions() == dimMass/dimTime)
+    {
+        const auto& rhop = patch().lookupPatchField<volScalarField>(rhoName_);
+        volFlowRate /= rhop;
+    }
+    else
+    {
+        FatalErrorInFunction
+            << "dimensions of phi are not correct\n"
+            << "    on patch " << patch().name()
+            << " of field " << internalField().name()
+            << " in file " << internalField().objectPath() << nl
+            << exit(FatalError);
+    }
 
-        // The non-dimensional parameters
 
-        scalar rpm(0);
-        scalar meanDiam(0);
+    // The non-dimensional parameters
+    scalar rpm(0);
+    scalar meanDiam(0);
 
-        if (nonDimensional_)
+    scalarField pdFan(patch().size(), Zero);
+
+    switch (operatingMode_)
+    {
+        case operatingMode::VELOCITY:
         {
-            rpm = rpm_->value(this->db().time().timeOutputValue());
-            meanDiam = dm_->value(this->db().time().timeOutputValue());
-        }
+            // Note: volFlowRate now becomes face normal velocity
+            volFlowRate /= patch().magSf();
+
+            // Per-face values
+            pdFan = this->jumpTable_->value(volFlowRate);
 
-        if (uniformJump_)
+            break;
+        }
+        case operatingMode::UNIFORM_VELOCITY:
         {
+            // Note: volFlowRate now becomes face normal velocity
+            volFlowRate /= patch().magSf();
+
+            // Set face values to patch area-averaged value
             const scalar area = gSum(patch().magSf());
-            Un = gSum(Un*patch().magSf())/area;
+            const scalar UnAve = gSum(volFlowRate*patch().magSf())/area;
 
-            if (nonDimensional_)
-            {
-                // Create an non-dimensional velocity
-                Un =
-                (
-                    120.0*Un
-                  / stabilise
-                    (
-                        pow3(constant::mathematical::pi) * meanDiam * rpm,
-                        VSMALL
-                    )
-                );
-            }
-        }
+            // Assign uniform value
+            pdFan = this->jumpTable_->value(UnAve);
 
-        if (phip.internalField().dimensions() == dimMass/dimTime)
-        {
-            Un /= patch().lookupPatchField<volScalarField>(rhoName_);
+            break;
         }
+        case operatingMode::VOL_FLOW_RATE:
+        {
+            // Face-based volFlowRate converted to patch-based volFlowRate
+            // for pd curve lookup
+            const scalar sumVolFlowRate = gSum(volFlowRate);
 
-        if (nonDimensional_)
+            // Assign uniform value
+            pdFan = this->jumpTable_->value(sumVolFlowRate);
+
+            break;
+        }
+        case operatingMode::NON_DIMENSIONAL:
         {
-            scalarField deltap(this->jumpTable_->value(Un));
+            // Face-based volFlowRate converted to patch-based volFlowRate
+            // for pd curve lookup
+            scalar sumVolFlowRate = gSum(volFlowRate);
+
+            rpm = rpm_->value(this->db().time().timeOutputValue());
+            meanDiam = dm_->value(this->db().time().timeOutputValue());
 
-            // Convert non-dimensional deltap from curve into deltaP
-            scalarField pdFan
+            // Create a non-dimensional flow rate
+            sumVolFlowRate *=
             (
-                deltap*pow4(constant::mathematical::pi)
-              * sqr(meanDiam*rpm)/1800.0
+                120.0
+               /stabilise
+                (
+                    pow3(constant::mathematical::pi*meanDiam)*rpm,
+                    VSMALL
+                )
             );
 
-            this->setJump(pdFan);
+            const scalar pdNonDim = this->jumpTable_->value(sumVolFlowRate);
+
+            // Convert uniform non-dimensional pdFan from curve into deltaP
+            pdFan =
+                pdNonDim
+               *pow4(constant::mathematical::pi)*sqr(meanDiam*rpm)/1800.0;
+
+            break;
         }
-        else
+        default:
         {
-            this->setJump(jumpTable_->value(Un));
+            FatalErrorInFunction
+                << "Unhandled enumeration "
+                << operatingModeNames_[operatingMode_]
+                << abort(FatalError);
         }
-
-        this->relax();
     }
+
+
+    this->setJump(pdFan);
+
+    this->relax();
 }
 
 
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.H b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.H
index f7b17cb367dae4a3ebf54a4356e522b70e7e3616..c84d5a9536a8c1989deb798dafd63f3b640ae2d7 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/fan/fanFvPatchFields.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2011 OpenFOAM Foundation
+    Copyright (C) 2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,8 +25,8 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef fanFvPatchFields_H
-#define fanFvPatchFields_H
+#ifndef foam_fanFvPatchFields_H
+#define foam_fanFvPatchFields_H
 
 #include "fanFvPatchField.H"
 #include "fieldTypes.H"