Commit dd9c2912 authored by Chris Cantwell's avatar Chris Cantwell
Browse files

Merge branch 'feature/filename-variables' into 'master'

Allow filename variable remapping

This MR adds the option to remap variable names inside files to different names in XML functions. For example, `IncNavierStokesSolver` fields containing `u,v,w,p` can be mapped to linear advection variables `Vx,Vy,Vz` using the syntax:

```xml
<FUNCTION NAME="AdvectionVelocity">
  <F VAR="Vx,Vy,Vz" VALUE="file.fld:u,v,w" />
</FUNCTION>
```

See merge request !428
parents e37607aa 233f5e25
\section{Analytic Expressions}
\label{sec:xml:analytic-expressions}
This section discusses particulars related to analytic expressions appearing in
Nektar++. Analytic expressions in Nektar++ are used to describe spatially or
temporally varying properties, for example
......
......@@ -242,20 +242,6 @@ the field data is specified. The expansion order used to generate the .rst file
must be the same as that for the simulation. The filename must be specified
relative to the location of the .xml file.
With the additional argument \inltt{TIMEDEPENDENT="1"}, different files can be
loaded for each timestep. The filenames are defined using
\href{http://www.boost.org/doc/libs/1_56_0/libs/format/doc/format.html#syntax}{boost::format syntax}
where the step time is used as variable. For example, the function
\inltt{Baseflow} would load the files \inltt{U0V0\_1.00000000E-05.fld},
\inltt{U0V0\_2.00000000E-05.fld} and so on.
\begin{lstlisting}[style=XMLStyle]
<FUNCTION NAME="Baseflow">
<F VAR="U0,V0" TIMEDEPENDENT="1"FILE="U0V0_%14.8R.fld"/>
</FUNCTION>
\end{lstlisting}
Other examples of this input feature can be the insertion of a forcing term,
\begin{lstlisting}[style=XMLStyle]
......@@ -278,7 +264,59 @@ or of a linear advection term
</FUNCTION>
\end{lstlisting}
[wiki:Reference/AnalyticExpressions This page] provides the list of acceptable mathematical functions and other related technical details.
\subsubsection{Remapping variable names}
Note that it is sometimes the case that the variables being used in the solver
do not match those saved in the FLD file. For example, if one runs a
three-dimensional incompressible Navier-Stokes simulation, this produces an FLD
file with the variables \inltt{u}, \inltt{v}, \inltt{w} and \inltt{p}. If we
wanted to use this velocity field as input for an advection velocity, the
advection-diffusion-reaction solver expects the variables \inltt{Vx}, \inltt{Vy}
and \inltt{Vz}.
We can manually specify this mapping by adding a colon to the
\begin{lstlisting}[style=XMLStyle]
<FUNCTION NAME="AdvectionVelocity">
<F VAR="Vx,Vy,Vz" VALUE="file.fld:u,v,w" />
</FUNCTION>
\end{lstlisting}
There are some caveats with this syntax:
\begin{itemize}
\item You must specify the same number of fields for both the variable, and
after the colon. For example, the following is not valid.
\begin{lstlisting}[style=XMLStyle,gobble=4]
<FUNCTION NAME="AdvectionVelocity">
<F VAR="Vx,Vy,Vz" VALUE="file.fld:u" />
</FUNCTION>\end{lstlisting}
\item This syntax is not valid with the wildcard operator \inltt{*}, so one
cannot write for example:
\begin{lstlisting}[style=XMLStyle,gobble=4]
<FUNCTION NAME="AdvectionVelocity">
<F VAR="*" VALUE="file.fld:u,v,w" />
</FUNCTION>
\end{lstlisting}
\end{itemize}
\subsubsection{Time-dependent file-based functions}
With the additional argument \inltt{TIMEDEPENDENT="1"}, different files can be
loaded for each timestep. The filenames are defined using
\href{http://www.boost.org/doc/libs/1_56_0/libs/format/doc/format.html#syntax}{boost::format
syntax} where the step time is used as variable. For example, the function
\inltt{Baseflow} would load the files \inltt{U0V0\_1.00000000E-05.fld},
\inltt{U0V0\_2.00000000E-05.fld} and so on.
\begin{lstlisting}[style=XMLStyle]
<FUNCTION NAME="Baseflow">
<F VAR="U0,V0" TIMEDEPENDENT="1" FILE="U0V0_%14.8R.fld" />
</FUNCTION>
\end{lstlisting}
Section~\ref{sec:xml:analytic-expressions} provides the list of acceptable
mathematical functions and other related technical details.
\subsection{Quasi-3D approach}
......@@ -375,3 +413,7 @@ available. In case of a 1D homogeneous extension, the homogeneous direction will
be the z-axis. In case of a 2D homogeneous extension, the homogeneous directions
will be the y-axis and the z-axis.
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "../user-guide"
%%% End:
......@@ -1217,6 +1217,48 @@ namespace Nektar
}
/**
*
*/
std::string SessionReader::GetFunctionFilenameVariable(
const std::string &pName,
const std::string &pVariable,
const int pDomain) const
{
FunctionMap::const_iterator it1;
FunctionVariableMap::const_iterator it2, it3;
std::string vName = boost::to_upper_copy(pName);
it1 = m_functions.find(vName);
ASSERTL0 (it1 != m_functions.end(),
std::string("Function '") + pName
+ std::string("' not found."));
// Check for specific and wildcard definitions
pair<std::string,int> key(pVariable,pDomain);
pair<std::string,int> defkey("*",pDomain);
bool specific = (it2 = it1->second.find(key)) !=
it1->second.end();
bool wildcard = (it3 = it1->second.find(defkey)) !=
it1->second.end();
// Check function is defined somewhere
ASSERTL0(specific || wildcard,
"No such variable " + pVariable
+ " in domain " + boost::lexical_cast<string>(pDomain)
+ " defined for function " + pName
+ " in session file.");
// If not specific, must be wildcard
if (!specific)
{
it2 = it3;
}
return it2->second.m_fileVariable;
}
/**
*
*/
......@@ -2368,6 +2410,7 @@ namespace Nektar
}
// Parse list of variables
std::vector<std::string> varSplit;
std::vector<unsigned int> domainList;
ParseUtils::GenerateSeqVector(domainStr.c_str(), domainList);
......@@ -2418,8 +2461,32 @@ namespace Nektar
"attribute of function '" + functionStr
+ "'.");
std::vector<std::string> fSplit;
boost::split(fSplit, filenameStr, boost::is_any_of(":"));
ASSERTL0(fSplit.size() == 1 || fSplit.size() == 2,
"Incorrect filename specification in function "
+ functionStr + "'. "
"Specify variables inside file as: "
"filename:var1,var2");
// set the filename
funcDef.m_filename = filenameStr;
funcDef.m_filename = fSplit[0];
if (fSplit.size() == 2)
{
ASSERTL0(variableList[0] != "*",
"Filename variable mapping not valid "
"when using * as a variable inside "
"function '" + functionStr + "'.");
boost::split(
varSplit, fSplit[1], boost::is_any_of(","));
ASSERTL0(varSplit.size() == variableList.size(),
"Filename variables should contain the "
"same number of variables defined in "
"VAR in function " + functionStr + "'.");
}
}
// Nothing else supported so throw an error
......@@ -2450,8 +2517,17 @@ namespace Nektar
+ boost::lexical_cast<std::string>(domainList[j])
+ "' in function '" + functionStr + "'. "
"Expression has already been defined.");
functionVarMap[key] = funcDef;
if (varSplit.size() > 0)
{
FunctionVariableDefinition funcDef2 = funcDef;
funcDef2.m_fileVariable = varSplit[i];
functionVarMap[key] = funcDef2;
}
else
{
functionVarMap[key] = funcDef;
}
}
}
......
......@@ -108,6 +108,7 @@ namespace Nektar
enum FunctionType m_type;
std::string m_filename;
EquationSharedPtr m_expression;
std::string m_fileVariable;
};
typedef std::map<std::pair<std::string,int>, FunctionVariableDefinition>
......@@ -366,6 +367,12 @@ namespace Nektar
const std::string &name,
const unsigned int &var,
const int pDomain = 0) const;
/// Returns the filename variable to be loaded for a given variable
/// index.
LIB_UTILITIES_EXPORT std::string GetFunctionFilenameVariable(
const std::string &name,
const std::string &variable,
const int pDomain = 0) const;
/// Returns the instance of AnalyticExpressionEvaluator specific to
/// this session.
......
......@@ -773,20 +773,28 @@ namespace Nektar
ffunc->Evaluate(x0,x1,x2,pTime,pArray);
}
else if (vType == LibUtilities::eFunctionTypeFile || vType == LibUtilities::eFunctionTypeTransientFile)
else if (vType == LibUtilities::eFunctionTypeFile ||
vType == LibUtilities::eFunctionTypeTransientFile)
{
std::string filename
= m_session->GetFunctionFilename(pFunctionName, pFieldName,domain);
std::string filename = m_session->GetFunctionFilename(
pFunctionName, pFieldName, domain);
std::string fileVar = m_session->GetFunctionFilenameVariable(
pFunctionName, pFieldName, domain);
if (fileVar.length() == 0)
{
fileVar = pFieldName;
}
std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef;
std::vector<std::vector<NekDouble> > FieldData;
Array<OneD, NekDouble> vCoeffs(m_fields[0]->GetNcoeffs());
Vmath::Zero(vCoeffs.num_elements(),vCoeffs,1);
int numexp = m_fields[0]->GetExpSize();
int numexp = m_fields[0]->GetExpSize();
Array<OneD,int> ElementGIDs(numexp);
// Define list of global element ids
// Define list of global element ids
for(int i = 0; i < numexp; ++i)
{
ElementGIDs[i] = m_fields[0]->GetExp(i)->GetGeom()->GetGlobalID();
......@@ -801,29 +809,29 @@ namespace Nektar
catch (...)
{
ASSERTL0(false, "Invalid Filename in function \""
+ pFunctionName + "\", variable \"" + pFieldName + "\"")
+ pFunctionName + "\", variable \"" + fileVar + "\"")
}
}
m_fld->Import(filename,FieldDef,FieldData,
LibUtilities::NullFieldMetaDataMap,
ElementGIDs);
m_fld->Import(filename, FieldDef, FieldData,
LibUtilities::NullFieldMetaDataMap,
ElementGIDs);
int idx = -1;
// Loop over all the expansions
for (int i = 0; i < FieldDef.size(); ++i)
{
// Find the index of the required field in the
// 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] == pFieldName)
if (FieldDef[i]->m_fields[j] == fileVar)
{
idx = j;
}
}
if (idx >= 0)
{
m_fields[0]->ExtractDataToCoeffs(
......@@ -832,11 +840,10 @@ namespace Nektar
}
else
{
cout << "Field " + pFieldName + " not found." << endl;
cout << "Field " + fileVar + " not found." << endl;
}
}
m_fields[0]->BwdTrans_IterPerExp(vCoeffs, pArray);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment