diff --git a/META-INFO/api-info b/META-INFO/api-info
index d88b77f16d2a7decbc6da3378d55bd932e06ded8..c1de2e582b5e6297cb8e7d86a1de03e7fc69d049 100644
--- a/META-INFO/api-info
+++ b/META-INFO/api-info
@@ -1,2 +1,2 @@
 api=2002
-patch=200316
+patch=200403
diff --git a/etc/caseDicts/postProcessing/forces/forces.cfg b/etc/caseDicts/postProcessing/forces/forces.cfg
index 2bc90992b0851b520f23dbde7f7cc8e6392704dd..e59366686754c6bae0e94e6b1f781fa4f1adc37f 100644
--- a/etc/caseDicts/postProcessing/forces/forces.cfg
+++ b/etc/caseDicts/postProcessing/forces/forces.cfg
@@ -9,8 +9,13 @@
 type            forces;
 libs            ("libforces.so");
 
-writeControl    timeStep;
-writeInterval   1;
+// How often force and moment volume fields will be written
+writeControl    writeTime; // none
+
+// How often the forces force.dat and moment.dat data files are updated
+// Note: .dat files are always updated on writeControl times
+executeControl  timeStep;
+executeInterval 1;
 
 log             off;
 
diff --git a/src/surfMesh/writers/x3d/x3dSurfaceWriter.C b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
index ae64cc9265c5300a27d46347856ee81d9ecab31a..9592b794309f8c2a37033dbd3162a2b2fe849949 100644
--- a/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
+++ b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
@@ -50,13 +50,30 @@ namespace surfaceWriters
 namespace Foam
 {
 
+//- A (0-1) range for colouring
+inline scalar srange01(const scalarMinMax& range, scalar x)
+{
+    if (x >= range.max())
+    {
+        return 1;
+    }
+
+    x -= range.min();
+
+    if (x < VSMALL)
+    {
+        return 0;
+    }
+
+    return x / (range.max() - range.min());
+}
+
+
 //- A (0-1) range for colouring
 template<class Type>
 static inline scalar rangex(const scalarMinMax& range, const Type& val)
 {
-    scalar x = Foam::mag(val);
-
-    return (x - range.min()) / (range.max() - range.min());
+    return srange01(range, Foam::mag(val));
 }
 
 
@@ -64,8 +81,7 @@ static inline scalar rangex(const scalarMinMax& range, const Type& val)
 template<>
 inline scalar rangex(const scalarMinMax& range, const scalar& val)
 {
-    scalar x = val;
-    return (x - range.min()) / (range.max() - range.min());
+    return srange01(range, val);
 }
 
 
@@ -73,8 +89,7 @@ inline scalar rangex(const scalarMinMax& range, const scalar& val)
 template<>
 inline scalar rangex(const scalarMinMax& range, const label& val)
 {
-    scalar x = val;
-    return (x - range.min()) / (range.max() - range.min());
+    return srange01(range, val);
 }
 
 
@@ -273,8 +288,17 @@ Foam::fileName Foam::surfaceWriters::x3dWriter::writeTemplate
         if (!range.valid())
         {
             range = minMaxMag(values);
+
+            if (equal(range.mag(), 0))
+            {
+                range.add(range.centre());
+            }
         }
 
+        // Slight rounding
+        range.min() -= VSMALL;
+        range.max() += VSMALL;
+
         if (!isDir(outputFile.path()))
         {
             mkDir(outputFile.path());
diff --git a/src/thermophysicalModels/radiation/radiationModels/P1/P1.C b/src/thermophysicalModels/radiation/radiationModels/P1/P1.C
index a678d888e964b4b38fa0c661001a3325dd3aad71..d4336dd3c7640bed79203fe3b267a6c009b01d5f 100644
--- a/src/thermophysicalModels/radiation/radiationModels/P1/P1.C
+++ b/src/thermophysicalModels/radiation/radiationModels/P1/P1.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -72,7 +72,7 @@ Foam::radiation::P1::P1(const volScalarField& T)
             "qr",
             mesh_.time().timeName(),
             mesh_,
-            IOobject::NO_READ,
+            IOobject::READ_IF_PRESENT,
             IOobject::AUTO_WRITE
         ),
         mesh_,
@@ -142,7 +142,7 @@ Foam::radiation::P1::P1(const dictionary& dict, const volScalarField& T)
             "qr",
             mesh_.time().timeName(),
             mesh_,
-            IOobject::NO_READ,
+            IOobject::READ_IF_PRESENT,
             IOobject::AUTO_WRITE
         ),
         mesh_,
