Source Code for Project Mixer


The following source files, led by gray banners, contain all the class functions needed for Project Mixer.  The sections highlighted by a yellow background Color are manually entered.  Code sections with white background color are generated by the SansGUI Source Code Framework.  The source files are compiled into a dynamic linked library to be invoked by SansGUI during simulation runs.

For more details about the complete package, please read the Mixer Example for SansGUI Manual on-line.

*MATLAB is a registered trademark of The Mathworks, Inc.

Implementation in C/C++ (MSVC)

Functions in Class Base.Container.Reactor     [Go to Top]

/* Base_Container_Reactor.c
 * - DLL routines for class <Component>Base.Container.Reactor
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include "../Mixer_1_0/Mixer_1_0.h"

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xInitSize_Base_Container_Reactor;
SG_EXPORT SG_SIM_FUNC SG_xInit_Base_Container_Reactor;
SG_EXPORT SG_SIM_FUNC SG_xPreEval_Base_Container_Reactor;
SG_EXPORT SG_SIM_FUNC SG_xEval_Base_Container_Reactor;
SG_EXPORT SG_SIM_FUNC SG_xPostEval_Base_Container_Reactor;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.7] */
#define SG_NDX_FCONCENTRATION 0 /* fConcentration - Concentration */
#define SG_NDX_RREACTOR 1 /* rReactor - Reactor Table */
#define SG_NDX_RCONSTANT 2 /* rConstant - Constant Matrix */
#define SG_NDX_IPARTINDEX 3 /* iPartIndex - Part Index (1-Based) */

/* Manually entered indices for simControl, link, and reference objects access */
#define SG_NDX_OBJ_REACTORTABLE    0 /* reactor table, always the first */
#define SG_NDX_OBJ_CONSTMATRIX     1 /* constant matrix, always the second */

/* ============================================================
 * SG_xInitSize - Resize for Init
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInitSize_Base_Container_Reactor(SG_OBJ *const self,
    SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
    SG_OBJ *const refObjs[], const INT *const piRefObjs,
    SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
    SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
    TCHAR *const cMessage, const INT iMsgLen,
    TCHAR *const cCommand, const INT iCmdLen,
    SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT *piNumReactors = &simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* register the reactor part for solver to resize matrices and tables */
    if (*piNumReactors < 0)
        *piNumReactors = 1;
    else
        *piNumReactors += 1;

    return SG_R_OK;
}

/* ============================================================
 * SG_xInit - Initialization
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInit_Base_Container_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT iPartNdx;
    const INT ciPartSN = (INT)self->nCmpnNo;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* set user type for future identification - to prevent class name comparison
     * during component class run-time type checking
     */
    MIX_SET_USER_TYPE(self, MIX_USER_TYPE_REACTOR);

    /* check to see if there are two reference objects */
    if (*piRefObjs != 2)
    {
        strcpy(cMessage, "Need a Reactor Table and a Constant Matrix.");
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }

    /* register the reactor in the reactor table and find the 1-based index.
     * registerReactor() is implemented in Table_Reactor.c and is called via
     * the function prototype defined in Mixer_1_0.h
     */
    iPartNdx = registerReactor(refObjs[SG_NDX_OBJ_REACTORTABLE], ciPartSN);
    if (iPartNdx < 1)
    {
        strcpy(cMessage, "Cannot register this part in the reactor table.");
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }
    else
    {   /* record the 1-based index for bi-directional reference */
        self->zValues[SG_NDX_IPARTINDEX].iData[0] = iPartNdx;
    }

    return SG_R_OK;
}

/* ============================================================
 * SG_xPreEval - Pre-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPreEval_Base_Container_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT i;
    const FLOAT cfConcentration = self->zValues[SG_NDX_FCONCENTRATION].fData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* Deposit Reactor Concentration to all the output links */
    for (i = 0; i < *piLnkObjs; i++)
    {
        if (lnkObjs[i]->zValues[SG_NDX_LINK_ILINKINFO].iData[0] == SG_LINK_OUT)
            lnkObjs[i]->zValues[SG_NDX_LINK_FCONCENTRATION].fData[0] =

                                cfConcentration;
    }

    return SG_R_OK;
}

