Commit ffa1489f authored by Chris Cantwell's avatar Chris Cantwell

Merge branch 'feature/Interpolator' into 'master'

Feature/interpolator

This MR introduces an Interpolator class which adds several features/improvements over how interpolation was handled by the PtsField class:

* The brute force search algorithm was swapped for boosts rtree algorithm. This change decreases the interpolation time from hours to seconds
* Besides the modified shepard and linear/quadratic interpolation, two new algorithms, nearest neighbor and Gaussian smoothing were added
* The new class can interpolate between ptFields, ptsFields and expansions and expansions. The latter is only useful when dealing with different meshes.
* Several bugfixes

FieldConvert and EquationSystem were ported to this new class to benefit from the speedup.

This MR also includes the changes what were originally in !582

The required boost version was increased to 1.56 as this is the first version that includes geometry::rtree which works on windows

See merge request !584
parents c8718cf4 f0708af8
......@@ -8,9 +8,9 @@
#If the user has not set BOOST_ROOT, look in a couple common places first.
MESSAGE(STATUS "Searching for Boost:")
SET(MIN_VER "1.52.0")
SET(MIN_VER "1.56.0")
SET(NEEDED_BOOST_LIBS thread iostreams date_time filesystem system
program_options regex timer)
program_options regex timer chrono)
SET(Boost_DEBUG 0)
SET(Boost_NO_BOOST_CMAKE ON)
IF( BOOST_ROOT )
......@@ -67,7 +67,7 @@ IF (THIRDPARTY_BUILD_BOOST)
# Only build the libraries we need
SET(BOOST_LIB_LIST --with-system --with-iostreams --with-filesystem
--with-program_options --with-date_time --with-thread
--with-regex --with-timer)
--with-regex --with-timer --with-chrono)
IF (NOT WIN32)
# We need -fPIC for 64-bit builds
......@@ -160,6 +160,9 @@ IF (THIRDPARTY_BUILD_BOOST)
ENDIF(THIRDPARTY_BUILD_ZLIB)
# Set up CMake variables
SET(Boost_CHRONO_LIBRARY boost_chrono)
SET(Boost_CHRONO_LIBRARY_DEBUG boost_chrono)
SET(Boost_CHRONO_LIBRARY_RELEASE boost_chrono)
SET(Boost_DATE_TIME_LIBRARY boost_date_time)
SET(Boost_DATE_TIME_LIBRARY_DEBUG boost_date_time)
SET(Boost_DATE_TIME_LIBRARY_RELEASE boost_date_time)
......@@ -189,7 +192,7 @@ IF (THIRDPARTY_BUILD_BOOST)
SET(Boost_CONFIG_INCLUDE_DIR ${TPINC})
SET(Boost_LIBRARY_DIRS ${TPSRC}/dist/lib)
SET(Boost_CONFIG_LIBRARY_DIR ${TPLIB})
SET(Boost_LIBRARIES boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_system boost_thread boost_timer)
SET(Boost_LIBRARIES boost_chrono boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_system boost_thread boost_timer)
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
STRING(REPLACE ";" ", " NEEDED_BOOST_LIBS_STRING "${NEEDED_BOOST_LIBS}")
......
This diff is collapsed.
......@@ -47,6 +47,7 @@
#include <LibUtilities/BasicUtils/FileSystem.h>
using namespace std;
namespace Nektar
{
......@@ -138,11 +139,14 @@ void PtsIO::Import(const string &inFile,
// Load metadata
ImportFieldMetaData(infile, fieldmetadatamap);
// TODO: This currently only loads the filename matching our rank.
filenames.clear();
boost::format pad("P%1$07d.%2$s");
pad % m_comm->GetRank() % GetFileEnding();
filenames.push_back(pad.str());
if (filenames.size() == m_comm->GetSize())
{
// only load the file that matches this rank
filenames.clear();
boost::format pad("P%1$07d.%2$s");
pad % m_comm->GetRank() % GetFileEnding();
filenames.push_back(pad.str());
}
for (int i = 0; i < filenames.size(); ++i)
{
......@@ -160,7 +164,19 @@ void PtsIO::Import(const string &inFile,
<< doc1.ErrorCol() << std::endl;
ASSERTL0(loadOkay1, errstr.str());
ImportFieldData(doc1, ptsField);
if (i == 0)
{
ImportFieldData(doc1, ptsField);
}
else
{
LibUtilities::PtsFieldSharedPtr newPtsField;
ImportFieldData(doc1, newPtsField);
Array<OneD, Array<OneD, NekDouble> > pts;
newPtsField->GetPts(pts);
ptsField->AddPoints(pts);
}
}
}
else
......
......@@ -399,6 +399,7 @@ TARGET_LINK_LIBRARIES(LibUtilities LINK_PUBLIC
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_TIMER_LIBRARY}
${Boost_CHRONO_LIBRARY}
debug ${ZLIB_LIBRARY_DEBUG} optimized ${ZLIB_LIBRARY_RELEASE}
)
......
......@@ -32,6 +32,7 @@ SET(SOLVER_UTILS_SOURCES
Filters/FilterSampler.cpp
Filters/FilterThresholdMax.cpp
Filters/FilterThresholdMin.cpp
Interpolator.cpp
RiemannSolvers/RiemannSolver.cpp
RiemannSolvers/UpwindSolver.cpp
RiemannSolvers/UpwindLDGSolver.cpp
......@@ -77,6 +78,7 @@ SET(SOLVER_UTILS_HEADERS
Filters/FilterSampler.h
Filters/FilterThresholdMax.h
Filters/FilterThresholdMin.h
Interpolator.h
RiemannSolvers/RiemannSolver.h
RiemannSolvers/UpwindSolver.h
RiemannSolvers/UpwindLDGSolver.h
......
......@@ -891,36 +891,51 @@ namespace Nektar
LibUtilities::PtsIO ptsIO(m_session->GetComm());
ptsIO.Import(filename, ptsField);
Array <OneD, Array<OneD, NekDouble> > coords(3);
coords[0] = Array<OneD, NekDouble>(nq);
coords[1] = Array<OneD, NekDouble>(nq);
coords[2] = Array<OneD, NekDouble>(nq);
m_fields[0]->GetCoords(coords[0], coords[1], coords[2]);
// check if we already computed this funcKey combination
std::string weightsKey = m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
if (m_interpWeights.count(weightsKey) != 0)
Array<OneD, Array<OneD, NekDouble> > pts(ptsField->GetDim() + ptsField->GetNFields());
for (int i = 0; i < ptsField->GetDim() + ptsField->GetNFields(); ++i)
{
// found, re-use
ptsField->SetWeights(m_interpWeights[weightsKey], m_interpInds[weightsKey]);
pts[i] = Array<OneD, NekDouble>(nq);
}
else
if (ptsField->GetDim() == 1)
{
m_fields[0]->GetCoords(pts[0]);
}
else if (ptsField->GetDim() == 2)
{
m_fields[0]->GetCoords(pts[0], pts[1]);
}
else if (ptsField->GetDim() == 3)
{
if (m_session->GetComm()->GetRank() == 0)
m_fields[0]->GetCoords(pts[0], pts[1], pts[2]);
}
LibUtilities::PtsFieldSharedPtr outPts =
MemoryManager<LibUtilities::PtsField>::
AllocateSharedPtr(ptsField->GetDim(), ptsField->GetFieldNames(), pts);
// check if we already computed this funcKey combination
std::string interpKey = m_session->GetFunctionFilename(pFunctionName, pFieldName, domain);
map<std::string, Interpolator >::iterator it
= m_interpolators.find(interpKey);
if (it == m_interpolators.end())
{
m_interpolators[interpKey] = SolverUtils::Interpolator(
Nektar::SolverUtils::eShepard);
if (m_comm->GetRank() == 0)
{
ptsField->setProgressCallback(&EquationSystem::PrintProgressbar, this);
cout << "Interpolating: ";
m_interpolators[interpKey].SetProgressCallback(
&EquationSystem::PrintProgressbar, this);
}
ptsField->CalcWeights(coords);
if (m_session->GetComm()->GetRank() == 0)
m_interpolators[interpKey].CalcWeights(ptsField, outPts);
if (m_comm->GetRank() == 0)
{
cout << endl;
if(GetSession()->DefinesCmdLineArgument("verbose"))
{
m_interpolators[interpKey].PrintStatistics();
}
}
ptsField->GetWeights(m_interpWeights[weightsKey], m_interpInds[weightsKey]);
}
Array<OneD, Array<OneD, NekDouble> > intFields;
ptsField->Interpolate(intFields);
m_interpolators[interpKey].Interpolate(ptsField, outPts);
int fieldInd;
vector<string> fieldNames = ptsField->GetFieldNames();
......@@ -933,7 +948,7 @@ namespace Nektar
}
ASSERTL0(fieldInd != fieldNames.size(), "field not found");
pArray = intFields[fieldInd];
pArray = pts[ptsField->GetDim() + fieldInd];
}
}
}
......
......@@ -46,6 +46,7 @@
#include <LibUtilities/BasicUtils/PtsField.h>
#include <LibUtilities/BasicUtils/PtsIO.h>
#include <MultiRegions/ExpList.h>
#include <SolverUtils/Interpolator.h>
#include <SolverUtils/SolverUtilsDeclspec.h>
#include <SolverUtils/Core/Misc.h>
......@@ -452,10 +453,8 @@ namespace Nektar
LibUtilities::SessionReaderSharedPtr m_session;
/// Field input/output
LibUtilities::FieldIOSharedPtr m_fld;
/// Map of the interpolation weights for a specific filename.
std::map<std::string, Array<OneD, Array<OneD, float> > > m_interpWeights;
/// Map of the interpolation indices for a specific filename.
std::map<std::string, Array<OneD, Array<OneD, unsigned int> > > m_interpInds;
/// Map of interpolator objects
std::map<std::string, Interpolator > m_interpolators;
/// Array holding all dependent variables.
Array<OneD, MultiRegions::ExpListSharedPtr> m_fields;
/// Base fields.
......
This diff is collapsed.
///////////////////////////////////////////////////////////////////////////////
//
// File Interpolator.h
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2016 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: Interpolator
//
///////////////////////////////////////////////////////////////////////////////
#ifndef NEKTAR_SOLVERUTILS_INTERPOLATOR_H
#define NEKTAR_SOLVERUTILS_INTERPOLATOR_H
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <MultiRegions/ExpList.h>
#include <LibUtilities/BasicUtils/ErrorUtil.hpp>
#include <LibUtilities/BasicUtils/SharedArray.hpp>
#include <LibUtilities/BasicUtils/VmathArray.hpp>
#include <LibUtilities/BasicUtils/PtsField.h>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
namespace Nektar
{
namespace SolverUtils
{
enum InterpMethod
{
eNoMethod,
eNearestNeighbour,
eQuadratic,
eShepard,
eGauss,
};
/// A class that contains algorithms for interpolation between pts fields,
/// expansions and different meshes
class Interpolator
{
public:
/**
* @brief Constructor of the Interpolator class
*
* @param method interpolation method, defaults to a sensible value if not
* set
* @param coordId coordinate id along which the interpolation should be
* performed
* @param filtWidth filter width, required by some algorithms such as eGauss
* @param maxPts limit number of considered points
*
* if method is not specified, the best algorithm is chosen autpomatically.
*
* If coordId is not specified, a full 1D/2D/3D interpolation is performed
* without
* collapsing any coordinate.
*
* filtWidth must be specified for the eGauss algorithm only.
*/
Interpolator(InterpMethod method = eNoMethod,
short int coordId = -1,
NekDouble filtWidth = 0.0,
int maxPts = 1000)
: m_method(method), m_filtWidth(filtWidth), m_maxPts(maxPts),
m_coordId(coordId){};
/// Compute interpolation weights without doing any interpolation
LIB_UTILITIES_EXPORT void CalcWeights(
const LibUtilities::PtsFieldSharedPtr ptsInField,
LibUtilities::PtsFieldSharedPtr &ptsOutField);
/// Interpolate from a pts field to a pts field
LIB_UTILITIES_EXPORT void Interpolate(
const LibUtilities::PtsFieldSharedPtr ptsInField,
LibUtilities::PtsFieldSharedPtr &ptsOutField);
/// Interpolate from an expansion to an expansion
LIB_UTILITIES_EXPORT void Interpolate(
const std::vector<MultiRegions::ExpListSharedPtr> expInField,
std::vector<MultiRegions::ExpListSharedPtr> &expOutField);
/// Interpolate from an expansion to a pts field
LIB_UTILITIES_EXPORT void Interpolate(
const std::vector<MultiRegions::ExpListSharedPtr> expInField,
LibUtilities::PtsFieldSharedPtr &ptsOutField);
/// Interpolate from a pts field to an expansion
LIB_UTILITIES_EXPORT void Interpolate(
const LibUtilities::PtsFieldSharedPtr ptsInField,
std::vector<MultiRegions::ExpListSharedPtr> &expOutField);
/// returns the dimension of the Interpolator.
/// Should be higher than the dimensions of the interpolated fields
LIB_UTILITIES_EXPORT int GetDim() const;
/// Returns the filter width
LIB_UTILITIES_EXPORT NekDouble GetFiltWidth() const;
/// Returns the coordinate id along which the interpolation should be
/// performed
LIB_UTILITIES_EXPORT int GetCoordId() const;
/// Returns the interpolation method used by this interpolator
LIB_UTILITIES_EXPORT InterpMethod GetInterpMethod() const;
/// Returns the input field
LIB_UTILITIES_EXPORT LibUtilities::PtsFieldSharedPtr GetInField() const;
/// Returns the output field
LIB_UTILITIES_EXPORT LibUtilities::PtsFieldSharedPtr GetOutField() const;
/// Print statics of the interpolation weights
LIB_UTILITIES_EXPORT void PrintStatistics();
/// sets a callback funtion which gets called every time the interpolation
/// progresses
template <typename FuncPointerT, typename ObjectPointerT>
void SetProgressCallback(FuncPointerT func, ObjectPointerT obj)
{
m_progressCallback = boost::bind(func, obj, _1, _2);
}
private:
class PtsPoint
{
public:
int idx;
Array<OneD, NekDouble> coords;
NekDouble dist;
PtsPoint() : idx(-1), coords(Array<OneD, NekDouble>(3)), dist(1E30){};
PtsPoint(int idx, Array<OneD, NekDouble> coords, NekDouble dist)
: idx(idx), coords(coords), dist(dist){};
bool operator<(const PtsPoint &comp) const
{
return (dist < comp.dist);
};
};
/// dimension of this interpolator. Hardcoded to 3
static const int m_dim = 3;
typedef bg::model::point<NekDouble, m_dim, bg::cs::cartesian> BPoint;
typedef std::pair<BPoint, unsigned int> PtsPointPair;
typedef bgi::rtree<PtsPointPair, bgi::rstar<16> > PtsRtree;
/// input field
LibUtilities::PtsFieldSharedPtr m_ptsInField;
/// output field
LibUtilities::PtsFieldSharedPtr m_ptsOutField;
/// input field
std::vector<MultiRegions::ExpListSharedPtr> m_expInField;
/// output field
std::vector<MultiRegions::ExpListSharedPtr> m_expOutField;
/// Interpolation Method
InterpMethod m_method;
/// A tree structure to speed up the neighbour search.
/// Note that we fill it with an iterator, so instead of rstar, the
/// packing algorithm is used.
boost::shared_ptr<PtsRtree> m_rtree;
/// Interpolation weights for each neighbour.
/// Structure: m_weights[physPtIdx][neighbourIdx]
Array<OneD, Array<OneD, float> > m_weights;
/// Indices of the relevant neighbours for each physical point.
/// Structure: m_neighInds[ptIdx][neighbourIdx]
Array<OneD, Array<OneD, unsigned int> > m_neighInds;
/// Filter width used for some interpolation algorithms
NekDouble m_filtWidth;
/// Max number of interpolation points
int m_maxPts;
/// coordinate id along which the interpolation should be performed
short int m_coordId;
boost::function<void(const int position, const int goal)>
m_progressCallback;
LIB_UTILITIES_EXPORT void CalcW_Gauss(const PtsPoint &searchPt,
const NekDouble sigma,
const int maxPts = 250);
LIB_UTILITIES_EXPORT void CalcW_Linear(const PtsPoint &searchPt,
int coordId);
LIB_UTILITIES_EXPORT void CalcW_NNeighbour(const PtsPoint &searchPt);
LIB_UTILITIES_EXPORT void CalcW_Shepard(const PtsPoint &searchPt);
LIB_UTILITIES_EXPORT void CalcW_Quadratic(const PtsPoint &searchPt,
int coordId);
LIB_UTILITIES_EXPORT void SetupTree();
LIB_UTILITIES_EXPORT void FindNeighbours(
const PtsPoint &searchPt,
std::vector<PtsPoint> &neighbourPts,
const NekDouble dist,
const unsigned int maxPts = 1);
LIB_UTILITIES_EXPORT void FindNNeighbours(
const PtsPoint &searchPt,
std::vector<PtsPoint> &neighbourPts,
const unsigned int numPts = 1);
};
typedef boost::shared_ptr<Interpolator> InterpolatorSharedPtr;
static InterpolatorSharedPtr NullInterpolator;
}
}
#endif
......@@ -11,14 +11,14 @@
</files>
<metrics>
<metric type="L2" id="1">
<value variable="p" tolerance="1e-12">22.1182</value>
<value variable="u" tolerance="1e-12">0.00207907</value>
<value variable="v" tolerance="1e-12">0.00207907</value>
<value variable="p" tolerance="1e-6">22.1182</value>
<value variable="u" tolerance="1e-6">0.00207907</value>
<value variable="v" tolerance="1e-6">0.00207907</value>
</metric>
<metric type="Linf" id="2">
<value variable="p" tolerance="1e-12">99.6757</value>
<value variable="u" tolerance="1e-12">0.00794651</value>
<value variable="v" tolerance="1e-12">0.0079465</value>
<value variable="p" tolerance="5e-4">99.6754</value>
<value variable="u" tolerance="1e-6">0.0079465</value>
<value variable="v" tolerance="1e-6">0.0079465</value>
</metric>
</metrics>
</test>
......@@ -15,9 +15,9 @@
</metric>
<metric type="Linf" id="2">
<value variable="p" tolerance="1e-12">4.28036</value>
<value variable="u" tolerance="1e-12">0.00930634</value>
<value variable="v" tolerance="1e-12">0.00930634</value>
<value variable="w" tolerance="1e-12">0.00930634</value>
<value variable="u" tolerance="1e-5">0.0093</value>
<value variable="v" tolerance="1e-5">0.0093</value>
<value variable="w" tolerance="1e-5">0.0093</value>
</metric>
</metrics>
</test>
......@@ -114,16 +114,6 @@ ADD_NEKTAR_TEST(chan3DH1D_stretch)
ADD_NEKTAR_TEST(chan3D_probe)
ADD_NEKTAR_TEST(cube_prismhex)
ADD_NEKTAR_TEST(outflow_pointdatatofld)
# windows produces slightly differently formatted files which results in
# different hashes
#IF(WIN32)
# ADD_NEKTAR_TEST(chan3D_probe_win)
# ADD_NEKTAR_TEST(chan3D_equispacedoutput_win)
# ADD_NEKTAR_TEST(chan3D_isocontour_win)
#ELSE(WIN32)
#ENDIF(WIN32)
ADD_NEKTAR_TEST(chan3D_equispacedoutput)
ADD_NEKTAR_TEST(chan3D_isocontour)
......
......@@ -40,6 +40,8 @@ using namespace std;
#include <LibUtilities/BasicUtils/SharedArray.hpp>
#include <LibUtilities/BasicUtils/ParseUtils.hpp>
#include <LibUtilities/BasicUtils/Progressbar.hpp>
#include <SolverUtils/Interpolator.h>
#include <boost/math/special_functions/fpclassify.hpp>
namespace Nektar
{
......@@ -217,23 +219,44 @@ void ProcessInterpField::Process(po::variables_map &vm)
m_f->m_exp[0]->GetCoords(x1, y1, z1);
}
if(m_f->m_session->GetComm()->TreatAsRankZero())
{
cout << "Interpolating [" << flush;
}
NekDouble clamp_low = m_config["clamptolowervalue"].as<NekDouble>();
NekDouble clamp_up = m_config["clamptouppervalue"].as<NekDouble>();
NekDouble def_value = m_config["defaultvalue"].as<NekDouble>();
InterpolateField(m_fromField->m_exp, m_f->m_exp,
x1, y1, z1, clamp_low, clamp_up,def_value);
for (int i = 0; i < nfields; i++)
{
for (int j = 0; j < nq1; ++j)
{
m_f->m_exp[i]->UpdatePhys()[j] = def_value;
}
}
if(m_f->m_session->GetComm()->TreatAsRankZero())
SolverUtils::Interpolator interp;
if (m_f->m_comm->GetRank() == 0)
{
cout << "]" << endl;
interp.SetProgressCallback(&ProcessInterpField::PrintProgressbar,
this);
}
interp.Interpolate(m_fromField->m_exp, m_f->m_exp);
if (m_f->m_comm->GetRank() == 0)
{
cout << endl;
}
for (int i = 0; i < nfields; ++i)
{
for (int j = 0; j < nq1; ++j)
{
if (m_f->m_exp[i]->GetPhys()[j] > clamp_up)
{
m_f->m_exp[i]->UpdatePhys()[j] = clamp_up;
}
else if (m_f->m_exp[i]->GetPhys()[j] < clamp_low)
{
m_f->m_exp[i]->UpdatePhys()[j] = clamp_low;
}
}
}
// put field into field data for output
std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef
......@@ -255,85 +278,13 @@ void ProcessInterpField::Process(po::variables_map &vm)
m_f->m_data = FieldData;
}
void ProcessInterpField::InterpolateField(
vector<MultiRegions::ExpListSharedPtr> &field0,
vector<MultiRegions::ExpListSharedPtr> &field1,
Array<OneD, NekDouble> x,
Array<OneD, NekDouble> y,
Array<OneD, NekDouble> z,
NekDouble clamp_low,
NekDouble clamp_up,
NekDouble def_value)
void ProcessInterpField::PrintProgressbar(const int position,
const int goal) const
{
int expdim = field0[0]->GetCoordim(0);
Array<OneD, NekDouble> coords(expdim), Lcoords(expdim);
int nq1 = field1[0]->GetTotPoints();
int elmtid, offset;
int r, f;
static int intpts = 0;
ASSERTL0(field0.size() == field1.size(),
"Input field dimension must be same as output dimension");
for (r = 0; r < nq1; r++)
{
coords[0] = x[r];
coords[1] = y[r];
if (expdim == 3)
{
coords[2] = z[r];
}
// Obtain nearest Element and LocalCoordinate to interpolate
elmtid = field0[0]->GetExpIndex(coords, Lcoords, 1e-3,true);
if(elmtid >= 0)
{
offset = field0[0]->GetPhys_Offset(field0[0]->
GetOffset_Elmt_Id(elmtid));
for (f = 0; f < field1.size(); ++f)
{
NekDouble value;
value = field0[f]->GetExp(elmtid)->
StdPhysEvaluate(Lcoords, field0[f]->GetPhys() +offset);
if ((boost::math::isnan)(value))
{
ASSERTL0(false, "new value is not a number");
}
else
{
if(value > clamp_up)
{
value = clamp_up;
}
else if( value < clamp_low)
{
value = clamp_low;
}
field1[f]->UpdatePhys()[r] = value;
}
}
}
else
{
for (f = 0; f < field1.size(); ++f)
{
field1[f]->UpdatePhys()[r] = def_value;
} <