The c_sysfn2() utility subroutine is exclusively used inside a FEloadsub user-written subroutine. The sole purpose of the c_sysfn2 utility subroutine is to register a scalar measure, for example, a position or a velocity component, needed for the desired computation. The c_sysfn2() subroutine has a C/C++ only implementation; there is no FORTRAN equivalent. The c_sysfn2() utility subroutine is supported only by Adams Solver C++.
The c_sysfn2() utility subroutine and associated FEloadsub user-written subroutine both implement a new paradigm. Users need to register the measures to be used by the subroutine only once when Adams Solver C++ calls the FEloadsub with the value of IFLAG equal to 1. When IFLAG is equal to 0 (normal evaluation call), all registered measures are evaluated by Adams Solver C++ and passed to the subroutine inside a data structure; see more details in
FEloadsub.
There is strong similarity between c_sysfn2() and c_sysfnc() (and the FORTRAN version SYSFNC). The main difference is that c_sysfn2() does not evaluate the requested measure but just registers the measure. Adams Solver C++ will keep an associated data structure with all registered measures and compute the values of all the registered measures before calling the
FEloadsub. The main similarity is in the use of parameters "fncnam", "ipar" and "nsize" as explained below.
Use
Called By
Function Prototype
void c_sysfn2(const void *beam, const char *fncnam, const int *ipar, int nsize, int *index, int *errflg);
Calling Sequence
c_sysfn2( beam, fncnam, ipar, nsize, &index, &errflag );
Input Arguments
beam | Pointer to a data structure passed to the FEloadsub. See examples in FEloadsub documentation. This pointer is passed to the user when Adams Solver C++ calls a FEloadsub. |
fncnam | A character variable specifying the name of the function (measure) whose data is being requested to be passed to the subroutine on subsequent calls. For example: c_sysfn2( beam, "DX", ipar, nsize, &index, &errflg ); Per C/C++ standards, the name of the measure (function) requires double quotes. All of the measure names permitted by a SYSFNC call are also permitted by the c_sysfn2(). The following measure names are allowed: |
ipar | An integer array containing the parameter list for fncnam. It consists of any valid list of parameters used in the associated Adams Solver measure (function), just as they would appear in a dataset FUNCTION=expression. |
nsize | An integer variable specifying the number of values in array ipar. |
Output Arguments
index | An integer pointer containing the index number of the registered measure (function). The index is zero-based. The returned index may be ignored. See example below on how the index may help writing more robust and easier-to-read code. |
errflg | An integer pointer containing either a 0 or 1. A value 0 signals no problems. A value o 1 signals a wrong specification of the registering measure. |
Extended Definition
The c_sysfnc2() subroutine registers a system-state value (such as displacement, velocities, non-dimensional arc length along a beam and so on.) to be used inside a FEloadsub user-written subroutine. Adams Solver C++ creates a list of all registered measures (the registration process takes place when IFLAG=1) and assigns an index to all registered measures. The index is 0-based and is based on the order in which the calls to c_sysfn2() are made. During normal evaluation (IFLAG=0), Adams Solver C++ computes the values of all registered measures and passes the computed values to the FEloadsub subroutine. See
FEloadsub subroutine for more details and examples.
Although c_sysfn2() is similar to c_sysfnc() (or FORTRAN equivalent SYSFNC), the main difference is that users must call it only when IFLAG=1. This new architecture increases performance by eliminating continuous checks done on every call to SYSFNC; for example, during normal evaluation calls to user-written subroutines, every call to the utility subroutine SYSFNC requires a construction of the requested measure and a mandatory check to make sure the measure was registered. When using the c_sysfn2() utility, no constructions, no checks are needed during normal calls to the FEloadsub.
Cautions
Calls to c_sysfn2() must be made only during the initialization stage (IFLAG=1).
Example 1
In this example we present a code snippet where two measures (DX(2,8) and SD(3)) are registered.
#include "slv_c_utils.h"
extern "C"
void FEloadsub( struct sAdamsANCF3DBeamDistrForce* sBeam, double TIME, int DFLAG, int IFLAG, double *RESULT )
{
if( IFLAG==1 )
{
// Initialization. Registration of measures used by this subroutine
int index, errflg, npar, par[3];
npar = 2;
par[0] = 2;
par[1] = 8;
c_sysfn2( sBeam, "DX", par, npar, &index, &errflg ); // DX(2,8)
npar = 1;
par[0] = 3;
c_sysfn2( sBeam, "SD", par, npar, &index, &errflg ); // SD(3)
}
// Rest of code not shown.
}
Example 2
In this complete example, four calls are made to c_sysfn2() in order to register the measures SD(2), SD(4), SD(5) and SD(6). The index is not used by the author of the subroutine.
#include "slv_c_utils.h"
#include <math.h>
extern "C"
void FEloadsub( struct sAdamsANCF3DBeamDistrForce* sBeam, double TIME, int DFLAG, int IFLAG, double *RESULT )
{
const double PI = 3.14159265358979323846;
if( IFLAG==1 )
{
// Initialization. Registration of measures used by this subroutine
int index, errflg, npar, par[3];
npar = 1;
par[0] = 2;
c_sysfn2( sBeam, "SD", par, npar, &index, &errflg ); // SD(2) - y position
par[0] = 4;
c_sysfn2( sBeam, "SD", par, npar, &index, &errflg ); // SD(4) - Psi
par[0] = 5;
c_sysfn2( sBeam, "SD", par, npar, &index, &errflg ); // SD(5) - Theta
par[0] = 6;
c_sysfn2( sBeam, "SD", par, npar, &index, &errflg ); // SD(6) - Phi
}
else if( IFLAG==3 )
{
// Mapping dependencies
sBeam->depend_Fx[0] = 1.0;
sBeam->depend_Fx[1] = 1.0;
sBeam->depend_Fx[2] = 1.0;
sBeam->depend_Fx[3] = 1.0;
sBeam->depend_Fy[0] = 1.0;
sBeam->depend_Fy[1] = 1.0;
sBeam->depend_Fy[2] = 1.0;
sBeam->depend_Fy[3] = 1.0;
}
else if( IFLAG==0 )
{
// Normal function evaluation. Get values of parameters and measures
double C = sBeam->PAR[0];
double y = sBeam->mea_values[0];
double Psi = sBeam->mea_values[1];
double Theta = sBeam->mea_values[2];
double Phi = sBeam->mea_values[3];
// Compute the pressure
RESULT[0] = -C*pow(y,4)*(-cos(Psi)*sin(Phi) - sin(Psi)*cos(Theta)*cos(Phi));
RESULT[1] = -C*pow(y,4)*(-sin(Psi)*sin(Phi) + cos(Psi)*cos(Theta)*cos(Phi));
// Partial derivatives
if( DFLAG==1 )
{
sBeam->depend_Fx[0] = -C*4.*pow(y,3)*(-cos(Psi)*sin(Phi) - sin(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fx[1] = -C*pow(y,4)*(sin(Psi)*sin(Phi) - cos(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fx[2] = -C*pow(y,4)*(sin(Psi)*sin(Theta)*cos(Phi));
sBeam->depend_Fx[3] = -C*pow(y,4)*(-cos(Psi)*cos(Phi) + sin(Psi)*cos(Theta)*sin(Phi));
sBeam->depend_Fy[0] = -C*4.*pow(y,3)*(-sin(Psi)*sin(Phi) + cos(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fy[1] = -C*pow(y,4)*(-cos(Psi)*sin(Phi) - sin(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fy[2] = -C*pow(y,4)*(-cos(Psi)*sin(Theta)*cos(Phi));
sBeam->depend_Fy[3] = -C*pow(y,4)*(-sin(Psi)*cos(Phi) - cos(Psi)*cos(Theta)*sin(Phi));
}
}
}
Example 3
This example is computational identical to the previous example; in this case the returned index from c_sysfn2() is used to make the code easier to understand.
#include "slv_c_utils.h"
#include <math.h>
extern "C"
void FEloadsub( struct sAdamsANCF3DBeamDistrForce* sBeam, double TIME, int DFLAG, int IFLAG, double *RESULT )
{
const double PI = 3.14159265358979323846;
// Make this variables 'static' so their values are kept between function calls
static int y_idx, Psi_idx, Theta_idx, Phi_idx;
if( IFLAG==1 )
{
// Initialization. Registration of measures used by this subroutine
int errflg, npar, par[3];
npar = 1;
par[0] = 2;
c_sysfn2( sBeam, "SD", par, npar, &y_idx, &errflg ); // SD(2) - y position
par[0] = 4;
c_sysfn2( sBeam, "SD", par, npar, &Psi_idx, &errflg ); // SD(4) - Psi
par[0] = 5;
c_sysfn2( sBeam, "SD", par, npar, &Theta_idx, &errflg ); // SD(5) - Theta
par[0] = 6;
c_sysfn2( sBeam, "SD", par, npar, &Phi_idx, &errflg ); // SD(6) - Phi
}
else if( IFLAG==3 )
{
// Mapping dependencies
sBeam->depend_Fx[y_idx] = 1.0;
sBeam->depend_Fx[Psi_idx] = 1.0;
sBeam->depend_Fx[Theta_idx] = 1.0;
sBeam->depend_Fx[Phi_idx] = 1.0;
sBeam->depend_Fy[y_idx] = 1.0;
sBeam->depend_Fy[Psi_idx] = 1.0;
sBeam->depend_Fy[Theta_idx] = 1.0;
sBeam->depend_Fy[Phi_idx] = 1.0;
}
else if( IFLAG==0 )
{
// Normal function evaluation. Get values of parameters and measures
double C = sBeam->PAR[0];
double y = sBeam->mea_values[y_idx];
double Psi = sBeam->mea_values[Psi_idx];
double Theta = sBeam->mea_values[Theta_idx];
double Phi = sBeam->mea_values[Phi_idx];
// Compute the pressure
RESULT[0] = -C*pow(y,4)*(-cos(Psi)*sin(Phi) - sin(Psi)*cos(Theta)*cos(Phi));
RESULT[1] = -C*pow(y,4)*(-sin(Psi)*sin(Phi) + cos(Psi)*cos(Theta)*cos(Phi));
// Partial derivatives
if( DFLAG==1 )
{
sBeam->depend_Fx[y_idx] = -C*4.*pow(y,3)*(-cos(Psi)*sin(Phi) - sin(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fx[Psi_idx] = -C*pow(y,4)*(sin(Psi)*sin(Phi) - cos(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fx[Theta_idx] = -C*pow(y,4)*(sin(Psi)*sin(Theta)*cos(Phi));
sBeam->depend_Fx[Phi_idx] = -C*pow(y,4)*(-cos(Psi)*cos(Phi) + sin(Psi)*cos(Theta)*sin(Phi));
sBeam->depend_Fy[y_idx] = -C*4.*pow(y,3)*(-sin(Psi)*sin(Phi) + cos(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fy[Psi_idx] = -C*pow(y,4)*(-cos(Psi)*sin(Phi) - sin(Psi)*cos(Theta)*cos(Phi));
sBeam->depend_Fy[Theta_idx] = -C*pow(y,4)*(-cos(Psi)*sin(Theta)*cos(Phi));
sBeam->depend_Fy[Phi_idx] = -C*pow(y,4)*(-sin(Psi)*cos(Phi) - cos(Psi)*cos(Theta)*sin(Phi));
}
}
}