/* ============================================================
 * SG_xEval - Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xEval_Base_Container_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT i;
    INT iType;
    BOOL bInput;
    SG_OBJ* pConstMatrix;
    SG_OBJ* pReactorTable;
    FLOAT fFlowRate;
    FLOAT fConcentration;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* start loading the constant matrix and RHS vector,
     * using the law of conservation
     */
    if (*piRefObjs < 2)
    {
        strcpy(cMessage, "Constant Matrix and Reactor Table objects are required.");
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }

    pReactorTable = refObjs[SG_NDX_OBJ_REACTORTABLE];
    pConstMatrix = refObjs[SG_NDX_OBJ_CONSTMATRIX];

    for (i = 0; i < *piLnkObjs; i++)
    {    /* going through all the links and adjacent objects */
         bInput = (lnkObjs[i]->zValues[SG_NDX_LINK_ILINKINFO].iData[0] ==

                   SG_LINK_IN);
        if (bInput)
        {   /* input */
            iType = MIX_GET_USER_TYPE(adjObjs[i]);
            switch (iType)
            {
            case MIX_USER_TYPE_REACTOR:
                loadMatrixConstant(pConstMatrix,
                    self->zValues[SG_NDX_IPARTINDEX].iData[0],
                    adjObjs[i]->zValues[SG_NDX_IPARTINDEX].iData[0],
                    lnkObjs[i]->zValues[SG_NDX_LINK_FFLOWRATE].fData[0],
                    bInput );
                break;
            case MIX_USER_TYPE_SOURCE:
                fFlowRate = lnkObjs[i]->zValues[SG_NDX_LINK_FFLOWRATE].fData[0];
                fConcentration =

                    lnkObjs[i]->zValues[SG_NDX_LINK_FCONCENTRATION].fData[0];
                if (fFlowRate < 0.f || fConcentration < 0.f)
                {
                    strcpy(cMessage, "Source to the reactor has not been initialized.");
                    /* important - reset the number of reactors in the simControl object */
                    simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
                    return SG_R_STOP;
                }
                loadTableConstant(pReactorTable,
                    self->zValues[SG_NDX_IPARTINDEX].iData[0],
                    fConcentration * fFlowRate,
                    bInput );
                break;
            case MIX_USER_TYPE_SINK:
                /* do nothing */
            default:
                break;
            }
        }
        else
        {   /* output */
            iType = MIX_GET_USER_TYPE(adjObjs[i]);
            switch (iType)
            {
            case MIX_USER_TYPE_REACTOR:
            case MIX_USER_TYPE_SINK:
                /* load constant to the main diagnal cell */
                /* same behavior for both reactor and sink in the output */
                loadMatrixConstant(pConstMatrix,
                    self->zValues[SG_NDX_IPARTINDEX].iData[0],
                    self->zValues[SG_NDX_IPARTINDEX].iData[0],
                    lnkObjs[i]->zValues[SG_NDX_LINK_FFLOWRATE].fData[0],
                    bInput );
                break;
            case MIX_USER_TYPE_SOURCE:
                /* do nothing */
            default:
                break;
            }
        }
    }

    return SG_R_OK;
}

/* ============================================================
 * SG_xPostEval - Post-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPostEval_Base_Container_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT i;
    const INT ciPartNdx = self->zValues[SG_NDX_IPARTINDEX].iData[0];
    FLOAT fConcentration;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* check the existence of reactor table */
    if (*piRefObjs < 2)
    {
        strcpy(cMessage,
        "ERROR: Constant Matrix and Reactor Table objects are required." );
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }

    /* fetch the solution from the reactor table */
    /* notice that ciPartNdx is 1-based */
    fConcentration = (FLOAT)(refObjs[SG_NDX_OBJ_REACTORTABLE]->
                     zValues[SG_NDX_TBL_DSOLUTION].dData[ciPartNdx - 1] );
    self->zValues[SG_NDX_FCONCENTRATION].fData[0] = fConcentration;

    /* deposit Reactor Concentration to all the output links */
    for (i = 0; i < *piLnkObjs; i++)
    {
        if (lnkObjs[i]->zValues[SG_NDX_LINK_ILINKINFO].iData[0] == SG_LINK_OUT)
            lnkObjs[i]->zValues[SG_NDX_LINK_FCONCENTRATION].fData[0] =

                fConcentration;
    }

    return SG_R_OK;
}
Functions in Class Base.Container.Sink      [Go to Top]

/* Base_Container_Sink.c
 * - DLL routines for class <Component>Base.Container.Sink
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include "../Mixer_1_0/Mixer_1_0.h"

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xInit_Base_Container_Sink;
SG_EXPORT SG_SIM_FUNC SG_xPostEval_Base_Container_Sink;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.7] */
#define SG_NDX_FCONCENTRATION 0 /* fConcentration - Concentration */

/* ============================================================
 * SG_xInit - Initialization
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInit_Base_Container_Sink(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* set user type for future identification - to prevent class name comparison
     * during component class run-time type checking
     */
    MIX_SET_USER_TYPE(self, MIX_USER_TYPE_SINK);

    return SG_R_OK;
}

/* ============================================================
 * SG_xPostEval - Post-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPostEval_Base_Container_Sink(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* fetch concentration from input link - one big requirement here is that
     * this routine in all sinks shall be executed AFTER all the PostEval
     * routines in the reactors have been executed.  Use the name order
     * or other execution sequence control in the simControl object.
     */
    if (*piLnkObjs > 0)
    {
        self->zValues[SG_NDX_FCONCENTRATION].fData[0] =
            lnkObjs[0]->zValues[SG_NDX_LINK_FCONCENTRATION].fData[0];
    }

    return SG_R_OK;
}
Functions in Class Base.Source      [Go to Top]

/* Base_Source.c
 * - DLL routines for class <Component>Base.Source
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include "../Mixer_1_0/Mixer_1_0.h"

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xInit_Base_Source;
SG_EXPORT SG_SIM_FUNC SG_xPreEval_Base_Source;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.3] */
#define SG_NDX_FCONCENTRATION 0 /* fConcentration - Initial Concentration */

/* ============================================================
 * SG_xInit - Initialization
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInit_Base_Source(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* set user type for future identification - to prevent class name comparison
     * during component class run-time type checking
     */
    MIX_SET_USER_TYPE(self, MIX_USER_TYPE_SOURCE);

    return SG_R_OK;
}

/* ============================================================
 * SG_xPreEval - Pre-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPreEval_Base_Source(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    const FLOAT cfConcentration = self->zValues[SG_NDX_FCONCENTRATION].fData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* Deposit Source Concentration to the output link - should be only one */
    if (*piLnkObjs > 0)
        lnkObjs[0]->zValues[SG_NDX_LINK_FCONCENTRATION].fData[0] = cfConcentration;

    return SG_R_OK;
}
Functions in Class Base.Source.Variable      [Go to Top]

