diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4caa742938733ba61e13228e792cba44dd6bb453..0cf50ff856f0ed30ec4051b0e599fcd1675bc657 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,8 @@ v5.0.0
 - Fix ThridpartyCCM options (!802)
 - Fix Windows CRLF tokens in GEO reader and improve comment handling (!805)
 - Use chrono in Timer (!807)
+- Fix caching of FUNCTION tags that read from file and provide the same
+  functionality in FUNCTIONs defined for forcings (!759)
 
 **NekMesh**:
 - Add feature to read basic 2D geo files as CAD (!731)
diff --git a/library/FieldUtils/Interpolator.h b/library/FieldUtils/Interpolator.h
index 3f9a8348c074aa999a7e5e3aa96f7f53798970dc..7176e2afd7ec8928d817ec3a64906cf8963b8ffd 100644
--- a/library/FieldUtils/Interpolator.h
+++ b/library/FieldUtils/Interpolator.h
@@ -147,7 +147,7 @@ public:
     /// Returns the output field
     FIELD_UTILS_EXPORT LibUtilities::PtsFieldSharedPtr GetOutField() const;
 
-    /// Print statics of the interpolation weights
+    /// Returns if the weights have already been computed
     FIELD_UTILS_EXPORT void PrintStatistics();
 
     /// sets a callback funtion which gets called every time the interpolation
