diff --git a/.gitignore b/.gitignore
index 6dbeb02b5764e4217656694881b4f01af02cd48f..1b64b6e89ba109e0ab247936a6be7ab51145a13c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 *.o
 *.a
 *.aux
+optimizer/Tests/*.exe
 build
 CMakeCache.txt
 CMakeFiles
diff --git a/src/Algorithms/ParallelCyclotronTracker.cpp b/src/Algorithms/ParallelCyclotronTracker.cpp
index 0e1943b378eda1ec35aeaf58c640f57dbbd808af..25244ea458835feccf5c338267e83e9a6f88d33c 100644
--- a/src/Algorithms/ParallelCyclotronTracker.cpp
+++ b/src/Algorithms/ParallelCyclotronTracker.cpp
@@ -53,6 +53,7 @@
 #include "AbsBeamline/CyclotronValley.h"
 #include "AbsBeamline/Stripper.h"
 #include "AbsBeamline/VariableRFCavity.h"
+#include "AbsBeamline/VariableRFCavityFringeField.h"
 
 #include "AbstractObjects/Element.h"
 
@@ -829,6 +830,16 @@ void ParallelCyclotronTracker::visitVariableRFCavity(const VariableRFCavity &cav
                             "Need to define a RINGDEFINITION to use VariableRFCavity element");
 }
 
+void ParallelCyclotronTracker::visitVariableRFCavityFringeField
+                                  (const VariableRFCavityFringeField &cav) {
+    *gmsg << "Adding Variable RF Cavity with Fringe Field" << endl;
+    if (opalRing_m != NULL)
+        opalRing_m->appendElement(cav);
+    else
+        throw OpalException("ParallelCyclotronTracker::visitVariableRFCavityFringeField",
+                            "Need to define a RINGDEFINITION to use VariableRFCavity element");
+}
+
 /**
  *
  *
diff --git a/src/Algorithms/ParallelCyclotronTracker.h b/src/Algorithms/ParallelCyclotronTracker.h
index 3ecd7dc72a5788b95cd94416ee3f218b1d9199d3..4555dd546bd898df9ca2cf9e3e6644df2ed1e6c2 100644
--- a/src/Algorithms/ParallelCyclotronTracker.h
+++ b/src/Algorithms/ParallelCyclotronTracker.h
@@ -33,6 +33,7 @@ class PlanarArcGeometry;
 class Ring;
 class SBend3D;
 class VariableRFCavity;
+class VariableRFCavityFringeField;
 class Offset;
 
 // Class ParallelCyclotronTracker
@@ -177,6 +178,10 @@ public:
     /// Apply the algorithm to a VariabelRFCavity.
     virtual void visitVariableRFCavity(const VariableRFCavity &cav);
 
+    /// Apply the algorithm to a VariabelRFCavity.
+    virtual void visitVariableRFCavityFringeField
+                                      (const VariableRFCavityFringeField &cav);
+
     /// Apply the algorithm to the top-level beamline.
     //  overwrite the execute-methode from DefaultVisitor
     virtual void execute();
diff --git a/src/BasicActions/DumpEMFields.cpp b/src/BasicActions/DumpEMFields.cpp
index cded6540ab1b3c4a437a5d9a6350f67c53284dfd..9ea7d346e060d6e7ddd677b8feb563d18ef4167f 100644
--- a/src/BasicActions/DumpEMFields.cpp
+++ b/src/BasicActions/DumpEMFields.cpp
@@ -41,7 +41,7 @@ std::unordered_set<DumpEMFields*> DumpEMFields::dumpsSet_m;
 std::string DumpEMFields::dumpemfields_docstring =
 std::string("The \"DUMPEMFIELDS\" statement dumps a field map to a user-defined")+
 std::string(" field file, for checking that fields are generated correctly.")+
-std::string(" The fields are written out on a grid in Cartesian space and time.");
+std::string(" The fields are written out on a grid in space and time.");
 
 DumpEMFields::DumpEMFields() :
                     Action(20, "DUMPEMFIELDS", dumpemfields_docstring.c_str()),
@@ -196,7 +196,8 @@ void DumpEMFields::writeFields(Component* field) {
 }
 
 void DumpEMFields::checkInt(double real, std::string name, double tolerance) {
-    if (fabs(floor(real) - real) > tolerance) {
+    real += tolerance; // prevent rounding error
+    if (fabs(floor(real) - real) > 2*tolerance) {
         throw OpalException("DumpEMFields::checkInt",
                             "Value for "+name+
                             " should be an integer but a real value was found");
@@ -210,30 +211,29 @@ void DumpEMFields::checkInt(double real, std::string name, double tolerance) {
 void DumpEMFields::writeHeader(std::ofstream& fout) const {
     fout << grid_m->end().toInteger() << "\n";
     if (coordinates_m == CYLINDRICAL) {
-        fout << 1 << " r [mm]\n";
-        fout << 2 << " phi [degree]\n";
+        fout << 1 << "  r [mm]\n";
+        fout << 2 << "  phi [degree]\n";
     } else {
-        fout << 1 << " x [mm]\n";
-        fout << 2 << " y [mm]\n";
+        fout << 1 << "  x [mm]\n";
+        fout << 2 << "  y [mm]\n";
     }
-    fout << 3 << " z [mm]\n";
-    fout << 4 << " t [ns]\n";
+    fout << 3 << "  z [mm]\n";
+    fout << 4 << "  t [ns]\n";
     if (coordinates_m == CYLINDRICAL) {
-        fout << 5 << " Br [kGauss]\n";
-        fout << 6 << " Bphi [kGauss]\n";
+        fout << 5 << "  Br [kGauss]\n";
+        fout << 6 << "  Bphi [kGauss]\n";
+        fout << 7 << "  Bz [kGauss]\n";
+        fout << 8 << "  Er [MV/m]\n";
+        fout << 9 << "  Ephi [MV/m]\n";
+        fout << 10 << " Ez [MV/m]\n";
     } else {
-        fout << 5 << " Bx [kGauss]\n";
-        fout << 6 << " By [kGauss]\n";
+        fout << 5 << "  Bx [kGauss]\n";
+        fout << 6 << "  By [kGauss]\n";
+        fout << 7 << "  Bz [kGauss]\n";
+        fout << 8 << "  Ex [MV/m]\n";
+        fout << 9 << "  Ey [MV/m]\n";
+        fout << 10 << " Ez [MV/m]\n";
     }
-    fout << 7 << " Bz [kGauss]\n";
-    if (coordinates_m == CYLINDRICAL) {
-        fout << 5 << " Er [MV/m]\n";
-        fout << 6 << " Ephi [MV/m]\n";
-    } else {
-        fout << 5 << " Ex [MV/m]\n";
-        fout << 6 << " Ey [MV/m]\n";
-    }
-    fout << 10 << " Ez [MV/m]\n";
     fout << 0 << std::endl;
 }
 
diff --git a/src/Classic/AbsBeamline/BeamlineVisitor.h b/src/Classic/AbsBeamline/BeamlineVisitor.h
index 15c19cc95d8348f87ff1d03da2d089320e4c5113..1e1899c77ef93312fa32224d18963a32435d297c 100644
--- a/src/Classic/AbsBeamline/BeamlineVisitor.h
+++ b/src/Classic/AbsBeamline/BeamlineVisitor.h
@@ -54,6 +54,7 @@ class RBend;
 class RBend3D;
 class RFCavity;
 class VariableRFCavity;
+class VariableRFCavityFringeField;
 class TravelingWave;
 class RFQuadrupole;
 class SBend;
@@ -171,6 +172,10 @@ public:
     /// Apply the algorithm to a variable RF cavity.
     virtual void visitVariableRFCavity(const VariableRFCavity &) = 0;
 
+    /// Apply the algorithm to a variable RF cavity with Fringe Field.
+    virtual void visitVariableRFCavityFringeField
+                                      (const VariableRFCavityFringeField &) = 0;
+
     /// Apply the algorithm to a RF cavity.
     virtual void visitTravelingWave(const TravelingWave &) = 0;
 
diff --git a/src/Classic/AbsBeamline/CMakeLists.txt b/src/Classic/AbsBeamline/CMakeLists.txt
index 2e8dab69e68e481423d58cff3ffb92046f3e00c0..d5dfedfef8ac7dbfa68c231ef6652f7739c72922 100644
--- a/src/Classic/AbsBeamline/CMakeLists.txt
+++ b/src/Classic/AbsBeamline/CMakeLists.txt
@@ -43,6 +43,7 @@ set (_SRCS
   Stripper.cpp
   TravelingWave.cpp
   VariableRFCavity.cpp
+  VariableRFCavityFringeField.cpp
   )
 
 include_directories (
@@ -96,6 +97,7 @@ set (HDRS
     Stripper.h
     TravelingWave.h
     VariableRFCavity.h
+    VariableRFCavityFringeField.h
 )
 
 install (FILES ${HDRS} DESTINATION "${CMAKE_INSTALL_PREFIX}/include/AbsBeamline")
\ No newline at end of file
diff --git a/src/Classic/AbsBeamline/EndFieldModel/EndFieldModel.h b/src/Classic/AbsBeamline/EndFieldModel/EndFieldModel.h
index c2e0580669834bfee6f6b1ba3c6af94c6ca3e644..f276bd9971c7f2924704a7f656fbec12ddcc1eca 100644
--- a/src/Classic/AbsBeamline/EndFieldModel/EndFieldModel.h
+++ b/src/Classic/AbsBeamline/EndFieldModel/EndFieldModel.h
@@ -32,7 +32,7 @@
 #include <vector>
 
 namespace endfieldmodel {
-
+  
 class EndFieldModel {
  public:
   virtual ~EndFieldModel() {;}
diff --git a/src/Classic/AbsBeamline/EndFieldModel/Tanh.cpp b/src/Classic/AbsBeamline/EndFieldModel/Tanh.cpp
index 43ff3146535fae866ecfdb0a396eef76ff1ecff8..3aa3fed0c4ae5eff147fbb884688b12207ee51bd 100644
--- a/src/Classic/AbsBeamline/EndFieldModel/Tanh.cpp
+++ b/src/Classic/AbsBeamline/EndFieldModel/Tanh.cpp
@@ -104,5 +104,11 @@ std::vector< std::vector<int> > Tanh::getTanhDiffIndices(size_t n) {
   return _tdi[n];
 }
 
+
+std::ostream& Tanh::print(std::ostream& out) const {
+    out << "Tanh model with centre length: " << _x0 
+        << " end length: " << _lambda;
+    return out;
+}
 }
 
diff --git a/src/Classic/AbsBeamline/EndFieldModel/Tanh.h b/src/Classic/AbsBeamline/EndFieldModel/Tanh.h
index b3418eb46b632f3df48db46082824b6493bb61b9..7d441f2d32b45cc5d40881dab66d7a579660a795 100644
--- a/src/Classic/AbsBeamline/EndFieldModel/Tanh.h
+++ b/src/Classic/AbsBeamline/EndFieldModel/Tanh.h
@@ -101,7 +101,7 @@ class Tanh : public EndFieldModel {
     inline void setX0(double x0)     {_x0 = x0;}
 
     /** Bug - does nothing */