/* Base_Source_Variable.c
 * - DLL routines for class <Component>Base.Source.Variable
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include <math.h>
#include "../Mixer_1_0/Mixer_1_0.h"

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xInit_Base_Source_Variable;
SG_EXPORT SG_SIM_FUNC SG_xPreEval_Base_Source_Variable;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.4] */
#define SG_NDX_FCONCENTRATION 0 /* fConcentration - Initial Concentration */
#define SG_NDX_FSTEADY 1 /* fSteady - Steady State Concentration */
#define SG_NDX_FCURRENT 2 /* fCurrent - Current Concentration */

/* ============================================================
 * SG_xInit - Initialization
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInit_Base_Source_Variable(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    extern SG_SIM_FUNC SG_xInit_Base_Source;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* call base class initialization function */
    return SG_xInit_Base_Source(self, simCtrl, chgChild, refObjs, piRefObjs,
           adjObjs, piAdjObjs, lnkObjs, piLnkObjs,
           cMessage, iMsgLen, cCommand, iCmdLen, pOutFile );

}

/* ============================================================
 * SG_xPreEval - Pre-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPreEval_Base_Source_Variable(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    const FLOAT cfCurTime = simCtrl->zValues[SG_NDX_CTRL_FCURTIME].fData[0];
    const FLOAT cfInit = self->zValues[SG_NDX_FCONCENTRATION].fData[0];
    const FLOAT cfSteady = self->zValues[SG_NDX_FSTEADY].fData[0];
    FLOAT *fConcentration = &self->zValues[SG_NDX_FCURRENT].fData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* use simple (exponential) lag for the first-order step response */
    /* the time constant is hard coded with 1 minute (not shown in terms) */
    *fConcentration = (cfSteady - cfInit) * (1.f - (FLOAT)exp((DOUBLE)-cfCurTime)) +
        cfInit;
    /* Deposit Source Concentration to the output link - should be only one */
    if (*piLnkObjs > 0)
    lnkObjs[0]->zValues[SG_NDX_LINK_FCONCENTRATION].fData[0] = *fConcentration;

    return SG_R_OK;
}
Functions in Class Collection.Solver      [Go to Top]

/* Collection_Solver.c
 * - DLL routines for class <Reference>Collection.Solver
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include "../Mixer_1_0/Mixer_1_0.h"

/* Define MIX_WITH_MATLAB in the compilation option to activate MATLAB solution.
 * If MIX_WITH_MATLAB is defined, it requires the MATLAB Engine from Mathworks.
 * The MATLAB Engine include and library files will be needed to build the DLL.
 */
#ifdef MIX_WITH_MATLAB
#include "matrix.h" /* mx routines header file */
#include "engine.h" /* matlab engine header file */
static Engine *pMatlabEng = (Engine*)NULL; /* MATLAB Engine */
static mxArray *pMatlabC; /* constant matrix */
static mxArray *pMatlabI; /* inverse matrix */
static mxArray *pMatlabR; /* RHS vector */
static mxArray *pMatlabS; /* solution vector */
static void matlabCleanUp(void);
#endif

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xBgnRun_Collection_Solver;
SG_EXPORT SG_SIM_FUNC SG_xEval_Collection_Solver;
SG_EXPORT SG_SIM_FUNC SG_xPostEval_Collection_Solver;
SG_EXPORT SG_SIM_FUNC SG_xEndRun_Collection_Solver;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.7] */
#define SG_NDX_RREACTOR 0 /* rReactor - Reactor Table */
#define SG_NDX_RCONSTANT 1 /* rConstant - Constant Matrix */
#define SG_NDX_RINVERSE 2 /* rInverse - Inverse Matrix */
#define SG_NDX_RSCRATCH 3 /* rScratch - Scratch Matrix for Temporaries */

/* Get linear index from row and column (column-major order) */
#define MIX_INDEX(R, C, N) ((C) * (N) + (R))

/* Solution methods */
#define MIX_SOLVE_GAUSS            0
#define MIX_SOLVE_LUDECOMP         1
#define MIX_SOLVE_MATLAB           2

static BOOL solveLinearEquationsGauss(DOUBLE[], DOUBLE[], DOUBLE[],

                                      DOUBLE[], DOUBLE[], const INT );
static BOOL solveLinearEquationsLUD(DOUBLE[], DOUBLE[], DOUBLE[],

                                    DOUBLE[], DOUBLE[], DOUBLE[],

                                    DOUBLE[], const INT );
static BOOL solveLinearEquationsMatlab(DOUBLE[], DOUBLE[], DOUBLE[],

                                       DOUBLE[], const INT );

static BOOL decompose(DOUBLE[], const INT);
static BOOL substitute(DOUBLE[], DOUBLE[], DOUBLE[], const INT);
static BOOL inverse(DOUBLE[], DOUBLE[], DOUBLE[], DOUBLE[], DOUBLE[], const INT);

/* ============================================================
 * SG_xBgnRun - Begin Run
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xBgnRun_Collection_Solver(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT iNumVars = simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    if (simCtrl->zValues[SG_NDX_CTRL_ISOLVER].iData[0] == MIX_SOLVE_MATLAB)
    {
#ifdef MIX_WITH_MATLAB
        /* The following statement may not be thread safe */
        /* open connection to the local Matlab Engine */
        if (!(pMatlabEng = engOpen("\0")))
        {
            strcpy(cMessage, "Cannot open MATLAB Engine.");
            return SG_R_STOP;
        }
        /* create all matrices for MATLAB Engine */
        if (!(pMatlabC = mxCreateDoubleMatrix(iNumVars, iNumVars, mxREAL)) ||
            !(pMatlabR = mxCreateDoubleMatrix(iNumVars, 1, mxREAL)) ||
            !(pMatlabS = mxCreateDoubleMatrix(iNumVars, 1, mxREAL)) ||
            !(pMatlabI = mxCreateDoubleMatrix(iNumVars, iNumVars, mxREAL)) )
        {
            engClose(pMatlabEng);
            strcpy(cMessage, "Cannot create MATLAB matrices.");
            return SG_R_STOP;
        }