diff --git a/library/SolverUtils/CMakeLists.txt b/library/SolverUtils/CMakeLists.txt
index 677a988393e3cd53e62918445f8b871d6fe86c12..55b4a8de3ba37449def02d597e94a5c04d887a20 100644
--- a/library/SolverUtils/CMakeLists.txt
+++ b/library/SolverUtils/CMakeLists.txt
@@ -1,5 +1,6 @@
 SET(SOLVER_UTILS_SOURCES
   Core/Misc.cpp
+  Core/SessionFunction.cpp
   AdvectionSystem.cpp
   Advection/Advection.cpp
   Advection/Advection3DHomogeneous1D.cpp
@@ -44,6 +45,7 @@ SET(SOLVER_UTILS_SOURCES
 
 SET(SOLVER_UTILS_HEADERS
   Core/Misc.h
+  Core/SessionFunction.h
   AdvectionSystem.h
   Advection/Advection.h
   Advection/AdvectionFR.h
diff --git a/library/SolverUtils/Core/SessionFunction.cpp b/library/SolverUtils/Core/SessionFunction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5c4140eb9f2eb1b77bf327c8a82ec0f46e45c9f1
--- /dev/null
+++ b/library/SolverUtils/Core/SessionFunction.cpp
@@ -0,0 +1,500 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// File: SessionFunction.cpp
+//
+// For more information, please see: http://www.nektar.info/
+//
+// The MIT License
+//
+// Copyright (c) 2017 Kilian Lackhove
+// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
+// Department of Aeronautics, Imperial College London (UK), and Scientific
+// Computing and Imaging Institute, University of Utah (USA).
+//
+// License for the specific language governing rights and limitations under
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// Description: Session Function
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <SolverUtils/Core/SessionFunction.h>
+
+#include <LibUtilities/BasicUtils/VmathArray.hpp>
+
+#include <boost/format.hpp>
+#include <boost/function.hpp>
+
+using namespace std;
+
+namespace Nektar
+{
+namespace SolverUtils
+{
+
+/**
+ * Representation of a FUNCTION defined in the session xml file.
+ *
+ * @param   session       The session where the function was defined.
+ * @param   field         The field the function is defined on.
+ * @param   functionName  The name of the function.
+ * @param   toCache       Store the evaluated function for later use.
+ */
+SessionFunction::SessionFunction(const LibUtilities::SessionReaderSharedPtr &session,
+                                 const MultiRegions::ExpListSharedPtr &field,
+                                 std::string functionName,
+                                 bool toCache)
+    : m_session(session), m_field(field), m_name(functionName), m_toCache(toCache)
+{
+    ASSERTL0(m_session->DefinesFunction(m_name),
+             "Function '" + m_name + "' does not exist.");
+}
+
+/**
+ * Evaluates a function defined in the xml session file at each quadrature point.
+ *
+ * @param   pArray       The array into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::Evaluate(Array<OneD, Array<OneD, NekDouble> > &pArray,
+                               const NekDouble pTime,
+                               const int domain)
+{
+    std::vector<std::string> vFieldNames = m_session->GetVariables();
+
+    for (int i = 0; i < vFieldNames.size(); i++)
+    {
+        Evaluate(vFieldNames[i], pArray[i], pTime, domain);
+    }
+}
+
+/**
+ * Evaluates a function defined in the xml session file at each quadrature point.
+ *
+ * @param   pFieldNames  The names of the fields to evaluate the function for.
+ * @param   pArray       The array into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::Evaluate(std::vector<std::string> pFieldNames,
+                               Array<OneD, Array<OneD, NekDouble> > &pArray,
+                               const NekDouble &pTime,
+                               const int domain)
+{
+    ASSERTL1(pFieldNames.size() == pArray.num_elements(),
+             "Function '" + m_name +
+             "' variable list size mismatch with array storage.");
+
+    for (int i = 0; i < pFieldNames.size(); i++)
+    {
+        Evaluate(pFieldNames[i], pArray[i], pTime, domain);
+    }
+}
+
+/**
+ * Evaluates a function defined in the xml session file at each quadrature point.
+ *
+ * @param   pFieldNames  The names of the fields to evaluate the function for.
+ * @param   pFields      The fields into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::Evaluate(
+    std::vector<std::string> pFieldNames,
+    Array<OneD, MultiRegions::ExpListSharedPtr> &pFields,
+    const NekDouble &pTime,
+    const int domain)
+{
+    ASSERTL0(pFieldNames.size() == pFields.num_elements(),
+             "Field list / name list size mismatch.");
+
+    for (int i = 0; i < pFieldNames.size(); i++)
+    {
+        Evaluate(pFieldNames[i], pFields[i]->UpdatePhys(), pTime, domain);
+        pFields[i]->FwdTrans_IterPerExp(pFields[i]->GetPhys(),
+                                        pFields[i]->UpdateCoeffs());
+    }
+}
+
+/**
+ * Evaluates a function defined in the xml session file at each quadrature point.
+ *
+ * @param   pFieldName   The name of the field to evaluate the function for.
+ * @param   pArray       The array into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::Evaluate(std::string pFieldName,
+                               Array<OneD, NekDouble> &pArray,
+                               const NekDouble &pTime,
+                               const int domain)
+{
+    LibUtilities::FunctionType vType =
+        m_session->GetFunctionType(m_name, pFieldName, domain);
+
+    unsigned int nq = m_field->GetNpoints();
+
+    std::pair<std::string, int> key(pFieldName, domain);
+    // sorry
+    if ((m_arrays.find(key) != m_arrays.end()) &&
+            (vType == LibUtilities::eFunctionTypeFile ||
+             ((m_lastCached.find(key) != m_lastCached.end()) &&
+              (pTime - m_lastCached[key] < NekConstants::kNekZeroTol))))
+    {
+        // found cached field
+        if (pArray.num_elements() < nq)
+        {
+            pArray = Array<OneD, NekDouble>(nq);
+        }
+        Vmath::Vcopy(nq, m_arrays[key], 1, pArray, 1);
+
+        return;
+    }
+
+    if (vType == LibUtilities::eFunctionTypeExpression)
+    {
+        EvaluateExp(pFieldName, pArray, pTime, domain);
+    }
+    else if (vType == LibUtilities::eFunctionTypeFile ||
+             vType == LibUtilities::eFunctionTypeTransientFile)
+    {
+        std::string filename =
+            m_session->GetFunctionFilename(m_name, pFieldName, domain);
+
+        if (boost::filesystem::path(filename).extension() == ".pts")
+        {
+            EvaluatePts(pFieldName, pArray, pTime, domain);
+        }
+        else
+        {
+            EvaluateFld(pFieldName, pArray, pTime, domain);
+        }
+    }
+
+    if (m_toCache)
+    {
+        m_arrays[key] = Array<OneD, NekDouble>(nq);
+        Vmath::Vcopy(nq, pArray, 1, m_arrays[key], 1);
+
+        m_lastCached[key] = pTime;
+    }
+}
+
+/**
+ * @brief Provide a description of a function for a given field name.
+ *
+ * @param pFieldName     Field name.
+ * @param domain         The domain to evaluate the function in.
+ */
+std::string SessionFunction::Describe(std::string pFieldName, const int domain)
+{
+    std::string retVal;
+
+    LibUtilities::FunctionType vType =
+        m_session->GetFunctionType(m_name, pFieldName, domain);
+    if (vType == LibUtilities::eFunctionTypeExpression)
+    {
+        LibUtilities::EquationSharedPtr ffunc =
+            m_session->GetFunction(m_name, pFieldName, domain);
+        retVal = ffunc->GetExpression();
+    }
+    else if (vType == LibUtilities::eFunctionTypeFile ||
+             LibUtilities::eFunctionTypeTransientFile)
+    {
+        std::string filename =
+            m_session->GetFunctionFilename(m_name, pFieldName, domain);
+        retVal = "from file " + filename;
+    }
+
+    return retVal;
+}
+
+/**
+ * Evaluates a function from expression
+ *
+ * @param   pFieldName   The name of the field to evaluate the function for.
+ * @param   pArray       The array into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::EvaluateExp(string pFieldName,
+                                  Array<OneD, NekDouble> &pArray,
+                                  const NekDouble &pTime,
+                                  const int domain)
+{
+    unsigned int nq = m_field->GetNpoints();
+    if (pArray.num_elements() < nq)
+    {
+        pArray = Array<OneD, NekDouble>(nq);
+    }
+
+    Array<OneD, NekDouble> x0(nq);
+    Array<OneD, NekDouble> x1(nq);
+    Array<OneD, NekDouble> x2(nq);
+
+    // Get the coordinates (assuming all fields have the same
+    // discretisation)
+    m_field->GetCoords(x0, x1, x2);
+    LibUtilities::EquationSharedPtr ffunc =
+        m_session->GetFunction(m_name, pFieldName, domain);
+
+    ffunc->Evaluate(x0, x1, x2, pTime, pArray);
+}
+
+/**
+ * Evaluates a function from fld file
+ *
+ * @param   pFieldName   The name of the field to evaluate the function for.
+ * @param   pArray       The array into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::EvaluateFld(string pFieldName,
+                                  Array<OneD, NekDouble> &pArray,
+                                  const NekDouble &pTime,
+                                  const int domain)
+{
+    unsigned int nq = m_field->GetNpoints();
+    if (pArray.num_elements() < nq)
+    {
+        pArray = Array<OneD, NekDouble>(nq);
+    }
+
+    std::string filename =
+        m_session->GetFunctionFilename(m_name, pFieldName, domain);
+    std::string fileVar =
+        m_session->GetFunctionFilenameVariable(m_name, pFieldName, domain);
+
+    if (fileVar.length() == 0)
+    {
+        fileVar = pFieldName;
+    }
+
+    //  In case of eFunctionTypeTransientFile, generate filename from
+    //  format string
+    LibUtilities::FunctionType vType =
+        m_session->GetFunctionType(m_name, pFieldName, domain);
+    if (vType == LibUtilities::eFunctionTypeTransientFile)
+    {
+        try
+        {
+#if (defined _WIN32 && _MSC_VER < 1900)
+            // We need this to make sure boost::format has always
+            // two digits in the exponents of Scientific notation.
+            unsigned int old_exponent_format;
+            old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
+            filename            = boost::str(boost::format(filename) % pTime);
+            _set_output_format(old_exponent_format);
+#else
+            filename = boost::str(boost::format(filename) % pTime);
+#endif
+        }
+        catch (...)
+        {
+            ASSERTL0(false,
+                     "Invalid Filename in function \"" + m_name +
+                     "\", variable \"" + fileVar + "\"")
+        }
+    }
+
+    // Define list of global element ids
+    int numexp = m_field->GetExpSize();
+    Array<OneD, int> ElementGIDs(numexp);
+    for (int i = 0; i < numexp; ++i)
+    {
+        ElementGIDs[i] = m_field->GetExp(i)->GetGeom()->GetGlobalID();
+    }
+
+    std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
+    std::vector<std::vector<NekDouble> > FieldData;
+    LibUtilities::FieldIOSharedPtr fldIO =
+        LibUtilities::FieldIO::CreateForFile(m_session, filename);
+    fldIO->Import(filename,
+                  FieldDef,
+                  FieldData,
+                  LibUtilities::NullFieldMetaDataMap,
+                  ElementGIDs);
+
+    int idx = -1;
+    Array<OneD, NekDouble> vCoeffs(m_field->GetNcoeffs(), 0.0);
+    // Loop over all the expansions
+    for (int i = 0; i < FieldDef.size(); ++i)
+    {
+        // Find the index of the required field in the
+        // expansion segment
+        for (int j = 0; j < FieldDef[i]->m_fields.size(); ++j)
+        {
+            if (FieldDef[i]->m_fields[j] == fileVar)
+            {
+                idx = j;
+            }
+        }
+
+        if (idx >= 0)
+        {
+            m_field->ExtractDataToCoeffs(
+                FieldDef[i], FieldData[i], FieldDef[i]->m_fields[idx], vCoeffs);
+        }
+        else
+        {
+            cout << "Field " + fileVar + " not found." << endl;
+        }
+    }
+
+    m_field->BwdTrans_IterPerExp(vCoeffs, pArray);
+}
+
+/**
+ * Evaluates a function from pts file
+ *
+ * @param   pFieldName   The name of the field to evaluate the function for.
+ * @param   pArray       The array into which to write the values.
+ * @param   pTime        The time at which to evaluate the function.
+ * @param   domain       The domain to evaluate the function in.
+ */
+void SessionFunction::EvaluatePts(string pFieldName,
+                                  Array<OneD, NekDouble> &pArray,
+                                  const NekDouble &pTime,
+                                  const int domain)
+{
+    unsigned int nq = m_field->GetNpoints();
+    if (pArray.num_elements() < nq)
+    {
+        pArray = Array<OneD, NekDouble>(nq);
+    }
+
+    std::string filename =
+        m_session->GetFunctionFilename(m_name, pFieldName, domain);
+    std::string fileVar =
+        m_session->GetFunctionFilenameVariable(m_name, pFieldName, domain);
+
+    if (fileVar.length() == 0)
+    {
+        fileVar = pFieldName;
+    }
+
+    //  In case of eFunctionTypeTransientFile, generate filename from
+    //  format string
+    LibUtilities::FunctionType vType =
+        m_session->GetFunctionType(m_name, pFieldName, domain);
+    if (vType == LibUtilities::eFunctionTypeTransientFile)
+    {
+        try
+        {
+#if (defined _WIN32 && _MSC_VER < 1900)
+            // We need this to make sure boost::format has always
+            // two digits in the exponents of Scientific notation.
+            unsigned int old_exponent_format;
+            old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
+            filename            = boost::str(boost::format(filename) % pTime);
+            _set_output_format(old_exponent_format);
+#else
+            filename = boost::str(boost::format(filename) % pTime);
+#endif
+        }
+        catch (...)
+        {
+            ASSERTL0(false,
+                     "Invalid Filename in function \"" + m_name +
+                     "\", variable \"" + fileVar + "\"")
+        }
+    }
+
+    LibUtilities::PtsFieldSharedPtr outPts;
+    // check if we already loaded this file. For transient files,
+    // funcFilename != filename so we can make sure we only keep the
+    // latest pts field per funcFilename.
+    std::string funcFilename =
+        m_session->GetFunctionFilename(m_name, pFieldName, domain);
+
+    LibUtilities::PtsFieldSharedPtr inPts;
+    LibUtilities::PtsIO ptsIO(m_session->GetComm());
+    ptsIO.Import(filename, inPts);
+
+    Array<OneD, Array<OneD, NekDouble> > pts(inPts->GetDim() +
+            inPts->GetNFields());
+    for (int i = 0; i < inPts->GetDim() + inPts->GetNFields(); ++i)
+    {
+        pts[i] = Array<OneD, NekDouble>(nq);
+    }
+    if (inPts->GetDim() == 1)
+    {
+        m_field->GetCoords(pts[0]);
+    }
+    else if (inPts->GetDim() == 2)
+    {
+        m_field->GetCoords(pts[0], pts[1]);
+    }
+    else if (inPts->GetDim() == 3)
+    {
+        m_field->GetCoords(pts[0], pts[1], pts[2]);
+    }
+    outPts = MemoryManager<LibUtilities::PtsField>::AllocateSharedPtr(
+                 inPts->GetDim(), inPts->GetFieldNames(), pts);
+
+    FieldUtils::Interpolator interp;
+    if (m_interpolators.find(funcFilename) != m_interpolators.end())
+    {
+        interp = m_interpolators[funcFilename];
+    }
+    else
+    {
+        interp = FieldUtils::Interpolator(Nektar::FieldUtils::eShepard);
+        if (m_session->GetComm()->GetRank() == 0)
+        {
+            interp.SetProgressCallback(&SessionFunction::PrintProgressbar,
+                                       this);
+        }
+        interp.CalcWeights(inPts, outPts);
+        if (m_session->GetComm()->GetRank() == 0)
+        {
+            cout << endl;
+            if (m_session->DefinesCmdLineArgument("verbose"))
+            {
+                interp.PrintStatistics();
+            }
+        }
+    }
+
+    if (m_toCache)
+    {
+        m_interpolators[funcFilename] = interp;
+    }
+
+    // TODO: only interpolate the field we actually want
+    interp.Interpolate(inPts, outPts);
+
+    int fieldInd;
+    vector<string> fieldNames = outPts->GetFieldNames();
+    for (fieldInd = 0; fieldInd < fieldNames.size(); ++fieldInd)
+    {
+        if (outPts->GetFieldName(fieldInd) == pFieldName)
+        {
+            break;
+        }
+    }
+    ASSERTL0(fieldInd != fieldNames.size(), "field not found");
+
+    pArray = outPts->GetPts(fieldInd + outPts->GetDim());
+}
+
+// end of namespaces
+}
+}
diff --git a/library/SolverUtils/Core/SessionFunction.h b/library/SolverUtils/Core/SessionFunction.h
new file mode 100644
index 0000000000000000000000000000000000000000..246a923e843b6c92a64960d1375293df0bab77b8
--- /dev/null
+++ b/library/SolverUtils/Core/SessionFunction.h
@@ -0,0 +1,152 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// File SessionFunction.h
+//
+// For more information, please see: http://www.nektar.info
+//
+// The MIT License
+//
+// Copyright (c) 2017 Kilian Lackhove
+// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
+// Department of Aeronautics, Imperial College London (UK), and Scientific
+// Computing and Imaging Institute, University of Utah (USA).
+//
+// License for the specific language governing rights and limitations under
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// Description: Session Function
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef NEKTAR_SOLVERUTILS_SESSIONFUNCTION_H
+#define NEKTAR_SOLVERUTILS_SESSIONFUNCTION_H
+
+#include <FieldUtils/Interpolator.h>
+#include <LibUtilities/BasicUtils/FieldIO.h>
+#include <LibUtilities/BasicUtils/FileSystem.h>
+#include <LibUtilities/BasicUtils/NekFactory.hpp>
+#include <LibUtilities/BasicUtils/Progressbar.hpp>
+#include <LibUtilities/BasicUtils/PtsField.h>
+#include <LibUtilities/BasicUtils/PtsIO.h>
+#include <LibUtilities/BasicUtils/SharedArray.hpp>
+#include <MultiRegions/ExpList.h>
+#include <SolverUtils/SolverUtilsDeclspec.h>
+
+namespace Nektar
+{
+namespace SolverUtils
+{
+
+class SessionFunction
+{
+public:
+    /// Representation of a FUNCTION defined in the session xml file.
+    SOLVER_UTILS_EXPORT SessionFunction(
+        const LibUtilities::SessionReaderSharedPtr &session,
+        const MultiRegions::ExpListSharedPtr &field,
+        std::string functionName,
+        bool toCache = false);
+
+    /// Evaluates a function defined in the xml session file at each quadrature point.
+    SOLVER_UTILS_EXPORT void Evaluate(
+        Array<OneD, Array<OneD, NekDouble> > &pArray,
+        const NekDouble pTime = 0.0,
+        const int domain      = 0);
+
+    /// Evaluates a function defined in the xml session file at each quadrature point.
+    SOLVER_UTILS_EXPORT void Evaluate(
+        std::vector<std::string> pFieldNames,
+        Array<OneD, Array<OneD, NekDouble> > &pArray,
+        const NekDouble &pTime = 0.0,
+        const int domain       = 0);
+
+    /// Evaluates a function defined in the xml session file at each quadrature point.
+    SOLVER_UTILS_EXPORT void Evaluate(
+        std::vector<std::string> pFieldNames,
+        Array<OneD, MultiRegions::ExpListSharedPtr> &pFields,
+        const NekDouble &pTime = 0.0,
+        const int domain       = 0);
+
+    // Evaluates a function defined in the xml session file at each quadrature point.
+    SOLVER_UTILS_EXPORT void Evaluate(std::string pFieldName,
+                                      Array<OneD, NekDouble> &pArray,
+                                      const NekDouble &pTime = 0.0,
+                                      const int domain       = 0);
+
+    /// Provide a description of a function for a given field name.
+    SOLVER_UTILS_EXPORT std::string Describe(std::string pFieldName,
+                                             const int domain = 0);
+
+    SOLVER_UTILS_EXPORT const LibUtilities::SessionReaderSharedPtr & GetSession()
+    {
+        return m_session;
+    }
+
+    SOLVER_UTILS_EXPORT const MultiRegions::ExpListSharedPtr & GetExpansion()
+    {
+        return m_field;
+    }
+
+private:
+    /// The session reader
+    LibUtilities::SessionReaderSharedPtr m_session;
+    /// The expansion we want to evaluate this function for
+    MultiRegions::ExpListSharedPtr m_field;
+    // Name of this function
+    std::string m_name;
+    /// Store resulting arrays (and interpolators)
+    bool m_toCache;
+    /// Last time the cache for this variable & domain combo was updated
+    std::map<std::pair<std::string, int>, NekDouble> m_lastCached;
+    /// Interpolator for pts file input for a variable & domain combination
+    std::map<std::string, FieldUtils::Interpolator> m_interpolators;
+    /// Cached result arrays
+    std::map<std::pair<std::string, int>, Array<OneD, NekDouble> > m_arrays;
+
+    // Evaluates a function from expression
+    SOLVER_UTILS_EXPORT void EvaluateExp(std::string pFieldName,
+                                         Array<OneD, NekDouble> &pArray,
+                                         const NekDouble &pTime = 0.0,
+                                         const int domain       = 0);
+
+    // Evaluates a function from fld file
+    SOLVER_UTILS_EXPORT void EvaluateFld(std::string pFieldName,
+                                         Array<OneD, NekDouble> &pArray,
+                                         const NekDouble &pTime = 0.0,
+                                         const int domain       = 0);
+
+    /// Evaluates a function from pts file
+    SOLVER_UTILS_EXPORT void EvaluatePts(std::string pFieldName,
+                                         Array<OneD, NekDouble> &pArray,
+                                         const NekDouble &pTime = 0.0,
+                                         const int domain       = 0);
+
+    SOLVER_UTILS_EXPORT void PrintProgressbar(const int position,
+                                              const int goal) const
+    {
+        LibUtilities::PrintProgressbar(position, goal, "Interpolating");
+    }
+};
+
+typedef boost::shared_ptr<SessionFunction> SessionFunctionSharedPtr;
+static SessionFunctionSharedPtr NullSessionFunction;
+}
+}
+
+#endif
diff --git a/library/SolverUtils/EquationSystem.cpp b/library/SolverUtils/EquationSystem.cpp
index 866026f52632bcb926611246a2987c3084cb4dc7..cec6ab95bd732af67ddf1003e120509d6d9a15d4 100644
--- a/library/SolverUtils/EquationSystem.cpp
+++ b/library/SolverUtils/EquationSystem.cpp
@@ -676,469 +676,35 @@ namespace Nektar
                 DNekScalBlkMat, LocalRegions::MatrixKey::opLess>::ClearManager();
         }
 
-        /**
-         * Evaluates a physical function at each quadrature point in the domain.
-         *
-         * @param   pArray          The array into which to write the values.
-         * @param   pEqn            The equation to evaluate.
-         */
-        void EquationSystem::EvaluateFunction(
-            Array<OneD, Array<OneD, NekDouble> >& pArray,
-            std::string pFunctionName,
-            const NekDouble pTime,
-            const int domain)
-        {
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                     "Function '" + pFunctionName + "' does not exist.");
-
-            std::vector<std::string> vFieldNames = m_session->GetVariables();
-
-            for(int i = 0 ; i < vFieldNames.size(); i++)
-            {
-                EvaluateFunction(vFieldNames[i], pArray[i], pFunctionName,
-                                 pTime, domain);
-            }
-        }
-
-        /**
-        * Populates a forcing function for each of the dependent variables
-        * using the expression provided by the BoundaryConditions object.
-        * @param   force           Array of fields to assign forcing.
-        */
-        void EquationSystem::EvaluateFunction(
-            std::vector<std::string> pFieldNames,
-            Array<OneD, Array<OneD, NekDouble> > &pFields,
-            const std::string &pFunctionName,
-            const NekDouble &pTime,
-            const int domain)
-        {
-            ASSERTL1(pFieldNames.size() == pFields.num_elements(),
-                    "Function '" + pFunctionName +
-                        "' variable list size mismatch with array storage.");
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                    "Function '" + pFunctionName + "' does not exist.");
-
-            for (int i = 0; i < pFieldNames.size(); i++)
-            {
-                EvaluateFunction(pFieldNames[i], pFields[i], pFunctionName, pTime,
-                                domain);
-            }
-        }
-
-        /**
-        * Populates a function for each of the dependent variables using
-        * the expression or filenames provided by the SessionReader object.
-        * @param   force           Array of fields to assign forcing.
-        */
-        void EquationSystem::EvaluateFunction(
-            std::vector<std::string> pFieldNames,
-            Array<OneD, MultiRegions::ExpListSharedPtr> &pFields,
-            const std::string &pFunctionName,
-            const NekDouble &pTime,
-            const int domain)
-        {
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                    "Function '" + pFunctionName + "' does not exist.");
-            ASSERTL0(pFieldNames.size() == pFields.num_elements(),
-                    "Field list / name list size mismatch.");
-
-            for (int i = 0; i < pFieldNames.size(); i++)
-            {
-                EvaluateFunction(pFieldNames[i], pFields[i]->UpdatePhys(),
-                                pFunctionName, pTime, domain);
-                pFields[i]->FwdTrans_IterPerExp(pFields[i]->GetPhys(),
-                                                pFields[i]->UpdateCoeffs());
-            }
-        }
-
-        void EquationSystem::EvaluateFunction(std::string pFieldName,
-                                            Array<OneD, NekDouble> &pArray,
-                                            const std::string &pFunctionName,
-                                            const NekDouble &pTime,
-                                            const int domain)
-        {
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                    "Function '" + pFunctionName + "' does not exist.");
-
-            LibUtilities::FunctionType vType;
-            vType = m_session->GetFunctionType(pFunctionName, pFieldName, domain);
-            if (vType == LibUtilities::eFunctionTypeExpression)
-            {
-                EvaluateFunctionExp(pFieldName, pArray, pFunctionName, pTime, domain);
-            }
-            else if (vType == LibUtilities::eFunctionTypeFile ||
-                    vType == LibUtilities::eFunctionTypeTransientFile)
-            {
-                std::string filename =
-                    m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
-
-                if (boost::filesystem::path(filename).extension() != ".pts")
-                {
-                    EvaluateFunctionFld(pFieldName, pArray, pFunctionName, pTime,
-                                        domain);
-                }
-                else
-                {
-                    EvaluateFunctionPts(pFieldName, pArray, pFunctionName, pTime,
-                                        domain);
-                }
-            }
-        }
-
-        void EquationSystem::EvaluateFunctionExp(string pFieldName,
-                                                Array<OneD, NekDouble> &pArray,
-                                                const string &pFunctionName,
-                                                const NekDouble &pTime,
-                                                const int domain)
-        {
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                    "Function '" + pFunctionName + "' does not exist.");
-
-            unsigned int nq = m_fields[0]->GetNpoints();
-            if (pArray.num_elements() < nq)
-            {
-                pArray = Array<OneD, NekDouble>(nq);
-            }
-
-            LibUtilities::FunctionType vType;
-            vType = m_session->GetFunctionType(pFunctionName, pFieldName, domain);
-            ASSERTL0(vType == LibUtilities::eFunctionTypeExpression,
-                    "vType not eFunctionTypeExpression");
-
-            Array<OneD, NekDouble> x0(nq);
-            Array<OneD, NekDouble> x1(nq);
-            Array<OneD, NekDouble> x2(nq);
-
-            // Get the coordinates (assuming all fields have the same
-            // discretisation)
-            m_fields[0]->GetCoords(x0, x1, x2);
-            LibUtilities::EquationSharedPtr ffunc =
-                m_session->GetFunction(pFunctionName, pFieldName, domain);
-
-            ffunc->Evaluate(x0, x1, x2, pTime, pArray);
-        }
-
-        void EquationSystem::EvaluateFunctionFld(string pFieldName,
-                                                Array<OneD, NekDouble> &pArray,
-                                                const string &pFunctionName,
-                                                const NekDouble &pTime,
-                                                const int domain)
-        {
-
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                    "Function '" + pFunctionName + "' does not exist.");
-
-            unsigned int nq = m_fields[0]->GetNpoints();
-            if (pArray.num_elements() < nq)
-            {
-                pArray = Array<OneD, NekDouble>(nq);
-            }
-
-            LibUtilities::FunctionType vType;
-            vType = m_session->GetFunctionType(pFunctionName, pFieldName, domain);
-            ASSERTL0(vType == LibUtilities::eFunctionTypeFile ||
-                        vType == LibUtilities::eFunctionTypeTransientFile,
-                    "vType not eFunctionTypeFile or eFunctionTypeTransientFile");
-
-            std::string filename =
-                m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
-            std::string fileVar = m_session->GetFunctionFilenameVariable(
-                pFunctionName, pFieldName, domain);
-
-            if (fileVar.length() == 0)
-            {
-                fileVar = pFieldName;
-            }
-
-            //  In case of eFunctionTypeTransientFile, generate filename from
-            //  format string
-            if (vType == LibUtilities::eFunctionTypeTransientFile)
-            {
-                try
-                {
-#if (defined _WIN32 && _MSC_VER < 1900)
-                    // We need this to make sure boost::format has always
-                    // two digits in the exponents of Scientific notation.
-                    unsigned int old_exponent_format;
-                    old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
-                    filename = boost::str(boost::format(filename) % pTime);
-                    _set_output_format(old_exponent_format);
-#else
-                    filename = boost::str(boost::format(filename) % pTime);
-#endif
-                }
-                catch (...)
-                {
-                    ASSERTL0(false, "Invalid Filename in function \"" + pFunctionName +
-                                        "\", variable \"" + fileVar + "\"")
-                }
-            }
-
-            std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
-            std::vector<std::vector<NekDouble> > FieldData;
-
-            // Define list of global element ids
-            int numexp = m_fields[0]->GetExpSize();
-            Array<OneD, int> ElementGIDs(numexp);
-            for (int i = 0; i < numexp; ++i)
-            {
-                ElementGIDs[i] = m_fields[0]->GetExp(i)->GetGeom()->GetGlobalID();
-            }
-
-            // check if we already loaded this file. For transient files,
-            // funcFilename != filename so we can make sure we only keep the
-            // latest field per funcFilename.
-            std::string funcFilename =
-                m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
-            if (m_loadedFldFields.find(funcFilename) != m_loadedFldFields.end())
-            {
-                // found
-                if (m_loadedFldFields[funcFilename].first == filename)
-                {
-                    // found
-                    FieldDef  = m_loadedFldFields[funcFilename].second.fieldDef;
-                    FieldData = m_loadedFldFields[funcFilename].second.fieldData;
-                }
-                else
-                {
-                    LibUtilities::FieldIOSharedPtr pts_fld =
-                        LibUtilities::FieldIO::CreateForFile(m_session, filename);
-                    pts_fld->Import(filename, FieldDef, FieldData,
-                                    LibUtilities::NullFieldMetaDataMap,
-                                    ElementGIDs);
-                }
-            }
-            else
-            {
-                LibUtilities::FieldIOSharedPtr pts_fld =
-                        LibUtilities::FieldIO::CreateForFile(m_session, filename);
-                pts_fld->Import(filename, FieldDef, FieldData,
-                                LibUtilities::NullFieldMetaDataMap,
-                                ElementGIDs);
-            }
-            // Now we overwrite the field we had in
-            // m_loadedFldFields[funcFilename] before, making sure we only keep
-            // one field per funcFilename in memory
-            m_loadedFldFields[funcFilename].first            = filename;
-            m_loadedFldFields[funcFilename].second.fieldDef  = FieldDef;
-            m_loadedFldFields[funcFilename].second.fieldData = FieldData;
-
-            int idx = -1;
-            Array<OneD, NekDouble> vCoeffs(m_fields[0]->GetNcoeffs(), 0.0);
-            // Loop over all the expansions
-            for (int i = 0; i < FieldDef.size(); ++i)
-            {
-                // Find the index of the required field in the
-                // expansion segment
-                for (int j = 0; j < FieldDef[i]->m_fields.size(); ++j)
-                {
-                    if (FieldDef[i]->m_fields[j] == fileVar)
-                    {
-                        idx = j;
-                    }
-                }
-
-                if (idx >= 0)
-                {
-                    m_fields[0]->ExtractDataToCoeffs(
-                        FieldDef[i], FieldData[i], FieldDef[i]->m_fields[idx], vCoeffs);
-                }
-                else
-                {
-                    cout << "Field " + fileVar + " not found." << endl;
-                }
-            }
-
-            m_fields[0]->BwdTrans_IterPerExp(vCoeffs, pArray);
-        }
-
-        void EquationSystem::EvaluateFunctionPts(string pFieldName,
-                                                Array<OneD, NekDouble> &pArray,
-                                                const string &pFunctionName,
-                                                const NekDouble &pTime,
-                                                const int domain)
+        SessionFunctionSharedPtr EquationSystem::GetFunction(
+            std::string name,
+            const MultiRegions::ExpListSharedPtr &field,
+            bool cache)
         {
-
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                    "Function '" + pFunctionName + "' does not exist.");
-
-            unsigned int nq = m_fields[0]->GetNpoints();
-            if (pArray.num_elements() < nq)
-            {
-                pArray = Array<OneD, NekDouble>(nq);
-            }
-
-            LibUtilities::FunctionType vType;
-            vType = m_session->GetFunctionType(pFunctionName, pFieldName, domain);
-            ASSERTL0(vType == LibUtilities::eFunctionTypeFile ||
-                        vType == LibUtilities::eFunctionTypeTransientFile,
-                    "vType not eFunctionTypeFile or eFunctionTypeTransientFile");
-
-            std::string filename =
-                m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
-            std::string fileVar = m_session->GetFunctionFilenameVariable(
-                pFunctionName, pFieldName, domain);
-
-            if (fileVar.length() == 0)
+            MultiRegions::ExpListSharedPtr vField = field;
+            if (!field)
             {
-                fileVar = pFieldName;
+                vField = m_fields[0];
             }
 
