diff --git a/Janus/CMakeLists.txt b/Janus/CMakeLists.txt index d47cdcf..e5684f9 100644 --- a/Janus/CMakeLists.txt +++ b/Janus/CMakeLists.txt @@ -108,10 +108,10 @@ add_library(Janus STATIC ${CMAKE_CURRENT_SOURCE_DIR}/PropertyDef.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Provenance.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Reference.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Signal.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SignalDef.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Signals.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SignalList.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Sgnl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SgnlDef.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Sgnls.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SgnlList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SolveMathML.cpp ${CMAKE_CURRENT_SOURCE_DIR}/StatespaceFn.cpp ${CMAKE_CURRENT_SOURCE_DIR}/StaticShot.cpp @@ -157,7 +157,7 @@ endif() if (MSVC) set_target_properties(Janus PROPERTIES COMPILE_FLAGS "/bigobj") -elseif (MINGW) +elseif (WIN32) set_target_properties(Janus PROPERTIES COMPILE_FLAGS "-Wa,-mbig-obj") endif() diff --git a/Janus/CheckSignal.h b/Janus/CheckSignal.h index 1a133e9..8d3c02d 100644 --- a/Janus/CheckSignal.h +++ b/Janus/CheckSignal.h @@ -50,8 +50,8 @@ */ // Local Includes -#include -#include +#include +#include #include "XmlElementDefinition.h" namespace janus diff --git a/Janus/Janus.cpp b/Janus/Janus.cpp index 5876a9d..aa6220c 100644 --- a/Janus/Janus.cpp +++ b/Janus/Janus.cpp @@ -753,6 +753,19 @@ bool Janus::propertyExists( const dstoute::aString& ptyID) //------------------------------------------------------------------------// +const BreakpointDef& Janus::getBreakpointDef( const aString& bpId) const +{ + for ( const auto& bp : breakpointDef_) { + if ( bp.getBpID() == bpId) return bp; + } + throw_message( std::range_error, + setFunctionName( "Janus::getBreakpointDef()") + << "\n - Can't find bpID \"" << bpId << "\"." + ); +} + +//------------------------------------------------------------------------// + SignalDef& Janus::getSignalDef( const aString& sigID) { for ( size_t i = 0; i < signalDef_.size(); ++i) { diff --git a/Janus/Janus.h b/Janus/Janus.h index ba682a1..6ae03fd 100644 --- a/Janus/Janus.h +++ b/Janus/Janus.h @@ -82,7 +82,7 @@ #include "GriddedTableDef.h" #include "UngriddedTableDef.h" #include "Function.h" -#include "SignalDef.h" +#include "SgnlDef.h" #include "CheckData.h" #include "Author.h" #include "Reference.h" @@ -718,6 +718,9 @@ namespace janus { * \return A reference to the list of BreakpointDef instances is returned. */ BreakpointDefList& getBreakpointDef() { return breakpointDef_;} + const BreakpointDefList& getBreakpointDef() const { return breakpointDef_;} + + const BreakpointDef& getBreakpointDef( const dstoute::aString& bpId) const; /** * Within the DOM, a \em griddedTableDef contains points arranged in an diff --git a/Janus/JanusConfig.h b/Janus/JanusConfig.h index 37f08ad..204d1f0 100644 --- a/Janus/JanusConfig.h +++ b/Janus/JanusConfig.h @@ -6,7 +6,7 @@ #define JANUS_VERSION_HEX "0x020300" #define JANUS_VERSION_SHORT "2.3.0" #define JANUS_VERSION_LONG "Janus-2.3.0" - #define JANUS_REVISION "2.3.0.1568" - #define JANUS_REVISION_COUNT 1568 - #define JANUS_REVISION_INFO "6688b7c8baf9bea367fed2e78150df7221ae9dd3" + #define JANUS_REVISION "2.3.0.1594" + #define JANUS_REVISION_COUNT 1594 + #define JANUS_REVISION_INFO "95cfbbd1403822ea0af5acfda0cf59cdbd873e03" #endif /* _JANUS_CONFIG_H_ */ diff --git a/Janus/JanusVariable.cpp b/Janus/JanusVariable.cpp index 6bee854..7b6b5f6 100644 --- a/Janus/JanusVariable.cpp +++ b/Janus/JanusVariable.cpp @@ -48,6 +48,7 @@ */ // C++ Includes +#include #include #include #include @@ -157,6 +158,38 @@ JanusVariable::JanusVariable( const aString &variableName, JanusVariableType var requiredValue_ = findUnits( specificUnits); } +set JanusVariable::getAllDependencies() const +{ + assert( janusFile_); + if ( !janusFile_ || !variableDef_) return {}; + + set workingIndices = { janusFile_->getVariableIndex( variableDef_->getVarID())}; + set outputIndices; + + while ( !workingIndices.empty()) { + const aOptionalSizeT tIndex = *workingIndices.begin(); + if ( tIndex.isValid()) { + outputIndices.insert( tIndex); + const vector& tIndvarIndices = janusFile_->getVariableDef( tIndex).getIndependentVarRef(); + for ( size_t i : tIndvarIndices) { + if ( outputIndices.find( i) == outputIndices.end()) { + workingIndices.insert( i); + } + } + } + workingIndices.erase( tIndex); + } + + workingIndices.erase( janusFile_->getVariableIndex( variableDef_->getVarID())); // Remove this + + set indvars; + for ( size_t i : outputIndices) { + indvars.insert( janusFile_->getVariableDef( i).getVarID()); + } + + return indvars; +} + void JanusVariable::setJanusFile( janus::Janus *janusFile) { if ( janusFile_ != janusFile) { diff --git a/Janus/JanusVariable.h b/Janus/JanusVariable.h index ff4206f..998a88d 100644 --- a/Janus/JanusVariable.h +++ b/Janus/JanusVariable.h @@ -61,6 +61,8 @@ #include #include +#include + // ---------------- // Class Definition // ---------------- @@ -155,6 +157,8 @@ class JanusVariable bool isStateDeriv() const { return isAvailable() ? variableDef_->isStateDeriv() : false;} bool isStdAIAA() const { return isAvailable() ? variableDef_->isStdAIAA() : false;} + std::set getAllDependencies() const; + friend class JanusVariableManager; protected: diff --git a/Janus/Signal.cpp b/Janus/Sgnl.cpp similarity index 99% rename from Janus/Signal.cpp rename to Janus/Sgnl.cpp index ef0aa5a..3f6618c 100644 --- a/Janus/Signal.cpp +++ b/Janus/Sgnl.cpp @@ -36,7 +36,7 @@ //------------------------------------------------------------------------// /** - * \file Signal.cpp + * \file Sgnl.cpp * * A Signal instance holds in its allocated memory alphanumeric data * derived from a \em signal element of a DOM corresponding to diff --git a/Janus/SignalDef.cpp b/Janus/SgnlDef.cpp similarity index 99% rename from Janus/SignalDef.cpp rename to Janus/SgnlDef.cpp index 343cb39..42c1b3c 100644 --- a/Janus/SignalDef.cpp +++ b/Janus/SgnlDef.cpp @@ -36,7 +36,7 @@ //------------------------------------------------------------------------// /** - * \file SignalDef.cpp + * \file SgnlDef.cpp * * A SignalDef instance holds in its allocated memory alphanumeric data * derived from a \em signalDef element of a DOM corresponding to @@ -72,7 +72,7 @@ // Local Includes #include "JanusConstants.h" #include "DomFunctions.h" -#include "SignalDef.h" +#include "SgnlDef.h" using namespace std; using namespace dstoute; diff --git a/Janus/SignalDef.h b/Janus/SgnlDef.h similarity index 100% rename from Janus/SignalDef.h rename to Janus/SgnlDef.h diff --git a/Janus/SignalList.cpp b/Janus/SgnlList.cpp similarity index 99% rename from Janus/SignalList.cpp rename to Janus/SgnlList.cpp index 2759a2f..00f8c92 100644 --- a/Janus/SignalList.cpp +++ b/Janus/SgnlList.cpp @@ -30,7 +30,7 @@ //------------------------------------------------------------------------// // Title: Janus/SignalList // Class: SignalList -// Module: SignalList.cpp +// Module: SgnlList.cpp // First Date: 2017-09-06 // Reference: Janus Reference Manual //------------------------------------------------------------------------// @@ -53,7 +53,7 @@ */ // Ute Includes -#include +#include #include #include diff --git a/Janus/SignalList.h b/Janus/SgnlList.h similarity index 99% rename from Janus/SignalList.h rename to Janus/SgnlList.h index 8a7fd20..32bdb4e 100644 --- a/Janus/SignalList.h +++ b/Janus/SgnlList.h @@ -38,7 +38,7 @@ //------------------------------------------------------------------------// /** - * \file SignalList.h + * \file SgnlList.h * * A SignalList instance behaves as a container for a list of Signal definition * elements (either signalDef or signalRef), which provide the properties of @@ -61,7 +61,7 @@ // Local Includes #include "XmlElementDefinition.h" -#include "SignalDef.h" +#include "SgnlDef.h" namespace janus { diff --git a/Janus/Signals.cpp b/Janus/Sgnls.cpp similarity index 99% rename from Janus/Signals.cpp rename to Janus/Sgnls.cpp index 7dde018..f2b83dc 100644 --- a/Janus/Signals.cpp +++ b/Janus/Sgnls.cpp @@ -30,7 +30,7 @@ //------------------------------------------------------------------------// // Title: Janus/Signals // Class: Signals -// Module: Signals.cpp +// Module: Sgnls.cpp // First Date: 2011-11-04 // Reference: Janus Reference Manual //------------------------------------------------------------------------// @@ -63,7 +63,7 @@ */ // Ute Includes -#include +#include #include #include "DomFunctions.h" diff --git a/Janus/Signals.h b/Janus/Sgnls.h similarity index 99% rename from Janus/Signals.h rename to Janus/Sgnls.h index 04b2097..e9d7326 100644 --- a/Janus/Signals.h +++ b/Janus/Sgnls.h @@ -39,7 +39,7 @@ //------------------------------------------------------------------------// /** - * \file Signals.h + * \file Sgnls.h * * A Signals instance functions as a container for the Signal class, and * provides the functions that allow a calling StaticShot instance to access diff --git a/README.md b/README.md index 058e5d9..6eb6e76 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ pip install python-janus ## Resources -- DST Group Janus website: +- DST Group Janus website: - DAVE-ML website: diff --git a/SFunction/JanusSFunction.cpp b/SFunction/JanusSFunction.cpp index 79e8d77..9f59a6f 100644 --- a/SFunction/JanusSFunction.cpp +++ b/SFunction/JanusSFunction.cpp @@ -38,7 +38,7 @@ using namespace std; -//#define DEBUG_PRINT( ...) printf( __VA_ARGS__) +// #define DEBUG_PRINT( ...) printf( __VA_ARGS__) #define DEBUG_PRINT( ...) template, class _Alloc = std::allocator<_Kty>> @@ -78,9 +78,9 @@ static void mdlInitializeSizes( SimStruct* S) ssSetNumSFcnParams( S, PARAM_COUNT); if ( ssGetNumSFcnParams( S) != ssGetSFcnParamsCount( S)) return; - ssSetSFcnParamTunable( S, PARAM_XML_FILENAME, 0); - ssSetSFcnParamTunable( S, PARAM_INDVARS, 0); - ssSetSFcnParamTunable( S, PARAM_DEPVARS, 0); + ssSetSFcnParamTunable( S, PARAM_XML_FILENAME, SS_PRM_NOT_TUNABLE); + ssSetSFcnParamTunable( S, PARAM_INDVARS, SS_PRM_NOT_TUNABLE); + ssSetSFcnParamTunable( S, PARAM_DEPVARS, SS_PRM_NOT_TUNABLE); ssSetNumContStates( S, 0); ssSetNumDiscStates( S, 0); @@ -104,7 +104,7 @@ static void mdlInitializeSizes( SimStruct* S) // Get number of dependent variables const mxArray* depvarArray = ssGetSFcnParam( S, PARAM_DEPVARS); if ( mxGetClassID( depvarArray) != mxCHAR_CLASS) { - ssSetErrorStatus( S, "Dependent varIDs must be a string array."); + // ssSetErrorStatus( S, "Dependent varIDs must be a string array."); return; } const int nDepVars = mxGetM( depvarArray); @@ -121,17 +121,23 @@ static void mdlInitializeSizes( SimStruct* S) ssSetNumNonsampledZCs( S, 0); ssSetOptions( S, 0); + /*ssSetOptions( S, SS_OPTION_USE_TLC_WITH_ACCELERATOR | SS_OPTION_WORKS_WITH_CODE_REUSE); + ssSetSupportedForCodeReuseAcrossModels( S, 1);*/ } static void mdlInitializeSampleTimes( SimStruct* S) { - ssSetSampleTime( S, 0, CONTINUOUS_SAMPLE_TIME); + ssSetSampleTime( S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime( S, 0, 0.0); + + ssSetModelReferenceSampleTimeInheritanceRule( S, INHERITED_SAMPLE_TIME); } #define MDL_START static void mdlStart( SimStruct* S) { + if ( ssGetNumOutputPorts( S) == 0) return; + ssGetPWork(S)[JANUS] = new janus::Janus; janus::Janus* janus = static_cast( ssGetPWork(S)[JANUS]); @@ -152,7 +158,7 @@ static void mdlStart( SimStruct* S) status = mxGetString( filenameArray, filename, filenameLength); DEBUG_PRINT( "filename: %s\n", filename); if ( status) { - ssSetErrorStatus( S, "XML filename could not be read"); + // ssSetErrorStatus( S, "XML filename could not be read"); return; } @@ -181,21 +187,15 @@ static void mdlStart( SimStruct* S) } n = mxGetN( indvarArray); for ( int var = 0; var < nIndVars; ++var) { - for ( int i = 0; i < n; ++i) { - int iof = var + nIndVars * i; - int len = -1; - if ( indVarBuf[iof] == ' ') len = i + 1; - if ( i + 1 == n) len = i + 2; - if ( len != -1) { - indVarIDs[var] = static_cast( calloc( len, sizeof( char))); - indVarIDs[var][len-1] = '\0'; - for ( int k = 0; k < len - 1; ++k) { - indVarIDs[var][k] = indVarBuf[var + nIndVars * k]; - } - DEBUG_PRINT( "indVarIDs[%d]: %s\n", var, indVarIDs[var]); - break; - } + indVarIDs[var] = static_cast( calloc( n + 1, sizeof( char))); + int i = 0; + for ( ; i < n; ++i) { + if ( indVarBuf[var + nIndVars * i] == ' ') break; + indVarIDs[var][i] = indVarBuf[var + nIndVars * i]; } + DEBUG_PRINT( "%d\t", i); + indVarIDs[var][i] = '\0'; + DEBUG_PRINT( "indVarIDs[%d]: %s\n", var, indVarIDs[var]); } ssSetPWorkValue( S, INDVARIDS, indVarIDs); free( indVarBuf); @@ -253,21 +253,15 @@ static void mdlStart( SimStruct* S) } n = mxGetN( depvarArray); for ( int var = 0; var < nDepVars; ++var) { - for ( int i = 0; i < n; ++i) { - int iof = var + nDepVars * i; - int len = -1; - if ( depVarBuf[iof] == ' ') len = i + 1; - if ( i + 1 == n) len = i + 2; - if ( len != -1) { - depVarIDs[var] = static_cast( calloc( len, sizeof( char))); - depVarIDs[var][len-1] = '\0'; - for ( int k = 0; k < len - 1; ++k) { - depVarIDs[var][k] = depVarBuf[var + nDepVars * k]; - } - DEBUG_PRINT( "depVarIDs[%d]: %s\n", var, depVarIDs[var]); - break; - } + depVarIDs[var] = static_cast( calloc( n + 1, sizeof( char))); + int i = 0; + for ( ; i < n; ++i) { + if ( depVarBuf[var + nDepVars * i] == ' ') break; + depVarIDs[var][i] = depVarBuf[var + nDepVars * i]; } + DEBUG_PRINT( "%d\t", i); + depVarIDs[var][i] = '\0'; + DEBUG_PRINT( "depVarIDs[%d]: %s\n", var, depVarIDs[var]); } ssSetPWorkValue( S, DEPVARIDS, depVarIDs); free( depVarBuf); diff --git a/SFunction/janusfun.cpp b/SFunction/janusfun.cpp index 998de23..9e89fca 100644 --- a/SFunction/janusfun.cpp +++ b/SFunction/janusfun.cpp @@ -75,38 +75,34 @@ class JanusElement janus_(0) { } - + JanusElement(Janus *janus, const string &fileName) { janus_ = janus; fileName_= fileName; } - + JanusElement(const JanusElement &element) { janus_ = element.janus_; fileName_ = element.fileName_; } ; - + string fileName_; Janus *janus_; }; -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - // - // vector containing instances of Janus. - // - static vector janusList; - - int iLen, iInp, iCols; - char* filename; - char* depVarID; - char** indepVarID; - char errmsg[1024]; +Janus* getJanusInstance( int nrhs, const mxArray *prhs[]); +string getDepVarId( int nrhs, const mxArray *prhs[]); +vector getIndepVarIds( int nrhs, const mxArray *prhs[]); +void writeValuesOutput( Janus* janus, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]); +void writeAxisOutput( Janus* janus, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]); +void writeUnitsOutput( Janus* janus, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]); - if ( ( nrhs != 1 && nrhs != 4 && nrhs != 5 ) || nlhs > 3 ) { +void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + if ( ( nrhs != 1 && nrhs != 2 && nrhs != 4 && nrhs != 5) || nlhs > 3) { mexErrMsgTxt( "\n\n Usage: \n" " [x, axis, unit] = janusfun( XMLfilename, depVarID, indepVarIDs, indepVars, )\n" " janusfun('@reset')\n\n" @@ -121,6 +117,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) " integer = no of standard deviations of Gaussian pdf\n" " boolean true/false = upper/lower bound of uniform pdf\n\n" " Examples:\n" + " x = janusfun( 'example19.xml', 'aerodynamicReferenceArea');\n" " x = janusfun( 'example19.xml', 'Cm_u', char('Alpha_deg'), [8.5]);\n" " x = janusfun( 'example19.xml', 'Cm_u', char('Alpha_deg'), [8.5], numSigmas);\n" " x = janusfun( 'MachCoeff.xml', 'MachCoeff2D', char('Alpha', 'Mach'), [-20.0; 0.8]);\n" @@ -129,193 +126,246 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) ); } - if (mxIsChar(prhs[0]) != 1) { + // + // Get Janus Instance - also handles reset + // + Janus* janus = getJanusInstance( nrhs, prhs); + if ( !janus) return; + + writeValuesOutput( janus, nlhs, plhs, nrhs, prhs); + writeAxisOutput( janus, nlhs, plhs, nrhs, prhs); + writeUnitsOutput( janus, nlhs, plhs, nrhs, prhs); +} + +Janus* getJanusInstance( int nrhs, const mxArray *prhs[]) +{ + static vector janusList; + + // + // Read filename + // + if ( nrhs < 1) return nullptr; + + if ( mxIsChar(prhs[0]) != 1) { mexErrMsgTxt("Dataset name must be a string."); } - iLen = ( mxGetM(prhs[0]) * mxGetN(prhs[0]) ) + 1; - filename = (char*)mxMalloc( iLen * sizeof(char)); + size_t iLen = ( mxGetM( prhs[0]) * mxGetN( prhs[0])) + 1; + char* filename = (char*)mxMalloc( iLen * sizeof(char)); int status = mxGetString( prhs[0], filename, iLen ); if ( status != 0) { mexWarnMsgTxt("Not enough space. Dataset name is truncated."); } - // - // JanusList commands: - // @reset: Delete all Janus instances. - // + if ( nrhs == 1) { string janusCommand = filename; + mxFree( filename); if ( janusCommand == "@reset") { for ( unsigned int i = 0; i < janusList.size(); ++i) { delete janusList[i].janus_; } janusList.clear(); - return; } - return; + else { + mexErrMsgTxt( "Unrecognised janus command"); + } + return nullptr; + } + + // + // Check for existing instance of this XML file within JanusList. + // + Janus* janus = nullptr; + for ( unsigned int i = 0; janus == 0&& i < janusList.size(); ++i) { + if ( janusList[i].fileName_ == filename) { + janus = janusList[i].janus_; + } + } + + // + // If instance does not exist in JanusList, create a new instance. + // + if ( !janus) { + janus = new Janus; + try { + janus->setXmlFileName( filename); + } + catch ( exception &excep ) { + mexErrMsgTxt( excep.what() ); + } + janusList.push_back( JanusElement( janus, filename)); } + mxFree( filename); + return janus; +} + +string getDepVarId( int nrhs, const mxArray *prhs[]) +{ + if ( nrhs < 2) return ""; + if ( mxIsChar(prhs[1]) != 1) { mexErrMsgTxt( "Dependent variable ID must be a string."); } - iLen = ( mxGetM(prhs[1]) * mxGetN(prhs[1]) ) + 1; - depVarID = (char*)mxMalloc( iLen * sizeof(char)); - status = mxGetString( prhs[1], depVarID, iLen ); + size_t iLen = ( mxGetM( prhs[1]) * mxGetN( prhs[1])) + 1; + char* depVarID = (char*)mxMalloc( iLen * sizeof(char)); + int status = mxGetString( prhs[1], depVarID, iLen); if ( status != 0) { mexWarnMsgTxt( "Not enough space. Dependent varID is truncated."); } + string ret( depVarID); + mxFree( depVarID); + return ret; +} + +vector getIndepVarIds( int nrhs, const mxArray *prhs[]) +{ + if ( nrhs < 3) return {}; if (mxIsChar(prhs[2]) != 1) { mexErrMsgTxt("Independent varIDs must be a string array."); } - iInp = mxGetM(prhs[2]); - indepVarID = (char**)mxCalloc(iInp, sizeof(char*)); - iLen = (mxGetM(prhs[2]) * mxGetN(prhs[2]) ) + 1; + size_t iInp = mxGetM( prhs[2]); + char** indepVarID = (char**)mxCalloc(iInp, sizeof(char*)); + size_t iLen = ( mxGetM(prhs[2]) * mxGetN( prhs[2])) + 1; char* input_buf = (char*)mxCalloc(iLen, sizeof(char)); - status = mxGetString(prhs[2], input_buf, iLen ); + int status = mxGetString(prhs[2], input_buf, iLen ); if ( 0 != status ) { mexWarnMsgTxt("Independent varID strings are truncated."); } - iLen = mxGetN(prhs[2]); - int iof, j2; - for ( int i = 0; i < iInp ; i++) { - for ( int j = 0; j < iLen ; j++) { + iLen = mxGetN( prhs[2]); + size_t iof, j2; + for ( size_t i = 0; i < iInp ; i++) { + for ( size_t j = 0; j < iLen ; j++) { iof = i + iInp * j; - if ( ' ' == input_buf[iof]|| j == iLen - 1) { + if ( ' ' == input_buf[iof] || j + 1 == iLen) { j2 = j + 1; if ( ' ' != input_buf[iof]) { j2 = j2 + 1; } indepVarID[i] = (char*)mxCalloc(j2, sizeof(char)); indepVarID[i][j2 - 1] = '\0'; - for ( int k = 0; k < j2 - 1; k++) { + for ( size_t k = 0; k + 1 < j2; k++) { indepVarID[i][k] = input_buf[i + iInp * k ]; } break; } } } - mxFree(input_buf ); - - if ( int( mxGetM(prhs[3])) != iInp ) { - sprintf( errmsg, "%s\n\t VarIDs = %d, Vars = %d\n", - "Input varID and variable rows mismatch", iInp, int( mxGetM(prhs[3]))); - mexErrMsgTxt( errmsg); + mxFree(input_buf); + vector ret( iInp); + for ( int i = 0; i < iInp; ++i) { + ret[i] = string( indepVarID[i]); + mxFree( indepVarID[i]); } - iCols = mxGetN(prhs[3]); - double* x = (double *)mxGetPr(prhs[3]); + mxFree( indepVarID ); + return ret; +} - plhs[0] = mxCreateDoubleMatrix( 1, iCols, mxREAL ); - double* y = (double *)mxGetPr(plhs[0]); +void writeValuesOutput( Janus* janus, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + const string depVarId = getDepVarId( nrhs, prhs); + const vector indepVarId = getIndepVarIds( nrhs, prhs); - /* - * Initialise Janus instance, not encrypted - */ + const size_t nInp = nrhs > 3 ? mxGetM( prhs[3]) : 0; + const size_t nCols = std::max( nrhs > 3 ? int( mxGetN( prhs[3])) : 1, 1); // Getting a constant - // - // Check for existing instance of this XML file within JanusList. - // - Janus *janus = 0; - for ( unsigned int i = 0; janus == 0&& i < janusList.size(); ++i) { - if ( janusList[i].fileName_ == filename) { - janus = janusList[i].janus_; - } + if ( nInp != int( indepVarId.size())) { + stringstream errStr; + errStr << "Input varID and variable rows mismatch\n\t" + << " VarIDs = " << indepVarId.size() + << ", Vars = " << nInp << "\n"; + mexErrMsgTxt( errStr.str().c_str() ); } - // - // If instance does not exist in JanusList, create a new instance. - // - if ( janus == 0) { - janus = new Janus; - try { - janus->setXmlFileName( filename); - } - catch ( exception &excep ) { - mexErrMsgTxt( excep.what() ); - } - janusList.push_back(JanusElement(janus, filename)); - } + double* x = nrhs > 3 ? (double *)mxGetPr( prhs[3]) : nullptr; + + plhs[0] = mxCreateDoubleMatrix( 1, nCols, mxREAL); + double* y = (double *)mxGetPr( plhs[0]); - VariableDef& outputVarDef = janus->getVariableDef( depVarID ); + VariableDef& outputVarDef = janus->getVariableDef( depVarId); int numSigmas = -1; bool isUpper = false; - if ( 5 == nrhs ) { - const Uncertainty::UncertaintyPdf& pdf = - outputVarDef.getUncertainty().getPdf(); - if ( mxIsNumeric( prhs[4] ) && Uncertainty::NORMAL_PDF == pdf ) { + if ( 5 == nrhs) { + const Uncertainty::UncertaintyPdf& pdf = outputVarDef.getUncertainty().getPdf(); + if ( mxIsNumeric( prhs[4]) && Uncertainty::NORMAL_PDF == pdf) { numSigmas = int( mxGetScalar( prhs[4])); } - else if ( mxIsLogicalScalarTrue( prhs[4] ) && - Uncertainty::UNIFORM_PDF == pdf ) { + else if ( mxIsLogicalScalarTrue( prhs[4]) && Uncertainty::UNIFORM_PDF == pdf) { isUpper = true; } - else if ( Uncertainty::UNIFORM_PDF == pdf ) { + else if ( Uncertainty::UNIFORM_PDF == pdf) { stringstream errStr; - errStr << "Variable \"" << depVarID - << "\" has uniform pdf ..."; + errStr << "Variable \"" << depVarId << "\" has uniform pdf ..."; mexErrMsgTxt( errStr.str().c_str() ); } else if ( Uncertainty::NORMAL_PDF == pdf ) { stringstream errStr; - errStr << "Variable \"" << depVarID - << "\" has Gaussian pdf ..."; + errStr << "Variable \"" << depVarId << "\" has Gaussian pdf ..."; mexErrMsgTxt( errStr.str().c_str() ); } } - string axisString = string(); - string unitString = string(); - - for ( int i = 0; i < iCols ; i++) { - for ( int j = 0; j < iInp ; j++) { - iof = j + i * iInp; + for ( size_t i = 0; i < nCols ; i++) { + for ( size_t j = 0; j < nInp ; j++) { + size_t iof = j + i * nInp; try { - janus->getVariableDef( dstoute::aString( indepVarID[j]) ).setValue( x[iof]); +#ifdef JANUSFUN_SI + janus->getVariableDef( indepVarId[j]).setValueSI( x[iof]); +#else + janus->getVariableDef( indepVarId[j]).setValue( x[iof]); +#endif } catch (...) { -// char errmsg[80]; - sprintf( errmsg, "Variable \"%s\" not set ...", indepVarID[j]); - mexErrMsgTxt( errmsg ); + stringstream errStr; + errStr << "Variable \"" << indepVarId[j] << "\" not set ..."; + mexErrMsgTxt( errStr.str().c_str() ); } } - if ( 4 == nrhs ) { + if ( nrhs != 5) { +#ifdef JANUSFUN_SI + y[i] = outputVarDef.getValueSI(); +#else y[i] = outputVarDef.getValue(); - axisString = outputVarDef.getAxisSystem(); - unitString = outputVarDef.getUnits(); +#endif + } + else if ( 0 < numSigmas) { + y[i] = outputVarDef.getUncertaintyValue( size_t( numSigmas)); } else { - if ( 0 < numSigmas ) { - y[i] = outputVarDef.getUncertaintyValue( size_t( numSigmas) ); - } - else { - y[i] = outputVarDef.getUncertaintyValue( isUpper ); - } + y[i] = outputVarDef.getUncertaintyValue( isUpper); } } +} - // Create Axis mxArray entry - if ( nlhs > 1) { - const char **axisCharArray = (const char**)mxCalloc(1, sizeof(const char*)); - *axisCharArray = axisString.c_str(); - plhs[1] = mxCreateCharMatrixFromStrings( 1, axisCharArray); - mxFree( axisCharArray ); - } - - // Create Unit mxArray entry - if ( nlhs > 2) { - const char **unitCharArray = (const char**)mxCalloc(1, sizeof(const char*)); - *unitCharArray = unitString.c_str(); - plhs[2] = mxCreateCharMatrixFromStrings( 1, unitCharArray); - mxFree( unitCharArray ); - } +void writeAxisOutput( Janus* janus, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + if ( nlhs < 2) return; - mxFree( filename ); - mxFree( depVarID ); - for ( int i = 0; i < iInp ; i++) { - mxFree ( indepVarID[i]); - } - mxFree( indepVarID ); + const string depVarId = getDepVarId( nrhs, prhs); + VariableDef& outputVarDef = janus->getVariableDef( depVarId); + const string axisString = outputVarDef.getAxisSystem(); + const char **axisCharArray = (const char**)mxCalloc(1, sizeof(const char*)); + *axisCharArray = axisString.c_str(); + plhs[1] = mxCreateCharMatrixFromStrings( 1, axisCharArray); + mxFree( axisCharArray ); +} - return; +void writeUnitsOutput( Janus* janus, int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + if ( nlhs < 3) return; + const string depVarId = getDepVarId( nrhs, prhs); + VariableDef& outputVarDef = janus->getVariableDef( depVarId); +#ifdef JANUSFUN_SI + const string sourceUnitsString = outputVarDef.getUnits(); + const dstoute::aUnits units( sourceUnitsString); + const string unitsString = units.unitsSI(); +#else + const string unitsString = outputVarDef.getUnits(); +#endif + const char **unitCharArray = (const char**)mxCalloc(1, sizeof(const char*)); + *unitCharArray = unitsString.c_str(); + plhs[2] = mxCreateCharMatrixFromStrings( 1, unitCharArray); + mxFree( unitCharArray ); } diff --git a/UnitConverter/convert.cpp b/UnitConverter/convert.cpp new file mode 100644 index 0000000..ee5d6f8 --- /dev/null +++ b/UnitConverter/convert.cpp @@ -0,0 +1,122 @@ + +// +// DST Janus Library (Janus DAVE-ML Interpreter Library) +// +// Defence Science and Technology (DST) Group +// Department of Defence, Australia. +// 506 Lorimer St +// Fishermans Bend, VIC +// AUSTRALIA, 3207 +// +// Copyright 2005-2021 Commonwealth of Australia +// +// 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. +// + +// C++ Includes +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +#include + +#include "units.h" + +using namespace std; + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + if ( nrhs != 2 && nrhs != 3) { + mexErrMsgTxt( + "\n\n Usage: \n" + " value = convert( value, from, to)\n" + " value = convert( value, from) % Converts to metric\n" + ); + } + + // + // Values + // + if ( mxIsDouble( prhs[0]) != 1) { + mexErrMsgTxt( "Value must be a double."); + } + const size_t xCols = mxGetN( prhs[0]); + const size_t xRows = mxGetM( prhs[0]); + const double* x = (double *) mxGetPr( prhs[0]); + + plhs[0] = mxCreateDoubleMatrix( xRows, xCols, mxREAL); + double* y = (double*) mxGetPr( plhs[0]); + + // + // From units + // + if ( mxIsChar( prhs[1]) != 1) { + mexErrMsgTxt( "From units must be a string."); + } + const size_t fromLen = mxGetM( prhs[1]) * mxGetN( prhs[1]) + 1; + char* from = (char*) mxMalloc( fromLen * sizeof( char)); + int fromStatus = mxGetString( prhs[1], from, fromLen); + if ( fromStatus != 0) { + mexWarnMsgTxt( "Not enough space. From units are truncated."); + } + + // + // To units + // + char* to; + + if ( nrhs == 2) { + const string metricTo = units::metric( from); + to = (char*) mxMalloc( metricTo.size() * sizeof( char)); + strcpy( to, metricTo.c_str()); + } + else { + if ( mxIsChar( prhs[2]) != 1) { + mexErrMsgTxt( "To units must be a string."); + } + const size_t toLen = mxGetM( prhs[2]) * mxGetN( prhs[2]) + 1; + to = (char*) mxMalloc( toLen * sizeof( char)); + int toStatus = mxGetString( prhs[2], to, toLen); + if ( toStatus != 0) { + mexWarnMsgTxt( "Not enough space. To units are truncated."); + } + } + + // + // Conversion + // + auto converter = units::get_converter( from, to); + + if ( !converter) { + const string err = "Units \"" + string( from) + "\" and \"" + string( to) + "\" are not compatible."; + mexErrMsgTxt( err.c_str()); + } + + for ( size_t j = 0; j < xRows; ++j) { + for ( size_t i = 0; i < xCols; ++i) { + y[i + j * xCols] = converter( x[i + j * xCols]); + } + } + + mxFree( from); + mxFree( to); +} diff --git a/UnitConverter/convert.def b/UnitConverter/convert.def new file mode 100644 index 0000000..75342bf --- /dev/null +++ b/UnitConverter/convert.def @@ -0,0 +1,2 @@ +EXPORTS + mexFunction diff --git a/UnitConverter/units.cpp b/UnitConverter/units.cpp new file mode 100644 index 0000000..51fac37 --- /dev/null +++ b/UnitConverter/units.cpp @@ -0,0 +1,718 @@ +// +// DST Janus Library (Janus DAVE-ML Interpreter Library) +// +// Defence Science and Technology (DST) Group +// Department of Defence, Australia. +// 506 Lorimer St +// Fishermans Bend, VIC +// AUSTRALIA, 3207 +// +// Copyright 2005-2021 Commonwealth of Australia +// +// 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. +// + +#include "units.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace { + + const double GRAVITY = 9.80665; + const double PI = 3.141592653589793238462643383279502884197169399375105821; + + const size_t N_DIMENSIONS = 8; + + struct unit + { + string symbol; + double scale = 1.0; + double bias = 0.0; + int dimensions[N_DIMENSIONS] = { 0, 0, 0, 0, 0, 0, 0, 0}; + + unit() = default; + unit( const string& s, const unit& rhs) : unit( rhs) { symbol = s;} + }; + + unit create( const int* dims) + { + unit u; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) u.dimensions[i] = dims[i]; + u.scale = 1.0; + u.bias = 0.0; + return u; + } + + bool has_dimension( const unit& u) + { + for ( size_t i = 0; i < N_DIMENSIONS; ++i) if ( u.dimensions[i] != 0) return true; + return false; + } + + unit compose( const unit& a, const unit& b) + { + unit u; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) u.dimensions[i] = a.dimensions[i] + b.dimensions[i]; + u.scale = a.scale * b.scale; + u.bias = 0.0; + if ( a.bias != 0.0 && !has_dimension( b)) u.bias = a.bias / b.scale; + if ( b.bias != 0.0 && !has_dimension( a)) u.bias = b.bias / a.scale; + return u; + } + + template + unit compose( const unit& a, const unit& b, Args... args) + { + return compose( a, compose( b, args...)); + } + + unit scale( const unit& original, const double& numerator, const double& denominator = 1.0) + { + unit u = original; + u.scale = ( u.scale * numerator) / denominator; + return u; + } + + unit translate( const unit& original, const double& bias) + { + unit u = original; + u.bias += bias; + return u; + } + + unit pow( const unit& original, const int exponent) + { + unit u; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) u.dimensions[i] = original.dimensions[i] * exponent; + u.scale = 1.0; + if ( exponent < 0) for ( int i = 0; i != exponent; --i) u.scale /= original.scale; + if ( exponent > 0) for ( int i = 0; i != exponent; ++i) u.scale *= original.scale; + u.bias = exponent == 1 ? original.bias : 0.0; + return u; + } + + class units_container + { + public: + units_container( const vector& prefixes, const vector& units, const vector& nonprefixunits) + { + for ( auto& u : units) { + assert( units_.find( u.symbol) == units_.end()); + units_[u.symbol] = u; + } + for ( auto& u : nonprefixunits) { + assert( units_.find( u.symbol) == units_.end()); + units_[u.symbol] = u; + } + + noPrefixUnits_ = units_; + + for ( auto& u :units) { + for ( auto& p : prefixes) { + if ( units_.find( p.symbol + u.symbol) == units_.end()) { + units_[p.symbol + u.symbol] = compose( p, u); + } + } + } + } + + const unit* get( const string& symbol) const + { + auto it = units_.find( symbol); + if ( it == units_.end()) return nullptr; + return &it->second; + } + + set get_compatible( const unit& u) const + { + set ret; + vector currentstr( N_DIMENSIONS); + vector currentdim( N_DIMENSIONS); + copy( u.dimensions, u.dimensions + N_DIMENSIONS, currentdim.begin()); + + /*for ( auto [str, a] : noPrefixUnits_) { + bool isCompatible = true; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) { + isCompatible &= a.dimensions[i] == u.dimensions[i]; + } + if ( isCompatible) { + ret.insert( str); + } + }*/ + + get_compatible_recursive( ret, 0, currentstr, currentdim); + + return ret; + } + + private: + + void get_compatible_recursive( set& ret, size_t idx, vector& currentstr, vector& currentdim) const + { + if ( idx == N_DIMENSIONS) { + for ( size_t i = 0; i < N_DIMENSIONS; ++i) { + if ( currentdim[i] != 0) return; + } + string s; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) { + if ( !currentstr[i].empty()) s += currentstr[i] + " "; + } + if ( !s.empty()) { + s = s.substr( 0, s.size() - 1); + ret.insert( s); + } + return; + } + + if ( currentdim[idx] == 0) { + get_compatible_recursive( ret, idx + 1, currentstr, currentdim); + return; + } + + for ( auto [str, a] : noPrefixUnits_) { + bool isCompatible = a.dimensions[idx] != 0 && abs( a.dimensions[idx]) <= abs( currentdim[idx]); + for ( size_t i = 0; i < idx; ++i) { + if ( i == idx) continue; + isCompatible &= a.dimensions[i] == 0; + } + if ( isCompatible) { + const int exp = currentdim[idx] / a.dimensions[idx]; + for ( size_t i = idx; i < N_DIMENSIONS; ++i) { + currentdim[i] -= exp * a.dimensions[i]; + } + if ( exp != 1) { + stringstream ss; + ss << str << exp; + currentstr[idx] = ss.str(); + } + else { + currentstr[idx] = str; + } + get_compatible_recursive( ret, idx + 1, currentstr, currentdim); + for ( size_t i = idx; i < N_DIMENSIONS; ++i) { + currentdim[i] += exp * a.dimensions[i]; + } + } + } + + currentstr[idx] = ""; + } + + map noPrefixUnits_; + map units_; + }; + + const string u_symbols[] = { "m", "kg", "K", "A", "mol", "cd", "rad", "s"}; + const int u_none_dims[] = { 0, 0, 0, 0, 0, 0, 0, 0}; + const int u_m_dims[] = { 1, 0, 0, 0, 0, 0, 0, 0}; + const int u_kg_dims[] = { 0, 1, 0, 0, 0, 0, 0, 0}; + const int u_K_dims[] = { 0, 0, 1, 0, 0, 0, 0, 0}; + const int u_A_dims[] = { 0, 0, 0, 1, 0, 0, 0, 0}; + const int u_mol_dims[] = { 0, 0, 0, 0, 1, 0, 0, 0}; + const int u_cd_dims[] = { 0, 0, 0, 0, 0, 1, 0, 0}; + const int u_rad_dims[] = { 0, 0, 0, 0, 0, 0, 1, 0}; + const int u_s_dims[] = { 0, 0, 0, 0, 0, 0, 0, 1}; + + // + // Base Units + // + const unit u_none = { "", create( u_none_dims)}; + const unit u_m = { "m", create( u_m_dims)}; + const unit u_kg = { "kg", create( u_kg_dims)}; + const unit u_K = { "K", create( u_K_dims)}; + const unit u_A = { "A", create( u_A_dims)}; + const unit u_mol = { "mol", create( u_mol_dims)}; + const unit u_cd = { "cd", create( u_cd_dims)}; + const unit u_rad = { "rad", create( u_rad_dims)}; + const unit u_s = { "s", create( u_s_dims)}; + + // + // Derived + // + const unit u_ND = { "ND", u_none}; + const unit u_Hz = { "Hz", compose( scale( u_rad, 2. * PI), pow( u_s, -1))}; + const unit u_N = { "N", compose( u_m, u_kg, pow( u_s, -2))}; // Newton (force, weight) + const unit u_Pa = { "Pa", compose( u_N, pow( u_m, -2))}; // Pascal (pressure, stress) + const unit u_J = { "J", compose( u_N, u_m)}; // Joule (energy, work, heat) + const unit u_W = { "W", compose( u_J, pow( u_s, -1))}; // Watt (power, radiant flux) + const unit u_C = { "Coulomb", compose( u_s, u_A)}; // Coulomb (electrical charge) potential conflict with degC, hence the name change + const unit u_V = { "V", compose( u_W, pow( u_A, -1))}; // Volt (voltage) + const unit u_F = { "Farad", compose( u_C, pow( u_V, -1))}; // Farad (electric capacitance) + const unit u_Ohm = { "Ohm", compose( u_V, pow( u_A, -1))}; // Ohm (electric resistance) + const unit u_H = { "H", compose( u_Ohm, u_s)}; // Henry (inductance) + const unit u_S = { "S", compose( u_A, pow( u_V, -1))}; // Siemens (electrical conductance) + const unit u_Wb = { "Wb", compose( u_V, u_s)}; // Weber (magnetic flux) + const unit u_T = { "T", compose( u_Wb, pow( u_m, -2))}; // Tesla (magnetic field strength) + const unit u_lm = { "lm", u_cd}; // Lumen (luminous flux) + const unit u_lx = { "lx", compose( u_lm, pow( u_m, -2))}; // Lux (illuminance) + const unit u_Bq = { "Bq", pow( u_s, -1)}; // Becquerel (radioactivity) + const unit u_Gy = { "Gy", compose( u_J, pow( u_kg, -1))}; // Gray (absorbed dose) + const unit u_Sv = { "Sv", u_Gy}; // Sievert (equivalent dose) + const unit u_kat = { "kat", compose( pow( u_s, -1), u_mol)}; // Katal (catalytic activity) + + // + // Length + // + const unit u_mm = { "mm", scale( u_m, 1, 1000)}; + const unit u_cm = { "cm", scale( u_m, 1, 100)}; + const unit u_km = { "km", scale( u_m, 1000)}; + const unit u_in = { "in", scale( scale( u_m, 1, 100), 254, 100)}; // Inch + const unit u_ft = { "ft", scale( u_in, 12)}; // Feet + const unit u_yd = { "yd", scale( u_in, 36)}; // Yard + const unit u_smi = { "smi", scale( u_yd, 1760)}; // Statute mile + const unit u_nmi = { "nmi", scale( u_m, 1852)}; // Nautical mile + const unit u_furlong = { "furlong", scale( u_smi, 1, 8)}; // Furlong + const unit u_lightyear = { "lightyear", scale( u_m, 9460730472580800.)}; // Light-year + const unit u_rod = { "rod", scale( u_ft, 16.5)}; // Rod + const unit u_chain = { "chain", scale( u_ft, 66)}; // Chain + + // + // Area + // + const unit u_ha = { "ha", scale( pow( u_m, 2), 10000)}; + const unit u_are = { "are", scale( pow( u_m, 2), 100)}; + const unit u_acre = { "acre", scale( u_ha, 10000000000000, 24710538146717)}; + + // + // Volume, fluid. + // + const unit u_l = { "l", scale( pow( u_m, 3), 1, 1000)}; // Litre (non-SI, accepted as SI), u_ml already SI scaled + const unit u_USgal = { "USgal", scale( pow( u_in, 3), 231000)}; // US gallon, scale SI m3 to Litre + const unit u_UKgal = { "UKgal", scale( u_l, 4546087, 1000000)}; // UK gallon, u_l already SI scaled via u_ml + + // + // Mass + // + const unit u_g = { "g", scale( u_kg, 1, 1000)}; // Gram + const unit u_tonne = { "tonne", scale( u_kg, 1000)}; // Tonne + const unit u_lbm = { "lbm", scale( u_kg, 0.45359237)}; // Pound mass (exact conversion) https://en.wikipedia.org/wiki/Pound_(mass) + const unit u_oz = { "oz", scale( u_lbm, 1, 16)}; // Ounce + const unit u_USton = { "USton", scale( u_lbm, 2000)}; // US ton + const unit u_UKton = { "UKton", scale( u_lbm, 2240)}; // UK ton + + // + // Force + // + const unit u_lbf = { "lbf", compose( u_lbm, scale( compose( u_m, pow( u_s, -2)), GRAVITY))}; // Pound force (lbm * G) + + // + // Mass - Others based on u_lbf + // + const unit u_slug = { "slug", compose( u_lbf, pow( u_s, 2), pow( u_ft, -1))}; // Slug + const unit u_snail = { "snail", scale( u_slug, 12)}; // Snail + + // + // Time + // + const unit u_min = { "min", scale( u_s, 60)}; // Minute + const unit u_hours = { "h", scale( u_min, 60)}; // Hour + const unit u_days = { "days", scale( u_hours, 24)}; // Day + const unit u_weeks = { "weeks", scale( u_days, 7)}; // Week + const unit u_fortnights = { "fortnights", scale( u_days, 14)}; // Fortnight + const unit u_years = { "years", scale( u_days, 365.25)}; // Year + const unit u_months = { "months", scale( u_years, 1, 12)}; // Month + + // + // Speed + // + const unit u_kn = { "kn", compose( u_nmi, pow( u_hours, -1))}; // Knots (nautical miles per hour) + + // Acceleration + const unit u_gee = { "gee", scale( compose( u_m, pow( u_s, -2)), GRAVITY)}; + + // + // Temperature + // + const unit u_degC = { "C", translate( u_K, -273.15)}; // Celcius + const unit u_degF = { "F", translate( scale( u_K, 5, 9), -459.67)}; // Fahrenheit + const unit u_degR = { "R", scale( u_K, 5, 9)}; // Rankine + + // + // Angles + // + const unit u_deg = { "deg", scale( u_rad, PI / 180.)}; // Degree + const unit u_grad = { "grad", scale( u_rad, PI, 200.0)}; // Gradian + const unit u_rev = { "rev", scale( u_deg, 360)}; // Revolutions + + // + // Angular Velocity + // + const unit u_rpm = { "rpm", compose( u_rev, pow( u_min, -1))}; // RPM + + // + // Pressure + // + const unit u_psi = { "psi", scale( scale( u_Pa, 1000), 10000000, 1450377)}; // Pounds per square inch + const unit u_psf = { "psf", scale( u_psi, 1, 144)}; // Pounds per square foot + const unit u_bar = { "bar", scale( u_Pa, 100000)}; // Bar + const unit u_mbar = { "millibar", scale( u_bar, 1, 1000)}; // Millibar + const unit u_mmHg = { "mmHg", scale( scale( u_Pa, 1000), 101.3250144354, 760)}; // Millimetres of mercury + const unit u_inHg = { "inHg", scale( u_mmHg, 254, 10)}; // Inches of mercury + const unit u_atm = { "atm", scale( u_Pa, 101325)}; // Atmosphere + const unit u_inH2O = { "inH2O", scale( u_Pa, 248.64536925)}; // Inches of water at a reference temperature of 20C + + // + // Power + // + const unit u_hp = { "hp", scale( compose( u_ft, u_lbf, pow( u_s, -1)), 550)}; // Horse power + + // + // Energy + // + const unit u_cal = { "cal", scale( u_J, 4.1867456)}; // Calorie + const unit u_btu = { "btu", scale( u_J, 1054.3507)}; // British Thermal Units + const unit u_erg = { "erg", scale( u_J, 1.0E-07)}; // Erg + + // + // Prefixes + // + const unit prefix_deka = { "da", scale( u_none, 10)}; + const unit prefix_hecto = { "h", scale( u_none, 100)}; + const unit prefix_kilo = { "k", scale( u_none, 1000)}; + const unit prefix_mega = { "M", scale( prefix_kilo, 1000)}; + const unit prefix_giga = { "G", scale( prefix_mega, 1000)}; + const unit prefix_tera = { "T", scale( prefix_giga, 1000)}; + const unit prefix_peta = { "P", scale( prefix_tera, 1000)}; + const unit prefix_exa = { "E", scale( prefix_peta, 1000)}; + const unit prefix_zetta = { "Z", scale( prefix_exa, 1000)}; + const unit prefix_yotta = { "Y", scale( prefix_zetta, 1000)}; + + const unit prefix_deci = { "d", scale( u_none, 1, 10)}; + const unit prefix_centi = { "c", scale( u_none, 1, 100)}; + const unit prefix_milli = { "m", scale( u_none, 1, 1000)}; + const unit prefix_micro = { "u", scale( prefix_milli, 1, 1000)}; + const unit prefix_nano = { "n", scale( prefix_micro, 1, 1000)}; + const unit prefix_pico = { "p", scale( prefix_nano, 1, 1000)}; + const unit prefix_femto = { "f", scale( prefix_pico, 1, 1000)}; + const unit prefix_atto = { "a", scale( prefix_femto, 1, 1000)}; + const unit prefix_zepto = { "z", scale( prefix_atto, 1, 1000)}; + const unit prefix_yocto = { "y", scale( prefix_zepto, 1, 1000)}; + + const units_container Units( + { + prefix_deka , + prefix_hecto , + prefix_kilo , + prefix_mega , + prefix_giga , + prefix_tera , + prefix_peta , + prefix_exa , + prefix_zetta , + prefix_yotta , + prefix_deci , + prefix_centi , + prefix_milli , + prefix_micro , + prefix_nano , + prefix_pico , + prefix_femto , + prefix_atto , + prefix_zepto , + prefix_yocto + }, + { + u_m , + u_K , + u_A , + u_mol , + u_cd , + u_rad , + u_s , + u_Hz , + u_N , + u_Pa , + u_J , + u_W , + u_C , + u_V , + u_F , + u_Ohm , + u_H , + u_S , + u_Wb , + u_T , + u_lm , + u_lx , + u_Bq , + u_Gy , + u_Sv , + u_kat , + u_l , + u_g , + u_tonne , + u_degC , + u_degF , + u_degR , + u_deg , + u_grad , + u_rev , + u_atm , + u_inH2O , + u_hp , + u_cal , + u_btu , + u_erg + }, + { + u_none , + u_ND , + u_kg , + u_mm , + u_cm , + u_km , + u_in , + u_ft , + u_yd , + u_smi , + u_nmi , + u_furlong , + u_lightyear , + u_rod , + u_chain , + u_ha , + u_are , + u_acre , + u_USgal , + u_UKgal , + u_lbm , + u_oz , + u_USton , + u_UKton , + u_lbf , + u_slug , + u_snail , + u_min , + u_hours , + u_days , + u_weeks , + u_fortnights, + u_years , + u_months , + u_kn , + u_gee , + u_rpm , + u_psi , + u_psf , + u_bar , + u_mbar , + u_mmHg , + u_inHg , + } + ); + + bool get_unit( unit& u, string s) + { + s += " "; + u = u_none; + + size_t off = 0; + while ( s.find_first_of( " ", off) != string::npos) { + const size_t end = s.find_first_of( " ", off); + const string piece = s.substr( off, end - off); + off = end + 1; + + int exp = 1; + const size_t startexp = piece.find_first_of( "+-0123456789"); + if ( startexp != string::npos) { + exp = atoi( piece.substr( startexp).c_str()); + } + + const string symbol = piece.substr( 0, startexp); + const unit* punits = Units.get( symbol); + + if ( !punits) return false; + + u = compose( u, pow( *punits, exp)); + } + + return true; + } + + const set AeroUnits = { + // Length + "mm", + "m", + "km", + "in", + "ft", + "smi", + "nmi", + + // Area + "mm2", + "m2", + "ft2", + + // Volume + "l", + "USGal", + "UKGal", + + // Mass + "g", + "kg", + "lbm", + + // Force + "N", + "lbf", + "slug", + + // Time + "s", + + // Speed + "m s-1", + "km h-1", + "ft s-1", + "kn", + + // Acceleration + "m s-2", + "ft s-2", + "kn s-1", + "gee", + + // Temperature + "C", + "K", + "F", + + // Angles + "deg", + "rad", + + // Angular Rate + "Hz", + "deg s-1", + "rad s-1", + + // Angular Acceleration + "deg s-2", + "rad s-2", + + // Pressure + "Pa", + "psi", + "bar", + "atm", + + // Power + "W", + "hp", + + // Misc + "m2 kg", + "ft2 slug" + }; + + void trim_whitespace_lr( string& str) + { + auto ltrim = [](string& str) + { + str.erase( str.begin(), find_if( str.begin(), str.end(), [](auto ch){ return !isspace( ch); })); + }; + auto rtrim = [](string& str) + { + str.erase( find_if( str.rbegin(), str.rend(), [](auto ch){ return !isspace( ch); }).base(), str.end()); + }; + ltrim( str); + rtrim( str); + } + + vector split_by( const string& str, const char delim) + { + vector ret; + stringstream ss( str); + string tmp; + while ( getline( ss, tmp, delim)) { + ret.push_back( tmp); + } + return ret; + } + +} // namespace + +namespace units { + + string metric( const string& str) + { + /*if ( str == "Hz") return "Hz";*/ + if ( str == "dB") return "ND"; + + unit u; + if ( !get_unit( u, str)) return str; + stringstream ss; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) { + if ( u.dimensions[i] != 0) { + ss << u_symbols[i]; + if ( u.dimensions[i] != 1) { + ss << u.dimensions[i]; + } + ss << " "; + } + } + string ret = ss.str(); + if ( !ret.empty()) ret = ret.substr( 0, ret.size() - 1); + else ret = "ND"; + return ret; + } + + bool is_compatible( const string& astr, const string& bstr) + { + /*if ( astr == "Hz" && bstr == "rad s-1") return true; + if ( bstr == "Hz" && astr == "rad s-1") return true;*/ + if ( astr == "ND" && bstr == "dB") return true; + if ( bstr == "ND" && astr == "dB") return true; + + unit a, b; + if ( !( get_unit( a, astr) && get_unit( b, bstr))) return false; + for ( size_t i = 0; i < N_DIMENSIONS; ++i) { + if ( a.dimensions[i] != b.dimensions[i]) return false; + } + return true; + } + + function get_converter( const string& fromstr, const string& tostr) + { + if ( fromstr == tostr) return []( const double& x) { return x;}; + if ( !is_compatible( fromstr, tostr)) return nullptr; + + if ( fromstr == "dB" && tostr == "ND") { + return []( const double& x) { return ::pow( 10., x / 20.);}; + } + if ( fromstr == "ND" && tostr == "dB") { + return []( const double& x) { return 20. * log10( x);}; + } + + unit from; (void) get_unit( from, fromstr); + unit to; (void) get_unit( to, tostr); + return [from,to]( const double& x) { return ( x - from.bias) * from.scale / to.scale + to.bias;}; + } + +} \ No newline at end of file diff --git a/UnitConverter/units.h b/UnitConverter/units.h new file mode 100644 index 0000000..78df43b --- /dev/null +++ b/UnitConverter/units.h @@ -0,0 +1,45 @@ +// +// DST Janus Library (Janus DAVE-ML Interpreter Library) +// +// Defence Science and Technology (DST) Group +// Department of Defence, Australia. +// 506 Lorimer St +// Fishermans Bend, VIC +// AUSTRALIA, 3207 +// +// Copyright 2005-2021 Commonwealth of Australia +// +// 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. +// + +#pragma once + +#include +#include +#include +#include + +#include + +namespace units { + + std::string metric( const std::string& str); + bool is_compatible( const std::string& a, const std::string& b); + std::function get_converter( const std::string& from, const std::string& to); + +} \ No newline at end of file diff --git a/Ute/CMakeLists.txt b/Ute/CMakeLists.txt index 4c10158..d19ee90 100644 --- a/Ute/CMakeLists.txt +++ b/Ute/CMakeLists.txt @@ -86,7 +86,7 @@ if (MSVC) ) set_target_properties(Ute PROPERTIES COMPILE_FLAGS "/bigobj") -elseif (MINGW) +elseif (WIN32) set_target_properties(Ute PROPERTIES COMPILE_FLAGS "-Wa,-mbig-obj") endif()