#else
        /* call MATLAB option is set, but no MATLAB access code */
        strcpy(cMessage, "This version does not have MATLAB support.");
        return SG_R_STOP;
#endif
    }

    return SG_R_OK;
}

/* ============================================================
 * SG_xEval - Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xEval_Collection_Solver(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    DOUBLE *pdConstantMatrix;
    DOUBLE *pdInverseMatrix;
    DOUBLE *pdScratchMatrix;
    DOUBLE *pdConstantRHS;
    DOUBLE *pdSolutionVector;
    DOUBLE *pdScratchVector1;
    DOUBLE *pdScratchVector2;
    const INT ciNumReactors = simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* Here we start to solve the simultaneous equations because all the
     * parts' evaluation routines have been called to load the constant
     * matrix and reactor table (RHS constants).
     */
    if (*piRefObjs < 4)
    {
        strcpy(cMessage,
        "Either Constant, Inverse, Scratch Matrix or Reactor Table is missing." );
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }
    /* The matrices are in column major order */
    pdConstantMatrix = refObjs[SG_NDX_RCONSTANT]->zValues[SG_NDX_MTX_DELEMENT].dData;
    pdInverseMatrix = refObjs[SG_NDX_RINVERSE]->zValues[SG_NDX_MTX_DELEMENT].dData;
    pdScratchMatrix = refObjs[SG_NDX_RSCRATCH]->zValues[SG_NDX_MTX_DELEMENT].dData;
    pdConstantRHS = refObjs[SG_NDX_RREACTOR]->zValues[SG_NDX_TBL_DCONSTANT].dData;
    pdSolutionVector = refObjs[SG_NDX_RREACTOR]->zValues[SG_NDX_TBL_DSOLUTION].dData;
    pdScratchVector1 = refObjs[SG_NDX_RREACTOR]->zValues[SG_NDX_TBL_DSCRATCH1].dData;
    pdScratchVector2 = refObjs[SG_NDX_RREACTOR]->zValues[SG_NDX_TBL_DSCRATCH2].dData;

    /* call the solver routine - the routine is destructive and that is why
     * we pass in the scratch matrix and vector instead
     */
    switch (simCtrl->zValues[SG_NDX_CTRL_ISOLVER].iData[0])
    {
    case MIX_SOLVE_GAUSS:
        if (!solveLinearEquationsGauss(pdConstantMatrix, pdConstantRHS,
            pdSolutionVector, pdScratchMatrix,
            pdScratchVector1, ciNumReactors ))
        {
            strcpy(cMessage, "No solution can be found using Gauss Elimination.");
            /* important - reset the number of reactors in the simControl object */
            simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
            return SG_R_STOP;
        }
        break;
    case MIX_SOLVE_LUDECOMP:
        if (!solveLinearEquationsLUD(pdConstantMatrix, pdConstantRHS,
            pdSolutionVector, pdInverseMatrix,
            pdScratchMatrix, pdScratchVector1,
            pdScratchVector2, ciNumReactors ))
        {
            strcpy(cMessage, "No solution can be found using LU Decomposition");
            /* important - reset the number of reactors in the simControl object */
            simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
            return SG_R_STOP;
        }
        break;
    case MIX_SOLVE_MATLAB:
        if (!solveLinearEquationsMatlab(pdConstantMatrix, pdConstantRHS,
            pdSolutionVector, pdInverseMatrix,
            ciNumReactors ))
        {
            strcpy(cMessage, "Cannot locate/use the MATLAB Engine to solve it.");
            /* important - reset the number of reactors in the simControl object */
            simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
            return SG_R_STOP;
        }
        break;
    default:
        strcpy(cMessage, "Unknown solver type.  Check the SimControl object.");
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
        break;
    }

    return SG_R_OK;
}

/* ============================================================
 * SG_xPostEval - Post-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPostEval_Collection_Solver(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* Advance system clock - access with care in other reference objects */
    simCtrl->zValues[SG_NDX_CTRL_FCURTIME].fData[0] +=
    simCtrl->zValues[SG_NDX_CTRL_FTIMEINC].fData[0];

    return SG_R_OK;
}

/* ============================================================
 * SG_xEndRun - End Run
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xEndRun_Collection_Solver(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    if (!SG_IsSchemaOK(self->nSGobjSchema))
    return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* Solver's duty to reset the reactor counter for the next run */
    simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;

    /* Reset the current time to 0 if it is preferred */
    /* simCtrl->zValues[SG_NDX_CTRL_FCURTIME].fData[0] = 0.f; */

#ifdef MIX_WITH_MATLAB
    if (simCtrl->zValues[SG_NDX_CTRL_ISOLVER].iData[0] == MIX_SOLVE_MATLAB)
    {
        if (pMatlabEng)
            matlabCleanUp();
    }
#endif

    return SG_R_OK;
}

/* ============================================================
 * solveLinearEquationsGauss - solve the linear simultaneous
 * equations using Naive Gauss Elimination
 * ------------------------------------------------------------
 * There is no inverse matrix calculated when using this method.
 * ------------------------------------------------------------
 */