-            //  In case of eFunctionTypeTransientFile, generate filename from
-            //  format string
-            if (vType == LibUtilities::eFunctionTypeTransientFile)
+            if (cache)
             {
-                try
+                if ((m_sessionFunctions.find(name) == m_sessionFunctions.end())
+                    || (m_sessionFunctions[name]->GetSession() != m_session)
+                    || (m_sessionFunctions[name]->GetExpansion() != vField)
+                )
                 {
-#if (defined _WIN32 && _MSC_VER < 1900)
-                    // We need this to make sure boost::format has always
-                    // two digits in the exponents of Scientific notation.
-                    unsigned int old_exponent_format;
-                    old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
-                    filename = boost::str(boost::format(filename) % pTime);
-                    _set_output_format(old_exponent_format);
-#else
-                    filename = boost::str(boost::format(filename) % pTime);
-#endif
+                    m_sessionFunctions[name] =
+                        MemoryManager<SessionFunction>::AllocateSharedPtr(
+                            m_session, vField, name, cache);
                 }
-                catch (...)
-                {
-                    ASSERTL0(false, "Invalid Filename in function \"" + pFunctionName +
-                                        "\", variable \"" + fileVar + "\"")
-                }
-            }
 
-            LibUtilities::PtsFieldSharedPtr outPts;
-            // check if we already loaded this file. For transient files,
-            // funcFilename != filename so we can make sure we only keep the
-            // latest pts field per funcFilename.
-            std::string funcFilename =
-                m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
-
-            if (m_loadedPtsFields.find(funcFilename) != m_loadedPtsFields.end())
-            {
-                // found
-                if (m_loadedPtsFields[funcFilename].first == filename)
-                {
-                    // found
-                    outPts = m_loadedPtsFields[funcFilename].second;
-                }
-                else
-                {
-                    LoadPts(funcFilename, filename, outPts);
-                }
+                return m_sessionFunctions[name];
             }
             else
             {
-                LoadPts(funcFilename, filename, outPts);
-            }
-            // Now we overwrite the field we had in
-            // m_loadedPtsFields[funcFilename] before, making sure we only keep
-            // one field per funcFilename in memory
-            m_loadedPtsFields[funcFilename].first  = filename;
-            m_loadedPtsFields[funcFilename].second = outPts;
-
-            int fieldInd;
-            vector<string> fieldNames = outPts->GetFieldNames();
-            for (fieldInd = 0; fieldInd < fieldNames.size(); ++fieldInd)
-            {
-                if (outPts->GetFieldName(fieldInd) == pFieldName)
-                {
-                    break;
-                }
-            }
-            ASSERTL0(fieldInd != fieldNames.size(), "field not found");
-
-            pArray = outPts->GetPts(fieldInd + outPts->GetDim());
-        }
-
-        void EquationSystem::LoadPts(std::string funcFilename,
-                                    std::string filename,
-                                    LibUtilities::PtsFieldSharedPtr &outPts)
-        {
-            unsigned int nq = m_fields[0]->GetNpoints();
-
-            LibUtilities::PtsFieldSharedPtr inPts;
-            LibUtilities::PtsIO ptsIO(m_session->GetComm());
-            ptsIO.Import(filename, inPts);
-
-            Array<OneD, Array<OneD, NekDouble> > pts(inPts->GetDim() +
-                                                    inPts->GetNFields());
-            for (int i = 0; i < inPts->GetDim() + inPts->GetNFields(); ++i)
-            {
-                pts[i] = Array<OneD, NekDouble>(nq);
-            }
-            if (inPts->GetDim() == 1)
-            {
-                m_fields[0]->GetCoords(pts[0]);
-            }
-            else if (inPts->GetDim() == 2)
-            {
-                m_fields[0]->GetCoords(pts[0], pts[1]);
-            }
-            else if (inPts->GetDim() == 3)
-            {
-                m_fields[0]->GetCoords(pts[0], pts[1], pts[2]);
-            }
-            outPts = MemoryManager<LibUtilities::PtsField>::AllocateSharedPtr(
-                inPts->GetDim(), inPts->GetFieldNames(), pts);
-
-            //  check if we already have an interolator for this funcFilename
-            if (m_interpolators.find(funcFilename) == m_interpolators.end())
-            {
-                m_interpolators[funcFilename] =
-                    FieldUtils::Interpolator(Nektar::FieldUtils::eShepard);
-                if (m_comm->GetRank() == 0)
-                {
-                    m_interpolators[funcFilename].SetProgressCallback(
-                        &EquationSystem::PrintProgressbar, this);
-                }
-                m_interpolators[funcFilename].CalcWeights(inPts, outPts);
-                if (m_comm->GetRank() == 0)
-                {
-                    cout << endl;
-                    if (GetSession()->DefinesCmdLineArgument("verbose"))
-                    {
-                        m_interpolators[funcFilename].PrintStatistics();
-                    }
-                }
-            }
-            m_interpolators[funcFilename].Interpolate(inPts, outPts);
-        }
-
-
-        /**
-         * @brief Provide a description of a function for a given field name.
-         *
-         * @param pFieldName     Field name.
-         * @param pFunctionName  Function name.
-         */
-        std::string EquationSystem::DescribeFunction(
-            std::string pFieldName,
-            const std::string &pFunctionName,
-            const int domain)
-        {
-            ASSERTL0(m_session->DefinesFunction(pFunctionName),
-                     "Function '" + pFunctionName + "' does not exist.");
-            
-            std::string retVal;
-            LibUtilities::FunctionType vType;
-            
-            vType = m_session->GetFunctionType(pFunctionName, pFieldName);
-            if (vType == LibUtilities::eFunctionTypeExpression)
-            {
-                LibUtilities::EquationSharedPtr ffunc
-                    = m_session->GetFunction(pFunctionName, pFieldName,domain);
-                retVal = ffunc->GetExpression();
+                return SessionFunctionSharedPtr(new SessionFunction(m_session, vField, name, cache));
             }
-            else if (vType == LibUtilities::eFunctionTypeFile)
-            {
-                std::string filename
-                    = m_session->GetFunctionFilename(pFunctionName, pFieldName,domain);
-                retVal = "from file " + filename;
-            }
-            
-            return retVal;
         }
         
         /**
@@ -1188,8 +754,7 @@ namespace Nektar
                     Array<OneD, NekDouble>
                         exactsoln(m_fields[field]->GetNpoints());
 
-                    EvaluateFunction(m_session->GetVariable(field), exactsoln, 
-                                     "ExactSolution", m_time);
+                    GetFunction("ExactSolution")->Evaluate(m_session->GetVariable(field), exactsoln, m_time);
 
                     L2error = m_fields[field]->L2(m_fields[field]->GetPhys(), exactsoln);
                 }
@@ -1247,8 +812,7 @@ namespace Nektar
                     Array<OneD, NekDouble>
                         exactsoln(m_fields[field]->GetNpoints());
 
-                    EvaluateFunction(m_session->GetVariable(field), exactsoln,
-                                     "ExactSolution", m_time);
+                    GetFunction("ExactSolution")->Evaluate(m_session->GetVariable(field), exactsoln, m_time);
 
                     Linferror = m_fields[field]->Linf(m_fields[field]->GetPhys(), exactsoln);
                 }
@@ -1356,8 +920,7 @@ namespace Nektar
         
             if (m_session->DefinesFunction("InitialConditions"))
             {
-                EvaluateFunction(m_session->GetVariables(), m_fields, 
-                                 "InitialConditions", m_time, domain);
+                GetFunction("InitialConditions")->Evaluate(m_session->GetVariables(), m_fields, m_time, domain);
                 
                 if (m_session->GetComm()->GetRank() == 0)
                 {
@@ -1366,7 +929,7 @@ namespace Nektar
                     {
                         std::string varName = m_session->GetVariable(i);
                         cout << "  - Field " << varName << ": "
-                             << DescribeFunction(varName, "InitialConditions",domain)
+                             << GetFunction("InitialConditions")->Describe(varName, domain)
                              << endl;
                     }
                 }
@@ -1406,8 +969,7 @@ namespace Nektar
             Vmath::Zero(outfield.num_elements(), outfield, 1);
             if (m_session->DefinesFunction("ExactSolution"))
             {
-                EvaluateFunction(m_session->GetVariable(field), outfield, 
-                                 "ExactSolution", time);
+                GetFunction("ExactSolution")->Evaluate(m_session->GetVariable(field), outfield, time);
             }
         }
 
@@ -1431,7 +993,7 @@ namespace Nektar
             vel.push_back("Vz");
             vel.resize(m_spacedim);
             SetUpBaseFields(m_graph);
-            EvaluateFunction(vel, base, "BaseFlow");
+            GetFunction("BaseFlow")->Evaluate(vel, base);
         }    	    
     
         void EquationSystem::SetUpBaseFields(
diff --git a/library/SolverUtils/EquationSystem.h b/library/SolverUtils/EquationSystem.h
index 6e8777469cd8ccfbc31f8adc071868fc0fa70f5d..fc0063a52cbb19e720d33919665e6a4fd2cec12e 100644
--- a/library/SolverUtils/EquationSystem.h
+++ b/library/SolverUtils/EquationSystem.h
@@ -48,6 +48,7 @@
 #include <MultiRegions/ExpList.h>
 #include <SolverUtils/SolverUtilsDeclspec.h>
 #include <SolverUtils/Core/Misc.h>
+#include <SolverUtils/Core/SessionFunction.h>
 
 namespace Nektar
 {
@@ -68,11 +69,6 @@ class Interpolator;
         > EquationSystemFactory;
         SOLVER_UTILS_EXPORT EquationSystemFactory& GetEquationSystemFactory();
 
-        struct loadedFldField {
-            std::vector<LibUtilities::FieldDefinitionsSharedPtr> fieldDef;
-            std::vector<std::vector<NekDouble> > fieldData;
-        } ;
-
         /// A base class for describing how to solve specific equations.
         class EquationSystem : public boost::enable_shared_from_this<EquationSystem>
         {
@@ -143,43 +139,12 @@ class Interpolator;
             
             /// Set parameter m_lambda
             SOLVER_UTILS_EXPORT inline void SetLambda(NekDouble lambda);
-            
-            /// Evaluates a function as specified in the session file.
-            SOLVER_UTILS_EXPORT void EvaluateFunction(
-                Array<OneD, Array<OneD, NekDouble> >& pArray,
-                std::string pFunctionName,
-                const NekDouble pTime = 0.0,
-                const int domain = 0);
-            
-            /// Populate given fields with the function from session.
-            SOLVER_UTILS_EXPORT void EvaluateFunction(
-                std::vector<std::string> pFieldNames,
-                Array<OneD, Array<OneD, NekDouble> > &pFields,
-                const std::string& pName,
-                const NekDouble& pTime = 0.0,
-                const int domain = 0);
-            
-            /// Populate given fields with the function from session.
-            SOLVER_UTILS_EXPORT void EvaluateFunction(
-                std::vector<std::string> pFieldNames,
-                Array<OneD, MultiRegions::ExpListSharedPtr> &pFields,
-                const std::string& pName,
-                const NekDouble& pTime = 0.0,
-                const int domain = 0);
-            
-            // Populate an array with a function variable from session.
-            SOLVER_UTILS_EXPORT void EvaluateFunction(
-                std::string pFieldName,
-                Array<OneD, NekDouble>& pArray,
-                const std::string& pFunctionName,
-                const NekDouble& pTime = 0.0,
-                const int domain = 0);
-            
-            // Describe a function.
-            SOLVER_UTILS_EXPORT std::string DescribeFunction(
-                std::string pFieldName,
-                const std::string &pFunctionName,
-                const int domain);
+
+            /// Get a SessionFunction by name
+            SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(
+                std::string name,
+                const MultiRegions::ExpListSharedPtr &field = MultiRegions::NullExpListSharedPtr,
+                bool cache = false);
             
             /// Perform initialisation of the base flow.
             SOLVER_UTILS_EXPORT void InitialiseBaseFlow(
@@ -458,14 +423,10 @@ class Interpolator;
             LibUtilities::CommSharedPtr                 m_comm;
             /// The session reader
             LibUtilities::SessionReaderSharedPtr        m_session;
+            /// Map of known SessionFunctions
+            std::map<std::string, SolverUtils::SessionFunctionSharedPtr> m_sessionFunctions;
             /// Field input/output
             LibUtilities::FieldIOSharedPtr              m_fld;
-            /// Map of interpolator objects
-            std::map<std::string, FieldUtils::Interpolator > m_interpolators;
-            /// pts fields we already read from disk: {funcFilename: (filename, ptsfield)}
-            std::map<std::string, std::pair<std::string, LibUtilities::PtsFieldSharedPtr> > m_loadedPtsFields;
-            // fld fiels already loaded from disk: {funcFilename: (filename, loadedFldField)}
-            std::map<std::string, std::pair<std::string, loadedFldField> > m_loadedFldFields;
             /// Array holding all dependent variables.
             Array<OneD, MultiRegions::ExpListSharedPtr> m_fields;
             /// Base fields.
@@ -605,34 +566,6 @@ class Interpolator;
                 unsigned int field,
                 Array<OneD, NekDouble> &outfield,
                 const NekDouble time);
-
-            // Populate an array with a function variable from session.
-            SOLVER_UTILS_EXPORT void EvaluateFunctionExp(
-                std::string pFieldName,
-                Array<OneD, NekDouble>& pArray,
-                const std::string& pFunctionName,
-                const NekDouble& pTime = 0.0,
-                const int domain = 0);
-
-            // Populate an array with a function variable from session.
-            SOLVER_UTILS_EXPORT void EvaluateFunctionFld(
-                std::string pFieldName,
-                Array<OneD, NekDouble>& pArray,
-                const std::string& pFunctionName,
-                const NekDouble& pTime = 0.0,
-                const int domain = 0);
-
-            SOLVER_UTILS_EXPORT void EvaluateFunctionPts(
-                std::string pFieldName,
-                Array<OneD, NekDouble>& pArray,
-                const std::string& pFunctionName,
-                const NekDouble& pTime = 0.0,
-                const int domain = 0);
-
-            SOLVER_UTILS_EXPORT void LoadPts(
-                std::string funcFilename,
-                std::string filename,
-                Nektar::LibUtilities::PtsFieldSharedPtr &outPts);
             
             //Initialise m_base in order to store the base flow from a file 
             SOLVER_UTILS_EXPORT void SetUpBaseFields(SpatialDomains::MeshGraphSharedPtr &mesh);
diff --git a/library/SolverUtils/Forcing/Forcing.cpp b/library/SolverUtils/Forcing/Forcing.cpp
index 1fd32714ecc61d5e86eda74be21eec587cc313b9..dc2c0da7911717cc7f2eada892cbc0eaa03be2a4 100644
--- a/library/SolverUtils/Forcing/Forcing.cpp
+++ b/library/SolverUtils/Forcing/Forcing.cpp
@@ -153,79 +153,29 @@ namespace Nektar
             pEqn->Evaluate(x0, x0, x0, pTime, pArray);
         }
         
-
-
-        void Forcing::EvaluateFunction(
-                Array<OneD, MultiRegions::ExpListSharedPtr>       pFields,
-                LibUtilities::SessionReaderSharedPtr              pSession,
-                std::string                                       pFieldName,
-                Array<OneD, NekDouble>&                           pArray,
-                const std::string&                                pFunctionName,
-                NekDouble                                         pTime)
+        SessionFunctionSharedPtr Forcing::GetFunction(
+                const Array<OneD, MultiRegions::ExpListSharedPtr>  &pFields,
+                const LibUtilities::SessionReaderSharedPtr         &pSession,
+                std::string                                         pName,
+                bool                                                pCache)
         {
-            ASSERTL0(pSession->DefinesFunction(pFunctionName),
-                     "Function '" + pFunctionName + "' does not exist.");
-
-            unsigned int nq = pFields[0]->GetNpoints();
-            if (pArray.num_elements() != nq)
+            if (pCache)
             {
-                pArray = Array<OneD, NekDouble> (nq);
-            }
+                if ((m_sessionFunctions.find(pName) == m_sessionFunctions.end())
+                    || (m_sessionFunctions[pName]->GetSession() != pSession)
+                    || (m_sessionFunctions[pName]->GetExpansion() != pFields[0])
+                )
+                {
+                    m_sessionFunctions[pName] =
+                        MemoryManager<SessionFunction>::AllocateSharedPtr(
+                            pSession, pFields[0], pName, pCache);
+                }
 
-            LibUtilities::FunctionType vType;
-            vType = pSession->GetFunctionType(pFunctionName, pFieldName);
-            if (vType == LibUtilities::eFunctionTypeExpression)
-            {
-                Array<OneD, NekDouble> x0(nq);
-                Array<OneD, NekDouble> x1(nq);
-                Array<OneD, NekDouble> x2(nq);
-                
-                pFields[0]->GetCoords(x0, x1, x2);
-                LibUtilities::EquationSharedPtr ffunc =
-                    pSession->GetFunction(pFunctionName, pFieldName);
-                
-                ffunc->Evaluate(x0, x1, x2, pTime, pArray);
+                return m_sessionFunctions[pName];
             }
-            else if (vType == LibUtilities::eFunctionTypeFile)
+            else
             {
-                std::string filename = pSession->GetFunctionFilename(
-                                                    pFunctionName,
-                                                    pFieldName);
-
-                std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
-                std::vector<std::vector<NekDouble> > FieldData;
-                Array<OneD, NekDouble> vCoeffs(pFields[0]->GetNcoeffs());
-                Vmath::Zero(vCoeffs.num_elements(), vCoeffs, 1);
-
-                LibUtilities::FieldIOSharedPtr fld =
-                    LibUtilities::FieldIO::CreateForFile(m_session, filename);
-                fld->Import(filename, FieldDef, FieldData);
-
-                int idx = -1;
-                for (int i = 0; i < FieldDef.size(); ++i)
-                {
-                    for (int j = 0; j < FieldDef[i]->m_fields.size(); ++j)
-                    {
-                        if (FieldDef[i]->m_fields[j] == pFieldName)
-                        {
-                            idx = j;
-                        }
-                    }
-
-                    if (idx >= 0)
-                    {
-                        pFields[0]->ExtractDataToCoeffs(
-                                                    FieldDef[i],
-                                                    FieldData[i],
-                                                    FieldDef[i]->m_fields[idx],
-                                                    vCoeffs);
-                    }
-                    else
-                    {
-                        cout << "Field " + pFieldName + " not found." << endl;
-                    }
-                }
-                pFields[0]->BwdTrans_IterPerExp(vCoeffs, pArray);
+                return SessionFunctionSharedPtr(new SessionFunction(pSession, pFields[0], pName, pCache));
             }
         }
 
diff --git a/library/SolverUtils/Forcing/Forcing.h b/library/SolverUtils/Forcing/Forcing.h
index 905dee1effd5e652819cc90d2cddb4683e1e475c..3b0c726fa4c2a902a6183f63725b4671503f66d0 100644
--- a/library/SolverUtils/Forcing/Forcing.h
+++ b/library/SolverUtils/Forcing/Forcing.h
@@ -41,6 +41,7 @@
 #include <LibUtilities/BasicUtils/NekFactory.hpp>
 #include <LibUtilities/BasicUtils/SharedArray.hpp>
 #include <MultiRegions/ExpList.h>
+#include <SolverUtils/Core/SessionFunction.h>
 #include <SolverUtils/SolverUtilsDeclspec.h>
 
 namespace Nektar
@@ -102,6 +103,8 @@ namespace SolverUtils
             Array<OneD, Array<OneD, NekDouble> > m_Forcing;
             /// Number of variables
             int m_NumVariable;
+            /// Map of known SessionFunctions
+            std::map<std::string, SolverUtils::SessionFunctionSharedPtr> m_sessionFunctions;
 
             /// Constructor
             SOLVER_UTILS_EXPORT Forcing(
@@ -118,13 +121,12 @@ namespace SolverUtils
                 Array<OneD, Array<OneD, NekDouble> >        &outarray,
                 const NekDouble &time)=0;
 
-            SOLVER_UTILS_EXPORT void EvaluateFunction(
-                    Array<OneD, MultiRegions::ExpListSharedPtr> pFields,
-                    LibUtilities::SessionReaderSharedPtr        pSession,
-                    std::string                                 pFieldName, 
-                    Array<OneD, NekDouble>&                     pArray,
-                    const std::string& pFunctionName,
-                    NekDouble pTime = NekDouble(0));
+                /// Get a SessionFunction by name
+            SOLVER_UTILS_EXPORT SessionFunctionSharedPtr GetFunction(
+                const Array<OneD, MultiRegions::ExpListSharedPtr>  &pFields,
+                const LibUtilities::SessionReaderSharedPtr         &pSession,
+                std::string                                         pName,
+                bool                                                pCache = false);
 
             SOLVER_UTILS_EXPORT void EvaluateTimeFunction(
                     LibUtilities::SessionReaderSharedPtr        pSession,
diff --git a/library/SolverUtils/Forcing/ForcingAbsorption.cpp b/library/SolverUtils/Forcing/ForcingAbsorption.cpp
index 6b632e9882e24e11c32fd399a4cb88fc71f01695..dc62e044ed753d3c5e21c1ee6655f941f15eb128 100644
--- a/library/SolverUtils/Forcing/ForcingAbsorption.cpp
+++ b/library/SolverUtils/Forcing/ForcingAbsorption.cpp
@@ -81,8 +81,7 @@ namespace SolverUtils
                      "Variable '" + s_FieldStr + "' not defined.");
             m_Absorption[i]  = Array<OneD, NekDouble> (npts, 0.0);
             m_Forcing[i] = Array<OneD, NekDouble> (npts, 0.0);
-            EvaluateFunction(pFields, m_session, s_FieldStr,
-                             m_Absorption[i], funcName);
+            GetFunction(pFields, m_session, funcName)->Evaluate(s_FieldStr, m_Absorption[i]);
         }
 
         funcNameElmt = pForce->FirstChildElement("REFFLOW");
@@ -99,8 +98,7 @@ namespace SolverUtils
                 ASSERTL0(m_session->DefinesFunction(funcName, s_FieldStr),
                          "Variable '" + s_FieldStr + "' not defined.");
                 m_Refflow[i] = Array<OneD, NekDouble> (npts, 0.0);
-                EvaluateFunction(pFields, m_session, s_FieldStr,
-                                 m_Refflow[i], funcName);
+                GetFunction(pFields, m_session, funcName)->Evaluate(s_FieldStr, m_Refflow[i]);
             }
             m_hasRefFlow = true;
         }
diff --git a/library/SolverUtils/Forcing/ForcingBody.cpp b/library/SolverUtils/Forcing/ForcingBody.cpp
index de4463a683c05542eb7f2de61caf10d520b7a792..657d1dcb078d7e1769c899978a3747b1bdeea472 100644
--- a/library/SolverUtils/Forcing/ForcingBody.cpp
+++ b/library/SolverUtils/Forcing/ForcingBody.cpp
@@ -129,8 +129,7 @@ namespace SolverUtils
             std::string  s_FieldStr   = m_session->GetVariable(i);
             ASSERTL0(m_session->DefinesFunction(m_funcName, s_FieldStr),
                      "Variable '" + s_FieldStr + "' not defined.");
-            EvaluateFunction(pFields, m_session, s_FieldStr,
-                             m_Forcing[i], m_funcName, time);
+            GetFunction(pFields, m_session, m_funcName, true)->Evaluate(s_FieldStr, m_Forcing[i], time);
         }
 
         // If singleMode or halfMode, transform the forcing term to be in
diff --git a/solvers/ADRSolver/EquationSystems/CFLtester.cpp b/solvers/ADRSolver/EquationSystems/CFLtester.cpp
index e66f4ca49a32775f192ca30ccb06de0fe065026e..0426e238714762740ca75a1f5266b2445e5837ac 100644
--- a/solvers/ADRSolver/EquationSystems/CFLtester.cpp
+++ b/solvers/ADRSolver/EquationSystems/CFLtester.cpp
@@ -62,7 +62,7 @@ namespace Nektar
         vel.push_back("Vz");
         vel.resize(m_spacedim);
 
-        EvaluateFunction(vel, m_velocity, "AdvectionVelocity");
+        GetFunction( "AdvectionVelocity")->Evaluate(vel,  m_velocity);
 
         if (m_explicitAdvection)
         {
diff --git a/solvers/ADRSolver/EquationSystems/EigenValuesAdvection.cpp b/solvers/ADRSolver/EquationSystems/EigenValuesAdvection.cpp
index 379e67d1725dbac06a00b35a7cd0ab87afa81f46..5d036d20e7d9a59e76684d964868bbcd8c20c7ac 100644
--- a/solvers/ADRSolver/EquationSystems/EigenValuesAdvection.cpp
+++ b/solvers/ADRSolver/EquationSystems/EigenValuesAdvection.cpp
@@ -61,7 +61,7 @@ namespace Nektar
         vel.push_back("Vz");
         vel.resize(m_spacedim);
 
-        EvaluateFunction(vel, m_velocity, "AdvectionVelocity");
+        GetFunction( "AdvectionVelocity")->Evaluate(vel,  m_velocity);
     }
 	
 	void EigenValuesAdvection::v_DoInitialise()
diff --git a/solvers/ADRSolver/EquationSystems/Poisson.cpp b/solvers/ADRSolver/EquationSystems/Poisson.cpp
index 579909c24b7f5d14d1d7dff31f2ff07b33620a35..9a7e8448f54f871d67a974e5ba27dd2f99e9a3ba 100644
--- a/solvers/ADRSolver/EquationSystems/Poisson.cpp
+++ b/solvers/ADRSolver/EquationSystems/Poisson.cpp
@@ -52,7 +52,7 @@ namespace Nektar
     {
         Laplace::v_InitObject();
 
-        EvaluateFunction(m_session->GetVariables(), m_fields, "Forcing");
+        GetFunction("Forcing")->Evaluate(m_session->GetVariables(), m_fields);
     }
 
     Poisson::~Poisson()
diff --git a/solvers/ADRSolver/EquationSystems/Projection.cpp b/solvers/ADRSolver/EquationSystems/Projection.cpp
index 78d86fccead0f59f77e3c892b7ea200aff0ed5ff..0c0ca8e56129acac445ff6a88679a79e0e3b4be2 100644
--- a/solvers/ADRSolver/EquationSystems/Projection.cpp
+++ b/solvers/ADRSolver/EquationSystems/Projection.cpp
@@ -51,7 +51,7 @@ void Projection::v_InitObject()
 {
     EquationSystem::v_InitObject();
 
-    EvaluateFunction(m_session->GetVariables(), m_fields, "Forcing");
+    GetFunction("Forcing")->Evaluate(m_session->GetVariables(), m_fields);
 }
 
 Projection::~Projection()
diff --git a/solvers/ADRSolver/EquationSystems/SteadyAdvectionDiffusion.cpp b/solvers/ADRSolver/EquationSystems/SteadyAdvectionDiffusion.cpp
index c603b166f6df2b144787fe74cbc4ec4adbd13b64..b886cfa30a2a025ddfd63740086c480c58d9ce8f 100644
--- a/solvers/ADRSolver/EquationSystems/SteadyAdvectionDiffusion.cpp
+++ b/solvers/ADRSolver/EquationSystems/SteadyAdvectionDiffusion.cpp
@@ -77,7 +77,7 @@ namespace Nektar
     void SteadyAdvectionDiffusion::v_DoInitialise()
     {
         // set initial forcing from session file
-        EvaluateFunction(m_session->GetVariables(), m_fields, "Forcing");
+        GetFunction("Forcing")->Evaluate(m_session->GetVariables(), m_fields);
     }
 
     void SteadyAdvectionDiffusion::v_DoSolve()
diff --git a/solvers/ADRSolver/EquationSystems/UnsteadyAdvection.cpp b/solvers/ADRSolver/EquationSystems/UnsteadyAdvection.cpp
index 6f9feed1efc252d1f850742908965aa1d2276658..7dc5aad8c0834618a544cc2dadf7923bb47d8628 100644
--- a/solvers/ADRSolver/EquationSystems/UnsteadyAdvection.cpp
+++ b/solvers/ADRSolver/EquationSystems/UnsteadyAdvection.cpp
@@ -74,7 +74,7 @@ namespace Nektar
 
         // Store in the global variable m_velocity the advection velocities
         m_velocity = Array<OneD, Array<OneD, NekDouble> >(m_spacedim);
-        EvaluateFunction(vel, m_velocity, "AdvectionVelocity");
+        GetFunction( "AdvectionVelocity")->Evaluate(vel,  m_velocity);
 
         // Type of advection class to be used
         switch(m_projectionType)
diff --git a/solvers/ADRSolver/EquationSystems/UnsteadyAdvectionDiffusion.cpp b/solvers/ADRSolver/EquationSystems/UnsteadyAdvectionDiffusion.cpp
index ac0afcce65a5d62cb2dac661c8606cb95ebfa0f0..7eeac15b60b7fa891c98004a77dc7ef2e53b55d9 100644
--- a/solvers/ADRSolver/EquationSystems/UnsteadyAdvectionDiffusion.cpp
+++ b/solvers/ADRSolver/EquationSystems/UnsteadyAdvectionDiffusion.cpp
@@ -77,7 +77,7 @@ namespace Nektar
         vel.push_back("Vz");
         vel.resize(m_spacedim);
         
-        EvaluateFunction(vel, m_velocity, "AdvectionVelocity");
+        GetFunction( "AdvectionVelocity")->Evaluate(vel,  m_velocity);
         
         m_session->MatchSolverInfo(
             "SpectralVanishingViscosity", "True", m_useSpecVanVisc, false);
diff --git a/solvers/APESolver/EquationSystems/APE.cpp b/solvers/APESolver/EquationSystems/APE.cpp
index 92661ea3cf994155fb30e1e62044a22dda9e4ab2..16da1cab5b4b0b3eb9149dabb402ecd7ed0643bc 100755
--- a/solvers/APESolver/EquationSystems/APE.cpp
+++ b/solvers/APESolver/EquationSystems/APE.cpp
@@ -137,7 +137,7 @@ void APE::v_InitObject()
     {
         m_bf[i] = Array<OneD, NekDouble>(GetTotPoints());
     }
-    EvaluateFunction(m_bfNames, m_bf, "Baseflow", m_time);
+    GetFunction("Baseflow", m_bfField, true)->Evaluate(m_bfNames, m_bf, m_time);
 
     m_forcing = SolverUtils::Forcing::Load(m_session, m_fields, m_spacedim + 1);
 
@@ -301,7 +301,7 @@ void APE::GetFluxVector(
  */
 bool APE::v_PreIntegrate(int step)
 {
-    EvaluateFunction(m_bfNames, m_bf, "Baseflow", m_time);
+    GetFunction("Baseflow", m_bfField, true)->Evaluate(m_bfNames, m_bf, m_time);
 
     Array<OneD, NekDouble> tmpC(GetNcoeffs());
     std::vector<SolverUtils::ForcingSharedPtr>::const_iterator x;
diff --git a/solvers/CardiacEPSolver/EquationSystems/BidomainRoth.cpp b/solvers/CardiacEPSolver/EquationSystems/BidomainRoth.cpp
index 1897d4e9cd365a114f1fc39c181893f8da6d9fcc..39ef519890064090721bab0f4e889d8e831f2116 100644
--- a/solvers/CardiacEPSolver/EquationSystems/BidomainRoth.cpp
+++ b/solvers/CardiacEPSolver/EquationSystems/BidomainRoth.cpp
@@ -158,8 +158,8 @@ void BidomainRoth::v_InitObject()
                                         aniso_var[j]),
                      "Function 'AnisotropicConductivity' not correctly "
                      "defined.");