-    std::ostream& print(std::ostream& out) const {return out;}
+    std::ostream& print(std::ostream& out) const;
   private:
     double _x0, _lambda;
 
diff --git a/src/Classic/AbsBeamline/SpecificElementVisitor.h b/src/Classic/AbsBeamline/SpecificElementVisitor.h
index 62af615761fd52a80b135300bed27462fca86e71..6c2fe198c48f16accc372245e5bac3b8d04233aa 100644
--- a/src/Classic/AbsBeamline/SpecificElementVisitor.h
+++ b/src/Classic/AbsBeamline/SpecificElementVisitor.h
@@ -27,6 +27,7 @@
 #include "AbsBeamline/Ring.h"
 #include "AbsBeamline/RFCavity.h"
 #include "AbsBeamline/VariableRFCavity.h"
+#include "AbsBeamline/VariableRFCavityFringeField.h"
 #include "AbsBeamline/TravelingWave.h"
 #include "AbsBeamline/RFQuadrupole.h"
 #include "AbsBeamline/SBend.h"
@@ -139,6 +140,10 @@ public:
     /// Apply the algorithm to a RF cavity.
     virtual void visitVariableRFCavity(const VariableRFCavity &vcav);
 
+    /// Apply the algorithm to a RF cavity.
+    virtual void visitVariableRFCavityFringeField
+                                      (const VariableRFCavityFringeField &vcav);
+
     /// Apply the algorithm to a RF cavity.
     virtual void visitRFCavity(const RFCavity &);
 
@@ -348,10 +353,18 @@ void SpecificElementVisitor<ELEM>::visitRBend3D(const RBend3D &element) {
 }
 
 template<class ELEM>
