/*****************************************************************************/ /* XDMF */ /* eXtensible Data Model and Format */ /* */ /* Id : XdmfFunction.cpp */ /* */ /* Author: */ /* Andrew Burns */ /* andrew.j.burns2@us.army.mil */ /* US Army Research Laboratory */ /* Aberdeen Proving Ground, MD */ /* */ /* Copyright @ 2013 US Army Research Laboratory */ /* All Rights Reserved */ /* See Copyright.txt for details */ /* */ /* This software is distributed WITHOUT ANY WARRANTY; without */ /* even the implied warranty of MERCHANTABILITY or FITNESS */ /* FOR A PARTICULAR PURPOSE. See the above copyright notice */ /* for more information. */ /* */ /*****************************************************************************/ #include "XdmfArray.hpp" #include "XdmfArrayType.hpp" #include "XdmfFunction.hpp" #include #include #include #include "XdmfError.hpp" class XdmfFunctionInternalImpl : public XdmfFunction::XdmfFunctionInternal { public: static shared_ptr New(shared_ptr (*newInternal)(std::vector >)) { shared_ptr p (new XdmfFunctionInternalImpl(newInternal)); return p; } ~XdmfFunctionInternalImpl() { } virtual shared_ptr execute(std::vector > valueVector) { return (*mInternalFunction)(valueVector); } private: XdmfFunctionInternalImpl(shared_ptr (*newInternal)(std::vector >)) { mInternalFunction = newInternal; } shared_ptr (*mInternalFunction)(std::vector >); }; class XdmfOperationInternalImpl : public XdmfFunction::XdmfOperationInternal { public: static shared_ptr New(shared_ptr (*newInternal)(shared_ptr, shared_ptr)) { shared_ptr p (new XdmfOperationInternalImpl(newInternal)); return p; } ~XdmfOperationInternalImpl() { } virtual shared_ptr execute(shared_ptr val1, shared_ptr val2) { return (*mInternalOperation)(val1, val2); } private: XdmfOperationInternalImpl(shared_ptr (*newInternal)(shared_ptr, shared_ptr)) { mInternalOperation = newInternal; } shared_ptr (*mInternalOperation)(shared_ptr, shared_ptr); }; std::string XdmfFunction::mSupportedOperations = "-+/*|#()"; const std::string XdmfFunction::mValidVariableChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_:."; const std::string XdmfFunction::mValidDigitChars = "1234567890."; // List the priorities for the operations, based on the order of operations // The index of the corresponding operation in validOperationChars // is the same as the index of its priority in this array std::map XdmfFunction::mOperationPriority = boost::assign::map_list_of ('-', 4) ('+', 4) ('/', 3) ('*', 3) ('|', 2) ('#', 1) ('(', 0) (')', 0); // The higher the value, the earlier the operation is // evaluated in the order of operations // With the exception of parenthesis which are evaluated // as soon as the closing parenthesis is found // Note, it doesn't handle overloaded functions well. // Will generate errors unless overload methods are typecast. std::map > XdmfFunction::arrayFunctions = boost::assign::map_list_of ("ABS", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::abs)) ("ABS_TOKEN", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::abs)) ("ACOS", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::arccos)) ("ASIN", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::arcsin)) ("ATAN", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::arctan)) ("AVE", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::average)) ("COS", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::cos)) ("EXP", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::exponent)) ("JOIN", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::join)) ("LOG", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::log)) ("SIN", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::sin)) ("SQRT", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::sqrt)) ("SUM", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::sum)) ("TAN", XdmfFunctionInternalImpl::New((shared_ptr (*)(std::vector >)) XdmfFunction::tan)); std::map > XdmfFunction::operations = boost::assign::map_list_of ('-', XdmfOperationInternalImpl::New(XdmfFunction::subtraction)) ('+', XdmfOperationInternalImpl::New(XdmfFunction::addition)) ('*', XdmfOperationInternalImpl::New(XdmfFunction::multiplication)) ('/', XdmfOperationInternalImpl::New(XdmfFunction::division)) ('|', XdmfOperationInternalImpl::New(XdmfFunction::chunk)) ('#', XdmfOperationInternalImpl::New(XdmfFunction::interlace)); shared_ptr XdmfFunction::New() { shared_ptr p(new XdmfFunction()); return p; } shared_ptr XdmfFunction::New(std::string newExpression, std::map > newVariables) { shared_ptr p(new XdmfFunction(newExpression, newVariables)); return p; } XdmfFunction::XdmfFunction(): mExpression("") { } XdmfFunction::XdmfFunction(std::string newExpression, std::map > newVariables): mVariableList(newVariables), mExpression(newExpression) { } XdmfFunction::~XdmfFunction() { } const std::string XdmfFunction::ItemTag = "Function"; shared_ptr XdmfFunction::abs(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function abs"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(std::abs(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } int XdmfFunction::addFunction(std::string name, shared_ptr(*functionref)(std::vector >)) { shared_ptr newFunction = XdmfFunctionInternalImpl::New(functionref); return XdmfFunction::addFunction(name, newFunction); } int XdmfFunction::addFunction(std::string name, shared_ptr newFunction) { // Check to ensure that the name has valid characters for (unsigned int i = 0; i < name.size(); ++i) { // If the character is not found in the list of valid characters if (mValidVariableChars.find(name[i]) == std::string::npos) { // Then throw an error XdmfError::message(XdmfError::FATAL, "Error: Function Name Contains Invalid Character(s)"); } } size_t origsize = arrayFunctions.size(); arrayFunctions[name] = newFunction; // If no new functions were added if (origsize == arrayFunctions.size()) { // Toss a warning, it's nice to let people know that they're doing this XdmfError::message(XdmfError::WARNING, "Warning: Function Overwritten"); } return arrayFunctions.size(); } int XdmfFunction::addOperation(char newoperator, shared_ptr(*operationref)(shared_ptr, shared_ptr), int priority) { shared_ptr newOperation = XdmfOperationInternalImpl::New(operationref); return XdmfFunction::addOperation(newoperator, newOperation, priority); } int XdmfFunction::addOperation(char newoperator, shared_ptr newOperation, int priority) { if (newoperator == '(' || newoperator == ')') { XdmfError::message(XdmfError::FATAL, "Error: Parenthesis can not be redefined"); } if (mValidVariableChars.find(newoperator) != std::string::npos || mValidDigitChars.find(newoperator) != std::string::npos) { XdmfError::message(XdmfError::FATAL, "Error: Operation Overlaps with Variables"); } // Give warning if the operation already exists size_t origsize = operations.size(); // Place reference in the associated location operations[newoperator] = newOperation; if (origsize == operations.size()) { // It's nice to let people know they're doing this // So they don't get surprised about changes in behavior XdmfError::message(XdmfError::WARNING, "Warning: Operation Overwritten"); // Overwrite the existing info for that operation // Add the priority to the specified location in the priority array mOperationPriority[newoperator] = priority; } else { // Create new operation // Add operation to the supported character string mSupportedOperations.push_back(newoperator); mOperationPriority[newoperator] = priority; } return operations.size(); } shared_ptr XdmfFunction::addition(shared_ptr val1, shared_ptr val2) { shared_ptr returnArray = XdmfArray::New(); bool release1 = false; bool release2 = false; if (!val1->isInitialized()) { val1->read(); release1 = true; } if (!val2->isInitialized()) { val2->read(); release2 = true; } for (unsigned int i = 0; i < val1->getSize() || i < val2->getSize(); ++i) { if (val1->getSize() == val2->getSize()) { returnArray->pushBack(val1->getValue(i) + val2->getValue(i)); } else if (val1->getSize() == 1) { returnArray->pushBack(val1->getValue(0) + val2->getValue(i)); } else if (val2->getSize() == 1) { returnArray->pushBack(val1->getValue(i) + val2->getValue(0)); } else { XdmfError::message(XdmfError::FATAL, "Error: Array Size Mismatch in Function addition"); } } if (release1) { val1->release() } if (release2) { val2->release() } return returnArray; } shared_ptr XdmfFunction::arcsin(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function arcsin"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(asin(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } shared_ptr XdmfFunction::arccos(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function arccos"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(acos(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } shared_ptr XdmfFunction::arctan(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function arctan"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(atan(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } shared_ptr XdmfFunction::average(std::vector > values) { double total = sum(values)->getValue(0);; int totalSize = 0; for (unsigned int i = 0; i < values.size(); ++i) { totalSize += values[i]->getSize(); } shared_ptr returnArray = XdmfArray::New(); returnArray->insert(0, total/totalSize); return returnArray; } shared_ptr XdmfFunction::cos(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function cos"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(std::cos(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } shared_ptr XdmfFunction::chunk(shared_ptr val1, shared_ptr val2) { // Join chunk (add the new array to the end of the first one) // Joins into new array and returns it shared_ptr returnArray = XdmfArray::New(); // Determining what type to class it as in order to not lose data // and to still have the smallest data type of the two shared_ptr resultType = XdmfArrayType::comparePrecision(val1->getArrayType(), val2->getArrayType()); bool release1 = false; bool release2 = false; if (!val1->isInitialized()) { val1->read(); release1 = true; } if (!val2->isInitialized()) { val2->read(); release2 = true; } if (resultType == XdmfArrayType::Int8()) { char sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Int16()) { short sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Int32()) { int sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Int64()) { long sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::UInt8()) { unsigned char sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::UInt16()) { unsigned short sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::UInt32()) { unsigned int sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Float32()) { float sampleValue = 0.0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Float64()) { double sampleValue = 0.0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::String()) { std::string sampleValue = ""; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else { // error type not supported XdmfError::message(XdmfError::FATAL, "Invalid type during Chunk"); } returnArray->insert(0, val1, 0, val1->getSize(), 1, 1); returnArray->insert(val1->getSize(), val2, 0, val2->getSize(), 1, 1); if (release1) { val1->release() } if (release2) { val2->release() } return returnArray; } shared_ptr XdmfFunction::exponent(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 2) { XdmfError::message(XdmfError::FATAL, "Error: Two Arrays Needed for Function exponent"); } bool release1 = false; bool release2 = false; if (!values[0]->isInitialized()) { values[0]->read(); release1 = true; } if (!values[1]->isInitialized()) { values[1]->read(); release2 = true; } for (unsigned int i = 0; i < values[0]->getSize() || i < values[1]->getSize(); ++i) { if (values[0]->getSize() == values[1]->getSize()) { returnArray->pushBack(std::pow(values[0]->getValue(i), values[1]->getValue(i))); } else if (values[0]->getSize() == 1) { returnArray->pushBack(std::pow(values[0]->getValue(0), values[1]->getValue(i))); } else if (values[1]->getSize() == 1) { returnArray->pushBack(std::pow(values[0]->getValue(i), values[1]->getValue(0))); } else { XdmfError::message(XdmfError::FATAL, "Error: Array Size Mismatch in Function exponent"); } } if (release1) { values[0]->release() } if (release2) { values[1]->release() } return returnArray; } shared_ptr XdmfFunction::division(shared_ptr val1, shared_ptr val2) { bool release1 = false; bool release2 = false; if (!val1->isInitialized()) { val1->read(); release1 = true; } if (!val2->isInitialized()) { val2->read(); release2 = true; } shared_ptr returnArray = XdmfArray::New(); for (unsigned int i = 0; i < val1->getSize() || i < val2->getSize(); ++i) { if (val1->getSize() == val2->getSize()) { returnArray->pushBack(val1->getValue(i) / val2->getValue(i)); } else if (val1->getSize() == 1) { returnArray->pushBack(val1->getValue(0) / val2->getValue(i)); } else if (val2->getSize() == 1) { returnArray->pushBack(val1->getValue(i) / val2->getValue(0)); } else { XdmfError::message(XdmfError::FATAL, "Error: Array Size Mismatch in Function division"); } } if (release1) { val1->release() } if (release2) { val2->release() } return returnArray; } shared_ptr XdmfFunction::evaluateExpression(std::string expression, std::map > variables) { std::stack > valueStack; std::stack 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) { bool hyphenIsDigit = false; // hyphen is a special case since it can be used to annotate negative numbers if (expression[i] == '-') { if (i == 0) { //would have to be a digit, otherwise it would be a unpaired operation hyphenIsDigit = true; } else if (mValidDigitChars.find(expression[i+1]) != std::string::npos) { // If value after is a valid digit, // check value before // If a digit, it's an operation // If a variable, it's an operation // If an operation, it's a digit character if (mSupportedOperations.find(expression[i-1]) != std::string::npos) { hyphenIsDigit = true; } else if (expression[i-1] <= ' ') { // If whitespace is in front of the hyphen it is presumed to be a negative sign // This is to handle passing negative values to functions properly hyphenIsDigit = true; } } } // Found to be a digit if (mValidDigitChars.find(expression[i]) != std::string::npos || (expression[i] == '-' && hyphenIsDigit)) { // Progress until a non-digit is found int valueStart = i; if (i + 1 < expression.size()) { while (mValidDigitChars.find(expression[i+1]) != std::string::npos) { i++; } } // Push back to the value stack shared_ptr valueArray = XdmfArray::New(); // Use this to convert to double valueArray->insert(0, atof(expression.substr(valueStart, i + 1 - valueStart).c_str())); valueStack.push(valueArray); } else if (mValidVariableChars.find(expression[i]) != std::string::npos) { // Found to be a variable int valueStart = i; // Progress until a nonvariable value is found if (i+1 < expression.size()){ while (mValidVariableChars.find(expression[i+1]) != std::string::npos) { i++; } } // Convert to equivalent if (variables.find(expression.substr(valueStart, i + 1 - valueStart)) == variables.end()) { if (arrayFunctions.find(expression.substr(valueStart, i + 1 - valueStart)) == arrayFunctions.end()) { 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 (i+1 >= expression.size()) { 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 if (i + 2 >= expression.size()) { XdmfError::message(XdmfError::FATAL, "Error: Missing closing parethesis to function " + expression.substr(valueStart, i + 1 - valueStart)); } 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 > 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 (mSupportedOperations.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() != '(') { // Must be at least two values for this loop to work properly if (valueStack.size() < 2) { XdmfError::message(XdmfError::FATAL, "Error: Not Enough Values in evaluateExpression"); } else { shared_ptr val2 = valueStack.top(); valueStack.pop(); shared_ptr 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 = getOperationPriority(expression[i]); int topOperationLocation = getOperationPriority(operationStack.top()); // See order of operations to determine importance while (operationStack.size() > 0 && operationLocation < topOperationLocation) { // Must be at least two values for this loop to work properly if (valueStack.size() < 2) { XdmfError::message(XdmfError::FATAL, "Error: Not Enough Values in evaluateExpression"); } else { shared_ptr val2 = valueStack.top(); valueStack.pop(); shared_ptr val1 = valueStack.top(); valueStack.pop(); valueStack.push(evaluateOperation(val1, val2, operationStack.top())); operationStack.pop(); if (operationStack.size() == 0) { break; } topOperationLocation = 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 val2 = valueStack.top(); valueStack.pop(); shared_ptr 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"); } // Ensure that an array is returned // Will error out if this is not done. if (valueStack.size() > 0) { return valueStack.top(); } else { return XdmfArray::New(); } } shared_ptr XdmfFunction::evaluateOperation(shared_ptr val1, shared_ptr val2, char operation) { if (operations.find(operation) != operations.end()) { return operations[operation]->execute(val1, val2); } else { return shared_ptr(); } } shared_ptr XdmfFunction::evaluateFunction(std::vector > valueVector, std::string functionName) { if (arrayFunctions.find(functionName) != arrayFunctions.end()) { return arrayFunctions[functionName]->execute(valueVector); } else { return shared_ptr(); } } std::string XdmfFunction::getExpression() const { return mExpression; } std::string XdmfFunction::getItemTag() const { return ItemTag; } std::map XdmfFunction::getItemProperties() const { std::map functionProperties; functionProperties["Expression"] = mExpression; functionProperties["ConstructedType"] = mConstructedType; for (std::map::const_iterator constructedIt = mConstructedProperties.begin(); constructedIt != mConstructedProperties.end(); ++constructedIt) { functionProperties[constructedIt->first] = constructedIt->second; } std::stringstream variableStream; for (std::map >::const_iterator variableIter = mVariableList.begin(); variableIter != mVariableList.end(); ++variableIter) { variableStream << "|" << variableIter->first; } functionProperties["VariableNames"] = variableStream.str(); return functionProperties; } int XdmfFunction::getOperationPriority(char operation) { size_t operationLocation = mSupportedOperations.find(operation); if (operationLocation != std::string::npos) { return mOperationPriority[operation]; } else { return -1; } } const std::string XdmfFunction::getSupportedOperations() { return mSupportedOperations; } const std::vector XdmfFunction::getSupportedFunctions() { std::vector returnVector; for (std::map >::iterator functionWalker = arrayFunctions.begin(); functionWalker != arrayFunctions.end(); ++functionWalker) { returnVector.push_back(functionWalker->first); } return returnVector; } const std::string XdmfFunction::getValidDigitChars() { return mValidDigitChars; } const std::string XdmfFunction::getValidVariableChars() { return mValidVariableChars; } shared_ptr XdmfFunction::getVariable(std::string key) { if (mVariableList.count(key) > 0) { return mVariableList[key]; } else { return shared_ptr(); } } std::vector XdmfFunction::getVariableList() { std::vector keyAccumulator; for (std::map >::iterator it = mVariableList.begin(); it != mVariableList.end(); ++it) { keyAccumulator.push_back(it->first); } return keyAccumulator; } shared_ptr XdmfFunction::interlace(shared_ptr val1, shared_ptr val2) { // Join interlace (evenly space the second array within the first one) // Builds a new array shared_ptr returnArray = XdmfArray::New(); // Resize to the combined size of both arrays // Determining what type to class it as in order to not lose data // and to still have the smallest data type of the two shared_ptr resultType = XdmfArrayType::comparePrecision(val1->getArrayType(), val2->getArrayType()); bool release1 = false; bool release2 = false; if (!val1->isInitialized()) { val1->read(); release1 = true; } if (!val2->isInitialized()) { val2->read(); release2 = true; } if (resultType == XdmfArrayType::Int8()) { char sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Int16()) { short sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Int32()) { int sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Int64()) { long sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::UInt8()) { unsigned char sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::UInt16()) { unsigned short sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::UInt32()) { unsigned int sampleValue = 0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Float32()) { float sampleValue = 0.0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::Float64()) { double sampleValue = 0.0; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else if (resultType == XdmfArrayType::String()) { std::string sampleValue = ""; returnArray->resize(val1->getSize()+val2->getSize(), sampleValue); } else { // error type not supported XdmfError::message(XdmfError::FATAL, "Invalid type during Interlace"); } // Determine ratio of array sizes int arrayRatio1 = (int)floor(static_cast(val1->getSize())/val2->getSize()); int arrayRatio2 = (int)floor(static_cast(val2->getSize())/val1->getSize()); if (arrayRatio1 < 1) { arrayRatio1 = 1; } if (arrayRatio2 < 1) { arrayRatio2 = 1; } // Stride is equal to the ratios rounded up and added together int stride = arrayRatio1+arrayRatio2; int arrayExcess1 = 0; int arrayExcess2 = 0; for (int i = 0; i < stride; ++i) { // Add the values of each array // using strides to interlace and starting index to offset // first array gets the first value of the new array if (igetSize()/arrayRatio1; if (((amountWritten * arrayRatio1) + i) < (int)val1->getSize()) { amountWritten++; } if (amountWritten > floor(static_cast(val2->getSize())/arrayRatio2)) { arrayExcess1 += amountWritten - (int)floor(static_cast(val2->getSize())/arrayRatio2); amountWritten = (int)floor(static_cast(val2->getSize())/arrayRatio2); } returnArray->insert(i, val1, i, amountWritten, stride, arrayRatio1); } else { // Second array takes the rest int amountWritten = val2->getSize()/arrayRatio2; if (((amountWritten * arrayRatio2) + i) < (int)val2->getSize()) { amountWritten++; } if (amountWritten > floor(static_cast(val1->getSize())/arrayRatio1)) { arrayExcess2 += amountWritten - (int)floor(static_cast(val1->getSize())/arrayRatio1); amountWritten = (int)floor(static_cast(val1->getSize())/arrayRatio1); } returnArray->insert(i, val2, i-arrayRatio1, amountWritten, stride, arrayRatio2); } } if (arrayExcess1 > 0) { returnArray->insert(val1->getSize()+val2->getSize()-arrayExcess1, val1, val1->getSize()-arrayExcess1, arrayExcess1, 1, 1); } else if (arrayExcess2 > 0) { returnArray->insert(val1->getSize()+val2->getSize()-arrayExcess2, val2, val2->getSize()-arrayExcess2, arrayExcess2, 1, 1); } // After all inserts are done, add the excess values to the end of the array if (release1) { val1->release() } if (release2) { val2->release() } return returnArray; } void XdmfFunction::insertVariable(std::string key, shared_ptr value) { mVariableList[key] = value; } shared_ptr XdmfFunction::join(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); for (unsigned int i = 0; i < values.size(); ++i) { returnArray->insert(returnArray->getSize(), values[i], 0, values[i]->getSize(), 1, 1); } return returnArray; } shared_ptr XdmfFunction::log(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function log"); } bool release1 = false; bool release2 = false; if (!values[0]->isInitialized()) { values[0]->read(); release1 = true; } if (values.size() > 1) { if (!values[1]->isInitialized()) { values[1]->read(); release2 = true; } } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { if (values.size() > 1) { if (values[0]->getSize() == values[1]->getSize()) { returnArray->pushBack(std::log(values[0]->getValue(i))/std::log(values[1]->getValue(i))); } else if (values[1]->getSize() == 1) { returnArray->pushBack(std::log(values[0]->getValue(i))/std::log(values[1]->getValue(0))); } else { XdmfError::message(XdmfError::FATAL, "Error: Array Size Missmatch in Function Log"); } } else { returnArray->pushBack(std::log(values[0]->getValue(i))); } } if (release1) { values[0]->release() } if (release2) { values[1]->release() } return returnArray; } shared_ptr XdmfFunction::multiplication(shared_ptr val1, shared_ptr val2) { shared_ptr returnArray = XdmfArray::New(); bool release1 = false; bool release2 = false; if (!val1->isInitialized()) { val1->read(); release1 = true; } if (!val2->isInitialized()) { val2->read(); release2 = true; } for (unsigned int i = 0; i < val1->getSize() || i < val2->getSize(); ++i) { if (val1->getSize() == val2->getSize()) { returnArray->pushBack(val1->getValue(i) * val2->getValue(i)); } else if (val1->getSize() == 1) { returnArray->pushBack(val1->getValue(0) * val2->getValue(i)); } else if (val2->getSize() == 1) { returnArray->pushBack(val1->getValue(i) * val2->getValue(0)); } else { XdmfError::message(XdmfError::FATAL, "Error: Array Size Mismatch in Function multiplication"); } } if (release1) { val1->release() } if (release2) { val2->release() } return returnArray; } shared_ptr XdmfFunction::read() const { return evaluateExpression(mExpression, mVariableList); } void XdmfFunction::removeVariable(std::string key) { std::map >::iterator removeWalker = mVariableList.find(key); if (removeWalker != mVariableList.end()) { mVariableList.erase(removeWalker); } } void XdmfFunction::setExpression(std::string newExpression) { mExpression = newExpression; } shared_ptr XdmfFunction::sin(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function sin"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(std::sin(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } shared_ptr XdmfFunction::sqrt(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function sqrt"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(std::sqrt(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } shared_ptr XdmfFunction::subtraction(shared_ptr val1, shared_ptr val2) { shared_ptr returnArray = XdmfArray::New(); bool release1 = false; bool release2 = false; if (!val1->isInitialized()) { val1->read(); release1 = true; } if (!val2->isInitialized()) { val2->read(); release2 = true; } for (unsigned int i = 0; i < val1->getSize() || i < val2->getSize(); ++i) { if (val1->getSize() == val2->getSize()) { returnArray->pushBack(val1->getValue(i) - val2->getValue(i)); } else if (val1->getSize() == 1) { returnArray->pushBack(val1->getValue(0) - val2->getValue(i)); } else if (val2->getSize() == 1) { returnArray->pushBack(val1->getValue(i) - val2->getValue(0)); } else { XdmfError::message(XdmfError::FATAL, "Error: Array Size Mismatch in Function subtraction"); } } if (release1) { val1->release() } if (release2) { val2->release() } return returnArray; } shared_ptr XdmfFunction::sum(std::vector > values) { double total = 0.0; bool release = false; for (unsigned int i = 0; i < values.size(); ++i) { release = false; if (!values[i]->getIsInitialized()) { values[i]->read(); release = true; } for (unsigned int j = 0; j < values[i]->getSize(); ++j) { total += values[i]->getValue(j); } if (release) { values[i]->release(); } } shared_ptr returnArray = XdmfArray::New(); returnArray->insert(0, total); return returnArray; } shared_ptr XdmfFunction::tan(std::vector > values) { shared_ptr returnArray = XdmfArray::New(); // Only working with the first array provided if (values.size() < 1) { XdmfError::message(XdmfError::FATAL, "Error: No Array Passed to Function tan"); } bool release = false; if (!values[0]->getIsInitialized()) { values[0]->read(); release = true; } for (unsigned int i = 0; i < values[0]->getSize(); ++i) { returnArray->pushBack(std::tan(values[0]->getValue(i))); } if (release) { values[0]->release(); } return returnArray; } void XdmfFunction::traverse(const shared_ptr visitor) { XdmfItem::traverse(visitor); shared_ptr spacerarray = XdmfArray::New(); spacerarray->pushBack((int)0); spacerarray->accept(visitor); for (std::map >::iterator it = mVariableList.begin(); it != mVariableList.end(); ++it) { it->second->accept(visitor); } }