-            EvaluateFunction(aniso_var[j], vTemp_j,
-                             "ExtracellularAnisotropicConductivity");
+
+            GetFunction("ExtracellularAnisotropicConductivity")->Evaluate(aniso_var[j], vTemp_j);
 
             // Loop through rows of D
             for (int i = 0; i < j + 1; ++i)
@@ -170,8 +170,7 @@ void BidomainRoth::v_InitObject()
                          "Function 'ExtracellularAnisotropicConductivity' not "
                          "correctly defined.");
 
-                EvaluateFunction(aniso_var[i], vTemp_i,
-                                 "ExtracellularAnisotropicConductivity");
+                GetFunction("ExtracellularAnisotropicConductivity")->Evaluate(aniso_var[i], vTemp_i);
 
                 Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1,
                                 m_vardiffe[varCoeffEnum[k]], 1);
@@ -232,8 +231,7 @@ void BidomainRoth::v_InitObject()
                      "Function 'IntracellularAnisotropicConductivity' not "
                      "correctly defined.");
 
-            EvaluateFunction(aniso_var[j], vTemp_j,
-                             "IntracellularAnisotropicConductivity");
+            GetFunction("IntracellularAnisotropicConductivity")->Evaluate(aniso_var[j], vTemp_j);
 
             // Loop through rows of D
             for (int i = 0; i < j + 1; ++i)