-void SpecificElementVisitor<ELEM>::visitVariableRFCavity(const VariableRFCavity &element) {
+void SpecificElementVisitor<ELEM>::visitVariableRFCavity
+                                             (const VariableRFCavity &element) {
     CastsTrait<ELEM, VariableRFCavity>::apply(allElementsOfTypeE, element);
 }
 
+template<class ELEM>
+void SpecificElementVisitor<ELEM>::visitVariableRFCavityFringeField
+                                  (const VariableRFCavityFringeField &element) {
+    CastsTrait<ELEM, VariableRFCavityFringeField>::apply(allElementsOfTypeE,
+                                                         element);
+}
+
 template<class ELEM>
 void SpecificElementVisitor<ELEM>::visitRFCavity(const RFCavity &element) {
     CastsTrait<ELEM, RFCavity>::apply(allElementsOfTypeE, element);
diff --git a/src/Classic/AbsBeamline/VariableRFCavity.cpp b/src/Classic/AbsBeamline/VariableRFCavity.cpp
index 4cc23ebd3bd379f30e488f9f7a46b8f3beecf40a..41a681e4a6db669ca8a26a997e24a30ad4950332 100644
--- a/src/Classic/AbsBeamline/VariableRFCavity.cpp
+++ b/src/Classic/AbsBeamline/VariableRFCavity.cpp
@@ -55,13 +55,13 @@ VariableRFCavity& VariableRFCavity::operator=(const VariableRFCavity& rhs) {
     setPhaseModel(NULL);
     setAmplitudeModel(NULL);
     setFrequencyModel(NULL);
-    if (rhs._phase_td != NULL)
-        setPhaseModel(std::shared_ptr<AbstractTimeDependence>(rhs._phase_td->clone()));
-    if (rhs._amplitude_td != NULL) {
-        setAmplitudeModel(std::shared_ptr<AbstractTimeDependence>(rhs._amplitude_td->clone()));
+    if (rhs.phaseTD_m != NULL)
+        setPhaseModel(std::shared_ptr<AbstractTimeDependence>(rhs.phaseTD_m->clone()));
+    if (rhs.amplitudeTD_m != NULL) {
+        setAmplitudeModel(std::shared_ptr<AbstractTimeDependence>(rhs.amplitudeTD_m->clone()));
     }
-    if (rhs._frequency_td != NULL)
-        setFrequencyModel(std::shared_ptr<AbstractTimeDependence>(rhs._frequency_td->clone()));
+    if (rhs.frequencyTD_m != NULL)
+        setFrequencyModel(std::shared_ptr<AbstractTimeDependence>(rhs.frequencyTD_m->clone()));
     phaseName_m = rhs.phaseName_m;
     amplitudeName_m = rhs.amplitudeName_m;
     frequencyName_m = rhs.frequencyName_m;
@@ -86,27 +86,27 @@ void VariableRFCavity::initNull() {
 }
 
 std::shared_ptr<AbstractTimeDependence> VariableRFCavity::getAmplitudeModel() const {
-    return _amplitude_td;
+    return amplitudeTD_m;
 }
 
 std::shared_ptr<AbstractTimeDependence> VariableRFCavity::getPhaseModel() const {
-    return _phase_td;
+    return phaseTD_m;
 }
 
 std::shared_ptr<AbstractTimeDependence> VariableRFCavity::getFrequencyModel() const {
-    return _frequency_td;
+    return frequencyTD_m;
 }
 
 void VariableRFCavity::setAmplitudeModel(std::shared_ptr<AbstractTimeDependence> amplitude_td) {
-    _amplitude_td = amplitude_td;
+    amplitudeTD_m = amplitude_td;
 }
 
 void VariableRFCavity::setPhaseModel(std::shared_ptr<AbstractTimeDependence> phase_td) {
-    _phase_td = phase_td;
+    phaseTD_m = phase_td;
 }
 
 void VariableRFCavity::setFrequencyModel(std::shared_ptr<AbstractTimeDependence> frequency_td) {
-    _frequency_td = frequency_td;
+    frequencyTD_m = frequency_td;
 }
 
 StraightGeometry &VariableRFCavity::getGeometry() {
@@ -146,9 +146,9 @@ bool VariableRFCavity::apply(const Vector_t &R, const Vector_t &P,
             return true;
         }
 
-        double E0 = _amplitude_td->getValue(t);
-        double f = _frequency_td->getValue(t) * 1.0E-3; // need GHz on the element we have MHz
-        double phi = _phase_td->getValue(t);
+        double E0 = amplitudeTD_m->getValue(t);
+        double f = frequencyTD_m->getValue(t) * 1.0E-3; // need GHz on the element we have MHz
+        double phi = phaseTD_m->getValue(t);
         E = Vector_t(0., 0., E0*sin(Physics::two_pi * f * t + phi));
         return false;
     }
@@ -173,6 +173,11 @@ ElementBase* VariableRFCavity::clone() const {
 }
 
 void VariableRFCavity::accept(BeamlineVisitor& visitor) const {
+    initialise();
+    visitor.visitVariableRFCavity(*this);
+}
+
+void VariableRFCavity::initialise() const {
     VariableRFCavity* cavity = const_cast<VariableRFCavity*>(this);
     std::shared_ptr<AbstractTimeDependence> phaseTD =
                     AbstractTimeDependence::getTimeDependence(phaseName_m);
@@ -183,7 +188,6 @@ void VariableRFCavity::accept(BeamlineVisitor& visitor) const {
         std::shared_ptr<AbstractTimeDependence> amplitudeTD =
                     AbstractTimeDependence::getTimeDependence(amplitudeName_m);
     cavity->setAmplitudeModel(std::shared_ptr<AbstractTimeDependence>(amplitudeTD->clone()));
-    visitor.visitVariableRFCavity(*this);
 
     if (halfHeight_m < 1e-9 || halfWidth_m < 1e-9)
         throw GeneralClassicException("VariableRFCavity::accept",
diff --git a/src/Classic/AbsBeamline/VariableRFCavity.h b/src/Classic/AbsBeamline/VariableRFCavity.h
index 7a319151277909b3d501ff439aa4ce5b01ac1fcd..ead071aa6d29007624adb84326fc579e5fa66bdd 100644
--- a/src/Classic/AbsBeamline/VariableRFCavity.h
+++ b/src/Classic/AbsBeamline/VariableRFCavity.h
@@ -39,7 +39,7 @@ class Fieldmap;
  *
  *  Generates a field like
  *      E = E0*a(t)*sin{f(t)*t-q(t)}
- *      B = B0*a(t)*cos{f(t)*t-q(t)}
+ *      B = 0
  *  where E0, B0 are user defined fields, a(t), f(t), q(t) are time
  *  dependent amplitude, frequency, phase respectively; it is assumed that these
  *  quantities vary sufficiently slowly that Maxwell is satisfied.
@@ -208,9 +208,11 @@ class VariableRFCavity: public Component {
     /// Not implemented
     virtual const EMField &getField() const;
   protected:
-    std::shared_ptr<AbstractTimeDependence> _phase_td;
-    std::shared_ptr<AbstractTimeDependence> _amplitude_td;
-    std::shared_ptr<AbstractTimeDependence> _frequency_td;
+    void initNull();
+    void initialise() const;
+    std::shared_ptr<AbstractTimeDependence> phaseTD_m;
+    std::shared_ptr<AbstractTimeDependence> amplitudeTD_m;
+    std::shared_ptr<AbstractTimeDependence> frequencyTD_m;
     std::string phaseName_m;
     std::string amplitudeName_m;
     std::string frequencyName_m;
@@ -221,21 +223,19 @@ class VariableRFCavity: public Component {
     StraightGeometry geometry;
     static const double lengthUnit_m;
 
-  private:
-    void initNull();
-
+private:
 };
 
 double VariableRFCavity::getAmplitude(double time) const {
-    return _amplitude_td->getValue(time);
+    return amplitudeTD_m->getValue(time);
 }
 
 double VariableRFCavity::getPhase(double time) const {
-    return _phase_td->getValue(time);
+    return phaseTD_m->getValue(time);
 }
 
 double VariableRFCavity::getFrequency(double time) const {
-    return _frequency_td->getValue(time);
+    return frequencyTD_m->getValue(time);
 }
 
 double VariableRFCavity::getHeight() const {
diff --git a/src/Classic/AbsBeamline/VariableRFCavityFringeField.cpp b/src/Classic/AbsBeamline/VariableRFCavityFringeField.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c5c6712a10a5d8c7c0affa2a0663ba03a4789a94
--- /dev/null
+++ b/src/Classic/AbsBeamline/VariableRFCavityFringeField.cpp
@@ -0,0 +1,233 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Physics/Physics.h"
+#include "Algorithms/PartBunchBase.h"
+#include "AbsBeamline/BeamlineVisitor.h"
+
+#include "AbsBeamline/EndFieldModel/EndFieldModel.h"
+#include "AbsBeamline/VariableRFCavityFringeField.h"
+
+VariableRFCavityFringeField::VariableRFCavityFringeField(const std::string &name) : VariableRFCavity(name) {
+    initNull();  // initialise everything to NULL
+}
+
+VariableRFCavityFringeField::VariableRFCavityFringeField() : VariableRFCavity() {
+    initNull();  // initialise everything to NULL
+}
+
+VariableRFCavityFringeField::VariableRFCavityFringeField(const VariableRFCavityFringeField& var) : VariableRFCavity() {
+    initNull();  // initialise everything to NULL
+    *this = var;
+}
+
+VariableRFCavityFringeField& VariableRFCavityFringeField::operator=(const VariableRFCavityFringeField& rhs) {
+  
+    if (&rhs == this) {
+        return *this;
+    }
+    VariableRFCavity::operator=(rhs);
+    setEndField(rhs.endField_m);
+    zCentre_m = rhs.zCentre_m;
+    f_m = rhs.f_m;
+    g_m = rhs.f_m;
+    h_m = rhs.f_m;
+    return *this;
+}
+
+VariableRFCavityFringeField::~VariableRFCavityFringeField() {
+}
+
+ElementBase* VariableRFCavityFringeField::clone() const {
+    return new VariableRFCavityFringeField(*this);
+}
+
+void VariableRFCavityFringeField::initNull() {
+    VariableRFCavity::initNull();
+    endField_m = std::shared_ptr<endfieldmodel::EndFieldModel>();
+    zCentre_m = 0;
+}
+
+void VariableRFCavityFringeField::accept(BeamlineVisitor& visitor) const {
+    VariableRFCavity::initialise();
+    VariableRFCavityFringeField* cavity =
+                                 const_cast<VariableRFCavityFringeField*>(this);
+    cavity->initialiseCoefficients();
+    visitor.visitVariableRFCavity(*this);
+}
+
+bool VariableRFCavityFringeField::apply(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) {
+    if (R[2] > _length || R[2] < 0.) {
+        return true;
+    }
+    if (std::abs(R[0]) > halfWidth_m || std::abs(R[1]) > halfHeight_m) {
+        return true;
+    }
+    double z_pos = R[2]-zCentre_m;
+    double E0 = amplitudeTD_m->getValue(t);
+    double omega = Physics::two_pi*frequencyTD_m->getValue(t) * 1.0E-3; // need GHz on the element we have MHz
+    double phi = phaseTD_m->getValue(t);
+    double E_sin_t = E0*sin(omega * t + phi);
+    double B_cos_t = E0*cos(omega * t + phi); // 1/c^2 factor in the h_n coefficients
+
+    std::vector<double> y_power(maxOrder_m+1, 0.);
+    y_power[0] = 1.;
+    for (size_t i = 1; i < y_power.size(); ++i) {
+        y_power[i] = y_power[i-1]*R[1];
+    }
+
+    // d^i f0 dz^i
+    std::vector<double> endField(maxOrder_m/2+2, 0.);
+    for (size_t i = 0; i < endField.size(); ++i) {
+        endField[i] = endField_m->function(z_pos, i);
+    }
+
+    // omega^i
+    std::vector<double> omegaPower(maxOrder_m+1, 1.);
+    for (size_t i = 1; i < omegaPower.size(); ++i) {
+        omegaPower[i] = omegaPower[i-1]*omega;
+    }
+
+    E = Vector_t(0., 0., 0.);
+    B = Vector_t(0., 0., 0.);
+    // even power of y
+    for (size_t n = 0; n <= maxOrder_m ; n += 2) { // power of y
+        double fCoeff = 0.;
+        size_t index = n/2;
+        for (size_t i = 0; i < f_m[index].size(); i += 2) { // derivative of f
+            fCoeff += f_m[index][i]*endField[i]*omegaPower[n-i];
+        }
+        E[2] += E_sin_t*y_power[n]*fCoeff;
+    }
+    // odd power of y
+    for (size_t n = 1; n <= maxOrder_m; n += 2) {
+        double gCoeff = 0.;
+        double hCoeff = 0.;
+        size_t index = (n-1)/2;
+        //std::cerr << "n: " << n << std::endl;
+        for (size_t j = 0; j < g_m[index].size(); ++j) {
+            gCoeff += g_m[index][j]*endField[j]*omegaPower[n-j];
+        }
+        for (size_t j = 0; j < h_m[index].size(); ++j) {
+            hCoeff += h_m[index][j]*endField[j]*omegaPower[n-j];
+            //std::cerr << "j: " << j << " " << hCoeff << " ";
+        }
+        //std::cerr << std::endl;
+        E[1] += E_sin_t*y_power[n]*gCoeff;
+        B[0] += B_cos_t*y_power[n]*hCoeff;
+        //std::cerr << "APPLY B " << n << " " << B[0] << " " << hCoeff << std::endl;
+    }
+    B *= 1e4; //B natural units are kT; convert to kGauss
+    return false;
+}
+
+bool VariableRFCavityFringeField::apply(const size_t &i, const double &t,
+                             Vector_t &E, Vector_t &B) {
+    return apply(RefPartBunch_m->R[i], RefPartBunch_m->P[i], t, E, B);
+}
+
+bool VariableRFCavityFringeField::applyToReferenceParticle(const Vector_t &R,
+                                                           const Vector_t &P,
+                                                           const double &t,
+                                                           Vector_t &E,
+                                                           Vector_t &B) {
+    return apply(R, P, t, E, B);
+}
+
+void VariableRFCavityFringeField::initialise(PartBunchBase<double, 3> *bunch,
+                                             double &startField,
+                                             double &endField) {
+    VariableRFCavity::initialise(bunch, startField, endField);
+    initialiseCoefficients();
+}
+
+void printVector(std::ostream& out, std::vector< std::vector<double> > vec) {
+    for (size_t i = 0; i < vec.size(); ++i) {
+        out << std::setw(3) << i;
+        for (size_t j = 0; j < vec[i].size(); ++j) {
+          out << " " << std::setw(14) << vec[i][j];
+        }
+        out << std::endl;
+    }
+}
+
+void VariableRFCavityFringeField::initialiseCoefficients() {
+    f_m = std::vector< std::vector<double> >();
+    g_m = std::vector< std::vector<double> >();
+    h_m = std::vector< std::vector<double> >();
+    f_m.push_back(std::vector<double>(1, 1.));
+    double c_l = Physics::c*1e-6; // speed of light in mm/ns
+    // generate f_{n+2} term
+    // note frequency term has to be added at apply(time) as we have
+    // time-dependent frequency
+    for(size_t n = 0; n+2 <= maxOrder_m; n += 2) {
+        // n denotes the subscript on f_n
+        // n+2 is the subscript on g_{n+2} and terms proportional to y^{n+2}
+        std::vector<double> f_n = f_m.back(); // f_n
+        std::vector<double> f_np2 = std::vector<double>(f_n.size()+2, 0.); // f_{n+2}
+        double n_const = 1./(n+1.)/(n+2.);
+        for (size_t j = 0; j < f_n.size(); ++j) {
+            f_np2[j] += f_n[j]*n_const/c_l/c_l;
+        }
+        for (size_t j = 0; j < f_n.size(); ++j) {
+            f_np2[j+2] += f_n[j]*n_const;
+        }
+        f_m.push_back(f_np2);
+    }
+    // generate g_{n+2} and h_{n+2} term
+    for(size_t n = 0; n+1 <= maxOrder_m; n += 2) {
+        // n denotes the subscript on f_n
+        // n+1 is the subscript on g_{n+1} and terms proportional to y^{n+1}
+        size_t f_index = n/2;
+        std::vector<double> f_n = f_m[f_index];
+        std::vector<double> g_np1 = std::vector<double>(f_n.size()+1, 0.);
+        std::vector<double> h_np1 = std::vector<double>(f_n.size(), 0.);
+        for (size_t j = 0; j < f_n.size(); ++j) {
+            g_np1[j+1] = -1./(n+1.)*f_n[j];
+            h_np1[j] = -1./c_l/c_l/(n+1.)*f_n[j];
+        }
+        g_m.push_back(g_np1);
+        h_m.push_back(h_np1);
+    }
+}
+
+void VariableRFCavityFringeField::printCoefficients(std::ostream& out) const {
+    out << "f_m" << std::endl;
+    printVector(out, f_m);
+    out << "g_m" << std::endl;
+    printVector(out, g_m);
+    out << "h_m" << std::endl;
+    printVector(out, h_m);
+    out << std::endl;
+}
+
+
+
+void VariableRFCavityFringeField::setEndField(
+                            std::shared_ptr<endfieldmodel::EndFieldModel> end) {
+    endField_m = end;
+}
diff --git a/src/Classic/AbsBeamline/VariableRFCavityFringeField.h b/src/Classic/AbsBeamline/VariableRFCavityFringeField.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0480e820251f51c546fdf789a63ce281d6602f8
--- /dev/null
+++ b/src/Classic/AbsBeamline/VariableRFCavityFringeField.h
@@ -0,0 +1,210 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CLASSIC_ABSBEAMLINE_VariableRFCavityFringeField_HH
+#define CLASSIC_ABSBEAMLINE_VariableRFCavityFringeField_HH
+
+#include <iostream>
+#include "AbsBeamline/VariableRFCavity.h"
+
+class Fieldmap;
+namespace endfieldmodel {
+    class EndFieldModel;
+}
+
+/** @class VariableRFCavityFringeField
+ *
+ *  Generates a field like
+ *      Ey = E0*a(t)*y^{2n+1} g_n(z) sin{f(t)*t-q(t)}
+ *      Ez = E0*a(t)*y^{2n}   f_n(z) sin{f(t)*t-q(t)}
+ *      Bx = B0*a(t)*y^{2n+1} h_n(z) cos{f(t)*t-q(t)}
+ *  where E0, is a user-defined field and B0 is the corresponding magnetic field
+ *  magnitude; f_n is a user-defined axial field dependence and g_n, h_n are the
+ *  corresponding off-axis field dependencies. a(t), f(t), q(t) are time
+ *  dependent amplitude, frequency, phase respectively; it is assumed that these
+ *  quantities vary sufficiently slowly that Maxwell is satisfied.
+ *
+ *  Inherits from VariableRFCavity; inheritance is used here to share code from
+ *  VariableRFCavity.
+ *
+ *  Set/get methods use metres; but internally we store as mm (for tracking)
+ * 
+ *  Field units are kG and GV/mm
+ */
+class VariableRFCavityFringeField : public VariableRFCavity {
+  public:
+    /// Constructor with given name.
+    explicit VariableRFCavityFringeField(const std::string &name);
+    /** Copy Constructor; performs deepcopy on time-dependence models */
+    VariableRFCavityFringeField(const VariableRFCavityFringeField &);
+    /** Default constructor */
+    VariableRFCavityFringeField();
+    /** Assignment operator; performs deepcopy on time-dependence models*/
+    VariableRFCavityFringeField& operator=(const VariableRFCavityFringeField &);
+    /** Destructor does nothing
+     * 
+     * The shared_ptrs will self-destruct when reference count goes to 0
+     */
+    virtual ~VariableRFCavityFringeField();
+
+    /** Apply visitor to RFCavity.
+     *
+     *  The RF cavity finds the "time dependence" models by doing a string
+     *  lookup against a list held by AbstractTimeDependence at accept time.
+     */
+    virtual void accept(BeamlineVisitor &) const;
+
+    /** Inheritable deepcopy method */
+    virtual ElementBase* clone() const;
+
+    /** Calculate the field at the position of the i^th particle 
+     *
+     *  @param i indexes the particle whose field we need
+     *  @param t the time at which the field is calculated
+     *  @param E return value with electric field strength
+     *  @param B return value with magnetic field strength
+     *
+     *  @returns True if particle is outside the boundaries; else False
+     */
+    virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B);
+
+    /** Calculate the field at a given position
+     *
+     *  @param R the position at which the field is calculated
+     *  @param P the momentum (not used)
+     *  @param t the time at which the field is calculated
+     *  @param E return value; filled with electric field strength
+     *  @param B return value; filled with magnetic field strength
+     *
+     *  @returns True if particle is outside the boundaries; else False
+     */
+    virtual bool apply(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B);
+
+
+    /** Calculate the field at a given position. This is identical to "apply".
+     *
+     *  @param R the position at which the field is calculated
+     *  @param P the momentum (not used)
+     *  @param t the time at which the field is calculated
+     *  @param E return value; filled with electric field strength
+     *  @param B return value; filled with magnetic field strength
+     *
+     *  @returns True if particle is outside the boundaries; else False
+     */
+    virtual bool applyToReferenceParticle(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B);
+
+    /** Set the endFieldModel
+     *
+     *  @param endField the new endFieldModel. VariableRFCavityFringe takes
+     *  ownership of the memory allocated to endField.
+     */
+    virtual void setEndField
+                       (std::shared_ptr<endfieldmodel::EndFieldModel> endField);
+
+    /** Get the endFieldModel
+     * 
+     *  @returns the endFieldModel; VariableRFCavityFringe retains ownership of
+     *  the memory allocated to the endFieldModel.
+     */
+    virtual inline std::shared_ptr<endfieldmodel::EndFieldModel>
+                                                            getEndField() const;
+
+    /** Initialise ready for tracking
+     * 
+     *  Does any setup on VirtualRFCavity and sets field expansion coefficients
+     */
+    virtual void initialise(PartBunchBase<double, 3> *bunch,
+                            double &startField,
+                            double &endField);
+
+    /** Get the offset of centre of the cavity field from the element start in metres */
+    virtual inline void setCavityCentre(double zCentre);
+    /** Set the offset of centre of the cavity field from the element start in metres */
+    virtual inline double getCavityCentre() const;
+    /** Set the maximum y power */
+    virtual inline void setMaxOrder(size_t maxOrder);
+    /** Get the maximum y power that will be used in field calculations */
+    virtual inline size_t getMaxOrder() const;
+    /** Set the coefficients for calculating the field expansion */
+    void initialiseCoefficients();
+    /** Print the coefficients to ostream out */
+    void printCoefficients(std::ostream& out) const;
+    /** Get the coefficients for Ez */
+    inline std::vector<std::vector<double> > getEzCoefficients() const;
+    /** Get the coefficients for Ey */
+    inline std::vector<std::vector<double> > getEyCoefficients() const;
+    /** Get the coefficients for Bx */
+    inline std::vector<std::vector<double> > getBxCoefficients() const;
+protected:
+    double zCentre_m; // offsets this element
+    size_t maxOrder_m;
+    std::shared_ptr<endfieldmodel::EndFieldModel> endField_m;
+    std::vector<std::vector<double> > f_m;
+    std::vector<std::vector<double> > g_m;
+    std::vector<std::vector<double> > h_m;
+private:
+    void initNull();
+};
+
+void VariableRFCavityFringeField::setCavityCentre(double zCentre) {
+    zCentre_m = zCentre*1000.; // stored internally as mm
+}
+
+double VariableRFCavityFringeField::getCavityCentre() const {
+    return zCentre_m/1000.; // stored internally as mm
+}
+
+void VariableRFCavityFringeField::setMaxOrder(size_t maxOrder) {
+    maxOrder_m = maxOrder;
+    initialiseCoefficients();
+}
+
+size_t VariableRFCavityFringeField::getMaxOrder() const {
+    return maxOrder_m;
+}
+
+std::shared_ptr<endfieldmodel::EndFieldModel>
+                              VariableRFCavityFringeField::getEndField() const {
+    return endField_m;
+}
+
+std::vector<std::vector<double> >
+                        VariableRFCavityFringeField::getEzCoefficients() const {
+    return f_m;
+}
+
+std::vector<std::vector<double> >
+                        VariableRFCavityFringeField::getEyCoefficients() const {
+    return g_m;
+}
+
+std::vector<std::vector<double> >
+                        VariableRFCavityFringeField::getBxCoefficients() const {
+    return h_m;
+}
+
+#endif // #ifdef CLASSIC_VirtualRFCavityFringeField_HH
\ No newline at end of file
diff --git a/src/Classic/Algorithms/AbstractTimeDependence.cpp b/src/Classic/Algorithms/AbstractTimeDependence.cpp
index 118634d80a53edee2f894c026de43bccb32e4d25..188230a5f43e773cb14be0c1514072502d6121a7 100644
--- a/src/Classic/Algorithms/AbstractTimeDependence.cpp
+++ b/src/Classic/Algorithms/AbstractTimeDependence.cpp
@@ -1,3 +1,30 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "Algorithms/AbstractTimeDependence.h"
 #include "Utilities/GeneralClassicException.h"
 
@@ -17,9 +44,6 @@ std::shared_ptr<AbstractTimeDependence> AbstractTimeDependence::getTimeDependenc
 
 void AbstractTimeDependence::setTimeDependence(std::string name,
                                                std::shared_ptr<AbstractTimeDependence> time_dep) {
-    // if (td_map.find(name) != td_map.end()) {
-    //     delete td_map[name];
-    // }
     td_map[name] = time_dep;
 }
 
diff --git a/src/Classic/Algorithms/AbstractTimeDependence.h b/src/Classic/Algorithms/AbstractTimeDependence.h
index f63f34ff5c3f87fd8fdfe7f7d304a30b9905692b..d36671870c0eb70877d5eaf7251677c650ba3c67 100644
--- a/src/Classic/Algorithms/AbstractTimeDependence.h
+++ b/src/Classic/Algorithms/AbstractTimeDependence.h
@@ -1,3 +1,30 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #ifndef _CLASSIC_SRC_ALGORITHMS_ABSTRACTTIMEDEPENDENCE_H_
 #define _CLASSIC_SRC_ALGORITHMS_ABSTRACTTIMEDEPENDENCE_H_
 
@@ -5,22 +32,64 @@
 #include <map>
 #include <memory>
 
-/** Time dependence abstraction for field parameters that vary slowly with time
+/** @class AbstractTimeDependence
+ * 
+ *  Time dependence abstraction for field parameters that vary slowly with time;
+ *  for example, in RF cavities for synchrotrons the RF frequency varies to
+ *  match the time-of-flight of the particles
+ * 
+ *  This base class stores a mapping of string to time dependence. At Visit
+ *  time, we do a map look-up to assign the appropriate TimeDependence to the
+ *  relevant field Elements.
  */
 class AbstractTimeDependence {
   // Unit tests for this class are in with PolynomialTimeDependence
   public:
+    /** Destructor does nothing */
     virtual ~AbstractTimeDependence() {}
-    virtual AbstractTimeDependence* clone() = 0;
+    /** Inheritable copy constructor
+     *
+     *  @returns new AbstractTimeDependence that is a copy of this. User owns
+     *  returned memory.
+     */
+     virtual AbstractTimeDependence* clone() = 0;
+
+    /** getValue(time) returns the value as a function of time.
+     *
+     *  This could represent RF voltage or frequency, magnetic field strength 
+     *  etc
+     */
     virtual double getValue(double time) = 0;
 
-    static std::shared_ptr<AbstractTimeDependence> getTimeDependence(std::string name);
+    /** Look up the time dependence that has a given name
+     *  
+     *  @param name name of the time dependence
+     * 
+     *  @returns shared_ptr to the appropriate time dependence.
+     *  @throws GeneralClassicException if name is not recognised
+     */
+    static std::shared_ptr<AbstractTimeDependence>
+                                            getTimeDependence(std::string name);
+
+    /** Add a value to the lookup table
+     *  
+     *  @param name name of the time dependence. If name already exists in the
+     *  map, it is overwritten with the new value.
+     *  @param time_dep shared_ptr to the time dependence.
+     */
     static void setTimeDependence(std::string name,
-                                  std::shared_ptr<AbstractTimeDependence> time_dep);
+                              std::shared_ptr<AbstractTimeDependence> time_dep);
 
-    /** Reverse the mapping - slow
+    /** Get the name corresponding to a given time_dep
+     *
+     *  @param time_dep time dependence to lookup
+     *
+     *  @returns name corresponding to the time dependence. Note that this
+     *  just does a dumb loop over the stored map values; so O(N).
+     *  @throws GeneralClassicException if time_dep is not recognised
      */
-    static std::string getName(std::shared_ptr<AbstractTimeDependence> time_dep);
+    static std::string getName
+                             (std::shared_ptr<AbstractTimeDependence> time_dep);
 
   private:
     static std::map<std::string, std::shared_ptr<AbstractTimeDependence> > td_map;
diff --git a/src/Classic/Algorithms/DefaultVisitor.cpp b/src/Classic/Algorithms/DefaultVisitor.cpp
index 2125b2f0f51c84d4bdfc24dc3a7c9b96bf073cd9..d47e6d0a0d710b33ec1fb71b0a85a18cd8597227 100644
--- a/src/Classic/Algorithms/DefaultVisitor.cpp
+++ b/src/Classic/Algorithms/DefaultVisitor.cpp
@@ -42,6 +42,7 @@
 #include "AbsBeamline/RBend3D.h"
 #include "AbsBeamline/RFCavity.h"
 #include "AbsBeamline/VariableRFCavity.h"
+#include "AbsBeamline/VariableRFCavityFringeField.h"
 #include "AbsBeamline/TravelingWave.h"
 #include "AbsBeamline/RFQuadrupole.h"
 #include "AbsBeamline/SBend.h"
@@ -180,6 +181,11 @@ void DefaultVisitor::visitVariableRFCavity(const VariableRFCavity &vcav) {
     applyDefault(vcav);
 }
 
+void DefaultVisitor::visitVariableRFCavityFringeField
+                                (const VariableRFCavityFringeField &vcav) {
+    applyDefault(vcav);
+}
+
 void DefaultVisitor::visitRFCavity(const RFCavity &cav) {
     applyDefault(cav);
 }
diff --git a/src/Classic/Algorithms/DefaultVisitor.h b/src/Classic/Algorithms/DefaultVisitor.h
index 3006f0e9381430d99e654d05229abf2e85266166..270ff1d6d33835277c3c5a8d33e52a1519da70de 100644
--- a/src/Classic/Algorithms/DefaultVisitor.h
+++ b/src/Classic/Algorithms/DefaultVisitor.h
@@ -115,6 +115,9 @@ public:
     /// Apply the algorithm to a RF cavity.
     virtual void visitVariableRFCavity(const VariableRFCavity &vcav);
 
+    /// Apply the algorithm to a RF cavity.
+    virtual void visitVariableRFCavityFringeField(const VariableRFCavityFringeField &vcav);
+
     /// Apply the algorithm to a RF cavity.
     virtual void visitRFCavity(const RFCavity &);
 
diff --git a/src/Classic/Algorithms/PolynomialTimeDependence.cpp b/src/Classic/Algorithms/PolynomialTimeDependence.cpp
index d0d270ac977457b4b6400a72ae4794c710a64fab..00a07a7bffbec68b1785b771f2d03c3087be900d 100644
--- a/src/Classic/Algorithms/PolynomialTimeDependence.cpp
+++ b/src/Classic/Algorithms/PolynomialTimeDependence.cpp
@@ -1,3 +1,30 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "Algorithms/PolynomialTimeDependence.h"
 
 Inform &PolynomialTimeDependence::print(Inform &os) {
diff --git a/src/Classic/Algorithms/PolynomialTimeDependence.h b/src/Classic/Algorithms/PolynomialTimeDependence.h
index f7d11aa9fb58ccbeae0eb3813f14f9bc824824ad..ac2e7abaa31ee5dc91cf7eb83241169dbd1fd016 100644
--- a/src/Classic/Algorithms/PolynomialTimeDependence.h
+++ b/src/Classic/Algorithms/PolynomialTimeDependence.h
@@ -1,3 +1,30 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #ifndef _CLASSIC_SRC_ALGORITHMS_POLYNOMIALTIMEDEPENDENCE_H_
 #define _CLASSIC_SRC_ALGORITHMS_POLYNOMIALTIMEDEPENDENCE_H_
 
@@ -6,18 +33,42 @@
 #include "Ippl.h"
 #include "Algorithms/AbstractTimeDependence.h"
 
+
+/** @class PolynomialTimeDependence
+ * 
+ *  Time dependence that follows a polynomial, like 
+ *      p_0 + p_1*t + p_2*t^2 + ... + p_i*t^i + ...
+ */
 class PolynomialTimeDependence : public AbstractTimeDependence {
   public:
+    /** Constructor
+     * 
+     *  @param ptd the polynomial coefficients p_i; can be of arbitrary length
+     *  (user is responsible for issues like floating point precision).
+     */
     PolynomialTimeDependence(std::vector<double> ptd) : coeffs(ptd) {}
+
+    /** Default Constructor makes a 0 length polynomial */
     PolynomialTimeDependence() {}
+    /** Destructor does nothing */
     ~PolynomialTimeDependence() {}
+    /** Return the polynomial Sum_i p_i t^i; returns 0 if p is of 0 length */
     inline double getValue(double time);
+    /** Inheritable copy constructor
+     *
+     *  @returns new PolynomialTimeDependence that is a copy of this. User owns
+     *  returned memory.
+     */
     PolynomialTimeDependence* clone() {
       std::vector<double> temp(coeffs);
       PolynomialTimeDependence* d = new PolynomialTimeDependence(temp);
       return d;
     }
 
+    /** Print the polynomials
+     *  
+     *  @param os "Inform" stream to which the polynomials are printed.
+     */
     Inform &print(Inform &os);
 
   private:
diff --git a/src/Elements/CMakeLists.txt b/src/Elements/CMakeLists.txt
index 826582a49f5e4b3ac462f1e1acb873e7a303bdff..5677cc467488f6979ab1c134a30cfd604253f630 100644
--- a/src/Elements/CMakeLists.txt
+++ b/src/Elements/CMakeLists.txt
@@ -45,6 +45,7 @@ set (_SRCS
   OpalSource.cpp
   OpalSRot.cpp
   OpalVariableRFCavity.cpp
+  OpalVariableRFCavityFringeField.cpp
   OpalVKicker.cpp
   OpalVMonitor.cpp
   OpalYRot.cpp
@@ -105,6 +106,7 @@ set (HDRS
     OpalStripper.h
     OpalTravelingWave.h
     OpalVariableRFCavity.h
+    OpalVariableRFCavityFringeField.h
     OpalVKicker.h
     OpalVMonitor.h
     OpalYRot.h
diff --git a/src/Elements/OpalVariableRFCavityFringeField.cpp b/src/Elements/OpalVariableRFCavityFringeField.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..893cc427007dda0b50995ef7b72f0c5608b65d79
--- /dev/null
+++ b/src/Elements/OpalVariableRFCavityFringeField.cpp
@@ -0,0 +1,188 @@
+/*
+ *  Copyright (c) 2018, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Physics/Physics.h"
+#include "Utilities/OpalException.h"
+#include "Attributes/Attributes.h"
+#include "Algorithms/AbstractTimeDependence.h"
+#include "Utilities/OpalException.h"
+#include "AbsBeamline/EndFieldModel/Tanh.h"
+#include "AbsBeamline/VariableRFCavityFringeField.h"
+#include "Elements/OpalVariableRFCavityFringeField.h"
+
+extern Inform *gmsg;
+
+const std::string OpalVariableRFCavityFringeField::doc_string =
+      std::string("The \"VARIABLE_RF_CAVITY_FRINGE_FIELD\" element defines an RF cavity ")+
+      std::string("with time dependent frequency, phase and amplitude.");
+
+OpalVariableRFCavityFringeField::OpalVariableRFCavityFringeField():
+    OpalElement(SIZE, "VARIABLE_RF_CAVITY_FRINGE_FIELD", doc_string.c_str()) {
+    itsAttr[PHASE_MODEL] = Attributes::makeString("PHASE_MODEL",
+                "The name of the phase time dependence model, which should give the phase in [rad].");
+    itsAttr[AMPLITUDE_MODEL] = Attributes::makeString("AMPLITUDE_MODEL",
+                "The name of the amplitude time dependence model, which should give the field in [MV/m]");
+    itsAttr[FREQUENCY_MODEL] = Attributes::makeString("FREQUENCY_MODEL",
+                "The name of the frequency time dependence model, which should give the field in [MHz].");
+    itsAttr[WIDTH] = Attributes::makeReal("WIDTH",
+                "Full width of the cavity [m].");
+    itsAttr[HEIGHT] = Attributes::makeReal("HEIGHT",
+                "Full height of the cavity [m].");
+    itsAttr[CENTRE_LENGTH] = Attributes::makeReal("CENTRE_LENGTH",
+                "Length of the cavity field flat top [m].");
+    itsAttr[END_LENGTH] = Attributes::makeReal("END_LENGTH",
+                "Length of the cavity fringe fields [m].");
+    itsAttr[CAVITY_CENTRE] = Attributes::makeReal("CAVITY_CENTRE",
+                "Offset of the cavity centre from the beginning of the cavity [m].");
+    itsAttr[MAX_ORDER] = Attributes::makeReal("MAX_ORDER",
+                "Maximum power of y that will be evaluated in field calculations.");
+
+    registerStringAttribute("PHASE_MODEL");
+    registerStringAttribute("AMPLITUDE_MODEL");
+    registerStringAttribute("FREQUENCY_MODEL");
+    registerRealAttribute("WIDTH");
+    registerRealAttribute("HEIGHT");
+    registerRealAttribute("CENTRE_LENGTH");
+    registerRealAttribute("END_LENGTH");
+    registerRealAttribute("CAVITY_CENTRE");
+    registerRealAttribute("MAX_ORDER");
+
+    registerOwnership();
+
+    setElement((new VariableRFCavityFringeField("VARIABLE_RF_CAVITY_FRINGE_FIELD"))->
+                                                            makeAlignWrapper());
+}
+
+OpalVariableRFCavityFringeField::OpalVariableRFCavityFringeField(
+                            const std::string &name,
+                            OpalVariableRFCavityFringeField *parent
+                        ) : OpalElement(name, parent) {
+    VariableRFCavityFringeField *cavity = dynamic_cast
+         <VariableRFCavityFringeField*>(parent->getElement()->removeWrappers());
+    setElement((new VariableRFCavityFringeField(*cavity))->makeAlignWrapper());
+}
+
+OpalVariableRFCavityFringeField::~OpalVariableRFCavityFringeField() {
+}
+
+OpalVariableRFCavityFringeField *OpalVariableRFCavityFringeField::clone(
+                                                      const std::string &name) {
+    return new OpalVariableRFCavityFringeField(name, this);
+}
+
+OpalVariableRFCavityFringeField *OpalVariableRFCavityFringeField::clone() {
+    return new OpalVariableRFCavityFringeField(this->getOpalName(), this);
+}
+
+void OpalVariableRFCavityFringeField::
+fillRegisteredAttributes(const ElementBase &base, ValueFlag flag) {
+    OpalElement::fillRegisteredAttributes(base, flag);
+    const VariableRFCavityFringeField* cavity =
+                        dynamic_cast<const VariableRFCavityFringeField*>(&base);
+    if (cavity == NULL) {
+        throw OpalException("OpalVariableRFCavityFringeField::fillRegisteredAttributes",
+                            "Failed to cast ElementBase to a VariableRFCavityFringeField");
+    }
+    std::shared_ptr<endfieldmodel::EndFieldModel> model = cavity->getEndField();
+    endfieldmodel::Tanh* tanh = dynamic_cast<endfieldmodel::Tanh*>(model.get());
+    if (tanh == NULL) {
+        throw OpalException("OpalVariableRFCavityFringeField::fillRegisteredAttributes",
+                            "Failed to cast EndField to a Tanh model");
+    }
+
+    
+    attributeRegistry["L"]->setReal(cavity->getLength());
+    std::shared_ptr<AbstractTimeDependence> phase_model = cavity->getPhaseModel();
+    std::shared_ptr<AbstractTimeDependence> freq_model = cavity->getFrequencyModel();
+    std::shared_ptr<AbstractTimeDependence> amp_model = cavity->getAmplitudeModel();
+    std::string phase_name = AbstractTimeDependence::getName(phase_model);
+    std::string amp_name = AbstractTimeDependence::getName(amp_model);
+    std::string freq_name = AbstractTimeDependence::getName(freq_model);
+    attributeRegistry["PHASE_MODEL"]->setString(phase_name);
+    attributeRegistry["AMPLITUDE_MODEL"]->setString(amp_name);
+    attributeRegistry["FREQUENCY_MODEL"]->setString(freq_name);
+    attributeRegistry["WIDTH"]->setReal(cavity->getWidth());
+    attributeRegistry["HEIGHT"]->setReal(cavity->getHeight());
+    // flat top length is 2*x0
+    attributeRegistry["CENTRE_LENGTH"]->setReal(tanh->getX0()/2.);
+    attributeRegistry["END_LENGTH"]->setReal(tanh->getLambda());
+    attributeRegistry["CAVITY_CENTRE"]->setReal(cavity->getCavityCentre());
+    attributeRegistry["MAX_ORDER"]->setReal(cavity->getMaxOrder());
+}
+
+
+
+void OpalVariableRFCavityFringeField::update() {
+    OpalElement::update();
+
+    VariableRFCavityFringeField *cavity = dynamic_cast
+                <VariableRFCavityFringeField*>(getElement()->removeWrappers());
+    double length = Attributes::getReal(itsAttr[LENGTH]);
+    cavity->setLength(length);
+    std::string phaseName = Attributes::getString(itsAttr[PHASE_MODEL]);
+    cavity->setPhaseName(phaseName);
+    std::string ampName = Attributes::getString(itsAttr[AMPLITUDE_MODEL]);
+    cavity->setAmplitudeName(ampName);
+    std::string freqName = Attributes::getString(itsAttr[FREQUENCY_MODEL]);
+    cavity->setFrequencyName(freqName);
+    double width = Attributes::getReal(itsAttr[WIDTH]);
+    cavity->setWidth(width);
+    double height = Attributes::getReal(itsAttr[HEIGHT]);
+    cavity->setHeight(height);
+    double maxOrderReal = Attributes::getReal(itsAttr[MAX_ORDER]);
+    size_t maxOrder = convertToUnsigned(maxOrderReal, "MAX_ORDER");
+    cavity->setMaxOrder(maxOrder);
+    double cavity_centre = Attributes::getReal(itsAttr[CAVITY_CENTRE]);
+    cavity->setCavityCentre(cavity_centre); // mm
+    // convert to mm; x0 is double length of flat top so divide 2
+    double centreLength = Attributes::getReal(itsAttr[CENTRE_LENGTH])*1e3;
+    double endLength = Attributes::getReal(itsAttr[END_LENGTH])*1e3;
+    endfieldmodel::Tanh* tanh = new endfieldmodel::Tanh(centreLength/2.,
+                                                        endLength,
+                                                        (maxOrder+1)/2);
+    std::shared_ptr<endfieldmodel::EndFieldModel> end(tanh);
+    cavity->setEndField(end);
+
+    setElement(cavity->makeAlignWrapper());
+}
+
+
+size_t OpalVariableRFCavityFringeField::convertToUnsigned(double value,
+                                                          std::string name) {
+    value += unsignedTolerance; // prevent rounding error
+    if (fabs(floor(value) - value) > 2*unsignedTolerance) {
+        throw OpalException("OpalVariableRFCavityFringeField::convertToUnsigned",
+                    "Value for "+name+
+                    " should be an unsigned int but a real value was found");
+    }
+    if (floor(value) < -0.5) {
+        throw OpalException("OpalVariableRFCavityFringeField::convertToUnsigned",
+                            "Value for "+name+" should be 0 or more");
+    }
+    size_t ret(floor(value));
+    return ret;
+}
\ No newline at end of file
diff --git a/src/Elements/OpalVariableRFCavityFringeField.h b/src/Elements/OpalVariableRFCavityFringeField.h
new file mode 100644
index 0000000000000000000000000000000000000000..192e8c6bc8a149f0492312d0cca327de958d309d
--- /dev/null
+++ b/src/Elements/OpalVariableRFCavityFringeField.h
@@ -0,0 +1,94 @@
+/* 
+ *  Copyright (c) 2018, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without 
+ *  modification, are permitted provided that the following conditions are met: 
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer. 
+ *  2. Redistributions in binary form must reproduce the above copyright notice, 
+ *     this list of conditions and the following disclaimer in the documentation 
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to 
+ *     endorse or promote products derived from this software without specific 
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OPAL_OPALVARIABLERFCAVITYFRINGEFIELD_H
+#define OPAL_OPALVARIABLERFCAVITYFRINGEFIELD_H
+
+#include "Elements/OpalElement.h"
+
+/** OpalVariableRFCavityFringeField
+ */
+class OpalVariableRFCavityFringeField : public OpalElement {
+  public:
+    /** enum maps string to integer value for UI definitions */
+    enum {
+        PHASE_MODEL = COMMON,
+        AMPLITUDE_MODEL,
+        FREQUENCY_MODEL,
+        WIDTH,
+        HEIGHT,
+        CENTRE_LENGTH,
+        END_LENGTH,
+        CAVITY_CENTRE,
+        MAX_ORDER,
+        SIZE // size of the enum
+    };
+
+    /** Copy constructor **/
+    OpalVariableRFCavityFringeField(const std::string &name,
+                                    OpalVariableRFCavityFringeField *parent);
+
+    /** Default constructor **/
+    OpalVariableRFCavityFringeField();
+
+    /** Inherited copy constructor
+     *
+     *  Call on a base class to instantiate an object of derived class's type
+    **/
+    OpalVariableRFCavityFringeField* clone();
+
+    /** Inherited copy constructor
+     *
+     *  Call on a base class to instantiate an object of derived class's type
+     */
+    virtual OpalVariableRFCavityFringeField *clone(const std::string &name);
+
+    /** Destructor does nothing */
+    virtual ~OpalVariableRFCavityFringeField();
+
+    /** Fill in all registered attributes
+     *
+     *  This updates the registered attributed with values from the ElementBase
+     */
+    virtual void fillRegisteredAttributes(const ElementBase &, ValueFlag);
+
+    /** Update the OpalVariableRFCavity with new parameters from UI parser */
+    virtual void update();
+  private:
+    // Not implemented.
+    OpalVariableRFCavityFringeField(const OpalVariableRFCavityFringeField &);
+    void operator=(const OpalVariableRFCavityFringeField &);
+
+    /** Check for conversion to unsigned int */
+    inline static size_t convertToUnsigned(double value, std::string name);
+
+    static const std::string doc_string;
+    static constexpr double unsignedTolerance = 1e-9;
+};
+
+
+#endif // OPAL_OPALVARIABLERFCAVITY_H
diff --git a/src/OpalConfigure/Configure.cpp b/src/OpalConfigure/Configure.cpp
index 93d0c942469c6293be4a998ae26a6d5b070fb3c0..08da087b89442a5a2c479d23bd18f5731dc03c4f 100644
--- a/src/OpalConfigure/Configure.cpp
+++ b/src/OpalConfigure/Configure.cpp
@@ -137,6 +137,7 @@
 #include "Elements/OpalStripper.h"
 #include "Elements/OpalRingDefinition.h"
 #include "Elements/OpalVariableRFCavity.h"
+#include "Elements/OpalVariableRFCavityFringeField.h"
 
 // Structure-related commands.
 #include "Lines/Line.h"
@@ -278,6 +279,7 @@ namespace {
         opal->create(new OpalSRot());
         opal->create(new OpalTravelingWave());
         opal->create(new OpalVariableRFCavity());
+        opal->create(new OpalVariableRFCavityFringeField());
         opal->create(new OpalVKicker());
         opal->create(new OpalVMonitor());
         // opal->create(new OpalWire());
diff --git a/tests/classic_src/AbsBeamline/CMakeLists.txt b/tests/classic_src/AbsBeamline/CMakeLists.txt
index 0dfd61844fd510a059dbe1ee7ac09887d378fdae..78a4b0fd05bfa4597cf5951c848bafa38ebef067 100644
--- a/tests/classic_src/AbsBeamline/CMakeLists.txt
+++ b/tests/classic_src/AbsBeamline/CMakeLists.txt
@@ -7,6 +7,7 @@ set (_SRCS
     ScalingFFAGMagnetTest.cpp
     TrimCoilTest.cpp
     VariableRFCavityTest.cpp
+    VariableRFCavityFringeFieldTest.cpp
 )
 
 include_directories (
diff --git a/tests/classic_src/AbsBeamline/VariableRFCavityFringeFieldTest.cpp b/tests/classic_src/AbsBeamline/VariableRFCavityFringeFieldTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b23f5c586f731f4565d6b8af2c60190cbbcf53f8
--- /dev/null
+++ b/tests/classic_src/AbsBeamline/VariableRFCavityFringeFieldTest.cpp
@@ -0,0 +1,304 @@
+/*
+ *  Copyright (c) 2014, Chris Rogers
+ *  All rights reserved.
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. Neither the name of STFC nor the names of its contributors may be used to
+ *     endorse or promote products derived from this software without specific
+ *     prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <memory>
+
+#include "gtest/gtest.h"
+
+#include "opal_test_utilities/SilenceTest.h"
+#include "Physics/Physics.h"
+
+#include "Algorithms/PolynomialTimeDependence.h"
+#include "AbsBeamline/EndFieldModel/Tanh.h"
+#include "AbsBeamline/VariableRFCavityFringeField.h"
+
+class VariableRFCavityFringeFieldTest : public ::testing::Test { 
+public:
+    VariableRFCavityFringeFieldTest() {
+        // OpalTestUtilities::SilenceTest silencer;
+
+        cav1 = VariableRFCavityFringeField("bob");
+        // centre, end, max_order
+        shared = std::shared_ptr<endfieldmodel::EndFieldModel>
+                                      (new endfieldmodel::Tanh(250., 50., 10));
+        cav1.setCavityCentre(0.500);
+        cav1.setEndField(shared);
+        PolynomialTimeDependence* time =
+                       new PolynomialTimeDependence(std::vector<double>(1, 1.));
+        std::shared_ptr<AbstractTimeDependence> timePtr(time);
+        cav1.setAmplitudeModel(timePtr);
+        cav1.setPhaseModel(timePtr);
+        cav1.setFrequencyModel(timePtr);
+        cav1.setHeight(0.500);
+        cav1.setWidth(0.200);
+        cav1.setLength(1.000);
+        cav1.initialiseCoefficients();
+
+        cav2 = cav1;
+        PolynomialTimeDependence* phase2 =
+                       new PolynomialTimeDependence(std::vector<double>(1, 0.));
+        PolynomialTimeDependence* freq2 =
+                       new PolynomialTimeDependence(std::vector<double>(1, 1000.));
+        std::shared_ptr<AbstractTimeDependence> phase2Ptr(phase2);
+        std::shared_ptr<AbstractTimeDependence> freq2Ptr(freq2);
+        cav2.setPhaseModel(phase2Ptr);
+        cav2.setFrequencyModel(freq2Ptr);
+    }
+
+    VariableRFCavityFringeField cav1;
+    VariableRFCavityFringeField cav2;
+    std::shared_ptr<endfieldmodel::EndFieldModel> shared;
+};
+
+TEST_F(VariableRFCavityFringeFieldTest, TestConstructor) {
+    OpalTestUtilities::SilenceTest silencer;
+    VariableRFCavityFringeField cav("bob");
+    EXPECT_FLOAT_EQ(cav.getCavityCentre(), 0.);
+    endfieldmodel::EndFieldModel* null = NULL;
+    EXPECT_EQ(&(*(cav.getEndField())), null);
+}
+
+TEST_F(VariableRFCavityFringeFieldTest, TestSetGet) {
+    OpalTestUtilities::SilenceTest silencer;
+    EXPECT_FLOAT_EQ(cav1.getCavityCentre(), 0.5); // mm
+    EXPECT_FLOAT_EQ(cav1.getWidth(), 0.2); // metres
+    EXPECT_EQ(&(*(cav1.getEndField())), &(*shared));
+    long int count = shared.use_count();
+    EXPECT_EQ(count, 3);
+    PolynomialTimeDependence* time = NULL;
+    EXPECT_NE(&(*(cav1.getFrequencyModel())), time);
+}
+
+TEST_F(VariableRFCavityFringeFieldTest, TestClone) {
+    VariableRFCavityFringeField* cav2 =
+                       dynamic_cast<VariableRFCavityFringeField*>(cav1.clone());
+    EXPECT_FLOAT_EQ(cav2->getCavityCentre(), 0.5);
+    EXPECT_EQ(&(*(cav2->getEndField())), &(*shared));
+    long int count = shared.use_count();
+    EXPECT_EQ(count, 4);
+}
+
+TEST_F(VariableRFCavityFringeFieldTest, TestAssignment) {
+    VariableRFCavityFringeField cav3 = cav1;
+    EXPECT_FLOAT_EQ(cav3.getCavityCentre(), 0.5);
+    EXPECT_EQ(&(*(cav3.getEndField())), &(*shared));
+    long int count = shared.use_count();
+    EXPECT_EQ(count, 4);
+}
+
+TEST_F(VariableRFCavityFringeFieldTest, TestCopyConstructor) {
+    VariableRFCavityFringeField cav4(cav1);
+    EXPECT_FLOAT_EQ(cav4.getCavityCentre(), 0.5);
+    EXPECT_EQ(&(*(cav4.getEndField())), &(*shared));
+    long int count = shared.use_count();
+    EXPECT_EQ(count, 4);
+}
+
+TEST_F(VariableRFCavityFringeFieldTest, TestApplyBoundingBox) {
+    Vector_t centroid(0., 0., 0.);
+    Vector_t B(0., 0., 0.);
+    Vector_t E(0., 0., 0.);
+    std::vector<Vector_t> rVectorFalse = {
+        Vector_t(-99.9, -249.9, 0.1),
+        Vector_t(-99.9, 249.9, 999.9),
+    };
+    for (size_t i = 0; i < rVectorFalse.size(); ++i) {
+        bool outOfBounds = cav1.apply(rVectorFalse[i], centroid, 0., B, E);
+        EXPECT_FALSE(outOfBounds);
+    }
+
+      std::vector<Vector_t> rVectorTrue = {
+        Vector_t(-100.1, 0., 500.),
+        Vector_t(+100.1, 0., 500.),
+        Vector_t(0., -250.1, 500.),
+        Vector_t(0., +250.1, 500.),
+        Vector_t(0., 0., -0.1),
+        Vector_t(0., 0., 1000.1),
+    };
+    for (size_t i = 0; i < rVectorTrue.size(); ++i) {
+        bool outOfBounds = cav1.apply(rVectorTrue[i], centroid, 0., B, E);
+        EXPECT_TRUE(outOfBounds) << rVectorTrue[i];
+    }
+}
+
+void testFieldLookup(VariableRFCavityFringeField& cav, Vector_t R, double t, Vector_t E, Vector_t B) {
+    Vector_t centroid(0., 0., 0.);
+    Vector_t Btest(0., 0., 0.);
+    Vector_t Etest(0., 0., 0.);
+    cav.apply(R, centroid, t, Etest, Btest);
+    for (size_t i = 0; i < 3; ++i) {
+        EXPECT_FLOAT_EQ(E[i], Etest[i]) << "\nR:" << R << " t: " << t
+        << "\nE expected: " << E << " " << " E meas: " << Etest 
+        << "\nB expected: " << B << " " << " B meas: " << Btest << std::endl;
+        EXPECT_FLOAT_EQ(B[i], Btest[i]) << "\nR:" << R 
+        << "\nE expected: " << E << " " << " E meas: " << Etest 
+        << "\nB expected: " << B << " " << " B meas: " << Btest << std::endl;
+    }
+}
+
+void partial(VariableRFCavityFringeField& cav, Vector_t pos, double t, double delta, int var, Vector_t& dE, Vector_t& dB) {
+    bool verbose = false;
+    Vector_t centroid(0., 0., 0.);
+    Vector_t Bplus(0., 0., 0.);
+    Vector_t Bminus(0., 0., 0.);
+    Vector_t Eplus(0., 0., 0.);
+    Vector_t Eminus(0., 0., 0.);
+    Vector_t posPlus(pos), posMinus(pos);
+    double tPlus(t), tMinus(t);
+    if (var == 3) {
+        tMinus -= delta;
+        tPlus += delta;
+    } else if (var >= 0 or var < 3) {
+        posMinus[var] -= delta;
+        posPlus[var] += delta;
+    }
+    cav.apply(posPlus, centroid, tPlus, Eplus, Bplus);
+    cav.apply(posMinus, centroid, tMinus, Eminus, Bminus);
+    dE = (Eplus - Eminus)/2/delta;
+    dB = (Bplus - Bminus)/2/delta;
+    if (verbose) {
+        std::cerr << "Partial " << var << " " << delta << std::endl;
+        std::cerr << "R: " << posPlus << " " << posMinus << std::endl;
+        std::cerr << "t: " << tPlus << " " << tMinus << std::endl;
+        std::cerr << "B: " << Bplus << " " << Bminus << std::endl;
+        std::cerr << "E: " << Eplus << " " << Eminus << std::endl;
+    }
+}
+
+// curl B = 1/c^2 dE/dt
+Vector_t testMaxwell4(VariableRFCavityFringeField& cav, Vector_t pos, double t, double deltaPos, double deltaT) {
+    bool verbose = false;
+    Vector_t dummy;
+    Vector_t dBdx(0, 0, 0);
+    Vector_t dBdy(0, 0, 0);
+    Vector_t dBdz(0, 0, 0);
+    Vector_t dEdt(0, 0, 0);
+    partial(cav, pos, t, deltaPos, 0, dummy, dBdx);
+    partial(cav, pos, t, deltaPos, 1, dummy, dBdy);
+    partial(cav, pos, t, deltaPos, 2, dummy, dBdz);
+    partial(cav, pos, t, deltaT,   3, dEdt, dummy);
+    Vector_t curlB(
+        dBdy[2] - dBdz[1],
+        dBdz[0] - dBdx[2],
+        dBdx[1] - dBdy[0]
+    );
+    double c_l = Physics::c*1e-6; // 3e8 m/s = 300 mm/ns
+    Vector_t result = dEdt - curlB*1e-4*c_l*c_l;
+
+    if (verbose) {
+        std::cerr << "dBdx           " << dBdx*1e-3 << std::endl;
+        std::cerr << "dBdy           " << dBdy*1e-3 << std::endl;
+        std::cerr << "dBdz           " << dBdz*1e-3 << std::endl;
+        std::cerr << "dEdt           " << dEdt << std::endl;
+        std::cerr << "c^2 curlB      " << curlB*1e-3*c_l*c_l << std::endl;
+        std::cerr << "dEdt-c^2 curlB " << result << std::endl << std::endl;
+    }
+    return result;
+}
+
+Vector_t testMaxwell3(VariableRFCavityFringeField& cav, Vector_t pos, double t, double deltaPos, double deltaT) {
+    bool verbose = false;
+    Vector_t dummy;
+    Vector_t dEdx(0, 0, 0);
+    Vector_t dEdy(0, 0, 0);
+    Vector_t dEdz(0, 0, 0);
+    Vector_t dBdt(0, 0, 0);
+    partial(cav, pos, t, deltaPos, 0, dEdx, dummy);
+    partial(cav, pos, t, deltaPos, 1, dEdy, dummy);
+    partial(cav, pos, t, deltaPos, 2, dEdz, dummy);
+    partial(cav, pos, t, deltaT,   3, dummy, dBdt);
+    Vector_t curlE(
+        dEdy[2] - dEdz[1],
+        dEdz[0] - dEdx[2],
+        dEdx[1] - dEdy[0]
+    );
+    Vector_t result = dBdt*1e-4 - curlE;
+
+    if (verbose) {
+        std::cerr << "maxwell3 at R: " << pos << " t: " << t << " with dx: " 
+                  << deltaPos << " dt: " << deltaT << std::endl;
+        std::cerr << "  dEdx           " << dEdx << std::endl;
+        std::cerr << "  dEdy           " << dEdy << std::endl;
+        std::cerr << "  dEdz           " << dEdz << std::endl;
+        std::cerr << "  dBdt           " << dBdt << std::endl;
+        std::cerr << "  curlE          " << curlE << std::endl;
+        std::cerr << "  dBdt-curlE     " << result << std::endl << std::endl;
+    }
+    return result;
+}
+
+
+std::vector<double> testMaxwell1and2(VariableRFCavityFringeField& cav, Vector_t pos, double t, double deltaPos) {
+    bool verbose = false;
+    Vector_t dummy;
+    Vector_t dEdx(0, 0, 0);
+    Vector_t dEdy(0, 0, 0);
+    Vector_t dEdz(0, 0, 0);
+    Vector_t dBdx(0, 0, 0);
+    Vector_t dBdy(0, 0, 0);
+    Vector_t dBdz(0, 0, 0);
+    partial(cav, pos, t, deltaPos, 0, dEdx, dBdx);
+    partial(cav, pos, t, deltaPos, 1, dEdy, dBdy);
+    partial(cav, pos, t, deltaPos, 2, dEdz, dBdz);
+    
+    double divE = dEdx[0] + dEdy[1] + dEdz[2];
+    double divB = dBdx[0] + dBdy[1] + dBdz[2];
+
+    if (verbose) {
+        std::cerr << "maxwell1+2 at R: " << pos << " t: " << t << " with dx: " 
+                  << deltaPos << std::endl;
+        std::cerr << "  dEidi          " << dEdx[0] << " " << dEdy[1] << " " << dEdz[2] << std::endl;
+        std::cerr << "  dBidi          " << dBdx[0] << " " << dBdy[1] << " " << dBdz[2] << std::endl;
+        std::cerr << "  divE           " << divE << std::endl;
+        std::cerr << "  divB           " << divB << std::endl;
+    }
+    std::vector<double> result = {divE, divB};
+    return result;
+}
+
+TEST_F(VariableRFCavityFringeFieldTest, TestMaxwell) {
+    //double pi = Physics::pi;
+    Vector_t centroid(0., 0., 0.);
+    Vector_t B(0., 0., 0.);
+    Vector_t E(0., 0., 0.);
+    Vector_t R(0., 0., 500.);
+    double t = 0.;
+    std::cerr << "\nOff midplane, 45 degree phase, in fringe field" << std::endl;
+    std::cerr << "order B        E   max1   max2   maxwell3    maxwell4" << std::endl;
+    R = Vector_t(0., 1., 750.);
+    t = 0.125;
+    for (size_t i = 0; i < 5; ++i) {
+        cav2.setMaxOrder(i);
+        cav2.apply(R, centroid, t, E, B);
+        Vector_t result1 = testMaxwell3(cav2, R, t, 0.01, 0.0001);
+        Vector_t result2 = testMaxwell4(cav2, R, t, 0.01, 0.0001);
+        std::vector<double> div = testMaxwell1and2(cav2, R, t, 0.01);
+        std::cerr << i << " ** " << B << " " << E << " " << div[0] << " " << div[1] << " " << result1 << " " << result2 << std::endl;
+
+      
+    }
+}