Commit 11e9f68f authored by Andrew J. Burns (Cont's avatar Andrew J. Burns (Cont

made changes for preparations to push to master; still need to finish...

made changes for preparations to push to master; still need to finish documentation changes and line length changes
parent 3bce6df4
......@@ -225,6 +225,7 @@ if(NOT XDMF_BUILD_CORE_ONLY)
XdmfAttributeType
XdmfCurvilinearGrid
XdmfDomain
XdmfFunction
XdmfGeometry
XdmfGeometryType
XdmfGraph
......
......@@ -43,6 +43,7 @@ swig -v -c++ -python -o XdmfPython.cpp Xdmf.i
#include <XdmfAttributeType.hpp>
#include <XdmfCurvilinearGrid.hpp>
#include <XdmfDomain.hpp>
#include <XdmfFunction.hpp>
#include <XdmfGeometry.hpp>
#include <XdmfGeometryType.hpp>
#include <XdmfGraph.hpp>
......@@ -92,6 +93,7 @@ swig -v -c++ -python -o XdmfPython.cpp Xdmf.i
#include <XdmfAttributeType.hpp>
#include <XdmfCurvilinearGrid.hpp>
#include <XdmfDomain.hpp>
#include <XdmfFunction.hpp>
#include <XdmfGeometry.hpp>
#include <XdmfGeometryType.hpp>
#include <XdmfGraph.hpp>
......@@ -237,7 +239,7 @@ swig -v -c++ -python -o XdmfPython.cpp Xdmf.i
%mpi4py_typemap(Comm, MPI_Comm);
#endif
#endif /* XDMF_BUILD_DSM */
%template(XdmfMapNodeIdSet) std::set<int>;
%template(XdmfMapNodeIdMap) std::map<int, std::set<int> >;
......@@ -350,6 +352,572 @@ swig -v -c++ -python -o XdmfPython.cpp Xdmf.i
}
}
/*This causes it to avoid throwing a warning for redefining fuctions that are defined for XdmfArray.
I do this because doing so was intentional.*/
#pragma SWIG nowarn=302
%extend XdmfFunction {
%{
#include <stack>
static std::map<std::string, PyObject *> pythonFunctions;
static std::map<char, PyObject *> pythonOperations;
static int pythonOperationPriority [4];
static std::string pythonSupportedOperations = "";
%}
/*These can't be accessed from python so don't worry about security issues.*/
/*Note, the things in this block are defined twice for a reason.
If they are not defined here they can not be referenced by other functions in swig.*/
%{
/*trying to transfer python funcitons*/
/*note, accessing private members is impossible from swig.*/
/*to generate new static functions mark them as static here.*/
static shared_ptr<XdmfArray> evaluateFunction(std::vector<shared_ptr<XdmfArray> > functValues, std::string functName)
{
if (pythonFunctions.find(functName)!= pythonFunctions.end()) {
swig_type_info * paramType = SWIG_TypeQuery("_p_std__vectorT_boost__shared_ptrT_XdmfArray_t_std__allocatorT_boost__shared_ptrT_XdmfArray_t_t_t");
PyObject * pyVector = SWIG_NewPointerObj(static_cast<void*>(& functValues), paramType, SWIG_POINTER_NEW);
PyObject * args = PyTuple_New(1);
PyTuple_SetItem(args, 0, pyVector);/*In this case you could also cast a pointer to the vector into the PyObject * type, but that doesn't work for all types*/
PyObject * resultObject = PyObject_CallObject(pythonFunctions[functName], args);
void * resultPointer = 0;
swig_type_info * returnType = SWIG_TypeQuery("_p_boost__shared_ptrT_XdmfArray_t");
SWIG_ConvertPtr(resultObject, &resultPointer, returnType, 0);
shared_ptr<XdmfArray> * returnArrayPointer = reinterpret_cast<shared_ptr<XdmfArray> *>(resultPointer);
shared_ptr<XdmfArray> returnArray = returnArrayPointer[0];
return returnArray;
}
else {
/*this does not actually cause an infinte recursive loop, it sends the values to the version of the function defined in XdmfArray.cpp*/
return XdmfFunction::evaluateFunction(functValues, functName);
}
}
static shared_ptr<XdmfArray> evaluateOperation(shared_ptr<XdmfArray> val1, shared_ptr<XdmfArray> val2, char functName)
{
if (pythonOperations.find(functName)!= pythonOperations.end()) {
swig_type_info * paramType = SWIG_TypeQuery("_p_boost__shared_ptrT_XdmfArray_t");
PyObject * pyVal1 = SWIG_NewPointerObj(static_cast<void*>(& val1), paramType, SWIG_POINTER_NEW);
PyObject * pyVal2 = SWIG_NewPointerObj(static_cast<void*>(& val2), paramType, SWIG_POINTER_NEW);
PyObject * args = PyTuple_New(2);
PyTuple_SetItem(args, 0, pyVal1);
PyTuple_SetItem(args, 1, pyVal2);
PyObject * resultObject = PyObject_CallObject(pythonOperations[functName], args);
void * resultPointer = 0;
swig_type_info * returnType = SWIG_TypeQuery("_p_boost__shared_ptrT_XdmfArray_t");
SWIG_ConvertPtr(resultObject, &resultPointer, returnType, 0);
shared_ptr<XdmfArray> * returnArrayPointer = reinterpret_cast<shared_ptr<XdmfArray> *>(resultPointer);
shared_ptr<XdmfArray> returnArray = returnArrayPointer[0];
return returnArray;
}
else {
/*this does not actually cause an infinte recursive loop, it sends the values to the version of the function defined in XdmfArray.cpp*/
return XdmfFunction::evaluateOperation(val1, val2, functName);
}
}
static shared_ptr<XdmfArray> evaluateExpression(std::string expression, std::map<std::string, shared_ptr<XdmfArray> > variables)
{
std::stack<shared_ptr<XdmfArray> > valueStack;
std::stack<char> operationStack;
/*string is parsed left to right
elements of the same priority are evaluated right to left*/
for (unsigned int i = 0; i < expression.size(); i++) {
if (XdmfFunction::getValidDigitChars().find(expression[i]) != std::string::npos) { /*found to be a digit*/
/*progress until a non-digit is found*/
int valueStart = i;
while (XdmfFunction::getValidDigitChars().find(expression[i + 1]) != std::string::npos) {
i++;
}
/*push back to the value stack*/
shared_ptr<XdmfArray> valueArray = XdmfArray::New();
valueArray->insert(0, atof(expression.substr(valueStart, i + 1 - valueStart).c_str()));/*use this to convert to double*/
valueStack.push(valueArray);
}
else if (XdmfFunction::getValidVariableChars().find(expression[i]) != std::string::npos) {/*found to be a variable*/
int valueStart = i;
/*progress until a nonvariable value is found*/
while (XdmfFunction::getValidVariableChars().find(expression[i + 1]) != std::string::npos) {
i++;
}
/*convert to equivalent*/
if (variables.find(expression.substr(valueStart, i + 1 - valueStart)) == variables.end()) {
std::vector<std::string> functionList = XdmfFunction::getSupportedFunctions();
bool functionExists = false;
for (unsigned int j = 0; j < functionList.size() && !functionExists; j++) {
if (functionList[j] == expression.substr(valueStart, i + 1 - valueStart)) {
functionExists = true;
}
}
if (functionExists) {
XdmfError::message(XdmfError::FATAL,
"Error: Invalid Variable in evaluateExpression " + expression.substr(valueStart, i + 1 - valueStart));
}
else {
std::string currentFunction = expression.substr(valueStart, i + 1 - valueStart);
/*check if next character is an open parenthesis*/
if (expression[i+1] != '(') {
XdmfError::message(XdmfError::FATAL,
"Error: No values supplied to function " + expression.substr(valueStart, i + 1 - valueStart));
}
/*if it is grab the string between paranthesis*/
i = i + 2;
valueStart = i;
int numOpenParenthesis = 0;
while ((expression[i] != ')' || numOpenParenthesis) && i < expression.size()) {
if (expression[i] == '(') {
numOpenParenthesis++;
}
else if (expression[i] == ')') {
numOpenParenthesis--;
}
i++;
}
std::string functionParameters = expression.substr(valueStart, i - valueStart);
std::vector<shared_ptr<XdmfArray> > parameterVector;
/*split that string at commas*/
size_t parameterSplit = 0;
while (parameterSplit != std::string::npos) {
parameterSplit = 0;
parameterSplit = functionParameters.find_first_of(",", parameterSplit);
/*feed the substrings to the parse function*/
if (parameterSplit == std::string::npos) {
parameterVector.push_back(evaluateExpression(functionParameters, variables));
}
else {
parameterVector.push_back(evaluateExpression(functionParameters.substr(0, parameterSplit), variables));
functionParameters = functionParameters.substr(parameterSplit+1);
}
}
valueStack.push(evaluateFunction(parameterVector, currentFunction));
}
}
else {
/*push equivalent to value stack*/
valueStack.push(variables.find(expression.substr(valueStart, i + 1 - valueStart))->second);
}
}
else if (XdmfFunction::getSupportedOperations().find(expression[i]) != std::string::npos) {/*found to be an operation*/
/*pop operations off the stack until one of a lower or equal importance is found*/
if (operationStack.size() > 0) {
if (expression[i] == ')') {
/*to close a parenthesis pop off all operations until another parentheis is found*/
while (operationStack.size() > 0 && operationStack.top() != '(') {
if (valueStack.size() < 2) {/*must be at least two values for this loop to work properly*/
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Values in evaluateExpression");
}
else {
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
valueStack.push(evaluateOperation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
operationStack.pop();
}
else if (expression[i] == '(') {
/*just add it if it's a start parenthesis
nothing happens here in that case
addition happens after the if statement block*/
}
else {
int operationLocation = XdmfFunction::getOperationPriority(expression[i]);
int topOperationLocation = XdmfFunction::getOperationPriority(operationStack.top());
/*see order of operations to determine importance*/
while (operationStack.size() > 0 && operationLocation < topOperationLocation) {
if (valueStack.size() < 2) {/*must be at least two values for this loop to work properly*/
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Values in evaluateExpression");
}
else {
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
valueStack.push(evaluateOperation(val1, val2, operationStack.top()));
operationStack.pop();
if (operationStack.size() == 0) {
break;
}
topOperationLocation = XdmfFunction::getOperationPriority(operationStack.top());
}
}
}
}
if (expression[i] != ')') {
/*add the operation to the operation stack*/
operationStack.push(expression[i]);
}
}
/*if not a value or operation the character is ignored*/
}
/*empty what's left in the stacks before finishing*/
while (valueStack.size() > 1 && operationStack.size() > 0) {
if (valueStack.size() < 2) {/*must be at least two values for this loop to work properly*/
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Values in evaluateExpression");
}
else {
if(operationStack.top() == '(') {
XdmfError::message(XdmfError::WARNING,
"Warning: Unpaired Parenthesis");
}
else {
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
if (operationStack.size() == 0) {
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Operators in evaluateExpression");
}
else {
valueStack.push(evaluateOperation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
}
}
/*throw error if there's extra operations*/
if (operationStack.size() > 0) {
XdmfError::message(XdmfError::WARNING,
"Warning: Left Over Operators in evaluateExpression");
}
if (valueStack.size() > 1) {
XdmfError::message(XdmfError::WARNING,
"Warning: Left Over Values in evaluateExpression");
}
return valueStack.top();
}
%}
/*trying to transfer python funcitons*/
/*note, accessing private members is impossible from swig.*/
static int addFunction(std::string newName, PyObject * functionref)
{
/*check if the object is callable*/
if (PyCallable_Check(functionref) == 1) {
pythonFunctions[newName] = functionref;
return pythonFunctions.size();
}
else {
XdmfError::message(XdmfError::FATAL,
"Error: Function is not callable");
return -1;
}
}
/*to generate new static functions mark them as static here.*/
static std::vector<std::string> getSupportedFunctions()
{
std::vector<std::string> returnVector = XdmfFunction::getSupportedFunctions();
for (std::map<std::string, PyObject *>::iterator functionWalker = pythonFunctions.begin(); functionWalker != pythonFunctions.end(); functionWalker++) {
returnVector.push_back(functionWalker->first);
}
return returnVector;
}
static shared_ptr<XdmfArray> evaluateFunction(std::vector<shared_ptr<XdmfArray> > functValues, std::string functName)
{
if (pythonFunctions.find(functName)!= pythonFunctions.end()) {
swig_type_info * paramType = SWIG_TypeQuery("_p_std__vectorT_boost__shared_ptrT_XdmfArray_t_std__allocatorT_boost__shared_ptrT_XdmfArray_t_t_t");
PyObject * pyVector = SWIG_NewPointerObj(static_cast<void*>(& functValues), paramType, SWIG_POINTER_NEW);
PyObject * args = PyTuple_New(1);
PyTuple_SetItem(args, 0, pyVector);/*In this case you could also cast a pointer to the vector into the PyObject * type, but that doesn't work for all types*/
PyObject * resultObject = PyObject_CallObject(pythonFunctions[functName], args);
void * resultPointer = 0;
swig_type_info * returnType = SWIG_TypeQuery("_p_boost__shared_ptrT_XdmfArray_t");
SWIG_ConvertPtr(resultObject, &resultPointer, returnType, 0);
shared_ptr<XdmfArray> * returnArrayPointer = reinterpret_cast<shared_ptr<XdmfArray> *>(resultPointer);
shared_ptr<XdmfArray> returnArray = returnArrayPointer[0];
return returnArray;
}
else {
/*this does not actually cause an infinte recursive loop, it sends the values to the version of the function defined in XdmfArray.cpp*/
return XdmfFunction::evaluateFunction(functValues, functName);
}
}
static int addOperation(char newName, PyObject * calcref, int priority)
{
if (newName == '(' || newName == ')') {
XdmfError::message(XdmfError::FATAL,
"Error: Parenthesis can not be redefined");
}
/*check if the object is callable*/
if (PyCallable_Check(calcref) == 1) {
if (pythonOperations.find(newName) != pythonOperations.end() || XdmfFunction::getSupportedOperations().find(newName) != std::string::npos) {
XdmfError::message(XdmfError::WARNING,
"Warning: Operation Redefined");/*It's a good idea to warn users when they're doing this*/
size_t operationLocation = pythonSupportedOperations.find(newName);
/*if not an already defined python function*/
if (pythonOperations.find(newName) == pythonOperations.end()) {
pythonSupportedOperations.push_back(newName);
unsigned int priorityArraySize = sizeof(pythonOperationPriority)/sizeof(int);
if (pythonSupportedOperations.size()-1 > priorityArraySize) {
int newArray [priorityArraySize*2];
std::copy(pythonOperationPriority, pythonOperationPriority+(priorityArraySize-1), newArray);
*pythonOperationPriority = *newArray;
}
}
pythonOperationPriority[operationLocation] = priority;
/*if defined on the c++ side same as adding a new one*/
}
else {
pythonSupportedOperations += newName;
if (XdmfFunction::getValidVariableChars().find(newName) != std::string::npos || XdmfFunction::getValidDigitChars().find(newName) != std::string::npos) {
XdmfError::message(XdmfError::FATAL,
"Error: Operation Overlaps with Variables");
}
else {
pythonSupportedOperations.push_back(newName);
unsigned int priorityArraySize = sizeof(pythonOperationPriority)/sizeof(int);
if (pythonSupportedOperations.size()-1 > priorityArraySize)
{
int newArray [priorityArraySize*2];
std::copy(pythonOperationPriority, pythonOperationPriority+(priorityArraySize-1), newArray);
*pythonOperationPriority = *newArray;
}
}
}
pythonOperations[newName] = calcref;
return pythonOperations.size();
}
else {
XdmfError::message(XdmfError::FATAL,
"Error: Operation is not callable");
return -1;
}
}
static std::string getSupportedOperations()
{
std::string returnVector = XdmfFunction::getSupportedOperations();
for (std::map<char, PyObject *>::iterator functionWalker = pythonOperations.begin(); functionWalker != pythonOperations.end(); functionWalker++) {
returnVector += functionWalker->first;
}
return returnVector;
}
static shared_ptr<XdmfArray> evaluateOperation(shared_ptr<XdmfArray> val1, shared_ptr<XdmfArray> val2, char functName)
{
if (pythonOperations.find(functName)!= pythonOperations.end()) {
swig_type_info * paramType = SWIG_TypeQuery("_p_boost__shared_ptrT_XdmfArray_t");
PyObject * pyVal1 = SWIG_NewPointerObj(static_cast<void*>(& val1), paramType, SWIG_POINTER_NEW);
PyObject * pyVal2 = SWIG_NewPointerObj(static_cast<void*>(& val2), paramType, SWIG_POINTER_NEW);
PyObject * args = PyTuple_New(2);
PyTuple_SetItem(args, 0, pyVal1);
PyTuple_SetItem(args, 1, pyVal2);
PyObject * resultObject = PyObject_CallObject(pythonOperations[functName], args);
void * resultPointer = 0;
swig_type_info * returnType = SWIG_TypeQuery("_p_boost__shared_ptrT_XdmfArray_t");
SWIG_ConvertPtr(resultObject, &resultPointer, returnType, 0);
shared_ptr<XdmfArray> * returnArrayPointer = reinterpret_cast<shared_ptr<XdmfArray> *>(resultPointer);
shared_ptr<XdmfArray> returnArray = returnArrayPointer[0];
return returnArray;
}
else {
/*this does not actually cause an infinte recursive loop, it sends the values to the version of the function defined in XdmfArray.cpp*/
return XdmfFunction::evaluateOperation(val1, val2, functName);
}
}
static shared_ptr<XdmfArray> evaluateExpression(std::string expression, std::map<std::string, shared_ptr<XdmfArray> > variables)
{
std::stack<shared_ptr<XdmfArray> > valueStack;
std::stack<char> operationStack;
/*string is parsed left to right
elements of the same priority are evaluated right to left*/
for (unsigned int i = 0; i < expression.size(); i++) {
if (XdmfFunction::getValidDigitChars().find(expression[i]) != std::string::npos) { /*found to be a digit*/
/*progress until a non-digit is found*/
int valueStart = i;
while (XdmfFunction::getValidDigitChars().find(expression[i + 1]) != std::string::npos) {
i++;
}
/*push back to the value stack*/
shared_ptr<XdmfArray> valueArray = XdmfArray::New();
valueArray->insert(0, atof(expression.substr(valueStart, i + 1 - valueStart).c_str()));/*use this to convert to double*/
valueStack.push(valueArray);
}
else if (XdmfFunction::getValidVariableChars().find(expression[i]) != std::string::npos) {/*found to be a variable*/
int valueStart = i;
/*progress until a nonvariable value is found*/
while (XdmfFunction::getValidVariableChars().find(expression[i + 1]) != std::string::npos) {
i++;
}
/*convert to equivalent*/
if (variables.find(expression.substr(valueStart, i + 1 - valueStart)) == variables.end()) {
std::vector<std::string> functionList = XdmfFunction::getSupportedFunctions();
bool functionExists = false;
for (unsigned int j = 0; j < functionList.size() && !functionExists; j++) {
if (functionList[j] == expression.substr(valueStart, i + 1 - valueStart)) {
functionExists = true;
}
}
if (functionExists) {
XdmfError::message(XdmfError::FATAL,
"Error: Invalid Variable in evaluateExpression " + expression.substr(valueStart, i + 1 - valueStart));
}
else {
std::string currentFunction = expression.substr(valueStart, i + 1 - valueStart);
/*check if next character is an open parenthesis*/
if (expression[i+1] != '(') {
XdmfError::message(XdmfError::FATAL,
"Error: No values supplied to function " + expression.substr(valueStart, i + 1 - valueStart));
}
/*if it is grab the string between paranthesis*/
i = i + 2;
valueStart = i;
int numOpenParenthesis = 0;
while ((expression[i] != ')' || numOpenParenthesis) && i < expression.size()) {
if (expression[i] == '(') {
numOpenParenthesis++;
}
else if (expression[i] == ')') {
numOpenParenthesis--;
}
i++;
}
std::string functionParameters = expression.substr(valueStart, i - valueStart);
std::vector<shared_ptr<XdmfArray> > parameterVector;
/*split that string at commas*/
size_t parameterSplit = 0;
while (parameterSplit != std::string::npos) {
parameterSplit = 0;
parameterSplit = functionParameters.find_first_of(",", parameterSplit);
/*feed the substrings to the parse function*/
if (parameterSplit == std::string::npos) {
parameterVector.push_back(evaluateExpression(functionParameters, variables));
}
else {
parameterVector.push_back(evaluateExpression(functionParameters.substr(0, parameterSplit), variables));
functionParameters = functionParameters.substr(parameterSplit+1);
}
}
valueStack.push(evaluateFunction(parameterVector, currentFunction));
}
}
else {
/*push equivalent to value stack*/
valueStack.push(variables.find(expression.substr(valueStart, i + 1 - valueStart))->second);
}
}
else if (XdmfFunction::getSupportedOperations().find(expression[i]) != std::string::npos) {/*found to be an operation*/
/*pop operations off the stack until one of a lower or equal importance is found*/
if (operationStack.size() > 0) {
if (expression[i] == ')') {
/*to close a parenthesis pop off all operations until another parentheis is found*/
while (operationStack.size() > 0 && operationStack.top() != '(') {
if (valueStack.size() < 2) {/*must be at least two values for this loop to work properly*/
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Values in evaluateExpression");
}
else {
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
valueStack.push(evaluateOperation(val1, val2, operationStack.top()));
operationStack.pop();
}
}
operationStack.pop();
}
else if (expression[i] == '(') {
/*just add it if it's a start parenthesis
nothing happens here in that case
addition happens after the if statement*/
}
else {
int operationLocation = XdmfFunction::getOperationPriority(expression[i]);
int topOperationLocation = XdmfFunction::getOperationPriority(operationStack.top());
/*see order of operations to determine importance*/
while (operationStack.size() > 0 && operationLocation < topOperationLocation) {
if (valueStack.size() < 2) {/*must be at least two values for this loop to work properly*/
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Values in evaluateExpression");
}
else {
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();
shared_ptr<XdmfArray> val1 = valueStack.top();
valueStack.pop();
valueStack.push(evaluateOperation(val1, val2, operationStack.top()));
operationStack.pop();
if (operationStack.size() == 0) {
break;
}
topOperationLocation = XdmfFunction::getOperationPriority(operationStack.top());
}
}
}
}
if (expression[i] != ')') {
/*add the operation to the operation stack*/
operationStack.push(expression[i]);
}
}
/*if not a value or operation the character is ignored*/
}
/*empty what's left in the stacks before finishing*/
while (valueStack.size() > 1 && operationStack.size() > 0) {
if (valueStack.size() < 2) {/*must be at least two values for this loop to work properly*/
XdmfError::message(XdmfError::FATAL,
"Error: Not Enough Values in evaluateExpression");
}
else {
if(operationStack.top() == '(') {
XdmfError::message(XdmfError::WARNING,
"Warning: Unpaired Parenthesis");
}
else {
shared_ptr<XdmfArray> val2 = valueStack.top();
valueStack.pop();