@@ -243,8 +241,7 @@ void BidomainRoth::v_InitObject()
                                     aniso_var[i]),
                          "Function 'IntracellularAnisotropicConductivity' not "
                          "correctly defined.");
-                EvaluateFunction(aniso_var[i], vTemp_i,
-                                 "IntracellularAnisotropicConductivity");
+                GetFunction("IntracellularAnisotropicConductivity")->Evaluate(aniso_var[i], vTemp_i);
 
                 Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1,
                                 m_vardiffi[varCoeffEnum[k]], 1);
diff --git a/solvers/CardiacEPSolver/EquationSystems/Monodomain.cpp b/solvers/CardiacEPSolver/EquationSystems/Monodomain.cpp
index 58dd3ccb210d2c0348dd69bf7143fdb316b41ece..2eec9c40f9e2eb6e06d77b24581d0caad32417b2 100644
--- a/solvers/CardiacEPSolver/EquationSystems/Monodomain.cpp
+++ b/solvers/CardiacEPSolver/EquationSystems/Monodomain.cpp
@@ -168,8 +168,7 @@ namespace Nektar
                                                     aniso_var[j]),
                          "Function 'AnisotropicConductivity' not correctly "
                          "defined.");
-                EvaluateFunction(aniso_var[j], vTemp_j,
-                                 "AnisotropicConductivity");
+                GetFunction("AnisotropicConductivity")->Evaluate(aniso_var[j], vTemp_j);
 
                 // Loop through rows of D
                 for (int i = 0; i < j + 1; ++i)