BOOL solveLinearEquationsGauss(DOUBLE dConstantMatrix[], DOUBLE dConstantRHS[],
          DOUBLE dSolutionVector[], DOUBLE dScratchMatrix[],
          DOUBLE dScratchVector[], const INT ciNumVars )
{
    const INT ciDoubleLength = sizeof(DOUBLE) * ciNumVars;
    INT i, j, k, n;
    DOUBLE dFactor;
    DOUBLE dDivisor;
    DOUBLE dSum;

    /* remember the constant matrix and RHS constant vector */
    memcpy(dScratchMatrix, dConstantMatrix, ciDoubleLength * ciNumVars);
    memcpy(dScratchVector, dConstantRHS, ciDoubleLength);

    for (k = 0; k < ciNumVars - 1; k++)
    {
        for (i = k + 1; i < ciNumVars; i++)
        {
            dDivisor = dScratchMatrix[MIX_INDEX(k, k, ciNumVars)];
            if (dDivisor == 0.)
                return FALSE;
            dFactor = dScratchMatrix[MIX_INDEX(i, k, ciNumVars)] / dDivisor;

            for (j = k + 1; j < ciNumVars; j++)
                dScratchMatrix[MIX_INDEX(i, j, ciNumVars)] -=
                    dFactor * dScratchMatrix[MIX_INDEX(k, j, ciNumVars)];
            dScratchVector[i] -= dFactor * dScratchVector[k];
        }
    }

    n = ciNumVars - 1;
    dDivisor = dScratchMatrix[MIX_INDEX(n, n, ciNumVars)];
    if (dDivisor == 0.)
        return FALSE;
    dSolutionVector[n] = dScratchVector[n] / dDivisor;

    for (i = n - 1; i >= 0; i--)
    {
        dSum = 0.;
        for (j = i + 1; j < ciNumVars; j++)
        {
            dSum += dScratchMatrix[MIX_INDEX(i, j, ciNumVars)] *

                    dSolutionVector[j];
        }
        dDivisor = dScratchMatrix[MIX_INDEX(i, i, ciNumVars)];
        if (dDivisor == 0.)
            return FALSE;
        dSolutionVector[i] = (dScratchVector[i] - dSum) / dDivisor;
    }
    return TRUE;
}

/* ============================================================
 * solveLinearEquationsLUD - solve the linear simultaneous
 * equations using LU Decomposition
 * ------------------------------------------------------------
 */
BOOL solveLinearEquationsLUD(DOUBLE dConstantMatrix[], DOUBLE dConstantRHS[],
          DOUBLE dSolutionVector[], DOUBLE dInverseMatrix[],
          DOUBLE dScratchMatrix[], DOUBLE dScratchVector1[],
          DOUBLE dScratchVector2[], const INT ciNumVars )
{
    const INT ciDoubleLength = sizeof(DOUBLE) * ciNumVars;

    /* remember the constant matrix and RHS constant vector */
    memcpy(dScratchMatrix, dConstantMatrix, ciDoubleLength * ciNumVars);
    if (!decompose(dScratchMatrix, ciNumVars))
        return FALSE;

    /* remember the LU matrix in dScratchMatrix for inverse matrix calculation */
    memcpy(dInverseMatrix, dScratchMatrix, ciDoubleLength * ciNumVars);

    /* copy the RHS vector for inverse matrix calculation */
    memcpy(dScratchVector1, dConstantRHS, ciDoubleLength);
    if (!substitute(dScratchMatrix, dScratchVector1, dSolutionVector, ciNumVars))
        return FALSE;

    /* Inverse matrix should contain the LU decomposed result */
    memcpy(dScratchMatrix, dInverseMatrix, ciDoubleLength * ciNumVars);
    return inverse(dScratchMatrix, dInverseMatrix, dConstantRHS, dScratchVector1,
                   dScratchVector2, ciNumVars );
}

/* ------------------------------------------------------------
 */
BOOL decompose(DOUBLE dConstantMatrix[], const INT ciNumVars)
{
    INT i, j, k;
    DOUBLE dFactor, dDivisor;

    for (k = 0; k < ciNumVars - 1; k++)
    {
        for (i = k + 1; i < ciNumVars; i++)
        {
            dDivisor = dConstantMatrix[MIX_INDEX(k, k, ciNumVars)];
            if (dDivisor == 0.)
                return FALSE;
            dFactor = dConstantMatrix[MIX_INDEX(i, k, ciNumVars)] / dDivisor;
            dConstantMatrix[MIX_INDEX(i, k, ciNumVars)] = dFactor;
            for (j = k + 1; j < ciNumVars; j++)
                dConstantMatrix[MIX_INDEX(i, j, ciNumVars)] -=
                    dFactor * dConstantMatrix[MIX_INDEX(k, j, ciNumVars)];
        }
    }
    return TRUE;
}

/* ------------------------------------------------------------
 */