@@ -190,12 +190,6 @@ Foam::radiation::P1::P1(const dictionary& dict, const volScalarField& T)
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::radiation::P1::~P1()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 bool Foam::radiation::P1::read()
@@ -240,19 +234,19 @@ void Foam::radiation::P1::calculate()
         fvm::laplacian(gamma, G_)
       - fvm::Sp(a_, G_)
      ==
-      - 4.0*(e_*physicoChemical::sigma*pow4(T_) ) - E_
+      - 4.0*(e_*physicoChemical::sigma*pow4(T_)) - E_
     );
 
+    // Calculate radiative heat flux on boundaries.
     volScalarField::Boundary& qrBf = qr_.boundaryFieldRef();
+    const volScalarField::Boundary& GBf = G_.boundaryField();
+    const volScalarField::Boundary& gammaBf = gamma.boundaryField();
 
-    // Calculate radiative heat flux on boundaries.
     forAll(mesh_.boundaryMesh(), patchi)
     {
-        if (!G_.boundaryField()[patchi].coupled())
+        if (!GBf[patchi].coupled())
         {
-            qrBf[patchi] =
-                -gamma.boundaryField()[patchi]
-                *G_.boundaryField()[patchi].snGrad();
+            qrBf[patchi] = -gammaBf[patchi]*GBf[patchi].snGrad();
         }
     }
 }
@@ -282,12 +276,9 @@ Foam::tmp<Foam::volScalarField> Foam::radiation::P1::Rp() const
 Foam::tmp<Foam::DimensionedField<Foam::scalar, Foam::volMesh>>
 Foam::radiation::P1::Ru() const
 {
-    const volScalarField::Internal& G =
-        G_();
-    const volScalarField::Internal E =
-        absorptionEmission_->ECont()()();
-    const volScalarField::Internal a =
-        absorptionEmission_->aCont()()();
+    const volScalarField::Internal& G = G_();
+    const volScalarField::Internal E = absorptionEmission_->ECont()()();
+    const volScalarField::Internal a = absorptionEmission_->aCont()()();
 
     return a*G - E;
 }
@@ -298,4 +289,5 @@ Foam::label Foam::radiation::P1::nBands() const
     return absorptionEmission_->nBands();
 }
 
+
 // ************************************************************************* //
diff --git a/src/thermophysicalModels/radiation/radiationModels/P1/P1.H b/src/thermophysicalModels/radiation/radiationModels/P1/P1.H
index 4b8a724434ba769c6895363a54321d5f2639c03d..b1daa691663412f89963653a56f43f353cdf2214 100644
--- a/src/thermophysicalModels/radiation/radiationModels/P1/P1.H
+++ b/src/thermophysicalModels/radiation/radiationModels/P1/P1.H
@@ -107,7 +107,7 @@ public:
 
 
     //- Destructor
-    virtual ~P1();
+    virtual ~P1() = default;
 
 
     // Member functions
diff --git a/wmake/rules/General/general b/wmake/rules/General/general
index 33df18c31c37d459c787e267347326d04ddf5062..879ed13b9b006bb9b6dfd6df1ee3320db7920c9f 100644
--- a/wmake/rules/General/general
+++ b/wmake/rules/General/general
@@ -17,7 +17,7 @@ GLIB_LIBS  =
 COMPILER_FAMILY = $(shell echo "$(WM_COMPILER)" | sed -e 's/[0-9].*//')
 DEFAULT_RULES   = $(WM_DIR)/rules/$(WM_ARCH)$(COMPILER_FAMILY)
 RULES           = $(WM_DIR)/rules/$(WM_ARCH)$(WM_COMPILER)