@@ -178,8 +177,7 @@ namespace Nektar
                                         "AnisotropicConductivity",aniso_var[i]),
                              "Function 'AnisotropicConductivity' not correctly "
                              "defined.");
-                    EvaluateFunction(aniso_var[i], vTemp_i,
-                                     "AnisotropicConductivity");
+                    GetFunction("AnisotropicConductivity")->Evaluate(aniso_var[i], vTemp_i);
 
                     Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1,
                                     m_vardiff[varCoeffEnum[k]], 1);
@@ -223,7 +221,7 @@ namespace Nektar
 
             const std::string varName  = "intensity";
             Array<OneD, NekDouble> vTemp;
-            EvaluateFunction(varName, vTemp, "IsotropicConductivity");
+            GetFunction( "IsotropicConductivity")->Evaluate(varName,  vTemp);
 
             // If the d_min and d_max parameters are defined, then we need to
             // rescale the isotropic conductivity to convert from the source
diff --git a/solvers/CompressibleFlowSolver/Forcing/ForcingQuasi1D.cpp b/solvers/CompressibleFlowSolver/Forcing/ForcingQuasi1D.cpp
index 6f8e6db25833f8a021a288de3dd4e0f18306f706..92794660ad05da1e0a90c9d3aa7c75fdad7bc29b 100644
--- a/solvers/CompressibleFlowSolver/Forcing/ForcingQuasi1D.cpp
+++ b/solvers/CompressibleFlowSolver/Forcing/ForcingQuasi1D.cpp
@@ -80,8 +80,8 @@ void ForcingQuasi1D::v_InitObject(
     std::string  sFieldStr   = m_session->GetVariable(0);
     ASSERTL0(m_session->DefinesFunction(funcName, sFieldStr),
              "Variable '" + sFieldStr + "' not defined.");
-    EvaluateFunction(pFields, m_session, sFieldStr,
-                     m_geomFactor, funcName, 0.0);
+    GetFunction(pFields, m_session, funcName, true)
+        ->Evaluate(sFieldStr, m_geomFactor, 0.0);
     pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[0], m_geomFactor, tmp);
     Vmath::Vdiv(pFields[0]->GetTotPoints(), tmp, 1,
                                             m_geomFactor, 1,
diff --git a/solvers/IncNavierStokesSolver/EquationSystems/CoupledLinearNS.cpp b/solvers/IncNavierStokesSolver/EquationSystems/CoupledLinearNS.cpp
index 50c241722f3a4c255eb843df98b8952e10d91d1c..0ac98a87eb0a9ff629ae6c1ff898dd5e9282ba9f 100644
--- a/solvers/IncNavierStokesSolver/EquationSystems/CoupledLinearNS.cpp
+++ b/solvers/IncNavierStokesSolver/EquationSystems/CoupledLinearNS.cpp
@@ -1258,7 +1258,7 @@ namespace Nektar
                 {
                     fieldStr.push_back(m_boundaryConditions->GetVariable(m_velocity[i]));
                 }
-                EvaluateFunction(fieldStr,AdvField,"AdvectionVelocity");
+                GetFunction("AdvectionVelocity")->Evaluate(fieldStr, AdvField);
                 
                 SetUpCoupledMatrix(0.0,AdvField,false);
             }