BOOL substitute(DOUBLE dMatrixLU[], DOUBLE dVectorRHS[],
          DOUBLE dVectorSolution[], const INT ciNumVars )
{
    INT i, j, n;
    DOUBLE dSum, dDivisor;

    /* forward substitution */
    for (i = 1; i < ciNumVars; i++)
    {
        dSum = dVectorRHS[i];
        for (j = 0; j < i; j++)
            dSum -= dMatrixLU[MIX_INDEX(i, j, ciNumVars)] * dVectorRHS[j];
        dVectorRHS[i] = dSum;
    }
    /* backward substitution */
    n = ciNumVars - 1;
    dDivisor = dMatrixLU[MIX_INDEX(n, n, ciNumVars)];
    if (dDivisor == 0.)
        return FALSE;
    dVectorSolution[n] = dVectorRHS[n] / dDivisor;
    for (i = n - 1; i >= 0; i--)
    {
        dSum = 0.;
        for (j = i + 1; j < ciNumVars; j++)
            dSum += dMatrixLU[MIX_INDEX(i, j, ciNumVars)] * dVectorSolution[j];
        dDivisor = dMatrixLU[MIX_INDEX(i, i, ciNumVars)];
        if (dDivisor == 0.)
            return FALSE;
        dVectorSolution[i] = (dVectorRHS[i] - dSum) / dDivisor;
    }
    return TRUE;
}

/* ------------------------------------------------------------
 */
BOOL inverse(DOUBLE dMatrixLU[], DOUBLE dMatrixInverse[], DOUBLE dVectorRHS[],
          DOUBLE dVectorScratch1[], DOUBLE dVectorScratch2[],
          const INT ciNumVars )
{
    /* calling decompose() is not necessary because the input is LU result */
    INT i, j;

    memcpy(dVectorScratch1, dVectorRHS, sizeof(DOUBLE) * ciNumVars);

    for (i = 0; i < ciNumVars; i++)
    {
        for (j = 0; j < ciNumVars; j++)
            dVectorScratch1[j] = (i == j) ? 1. : 0.;

        /* use dVectorScratch2 to receive solution vector X */
        if (!substitute(dMatrixLU, dVectorScratch1, dVectorScratch2, ciNumVars))
            return FALSE;

        for (j = 0; j < ciNumVars; j++)
            dMatrixInverse[MIX_INDEX(j, i, ciNumVars)] = dVectorScratch2[j];
    }
    return TRUE;
}

/* ============================================================
 * solveLinearEquationsMatlab - solve the linear simultaneous
 * equations using the MATLAB Engine
 * ------------------------------------------------------------
 */
BOOL solveLinearEquationsMatlab(DOUBLE dConstantMatrix[], DOUBLE dConstantRHS[],
          DOUBLE dSolutionVector[], DOUBLE dInverseMatrix[],
          const INT ciNumVars )
{
#ifdef MIX_WITH_MATLAB
    const INT ciDoubleLength = sizeof(DOUBLE) * ciNumVars;

    /* prepare input matrices */
    memcpy((void*)mxGetPr(pMatlabC), (void*)dConstantMatrix,
           ciDoubleLength * ciNumVars );
    memcpy((void*)mxGetPr(pMatlabR), (void*)dConstantRHS, ciDoubleLength);
    memset((void*)mxGetPr(pMatlabS), 0, ciDoubleLength);
    memset((void*)mxGetPr(pMatlabI), 0, ciDoubleLength * ciNumVars);

    if (engPutVariable(pMatlabEng, "C", pMatlabC) ||
        engPutVariable(pMatlabEng, "R", pMatlabR) ||
        engPutVariable(pMatlabEng, "S", pMatlabS) ||
        engPutVariable(pMatlabEng, "I", pMatlabI) )
    {
        matlabCleanUp();
        return FALSE;
    }

    /* now execute MATLAB commands - both must be executed */
    if (engEvalString(pMatlabEng, "S = C \\ R;") ||
        engEvalString(pMatlabEng, "I = inv(C);") )
    {
        matlabCleanUp();
        return FALSE;
    }

    /* now fetch the solutions */
    if (!(pMatlabS = engGetVariable(pMatlabEng, "S")))
    {
        matlabCleanUp();
        return FALSE;
    }
    memcpy((void*)dSolutionVector, (void*)mxGetPr(pMatlabS), ciDoubleLength);

    if (!(pMatlabI = engGetVariable(pMatlabEng, "I")))
    {
        matlabCleanUp();
        return FALSE;
    }
    memcpy((void*)dInverseMatrix, (void*)mxGetPr(pMatlabI),
           ciDoubleLength * ciNumVars );

    return TRUE;
#else
    /* call MATLAB option is set, but no MATLAB access code */
    return FALSE;
#endif
}

/* ============================================================
 * matlabCleanUp - subroutine to clean up MATLAB access
 * ------------------------------------------------------------
 */
#ifdef MIX_WITH_MATLAB
void matlabCleanUp()
{
    mxDestroyArray(pMatlabC);
    mxDestroyArray(pMatlabR);
    mxDestroyArray(pMatlabS);
    mxDestroyArray(pMatlabI);
    engClose(pMatlabEng);
}
#endif

Functions in Class Matrix.Calculation      [Go to Top]

/* Matrix_Calculation.c
 * - DLL routines for class <Reference>Matrix.Calculation
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include "../Mixer_1_0/Mixer_1_0.h"

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xInitSize_Matrix_Calculation;
SG_EXPORT SG_SIM_FUNC SG_xPreEval_Matrix_Calculation;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.5] */
#define SG_NDX_ICOLS 0 /* iCols - Number of Columns */
#define SG_NDX_IROWS 1 /* iRows - Number of Rows */
#define SG_NDX_ISHEETS 2 /* iSheets - Number of Sheets */
#define SG_NDX_DELEMENT 3 /* dElement - Elements in Matrix */