-WMAKE_BIN       = $(WM_DIR)/platforms/$(WM_ARCH)$(WM_COMPILER)
+WMAKE_BIN       = $(WM_PROJECT_DIR)/platforms/tools/$(WM_ARCH)$(WM_COMPILER)
 
 # Default compilation is 'Opt' - never permit an empty value
 ifeq ($(WM_COMPILE_OPTION),)
diff --git a/wmake/scripts/wrap-lemon b/wmake/scripts/wrap-lemon
index 5b01d9e77e64db1185fe9490a314a4a1efa224c3..f9080d95ce0fe81300a5bdf801db3a7f151ec163 100755
--- a/wmake/scripts/wrap-lemon
+++ b/wmake/scripts/wrap-lemon
@@ -6,11 +6,10 @@
 #   \\  /    A nd           | www.openfoam.com
 #    \\/     M anipulation  |
 #-------------------------------------------------------------------------------
-#   Copyright (C) 2019 OpenCFD Ltd.
+#   Copyright (C) 2019-2020 OpenCFD Ltd.
 #-------------------------------------------------------------------------------
 # License
-#     This file is part of OpenFOAM, licensed under GNU General Public License
-#     <http://www.gnu.org/licenses/>.
+#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
 #
 # Script
 #     wrap-lemon
@@ -31,7 +30,7 @@
 #
 #------------------------------------------------------------------------------
 
-binDir="${WMAKE_BIN:-$WM_PROJECT_DIR/wmake/platforms/$WM_ARCH$WM_COMPILER}"
+binDir="${WMAKE_BIN:-$WM_PROJECT_DIR/platforms/tools/$WM_ARCH$WM_COMPILER}"
 etcDir="${WM_DIR:-$WM_PROJECT_DIR/wmake}/etc"
 
 # Executable and skeleton locations
diff --git a/wmake/src/Allmake b/wmake/src/Allmake
index 4ef5a56975b60daf798416648f793dc31846969e..9e78c5eb5284847bdb6acf6f07914ec6c403f673 100755
--- a/wmake/src/Allmake
+++ b/wmake/src/Allmake
@@ -1,23 +1,38 @@
 #!/bin/sh
-cd "${0%/*}" || exit                    # Run from this directory
+cd "${0%/*}" || exit            # This directory (/path/project/wmake/src)
 
-if [ -z "$WM_DIR" ]                     # Require WM_DIR
+if [ -z "$WM_DIR" ]             # Require WM_DIR (/path/project/wmake)
 then
-    WM_DIR="$(\cd $(dirname $0)/.. && \pwd -L)"
+    WM_DIR="$(dirname "$(pwd -L)")"
     export WM_DIR
 fi
 
+if [ -z "$WM_PROJECT_DIR" ]     # Expect WM_PROJECT_DIR (/path/project)
+then
+    echo "Warning (${0##*/}) : No WM_PROJECT_DIR set" 1>&2
+    WM_PROJECT_DIR="${WM_DIR%/*}"
+    export WM_PROJECT_DIR
+fi
+
+if [ -z "$WM_ARCH" ] || [ -z "$WM_COMPILER" ]
+then
+    echo "Error (${0##*/}) : No WM_ARCH or WM_COMPILER set"
+    echo "    Check your OpenFOAM environment and installation"
+    exit 1
+fi
+
 case "$WM_COMPILER" in
 Mingw*)
     # Host wmake toolchain with system gcc (when cross-compiling)
     make \
         WM_COMPILER=Gcc WM_COMPILER_TYPE=system \
-        WMAKE_BIN="${WM_DIR}/platforms/${WM_ARCH}${WM_COMPILER}"
+        WMAKE_BIN="${WM_PROJECT_DIR}/platforms/tools/${WM_ARCH}${WM_COMPILER}" \
+        "$@"
     ;;
 
 *)
-    # Compile wmake toolchain
-    make
+    # Regular wmake toolchain
+    make "$@"
     ;;
 esac