@@ -1290,7 +1290,7 @@ namespace Nektar
                     {
                         fieldStr.push_back(m_boundaryConditions->GetVariable(m_velocity[i]));
                     }
-                    EvaluateFunction(fieldStr, Restart, "Restart");
+                    GetFunction( "Restart")->Evaluate(fieldStr,  Restart);
                     
                     for(int i = 0; i < m_velocity.num_elements(); ++i)
                     {
@@ -1338,7 +1338,7 @@ namespace Nektar
                 {
                     fieldStr.push_back(m_boundaryConditions->GetVariable(m_velocity[i]));
                 }
-                EvaluateFunction(fieldStr,AdvField,"AdvectionVelocity");
+                GetFunction("AdvectionVelocity")->Evaluate(fieldStr, AdvField);
                 
                 SetUpCoupledMatrix(m_lambda,AdvField,true);
             }
@@ -1548,7 +1548,7 @@ namespace Nektar
             {
                 fieldStr.push_back(m_boundaryConditions->GetVariable(m_velocity[i]));
             }
-            EvaluateFunction(fieldStr, m_ForcingTerm, "ForcingTerm");
+            GetFunction( "ForcingTerm")->Evaluate(fieldStr,  m_ForcingTerm);
             for(int i = 0; i < m_velocity.num_elements(); ++i)
             {
                 m_fields[m_velocity[i]]->FwdTrans_IterPerExp(m_ForcingTerm[i], m_ForcingTerm_Coeffs[i]);
diff --git a/solvers/IncNavierStokesSolver/Forcing/ForcingMovingBody.cpp b/solvers/IncNavierStokesSolver/Forcing/ForcingMovingBody.cpp
index ac734c19edc8500f139b31b16a1094c7bb3dcf4b..d8ab9ed5b114c654da8cfb7c1e96307b0800ad18 100644
--- a/solvers/IncNavierStokesSolver/Forcing/ForcingMovingBody.cpp
+++ b/solvers/IncNavierStokesSolver/Forcing/ForcingMovingBody.cpp
@@ -155,10 +155,8 @@ void ForcingMovingBody::v_Apply(
             }
             else
             {
-                EvaluateFunction(pFields, m_session, m_motion[0], m_zta[j],
-                                 m_funcName[j], time);
-                EvaluateFunction(pFields, m_session, m_motion[1], m_eta[j],
-                                 m_funcName[j], time);
+                GetFunction(pFields, m_session, m_funcName[j], true)->Evaluate(m_motion[0], m_zta[j], time);
+                GetFunction(pFields, m_session, m_funcName[j], true)->Evaluate(m_motion[1], m_eta[j], time);
                 cnt = cnt + 2;
             }
         }