/* ============================================================
 * SG_xInitSize - Resize for Init
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInitSize_Matrix_Calculation(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    const INT ciNumReactors = simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* resize constant matrix according to the number of reactors registered */
    if (ciNumReactors < 1)
    {
        strcpy(cMessage, "At least one reactor part is required.");
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }
    self->zValues[SG_NDX_ICOLS].iData[0] = ciNumReactors;
    self->zValues[SG_NDX_IROWS].iData[0] = ciNumReactors;
    self->zValues[SG_NDX_ISHEETS].iData[0] = 1; /* always */

    return SG_R_OK;
}

/* ============================================================
 * SG_xPreEval - Pre-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPreEval_Matrix_Calculation(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT iSize = self->zValues[SG_NDX_DELEMENT].iSize;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* initialize the matrix to 0 to prepare for loading constants */
    memset(self->zValues[SG_NDX_DELEMENT].dData, 0, sizeof(DOUBLE) * iSize);

    return SG_R_OK;
}

/* ============================================================
 * loadMatrixConstant - load a simultaneous equation constant into
 * the constant matrix
 * ------------------------------------------------------------
 * ARGUMENT:
 * self - the Matrix.Constant object to load constants to
 * ciPartNdx- the registered 1-based index of the reactor (row)
 * ciLoadNdx- the 1-based index of the reactor associated (column)
 * cfValue- the constant value to be loaded
 * cbInput- TRUE, if input to the part; FALSE, if output
 *
 * RETURN:
 * 1-based index of the reactor (row); 0 when failed.
 *
 * NOTES:
 * The convention for loading equation constants (LHS) is that
 * the input values are negative and output values are positive.
 * The matrix is stored in column major order.
 * ------------------------------------------------------------
 */
INT loadMatrixConstant(SG_OBJ *const self, const INT ciPartNdx,
                       const INT ciLoadNdx, const FLOAT cfValue,
                       const BOOL cbInput )
{
    const INT ciRow = ciPartNdx - 1; /* now 0-based */
    const INT ciCol = ciLoadNdx - 1; /* now 0-based */
    const INT ciSize = self->zValues[SG_NDX_IROWS].iData[0];
    INT iNdx; /* to store linearized index */

    /* should be a square matrix */
    if (ciRow < 0 || ciCol < 0 || ciRow >= ciSize || ciCol >= ciSize)
        return 0; /* out of bound error */

    /* calculate linear index */
    iNdx = ciSize * ciCol + ciRow;
    if (cbInput)
        self->zValues[SG_NDX_DELEMENT].dData[iNdx] -= (DOUBLE)cfValue;
    else
        self->zValues[SG_NDX_DELEMENT].dData[iNdx] += (DOUBLE)cfValue;

    return ciPartNdx;
}

Functions in Class Table.Reactor      [Go to Top]

/* Table_Reactor.c
 * - DLL routines for class <Reference>Table.Reactor
 * DATE: Monday, September 10, 2001  TIME: 03:57:13 PM
 * The skeleton of this file is generated by SansGUI(tm)
 */

#include <stdio.h>
#include "SGdll.h"

#include "../Mixer_1_0/Mixer_1_0.h"

#ifdef __cplusplus
extern "C"
{
#endif

SG_EXPORT SG_SIM_FUNC SG_xInitSize_Table_Reactor;
SG_EXPORT SG_SIM_FUNC SG_xInit_Table_Reactor;
SG_EXPORT SG_SIM_FUNC SG_xPreEval_Table_Reactor;

#ifdef __cplusplus
}
#endif

/* Macros for attribute indices in class version [1.0.alpha.9] */
#define SG_NDX_ISIZE 0 /* iSize - Table Size */
#define SG_NDX_ISHEETS 1 /* iSheets - Number of Sheets */
#define SG_NDX_IPARTSN 2 /* iPartSN - Part Internal Serial Number */
#define SG_NDX_DCONSTANT 3 /* dConstant - Constants in Mass Balance Eqns */
#define SG_NDX_DSOLUTION 4 /* dSolution - Solutions in Mass Balance Eqns */
#define SG_NDX_DSCRATCH1 5 /* dScratch1 - Vector Buffer 1 for Temporaries */
#define SG_NDX_DSCRATCH2 6 /* dScratch2 - Vector Buffer 2 for Temporaries */

/* ============================================================
 * SG_xInitSize - Resize for Init
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInitSize_Table_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    const INT ciNumReactors = simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0];

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    if (ciNumReactors < 1)
    {
        strcpy(cMessage, "ERROR: At least one reactor part is required.");
        /* important - reset the number of reactors in the simControl object */
        simCtrl->zValues[SG_NDX_CTRL_INUMREACTORS].iData[0] = 0;
        return SG_R_STOP;
    }
    self->zValues[SG_NDX_ISIZE].iData[0] = ciNumReactors;
    self->zValues[SG_NDX_ISHEETS].iData[0] = 1; /* always */

    return SG_R_OK;
}

/* ============================================================
 * SG_xInit - Initialization
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xInit_Table_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT iSize = sizeof(INT) * self->zValues[SG_NDX_IPARTSN].iSize;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* zero out the reactor parts registration */
    /* all the other vectors need to be initialized in each Pre-Eval cycle */
    memset(self->zValues[SG_NDX_IPARTSN].iData, 0, iSize);

    return SG_R_OK;
}

/* ============================================================
 * SG_xPreEval - Pre-Evaluation
 * ------------------------------------------------------------
 */