diff --git a/solvers/LinearElasticSolver/EquationSystems/LinearElasticSystem.cpp b/solvers/LinearElasticSolver/EquationSystems/LinearElasticSystem.cpp
index 66001cbba9e467e58c2286c192fec81c584edfac..042ebe4211583eca5fd41218339ac9e5745d614a 100644
--- a/solvers/LinearElasticSolver/EquationSystems/LinearElasticSystem.cpp
+++ b/solvers/LinearElasticSolver/EquationSystems/LinearElasticSystem.cpp
@@ -453,7 +453,7 @@ void LinearElasticSystem::v_DoSolve()
 
     // Evaluate the forcing function from the XML file.
     Array<OneD, Array<OneD, NekDouble> > forcing(nVel);
-    EvaluateFunction(forcing, "Forcing");
+    GetFunction("Forcing")->Evaluate(forcing);
 
     // Add temperature term
     string tempEval;
diff --git a/solvers/PulseWaveSolver/EquationSystems/PulseWaveSystem.cpp b/solvers/PulseWaveSolver/EquationSystems/PulseWaveSystem.cpp
index b641aba351b265bc4e746353cc0825e49e6479ec..86acd3bb134292b1c45e4095070e4ec325244131 100755
--- a/solvers/PulseWaveSolver/EquationSystems/PulseWaveSystem.cpp
+++ b/solvers/PulseWaveSolver/EquationSystems/PulseWaveSystem.cpp
@@ -220,10 +220,10 @@ namespace Nektar
             m_fields[0] = m_vessels[2*omega];
             
             m_beta[omega] = Array<OneD, NekDouble>(nq);
-            EvaluateFunction("beta", m_beta[omega], "MaterialProperties", m_time, omega);
+            GetFunction("MaterialProperties")->Evaluate("beta",  m_beta[omega], m_time, omega);
 
             m_A_0[omega] = Array<OneD, NekDouble>(nq); 
-            EvaluateFunction("A_0", m_A_0[omega], "A_0", m_time, omega);
+            GetFunction("A_0")->Evaluate("A_0",  m_A_0[omega], m_time, omega);
 
             int nqTrace = GetTraceTotPoints();
 
@@ -1187,8 +1187,7 @@ namespace Nektar
                     
                     LibUtilities::EquationSharedPtr vEqu
                         = m_session->GetFunction("ExactSolution",field,omega);
-                    EvaluateFunction(m_session->GetVariable(field),exactsoln,"ExactSolution",
-                                     m_time);
+                    GetFunction("ExactSolution")->Evaluate(m_session->GetVariable(field), exactsoln, m_time);
                     
                     L2error_dom = m_vessels[vesselid]->L2(
                                         m_vessels[vesselid]->GetPhys(),
@@ -1266,8 +1265,7 @@ namespace Nektar
                 {
                     Array<OneD, NekDouble> exactsoln(m_vessels[vesselid]->GetNpoints());
                     
-                    EvaluateFunction(m_session->GetVariable(field),exactsoln,"ExactSolution",
-                                     m_time);
+                    GetFunction("ExactSolution")->Evaluate(m_session->GetVariable(field), exactsoln, m_time);
                     
                     LinferrorDom = m_vessels[vesselid]->Linf(
                                         m_vessels[vesselid]->GetPhys(),
diff --git a/solvers/ShallowWaterSolver/EquationSystems/ShallowWaterSystem.cpp b/solvers/ShallowWaterSolver/EquationSystems/ShallowWaterSystem.cpp
index d412e8f1f0f5d6176b8307657a275f0abd23b74b..a4d8af8caf66647b616e0c4a6aeceb38a6d73c80 100644
--- a/solvers/ShallowWaterSolver/EquationSystems/ShallowWaterSystem.cpp
+++ b/solvers/ShallowWaterSolver/EquationSystems/ShallowWaterSystem.cpp
@@ -166,13 +166,13 @@ namespace Nektar
 
   void ShallowWaterSystem::EvaluateWaterDepth(void)
   {
-    EvaluateFunction("d",m_depth,"WaterDepth");
+    GetFunction("WaterDepth")->Evaluate("d", m_depth);
   }
   
   
   void ShallowWaterSystem::EvaluateCoriolis(void)
   {
-    EvaluateFunction("f",m_coriolis,"Coriolis");
+    GetFunction("Coriolis")->Evaluate("f", m_coriolis);
   }
 
   void ShallowWaterSystem::CopyBoundaryTrace(const Array<OneD, NekDouble>&Fwd, Array<OneD, NekDouble>&Bwd)
diff --git a/solvers/VortexWaveInteraction/VortexWaveInteraction.cpp b/solvers/VortexWaveInteraction/VortexWaveInteraction.cpp
index 010074f590a93cd572aa179a6c8727c57748b55c..d72e783bb56f293ca6dd133191768c078deca878 100644
--- a/solvers/VortexWaveInteraction/VortexWaveInteraction.cpp
+++ b/solvers/VortexWaveInteraction/VortexWaveInteraction.cpp
@@ -393,7 +393,7 @@ namespace Nektar
                     std::vector<std::string> vFieldNames = m_sessionRoll->GetVariables();
                     vFieldNames.erase(vFieldNames.end()-1);
 
-                    m_solverRoll->EvaluateFunction(vFieldNames, m_vwiForcingObj->UpdateForces(), "BodyForce");
+                    m_solverRoll->GetFunction("BodyForce")->Evaluate(vFieldNames, m_vwiForcingObj->UpdateForces());
 
                     // Scale forcing
                     for(int i = 0; i < m_vwiForcingObj->UpdateForces().num_elements(); ++i)