SG_RET_CODE SG_xPreEval_Table_Reactor(SG_OBJ *const self,
          SG_OBJ *const simCtrl, SG_OBJ *const chgChild,
          SG_OBJ *const refObjs[], const INT *const piRefObjs,
          SG_OBJ *const adjObjs[], const INT *const piAdjObjs,
          SG_OBJ *const lnkObjs[], const INT *const piLnkObjs,
          TCHAR *const cMessage, const INT iMsgLen,
          TCHAR *const cCommand, const INT iCmdLen,
          SG_FILE *const pOutFile )
{
    /* TODO: declare your local variables here */

    INT iDoubleSize = sizeof(DOUBLE) * self->zValues[SG_NDX_DCONSTANT].iSize;

    if (!SG_IsSchemaOK(self->nSGobjSchema))
        return SG_R_SCHM;

    /* TODO: put your simulator code here */

    /* reset constant and solution vectors to prepare for loading */
    memset(self->zValues[SG_NDX_DCONSTANT].dData, 0, iDoubleSize);
    memset(self->zValues[SG_NDX_DSOLUTION].dData, 0, iDoubleSize);
    memset(self->zValues[SG_NDX_DSCRATCH1].dData, 0, iDoubleSize);
    memset(self->zValues[SG_NDX_DSCRATCH2].dData, 0, iDoubleSize);

    return SG_R_OK;
}

/* ============================================================
 * registerReactor - register reactor to the table
 * ------------------------------------------------------------
 * ARGUMENT:
 * self - the Table.Reactor object to provide registration
 * ciPartSN- the unique serial number of the reactor
 *
 * RETURN:
 * 1-based index of the reactor; 0 when failed.
 * ------------------------------------------------------------
 */
INT registerReactor(SG_OBJ *const self, const INT ciPartSN)
{
    INT i;
    const INT ciSize = self->zValues[SG_NDX_IPARTSN].iSize;
    INT *piPartSN = self->zValues[SG_NDX_IPARTSN].iData;

    for (i = 0; i < ciSize; i++)
    {
        if (*piPartSN < 1)
        {   /* it is not occupied, register it in the table */
            *piPartSN = ciPartSN;
            return i + 1; /* return 1-based index */
        }
        else if (*piPartSN == ciPartSN)
        {   /* it has been registered before */
            return i + 1; /* return 1-based index */
        }
        piPartSN++; /* move the pointer to the next element */
    }
    return 0; /* failed */
}

/* ============================================================
 * loadTableConstant - load a constant into the RHS vector
 * ------------------------------------------------------------
 * ARGUMENT:
 * self - the Table.Reactor object to load RHS constants to
 * ciPartNdx- the registered 1-based index of the reactor
 * cfValue- the constant value to be loaded
 * cbInput- TRUE, if input to the part; FALSE, if output
 *
 * RETURN:
 * 1-based index of the reactor; 0 when failed.
 *
 * NOTES:
 * The convention for loading RHS constants is that the input
 * values are positive and output values are negative.
 * ------------------------------------------------------------
 */
INT loadTableConstant(SG_OBJ *const self, const INT ciPartNdx,
          const FLOAT cfValue, const BOOL cbInput )
{
    const INT ciNdx = ciPartNdx - 1; /* now 0-based */
    const INT ciSize = self->zValues[SG_NDX_DCONSTANT].iSize;

    if (ciNdx < 0 || ciNdx >= ciSize)
        return 0; /* out of bound error */

    /* See NOTES above for the sign of the value */
    if (cbInput)
        self->zValues[SG_NDX_DCONSTANT].dData[ciNdx] += (DOUBLE)cfValue;
    else
        self->zValues[SG_NDX_DCONSTANT].dData[ciNdx] -= (DOUBLE)cfValue;

    return ciPartNdx;
}

Contents in Mixer_1_0.h     [Go to Top]

/* Mixer_1_0.h - manually created header file for macros and
 * function prototype, called from various classes
 */

#include <memory.h>
#include <string.h>

typedef INT BOOL;
#define FALSE 0
#define TRUE (!FALSE)

#define SG_NDX_CTRL_ISOLVER        9 /* from class simControl.Mixer */
#define SG_NDX_CTRL_FTIMEINC       10
#define SG_NDX_CTRL_FCURTIME       11
#define SG_NDX_CTRL_INUMREACTORS   12

#define SG_NDX_MTX_DELEMENT        3 /* from class Matrix.Calculation */

#define SG_NDX_TBL_IPARTSN         2 /* from class Table.Reactor */
#define SG_NDX_TBL_DCONSTANT       3
#define SG_NDX_TBL_DSOLUTION       4
#define SG_NDX_TBL_DSCRATCH1       5
#define SG_NDX_TBL_DSCRATCH2       6

#define SG_NDX_LINK_ILINKINFO      0 /* from class Link.Pipe */
#define SG_NDX_LINK_FFLOWRATE      1
#define SG_NDX_LINK_FCONCENTRATION 2

#define MIX_USER_TYPE_UNKNOWN      0 /* for class type info in iUserData */
#define MIX_USER_TYPE_REACTOR      1
#define MIX_USER_TYPE_SOURCE       2
#define MIX_USER_TYPE_SINK         3
#define MIX_SET_USER_TYPE(X, T)    ((X)->iUserData = (T))
#define MIX_GET_USER_TYPE(X)       ((X)->iUserData)

extern INT registerReactor(SG_OBJ *const, const INT);
extern INT loadTableConstant(SG_OBJ *const, const INT, const FLOAT, const BOOL);
extern INT loadMatrixConstant(SG_OBJ *const, const INT, const INT,
                              const FLOAT, const BOOL );

 


Mixer Example for SansGUI version 1.0.2

Copyright 2001-2003 ProtoDesign, Inc. All rights reserved.

http://protodesign-inc.com