02.04.2013 Views

Welcome to Adams/Solver Subroutines - Kxcad.net

Welcome to Adams/Solver Subroutines - Kxcad.net

Welcome to Adams/Solver Subroutines - Kxcad.net

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

User subroutines are commonly used in <strong>Adams</strong>/<strong>Solver</strong>, part of the <strong>Adams</strong>® suite of software, <strong>to</strong> model<br />

a variety of non-standard phenomena. You can cus<strong>to</strong>mize <strong>Adams</strong>/<strong>Solver</strong> for their specific application by<br />

writing these subroutines.<br />

This section provides an overview of the subroutines you can use with <strong>Adams</strong>/<strong>Solver</strong>. This material<br />

applies <strong>to</strong> both FORTRAN and C++ versions of <strong>Adams</strong>/<strong>Solver</strong> unless specified otherwise. For more<br />

information on the FORTRAN version, see the <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN) online help. For information<br />

on the C++ version, see the <strong>Adams</strong>/<strong>Solver</strong> (C++) online help.<br />

1


2<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Conventions, Requirements and Types<br />

Subroutine Conventions<br />

Throughout the help, the following type styles are used as visual cues:<br />

This type of style: Indicates:<br />

CONSUB The subroutines that <strong>Adams</strong> recognizes.<br />

x The argument in <strong>Adams</strong> subroutines.<br />

i The type of value or types of parameters that are <strong>to</strong> follow the<br />

statement, command, or argument. A summary of these terms include:<br />

System Requirements<br />

i<br />

r<br />

c<br />

e<br />

v<br />

id<br />

x,y,z<br />

a,b,c<br />

Integer<br />

Real<br />

Character string (alphanumeric)<br />

Function expression<br />

Varying type (integer, real or<br />

alphanumeric)<br />

Identifier<br />

Cartesian coordinate (real)<br />

Angular coordinate (real)<br />

PART The underscored letters indicated the minimum allowable<br />

abbreviations of statements, commands, and arguments.<br />

{ } That you are <strong>to</strong> make a selection from a series of items.<br />

[ ] That you can optionally select an item.<br />

[[ ]] That you can select any combination of the items.<br />

A A two-dimensional matrix.<br />

a A one-dimensional matrix.<br />

R<br />

xˆ<br />

A vec<strong>to</strong>r.<br />

Unit vec<strong>to</strong>rs.<br />

To use subroutines, you need the system requirements outlined in the following sections.


Compilers and Linkers<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

To work with user-written subroutines you must have the appropriate compilers and linkers. For more<br />

information, refer <strong>to</strong> the hardware and software specifications included with your installation<br />

instructions, and on the <strong>Adams</strong> Web site.<br />

Languages<br />

You can write user-written subroutines in any language, provided there is a way <strong>to</strong> call FORTRAN<br />

subroutines in that language. FORTRAN is the preferred language for writing user-written subroutines,<br />

although C and C++ are acceptable.<br />

Debuggers<br />

To facilitate the debugging of user-written subroutines, you should have a source-level debugger.<br />

Debuggers are not required when using your own subroutines with <strong>Adams</strong>/<strong>Solver</strong>, but are useful for<br />

finding mistakes, such as improper syntax or logic, in your subroutines.<br />

Types of <strong>Subroutines</strong><br />

The following sections introduce the three types of subroutines that <strong>Adams</strong>/<strong>Solver</strong> provides:<br />

• About User-Written <strong>Subroutines</strong><br />

• About Utility <strong>Subroutines</strong><br />

• About Callable <strong>Subroutines</strong> (no longer supported)<br />

About User-Written <strong>Subroutines</strong><br />

User-written subroutines are used primarily for modeling specialized phenomena or calculating<br />

nonstandard results. Many simulations require the modeling of special phenomena that are not a part of<br />

the standard <strong>Adams</strong> software. These phenomena may be expressed mathematically as differential<br />

equations, algebraic equations, applied forces, constraints, motion inputs <strong>to</strong> system, or a combination of<br />

these general modeling entities.<br />

<strong>Adams</strong>/<strong>Solver</strong> can accept user-specified descriptions of phenomena. You define the governing<br />

relationships for the phenomena in the user-written subroutines. <strong>Adams</strong> then evaluates these<br />

relationships as part of the solution process.<br />

For more information about user-written subroutines and details about each of the user-written<br />

subroutines, see User-Written <strong>Subroutines</strong>.<br />

About Utility <strong>Subroutines</strong><br />

Utility subroutines are used for accessing current system state information. You typically use this<br />

information as input for defining phenomena or modeling elements that are not available as a part of<br />

standard <strong>Adams</strong>.<br />

For more information about utility subroutines and details about each of the utility subroutines, see<br />

Utility <strong>Subroutines</strong>.<br />

About Callable <strong>Subroutines</strong><br />

3


4<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

MSC no longer supports callable subroutines. If you have questions on callable subroutines, please refer<br />

<strong>to</strong>:<br />

• Knowledge Base (http://support.adams.com/kb/)<br />

• ASK List (http://support.adams.com/services/support/tech_ask.shtm).


Utility <strong>Subroutines</strong><br />

About Utility <strong>Subroutines</strong><br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The utility subroutines provide all the functionality found in the dataset function expressions, and more.<br />

You use utility subroutines <strong>to</strong> perform operations such as the following:<br />

• Access data defined in a model.<br />

• Access current state information.<br />

• Interpolate through raw data using standard curve-fitting techniques.<br />

• Evaluate standard functions.<br />

The utility subroutines are divided in<strong>to</strong> the following categories:<br />

• Execution Control <strong>Subroutines</strong><br />

• Data Access <strong>Subroutines</strong><br />

• Unsupported <strong>Subroutines</strong><br />

Execution Control <strong>Subroutines</strong><br />

CONSUB is the only subroutine that can call execution control subroutines. In conjunction with<br />

ANALYS, DATOUT, and MODIFY, you can use CONSUB <strong>to</strong> control an <strong>Adams</strong> simulation.<br />

ANALYS and MODIFY contain the FORTRAN equivalents of interactive commands <strong>to</strong> initiate analysis<br />

and <strong>to</strong> modify the <strong>Adams</strong>/<strong>Solver</strong> dataset, respectively. DATOUT produces output from the simulation(s).<br />

These subroutines are of most value if you want <strong>to</strong> run many simulations on a single dataset or on<br />

variations of that dataset.<br />

Data Access <strong>Subroutines</strong><br />

Subroutine: Does the following:<br />

ANALYS Performs an <strong>Adams</strong> analysis.<br />

DATOUT Outputs all data for the current time step<br />

in<strong>to</strong> the specified output files.<br />

MODIFY Allows execution of any <strong>Adams</strong>/<strong>Solver</strong><br />

commands, except CONTROL and STOP.<br />

The data access subroutines report the current values for system variables, or return static data s<strong>to</strong>red in<br />

a model. User subroutines can use this data <strong>to</strong> define their output quantities.<br />

The following table lists the names and definitions for the data access subroutines:<br />

5


6<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Subroutine: Does the following:<br />

AKISPL Uses the Akima cubic-curve fitting method <strong>to</strong> interpolate data specified<br />

in a SPLINE statement.<br />

BISTOP Evaluates a BISTOP function.<br />

CHEBY Evaluates a Chebyshev polynomial.<br />

CUBSPL Uses the traditional cubic-curve fitting method <strong>to</strong> interpolate data<br />

specified in a SPLINE statement.<br />

ERRMES Allows user subroutines <strong>to</strong> output information/warning error messages.<br />

FORCOS Evaluates a Fourier cosine series.<br />

FORSIN Evaluates a Fourier sine series.<br />

GETCPU Retrieves the current CPU time.<br />

GETINM Retrieves information as <strong>to</strong> whether the current <strong>Adams</strong>/<strong>Solver</strong><br />

command input mode is interactive or command file-driven.<br />

GETINT Retrieves the type of integra<strong>to</strong>r used for the current simulation.<br />

GETMOD Returns an integer variable that specifies the current analysis mode.<br />

GETSLV Retrieves the name of the active solver, either HARWELL or<br />

CALAHAN.<br />

GETSTM Retrieves the current simulation time.<br />

GETVER Retrieves the current <strong>Adams</strong>/<strong>Solver</strong> version number as it appears in the<br />

<strong>Adams</strong>/<strong>Solver</strong> banner.<br />

GTARAY Accesses the double-precision numbers s<strong>to</strong>red by an IC-type ARRAY<br />

statement.<br />

GTCMAT Computes the compliance matrix for a set of markers in an<br />

<strong>Adams</strong>/<strong>Solver</strong> model.<br />

GTCURV Evaluates a B-spline or user-written curve that a CURVE statement<br />

creates.<br />

GTSTRG Accesses the character string that a STRING statement s<strong>to</strong>res.<br />

GTUNTS Accesses model unit information from <strong>Adams</strong>/<strong>Solver</strong>.<br />

HAVSIN Evaluates a haversine function.<br />

IMPACT Provides a simple contact model.<br />

ISTRNG Converts a number in an integer variable <strong>to</strong> the characters representing<br />

that number. The character data in ISTRNG is always left justified.<br />

Unused space in ISTRNG is padded with blanks.<br />

MODINF Accesses the original mode numbers and the modal frequencies, in<br />

Hertz, of all active modes associated with a FLEX_BODY statement.


Subroutine: Does the following:<br />

Unsupported <strong>Subroutines</strong><br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

NMODES Accesses the number of modal generalized coordinates associated with<br />

a FLEX_BODY statement.<br />

POLY Evaluates a polynomial function.<br />

PUT_SPLINE Passes <strong>Adams</strong>/<strong>Solver</strong> the x, y, and z data that defines a SPLINE element.<br />

RCNVRT Converts rotational coordinates from one representation <strong>to</strong> another.<br />

RSTRNG Converts a double-precision variable <strong>to</strong> a character string.<br />

SHF Evaluates a simple harmonic function.<br />

STEP Approximates a STEP function with a cubic polynomial.<br />

STEP5 Approximates a STEP5 function with a quintic polynomial.<br />

SYSARY Provides system-state values, such as displacement and velocity, <strong>to</strong> your<br />

subroutines, and defines and s<strong>to</strong>res the <strong>Adams</strong>/<strong>Solver</strong> state variables on<br />

which the system states are dependent.<br />

SYSFNC Provides a single-system state value, such as displacement or velocity,<br />

<strong>to</strong> your subroutines, and defines and s<strong>to</strong>res the <strong>Adams</strong>/<strong>Solver</strong> state<br />

variables on which the system state is dependent.<br />

SYSPAR Allows you <strong>to</strong> supply the analytical partial derivatives of a subroutine<br />

with respect <strong>to</strong> values measured through SYSFNC and SYSARY.<br />

TCNVRT Converts translational coordinates from one type of coordinate system<br />

<strong>to</strong> another.<br />

TIMGET Returns the simulation time corresponding <strong>to</strong> the last successful<br />

simulation step.<br />

UCOVAR Used with UCOSUB, tells <strong>Adams</strong>/<strong>Solver</strong> which of the principal axes<br />

coordinates are used in the user-defined constraint.<br />

USRMES Allows you <strong>to</strong> output messages for information or for documenting<br />

errors that occur in user-written subroutines.<br />

Although <strong>Adams</strong>/<strong>Solver</strong> continues <strong>to</strong> recognize unsupported subroutines, new subroutines have made<br />

them obsolete. The new subroutines are more flexible and straightforward <strong>to</strong> use. We recommend that<br />

you use the new subroutines, as the unsupported ones might be removed from future <strong>Adams</strong>/<strong>Solver</strong><br />

releases.<br />

The following table lists the unsupported subroutines, along with references <strong>to</strong> alternate subroutines:<br />

7


8<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Unsupported <strong>Subroutines</strong> and Their Alternates<br />

ADAMS_DECLARE_THREADSAFE<br />

A call <strong>to</strong> the ADAMS_DECLARE_THREADSAFE subroutine informs <strong>Adams</strong>/<strong>Solver</strong> (C++) that the<br />

user-written subroutine is threadsafe and that multiple threads can execute this user-written subroutine<br />

simultaneously.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL ADAMS_DECLARE_THREADSAFE ()<br />

Input Arguments<br />

None<br />

Output Arguments<br />

None<br />

Extended Definition<br />

Instead of: Use:<br />

DEQINF SYSFNC<br />

FNCDEP SYSARY; SYSFNC<br />

INFO SYSARY; SYSFNC<br />

SPLINE AKISPL; CUBSPL<br />

ANLMOD GETMOD<br />

<strong>Adams</strong>/<strong>Solver</strong> (C++) includes the option of threaded (parallel) execution. That is, multiple threads are<br />

permitted <strong>to</strong> execute portions of the code simultaneously. On machines with multiple processors, this can<br />

result in a significant reduction in the wall time required for a simulation <strong>to</strong> complete.<br />

This parallel capability places restrictions on the way the code is written <strong>to</strong> ensure that different threads<br />

do not adversely interact with each other. Code that is written in such a way is threadsafe. Care has been<br />

take <strong>to</strong> ensure that relevant portions of <strong>Adams</strong>/<strong>Solver</strong> (C++) are threadsafe, but no such assumption can


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

be made about user-written subroutines. Consequently, by default, all user-written subroutines are<br />

executed serially. By default, no user-supplied subroutine will take advantage of the parallel capabilities<br />

of <strong>Adams</strong>/<strong>Solver</strong> (C++).<br />

Because complex models often use user-written subroutines extensively, it can greatly improve<br />

performance <strong>to</strong> execute these in parallel, as well. If this is <strong>to</strong> be done, you must ensure that the userwritten<br />

subroutine and its dependants are threadsafe. If so, the user-written subroutine can indicate this<br />

with a call <strong>to</strong> ADAMS_DECLARE_THREADSAFE. This call should occur during subroutine<br />

initialization (iflag = true). <strong>Adams</strong>/<strong>Solver</strong> (C++) then permits threads <strong>to</strong> make simultaneous calls <strong>to</strong> that<br />

user-written subroutine. For more information, see the PREFERENCES statement.<br />

Writing Threadsafe Code<br />

While a complete guide <strong>to</strong> writing parallel code is left <strong>to</strong> other texts, a few general points are covered<br />

here.<br />

Code can be made thread-safe by eliminating any possibility for data (program variables) <strong>to</strong> be shared<br />

between different threads. For example, if all variables in a user-written subroutine were either passed in<br />

as arguments or are dynamically allocated local variables, then that user-written subroutine would be<br />

threadsafe.<br />

Coding in such a manner, however, is often not practical. There may be a need for a user-written<br />

subroutine <strong>to</strong> access constant tabular data or other parameters, which is most efficiently implemented as<br />

global data and shared by multiple threads. To allow for this, during subroutine initialization, all userwritten<br />

subroutines are run serially. In addition, calls <strong>to</strong> REQSUBs are always performed serially.<br />

General Guidelines<br />

1. The only data that can be modified at any time is:<br />

Dynamically allocated local variables.<br />

Static or global variable that are uniquely indexed so there is no possibility that two threads will<br />

modify them simultaneously. For example, a user-written subroutine with a static array of data<br />

could safely modify the array element that is uniquely mapped <strong>to</strong> the ID of the current modeling<br />

element being evaluated. Because each thread is evaluating a different modeling element, the<br />

threads will not access the same array element at the same time.<br />

2. All data that will be shared by multiple threads must be allocated and set during subroutine<br />

initialization. At other times, this data may be read, but must not be written <strong>to</strong>.<br />

3. No special coding practices need <strong>to</strong> be followed inside a REQSUB.<br />

FORTRAN-Specific Guidelines<br />

1. Some FORTRAN compilers (such as Digital/Compaq Visual FORTRAN) statically allocate<br />

local variables by default. This is avoided by using a compiler option (/au<strong>to</strong>matic) that causes all<br />

local variables <strong>to</strong> be allocated on the stack (unless the SAVE statement is used).<br />

9


10<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

2. Avoid or minimize the use of data in COMMON blocks. Such data is statically allocated and<br />

shared between threads. As stated in the General Guidelines above, such data must either be<br />

written during the initialization phase only or uniquely indexed.<br />

3. Avoid or minimize the use of SAVE statements. Again, this data is statically allocated and must<br />

either be written during the initialization phase only or uniquely indexed.<br />

Note: • There is no way <strong>to</strong> specify, ensure, or verify that any modeling element be<br />

evaluated by any particular thread.<br />

ADD_MASS_PROPERTY<br />

The ADD_MASS_PROPERTY utility subroutine accepts the mass properties for two parts or sets of<br />

parts and returns the mass properties for the aggregate set.<br />

It is primarily intended for use with the BODY_MASS_PROPERTY utility subroutine <strong>to</strong> compute the<br />

aggregate mass properties for a group of parts.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

• The use of synchronization constructs within the user-written subroutines<br />

themselves is not recommended. Because user-written subroutines are called so<br />

frequently, it is likely that the overhead of the synchronization will exceed the<br />

benefit of parallelization.<br />

vec<strong>to</strong>r returns: For iord value:<br />

(1)<br />

(2)<br />

0 1 2<br />

F( x, x')<br />

0<br />

∂ F( x, x')<br />

---------------------<br />

∂ x<br />

∂ F( x, x')<br />

---------------------<br />

∂ x'<br />

∂ 2 F( x, x')<br />

x 2<br />

-----------------------<br />

∂<br />

∂ 2 F( x, x')<br />

-----------------------<br />

∂ x'∂<br />

x<br />

Calling Sequence<br />

CALL ADD_MASS_PROPERTY (cm1, mass1, ip1, cm2, mass2, ip2)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

cm1 A double-precision array of length 3 containing the center of mass of the first part or set<br />

of parts expressed in the GCS.<br />

mass1 A double-precision variable containing the mass of the first part or set of parts.<br />

ip1 A double-precision array of length 6 giving the 6 independent terms in the inertia tensor<br />

for the first part or set of parts. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These inertia terms much be<br />

computed about the center of mass of the part and oriented in GCS.<br />

cm2 A double-precision array of length 3 containing the center of mass of the second part or<br />

set of parts expressed in the GCS.<br />

mass2 A double-precision variable containing the mass of the second set.<br />

ip2 A double-precision array of length 6 giving the 6 independent terms in the inertia tensor<br />

for the second part or set of parts. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These inertia terms much<br />

be computed about the center of mass of the part and oriented in GCS.<br />

Output Arguments<br />

cm2 A double-precision array of length 3 containing the center of mass of the combined<br />

system of parts expressed in GCS.<br />

mass2 A double-precision variable containing the mass of the combined system of parts.<br />

Ip2 A double-precision array of length 6 containing the 6 independent components of in the<br />

inertia tensor for the combined system of parts. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These inertia<br />

terms are expressed about the combined center of mass and are oriented in GCS.<br />

Extended Definition<br />

The ADD_MASS_PROPERTY utility subroutine provides a convenient way for user-written<br />

subroutines <strong>to</strong> compute the current mass properties of sets of parts.<br />

Cautions<br />

The user is responsible for employing consistent units when adding mass properties.<br />

Example<br />

C=======================================+===========================<br />

SUBROUTINE REQSUB (ID, TIME, PAR, NPAR, IFLAG, RESULT)<br />

C+-----------------------------------------------------------------*<br />

C<br />

C This REQSUB gets the mass properties of part 2, and constructs the<br />

C aggregate mass properties of the set of parts 3-9 (constructed <strong>to</strong> be<br />

C equivalent, in aggregate, <strong>to</strong> part 2) and returns the first four<br />

terms<br />

C of the inertia tensor for each, 2 and 3-9, for comparison.<br />

C<br />

11


12<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

IMPLICIT NONE<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID, NPAR, IBODY<br />

DOUBLE PRECISION PAR(*), TIME<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION RESULT(8)<br />

C<br />

C Local Variables:<br />

C<br />

DOUBLE PRECISION CM(3), MASS, IP(6)<br />

DOUBLE PRECISION SUMCM(3), SUMMASS, SUMIP(6)<br />

C<br />

C+-----------------------------------------------------------------*<br />

C<br />

C<br />

C Output 8 variables.<br />

C - The first four elements of the IP of the reference body<br />

C - The first four elements of the IP of the equivalent set of<br />

bodies.<br />

C<br />

C Get the properties of the reference body<br />

C<br />

CALL BODY_MASS_PROPERTY ('Part', 2, CM, MASS, IP)<br />

C<br />

RESULT(1) = IP(1)<br />

RESULT(2) = IP(2)<br />

RESULT(3) = IP(3)<br />

RESULT(4) = IP(4)<br />

C<br />

C Get the aggregate properties of the equivalent set of bodies.<br />

C<br />

SUMMASS = 0<br />

SUMCM(1) = 0<br />

SUMCM(2) = 0<br />

SUMCM(3) = 0<br />

SUMIP(1) = 0<br />

SUMIP(2) = 0<br />

SUMIP(3) = 0<br />

SUMIP(4) = 0<br />

SUMIP(5) = 0<br />

SUMIP(6) = 0<br />

DO IBODY=3, 9<br />

CALL BODY_MASS_PROPERTY ('Part', IBODY, CM, MASS, IP)<br />

CALL ADD_MASS_PROPERTY (CM, MASS, IP, SUMCM, SUMMASS, SUMIP)<br />

ENDDO<br />

RESULT (5) = SUMIP(1)<br />

RESULT (6) = SUMIP(2)<br />

RESULT (7) = SUMIP(3)<br />

RESULT (8) = SUMIP(4)


RETURN<br />

END<br />

AKISPL<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The AKISPL data access subroutine uses the Akima cubic-curve fitting method <strong>to</strong> interpolate data from<br />

the SPLINE statement (C++ or FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

SPLINE statement in the dataset<br />

Calling Sequence<br />

CALL AKISPL (xval, zval, id, iord, array, errflg)<br />

13


14<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

xval A double-precision value that specifies the x value at which AKISPL is<br />

<strong>to</strong> interpolate y.<br />

zval A double-precision value that specifies the z value at which AKISPL is<br />

<strong>to</strong> interpolate y.<br />

id An integer variable that specifies the identifier of the corresponding<br />

SPLINE statement.<br />

iord An integer variable that specifies the order of the derivative that AKISPL<br />

is <strong>to</strong> return. The order is usually zero, but it can be one or two.<br />

Output Arguments<br />

array A double-precision array of length three. If iord equals zero, array(1)<br />

returns the value of y that AKISPL calculates. If iord equals one, array<br />

returns:<br />

Extended Definition<br />

∂ y<br />

-----<br />

∂ x<br />

2<br />

y<br />

∂<br />

∂ 2 ------x<br />

AKISPL accesses data in a SPLINE statement (C++ or FORTRAN), using the Akima cubic-curve fitting<br />

method <strong>to</strong> fit a spline <strong>to</strong> the data (that is, <strong>to</strong> add interpolated points), and returns one of the following:<br />

• A value for the dependent variable (y) for each value it receives for the independent variable or<br />

variables.<br />

• The first partial derivatives of the dependent variable.<br />

and , respectively. If iord equals two, array returns:<br />

Note that:<br />

∂ y-----<br />

∂ z<br />

2<br />

y<br />

∂<br />

-----------<br />

∂ x∂ z<br />

2<br />

y<br />

∂<br />

∂ 2 -----z<br />

, , and , respectively.<br />

2<br />

y<br />

∂ ∂<br />

----------- =<br />

-----------<br />

∂ z∂ x ∂ x∂ z<br />

errflg A logical (true or false) variable that AKISPL returns <strong>to</strong> the calling<br />

subroutine. If AKISPL detects an error in its calculations, it sets errflg <strong>to</strong><br />

true before it returns errflg <strong>to</strong> the calling subroutine.<br />

• The second partial derivatives of the dependent variable.<br />

If the spline data input with the SPLINE statement has one independent variable, <strong>Adams</strong>/<strong>Solver</strong> uses a<br />

cubic polynomial <strong>to</strong> interpolate between points. If the spline data has two independent variables,<br />

<strong>Adams</strong>/<strong>Solver</strong> first uses a cubic interpolation method <strong>to</strong> interpolate between points of the first (x)<br />

2<br />

y


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

independent variable, and then uses a linear method <strong>to</strong> interpolate between curves of the second (z)<br />

independent variable.<br />

In addition <strong>to</strong> the AKISPL data access subroutine, <strong>Adams</strong>/<strong>Solver</strong> includes the CUBSPL data access<br />

subroutine, which uses the traditional cubic curve fitting method. Use CUBSPL if the primary usage is<br />

in MOTIONs. Use AKISPL if the primary concern is with the forces or <strong>to</strong>rques acting on a model.<br />

If the spline data incorporates sudden changes in value, the CUBSPL data access subroutine gives more<br />

oscilla<strong>to</strong>ry results for the curve or surface than AKISPL gives. However, the first and second derivatives<br />

of CUBSPL are smoother than those AKISPL calculates.<br />

ANALYS<br />

The ANALYS subroutine performs the analysis requested of it.<br />

Use<br />

Called By<br />

CONSUB<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL ANALYS (antype, cid, timbeg, timend, init, istat)<br />

15


16<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

antype One of the character strings, DYNAMICS, KINEMATICS, STATICS,<br />

or TRANSIENT, that indicate the analysis type <strong>Adams</strong>/<strong>Solver</strong> is <strong>to</strong><br />

perform.<br />

cid A character string or variable associated with this analysis. If the<br />

CONSUB driver subroutine calls DATOUT, <strong>Adams</strong>/<strong>Solver</strong> prints the<br />

current value of cid (truncated <strong>to</strong> twenty characters) in the IDANAL<br />

field of the analysis output block in the results file.<br />

timbeg A double-precision value that specifies the time at which you want the<br />

analysis <strong>to</strong> begin. This must equal the current simulation time. If it does<br />

not equal the current simulation time, <strong>Adams</strong>/<strong>Solver</strong> issues an error<br />

message, s<strong>to</strong>ps the simulation, and returns <strong>to</strong> the calling subroutine.<br />

timend A double-precision value that specifies the time at which you want the<br />

analysis <strong>to</strong> end. The value must be greater than or equal <strong>to</strong> timbeg. If<br />

timend is less than timbeg, <strong>Adams</strong>/<strong>Solver</strong> issues an error message,<br />

s<strong>to</strong>ps the simulation, and returns <strong>to</strong> the calling subroutine.<br />

Output Argument<br />

Extended Definition<br />

Note that <strong>Adams</strong>/<strong>Solver</strong> modifies this argument <strong>to</strong> reflect the<br />

simulation time <strong>to</strong> which the simulation has progressed. Therefore, you<br />

must be careful <strong>to</strong> pass a double-precision variable, not a constant, in<br />

the argument list for this variable. Passing in a constant can result in a<br />

fatal error or program crash.<br />

init A logical variable that tells <strong>Adams</strong> whether or not it should reformulate<br />

the equations of motion and perform system assembly at the start of the<br />

simulation.<br />

istat An integer variable that indicates either the success or the reason for the<br />

failure of the call <strong>to</strong> ANALYS.<br />

If: Then:<br />

istat = 0 The call <strong>to</strong> ANALYS was successful.<br />

istat = -1 antype is neither DYNAMICS, KINEMATICS, STATICS, nor<br />

TRANSIENT.<br />

istat = -9 timbeg is not equal <strong>to</strong> the current simulation time.<br />

istat =-10 timend is less than timbeg.<br />

ANALYS passes control <strong>to</strong> the <strong>Adams</strong>/<strong>Solver</strong> simulation routines. <strong>Adams</strong>/<strong>Solver</strong> performs the analysis


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

requested. This gives you complete control over the time for which <strong>to</strong> get a simulation.<br />

Call ANALYS from CONSUB as often as necessary <strong>to</strong> create the simulation required. After completion<br />

of each analysis, <strong>Adams</strong>/<strong>Solver</strong> returns program control <strong>to</strong> CONSUB. For an example of a CONSUB<br />

driver subroutine that calls ANALYS, see CONSUB.<br />

Caution: • ANALYS may only be called by CONSUB.<br />

BISTOP<br />

BISTOP evaluates a BISTOP function (C++ or FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

• <strong>Adams</strong>/<strong>Solver</strong> must generate the state equations before performing any analysis. If<br />

an analysis has been performed before ANALYS is called, the equations have<br />

already been set up for that type of analysis. Set init equal <strong>to</strong> true on the first call <strong>to</strong><br />

ANALYS, otherwise.<br />

• When program control passes <strong>to</strong> CONSUB, au<strong>to</strong>matic generation of output s<strong>to</strong>ps.<br />

To generate output, call DATOUT.<br />

CALL BISTOP (x, x', x1, x2, k, e, cmax, d, iord, vec<strong>to</strong>r, errflg)<br />

17


18<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

x A double-precision variable that specifies the deformation <strong>to</strong> be used <strong>to</strong><br />

compute the force.<br />

x' A double-precision variable containing the first time derivative of x.<br />

x1 A double-precision variable that specifies the lower bound of x. If x is less<br />

than x1, <strong>Adams</strong>/<strong>Solver</strong> calculates a positive value for the force. The value of<br />

x1 must be less than the value of x2.<br />

x2 A double-precision variable that specifies the upper bound of x. If<br />

x is greater than x2, <strong>Adams</strong>/<strong>Solver</strong> calculates a negative value for the force.<br />

The value of x2 must be greater than the value of x1.<br />

k A positive, double-precision variable that specifies the stiffness for the<br />

force-deformation law.<br />

e A positive, double-precision variable that specifies the exponent in the forcedeformation<br />

law. For a stiffening spring characteristic, use e > 1.0. For a<br />

softening spring characteristic, use 0 < e < 1.0.<br />

cmax A non-negative, double-precision variable that specifies the maximum<br />

damping coefficient that is <strong>to</strong> be applied.<br />

d A positive, double-precision variable that specifies the pe<strong>net</strong>ration at which<br />

<strong>Adams</strong>/<strong>Solver</strong> applies full damping, CMAX.<br />

iord An integer variable that specifies the order of the derivative that BISTOP is<br />

<strong>to</strong> return. IORD can be zero, one, or two.<br />

Output Arguments<br />

vec<strong>to</strong>r A double-precision vec<strong>to</strong>r that returns the values calculated by the<br />

subroutine. For BISTOP, vec<strong>to</strong>r is a vec<strong>to</strong>r of length three. The following<br />

table indicates what information vec<strong>to</strong>r returns for each of the possible values<br />

of iord.<br />

errflg A logical (true or false) variable that BISTOP returns <strong>to</strong> the calling<br />

subroutine. If BISTOP detects an error in a subroutine call statement, it sets<br />

errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

Extended Definition<br />

The BISTOP function models a force restricting the displacement of a body relative <strong>to</strong> a gap in another<br />

body.<br />

The force BISTOP evaluates is zero, as long as the floating part lies within the gap in the restricting body.<br />

It is nonzero when the floating part tries <strong>to</strong> move beyond the gap boundaries in either direction.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The force has two components: a spring or stiffness component and a damping or viscous component.<br />

The stiffness component is a function of the pe<strong>net</strong>ration of the floating part in<strong>to</strong> the restricting part. The<br />

stiffness opposes the pe<strong>net</strong>ration.<br />

The damping component of the force is a function of the speed of pe<strong>net</strong>ration multiplied by a damping<br />

coefficient. The damping opposes the direction of relative motion. To prevent a discontinuity in the<br />

damping force at contact, the damping coefficient is, by definition, a cubic step function of the<br />

pe<strong>net</strong>ration. Therefore, at zero pe<strong>net</strong>ration, the damping coefficient is always zero. The damping<br />

coefficient achieves a maximum, cmax, at a user-defined pe<strong>net</strong>ration, d. Even though the points of<br />

contact between the floating part and the restricting part may change as the system moves, <strong>Adams</strong>/<strong>Solver</strong><br />

always exerts the force between the I and the J markers. Examples of systems you can model with the<br />

BISTOP function include a ball rebounding between two walls and a slider moving in a slot. The slider<br />

is the floating body, and the part containing the slot is the restricting body. As long as the slider remains<br />

within the confines of the slot, there is no force acting on the slider. But if the slider tries <strong>to</strong> move beyond<br />

the slot, a force turns on, effectively preventing the slider's escape.<br />

The following summarizes the BISTOP function:<br />

• When x1 x x2, force = 0.<br />

• When x < x1, p = x1 - x and the force is positive.<br />

• When x > x2, p = x - x2 and the force is negative.<br />

• When p < d, the damping coefficient is a cubic step function of the pe<strong>net</strong>ration.<br />

• When p d, the damping coefficient is cmax.<br />

The values of k, e, cmax, and d depend on the materials used in the two parts and on the shapes<br />

of the parts.<br />

The following equation defines BISTOP:<br />

STOP<br />

Min k ( x1 – x)<br />

e ( ⋅ – STEP ( x, x1 – d, cmax, x10) ⋅x′0<br />

, )<br />

0<br />

Max – k ( x – x2) e ⎧<br />

x < x1 ⎪<br />

= ⎨<br />

x1 ≤x ≤x2<br />

⎪<br />

⎩ ( ⋅ – STEP ( x, x2, 0, x2 + d, cmax ) ⋅x′0<br />

, ) x > x2 See an explanation of the STEP function (C++ or FORTRAN).<br />

Caution: • BISTOP is only used <strong>to</strong> determine forces or <strong>to</strong>rques.<br />

• When e is less than or equal <strong>to</strong> one, the rate of change of the force is discontinuous<br />

at contact. This may cause convergence problems.<br />

BODY_MASS_PROPERTY<br />

The BODY_MASS_PROPERTY utility subroutine accepts specifiers for either a single part or the entire<br />

ADAMS model and returns <strong>to</strong> the caller the mass properties (mass, center of mass and inertia tensor) for<br />

that part or model.<br />

19


20<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Called By<br />

Any of a REQSUB, SENSUB, SEVSUB or CONSUB.<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL BODY_MASS_PROPERTY (type, id, cm, mass, ip)<br />

Input Arguments<br />

type A character variable that specifies the type of modeling element for which the mass<br />

properties are requested. The valid options are one of "Part", "Point_Mass",<br />

"Flex_Body" or "Model". The input is case-insensitive but abbreviations are not<br />

permitted.<br />

id An integer variable that specifies the ID of the element of the type specified for which<br />

the mass properties are requested. If the type is "Model" then this input is ignored.<br />

For all other types this is required.<br />

Output Arguments<br />

cm A double-precision array of length 3 containing the center of mass of the requested<br />

modeling element expressed in GCS.<br />

mass A double-precision variable containing the mass of the requested modeling element.<br />

ip A double-precision array of length 6 containing the 6 independent components of in<br />

the inertia tensor for requested modeling element. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These<br />

inertia terms are expressed about the elements center of mass and are oriented in GCS.<br />

Caution: The BODY_MASS_PROPERTY utility subroutine provides access <strong>to</strong> state-dependent<br />

information <strong>to</strong> the user-written subroutines. However, since this information is expected<br />

<strong>to</strong> be used only for moni<strong>to</strong>ring and control purposes and not <strong>to</strong> affect the dynamics, no<br />

functional dependencies are registered. Consequently, this utility subroutine can only be<br />

called from the user-written subroutines that cannot add functional dependencies -<br />

REQSUB, SENSUB, SEVSUB and CONSUB.<br />

CHEBY<br />

The CHEBY subroutine evaluates a Chebyshev polynomial.


Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisites<br />

None<br />

Calling Sequence<br />

CALL CHEBY (x, x0, par, npar, iord, value, errflg)<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

21


22<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies a shift in the Chebyshev<br />

polynomial.<br />

par A double-precision array of coefficients (a0,...,an).<br />

npar An integer variable that specifies the number of coefficients specified.<br />

iord An integer variable that specifies the order of the derivative that CHEBY<br />

is <strong>to</strong> return. IORD can be zero, one, or two.<br />

Output Arguments<br />

value A double-precision value the subroutine returns. The table below<br />

summarizes the value it returns:<br />

errflg A logical (true or false) variable that CHEBY returns <strong>to</strong> the calling<br />

subroutine. If CHEBY detects an error in the subroutine call statement,<br />

it sets errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

Extended Definition<br />

CHEBY evaluates a Chebyshev polynomial. The following equation defines CHEBY:<br />

where:<br />

and:<br />

0<br />

1<br />

2<br />

,<br />

IORD: Value:<br />

F( x)<br />

∂ F( x)<br />

--------------<br />

∂ x<br />

∂ F 2 ( x)<br />

∂ x 2<br />

----------------<br />

Tj( x – x0) – 2 ⋅( x – x0) ⋅Tj<br />

– 1( ( x – x0) ⋅Tj<br />

– 2( x – x0) )<br />

T0( x – x0) =<br />

1<br />

,


T1( x – x0) =<br />

x – x0 CUBSPL<br />

,<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

CUBSPL uses the traditional cubic-curve fitting method <strong>to</strong> interpolate data in the SPLINE statement<br />

(C++ or FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

SPLINE statement in the dataset<br />

Calling Sequence<br />

j = 0<br />

ajTj( x – x0) CALL CUBSPL (xval, zval, id, iord, array, errflg)<br />

N<br />

∑<br />

23


24<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

xval A double-precision value that specifies the x value at which CUBSPL<br />

is <strong>to</strong> interpolate y.<br />

zval A double-precision value that specifies the z value at which CUBSPL<br />

is <strong>to</strong> interpolate y.<br />

id An integer variable that specifies the identifier of the corresponding<br />

SPLINE statement.<br />

iord An integer variable that specifies the order of the derivative that<br />

CUBSPL is <strong>to</strong> return. The order is usually zero, but can be one or two.


Output Arguments<br />

Extended Definition<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

array A double-precision array of length three. The values contained in array<br />

depend on IORD. The table below summarizes what array is <strong>to</strong> contain:<br />

IORD: Array:<br />

0 The interpolated value of<br />

y<br />

Array(0) = y<br />

Array(1) = 0<br />

Array(2) = 0<br />

1 The first partial<br />

derivatives of y with<br />

respect <strong>to</strong> x and z. Array(1) =<br />

2 The second partial<br />

derivatives of y with<br />

respect <strong>to</strong> x and z.<br />

Note that:<br />

∂ 2 y<br />

-----------<br />

∂ z∂ x<br />

Array(2) =<br />

Array(3) = 0<br />

Array(1) =<br />

Array(2) =<br />

Array(3) =<br />

errflg A logical (true or false) variable that CUBSPL returns <strong>to</strong> the calling<br />

subroutine. If CUBSPL detects an error in its calculations, it sets errflg<br />

<strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

CUBSPL accesses data in a SPLINE statement, using the traditional cubic curve-fitting method <strong>to</strong> fit a<br />

spline <strong>to</strong> the data, and returns one of the following:<br />

• A value for the dependent variable (y) for each value it receives for the independent variable or<br />

variables.<br />

• The first partial derivatives of y with respect <strong>to</strong> the dependent variable(s).<br />

=<br />

∂ 2 y<br />

-----------<br />

∂ x∂ z<br />

∂ y<br />

-----<br />

∂ x<br />

∂ y<br />

-----<br />

∂ z<br />

∂ 2 y<br />

∂ 2 -------x<br />

∂ 2 y<br />

-----------<br />

∂ x∂ z<br />

∂ 2 y<br />

--------<br />

25


26<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

• The second partial derivatives of y with respect <strong>to</strong> the dependent variable(s).<br />

If the spline data input with the SPLINE statement has one independent variable, <strong>Adams</strong>/<strong>Solver</strong> uses a<br />

cubic polynomial <strong>to</strong> interpolate between points. If the spline data has two independent variables,<br />

<strong>Adams</strong>/<strong>Solver</strong> first uses a cubic interpolation method <strong>to</strong> interpolate between points of the first (x)<br />

independent variable, and then uses a linear method <strong>to</strong> interpolate between curves of the second (z)<br />

independent variable.<br />

In addition <strong>to</strong> CUBSPL, <strong>Adams</strong>/<strong>Solver</strong> includes the AKISPL data access subroutine, which uses the<br />

Akima cubic curve-fitting method. Use CUBSPL when defining motion inputs. Use AKISPL if the<br />

primary concern is with the forces or <strong>to</strong>rques acting on the model.<br />

If the spline data incorporates sudden changes in value, CUBSPL gives more oscilla<strong>to</strong>ry results for the<br />

curve or surface than are given by the AKISPL data access subroutine. However, the first and second<br />

derivatives are smoother than those of the curve or surface given by AKISPL. This may be an important<br />

consideration. For example, if one of these spline subroutines is used <strong>to</strong> define a motion, <strong>Adams</strong>/<strong>Solver</strong><br />

uses the second derivative <strong>to</strong> compute the force or <strong>to</strong>rque attributable <strong>to</strong> the motion. It also uses the first<br />

and second derivatives <strong>to</strong> calculate results. If one of these spline subroutines is used <strong>to</strong> define a force, the<br />

dependent values give the force, and <strong>Adams</strong>/<strong>Solver</strong> uses the first derivative <strong>to</strong> calculate results.<br />

DATOUT<br />

DATOUT outputs all data from a simulation initiated by the ANALYS execution control subroutine.<br />

Depending on the statements in the dataset, <strong>Adams</strong>/<strong>Solver</strong> may output data <strong>to</strong> the request, graphics,<br />

results, and FEM files.<br />

Use<br />

Called By<br />

CONSUB<br />

Prerequisite<br />

Call <strong>to</strong> ANALYS<br />

Calling Sequence<br />

CALL DATOUT (istat) Output Argument<br />

istat An integer variable that indicates whether the call <strong>to</strong> DATOUT was<br />

successful. If istat = 0, the call <strong>to</strong> DATOUT was successful. Currently,<br />

<strong>Adams</strong>/<strong>Solver</strong> always returns a value of zero. You do not need <strong>to</strong> check istat<br />

before continuing.


Extended Definition<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

DATOUT outputs data from a simulation initiated by ANALYS. When you advance the simulation by a<br />

call <strong>to</strong> ANALYS, <strong>Adams</strong>/<strong>Solver</strong> does not au<strong>to</strong>matically output data. If you want <strong>to</strong> process output (for<br />

example, requests, graphics), call DATOUT from the CONSUB driver subroutine. In this way, you can<br />

choose the type and amount of output. For an example of a CONSUB driver subroutine that calls<br />

DATOUT, see CONSUB.<br />

ERRMES<br />

ERRMES provides the facility for outputting error messages from user-written subroutines.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL ERRMES (errflg, mesage, id, endflg)<br />

Input Arguments<br />

errflg A logical (true or false) variable. When errflg is true, ERRMES writes the<br />

message passed in <strong>to</strong> its output files.<br />

mesage A character string or variable of as many as eighty characters that you want<br />

ERRMES <strong>to</strong> document when the subroutine has an error. This character string<br />

should be a descriptive message and should include the name of the<br />

subroutine with the error.<br />

id An integer variable that specifies the identifier of the statement that is<br />

currently invoking the user-written subroutine.<br />

endflg A character variable that s<strong>to</strong>ps execution when it equals STOP. If endflg has<br />

any other value, <strong>Adams</strong>/<strong>Solver</strong> continues execution.<br />

Extended Definition<br />

The ERRMES data access subroutine allows you <strong>to</strong> output messages <strong>to</strong> document errors that occur in<br />

user-written subroutines. The messages always go <strong>to</strong> the message file, and during interactive execution,<br />

<strong>Adams</strong>/<strong>Solver</strong> displays them on the screen.<br />

27


28<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Although ERRMES can be called in response <strong>to</strong> any execution problem, it should always be called in<br />

response <strong>to</strong> a data access or a general subroutine call that returns an error flag. For an example of a<br />

DIFSUB evaluation subroutine that calls ERRMES, see DIFSUB.<br />

FORCOS<br />

FORCOS evaluates a Fourier cosine series.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL FORCOS (x, x0, w, par, npar, iord, value, errflg)


Input Arguments<br />

Output Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies a shift in the Fourier cosine<br />

function.<br />

w A double-precision variable that specifies the fundamental frequency of the<br />

series. The variable w must be in radians per unit of the independent<br />

variable.<br />

par A double-precision array of coefficients (a0,...,an).<br />

npar An integer variable that indicates the number of coefficients specified in the<br />

Fournier cosine series.<br />

iord An integer variable that defines the order of the derivative that FORCOS is<br />

<strong>to</strong> return. IORD can be zero, one, or two.<br />

errflg A logical (true or false) variable that FORCOS returns <strong>to</strong> the calling<br />

subroutine. If FORCOS detects an error in the subroutine call statement, it<br />

sets errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

value A double-precision number returned by FORCOS. The meaning of the<br />

quantity depends on the value of IORD. The table below explains in more<br />

detail:<br />

IORD: Value:<br />

0 Value of the FORCOS function.<br />

1 Partial derivative of the FORCOS<br />

function with respect <strong>to</strong> the<br />

independent variable, x.<br />

2 Second partial derivative of the<br />

FORCOS function with respect <strong>to</strong><br />

the independent variable, x.<br />

F( x)<br />

∂ F<br />

-----<br />

∂ x<br />

∂ 2 F<br />

∂ 2 -------x<br />

29


30<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Extended Definition<br />

FORCOS evaluates a Fourier cosine series. The following equation defines FORCOS:<br />

n<br />

∑<br />

j = 0<br />

where:<br />

For an example of a MOTSUB evaluation subroutine that calls FORCOS, see MOTSUB.<br />

FORSIN<br />

FORSIN evaluates a Fourier sine series.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

ajTj ( x – x0) Tj( x – x0) =<br />

cos(<br />

j ⋅w ⋅(<br />

x – x0) )<br />

Calling Sequence<br />

CALL FORSIN (x, x0, w, par, npar, iord, value, errflg)


Input Arguments<br />

Output Arguments<br />

Extended Definition<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

x A double-precision variable that specifies the independent variable. If the<br />

independent variable in the function is time, x is the system variable TIME<br />

(click here <strong>to</strong> see the FORTRAN version of the TIME function or for C++,<br />

click here).<br />

x0 A double-precision variable that specifies a shift in the Fourier sine<br />

function.<br />

w A double-precision variable that specifies the fundamental frequency of<br />

the series. The variable w must be in radians per unit of the independent<br />

variable.<br />

par A double-precision array of coefficients (a0,...,an).<br />

npar An integer variable that indicates the number of coefficients specified in<br />

the Fournier sine series.<br />

iord An integer variable that defines the order of the derivative that FORSIN is<br />

<strong>to</strong> return. IORD can be zero, one, or two.<br />

errflg A logical (true or false) variable that FORSIN returns <strong>to</strong> the calling<br />

subroutine. If FORSIN detects an error in the subroutine call statement, it<br />

sets errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

value A double-precision number returned by FORSIN. The meaning of the<br />

quantity depends on the value of IORD. The table below explains in more<br />

detail:<br />

IORD: Value:<br />

0 Value of the FORSIN function.<br />

1 Partial derivative of the FORSIN<br />

function with respect <strong>to</strong> the<br />

independent variable, x.<br />

2 Second partial derivative of the<br />

FORSIN function with respect <strong>to</strong> the<br />

independent variable, x.<br />

F( x)<br />

∂ F<br />

-----<br />

∂ x<br />

∂ 2 F<br />

∂ 2 -------x<br />

31


32<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

FORSIN evaluates a Fourier sine series. The following equation defines FORSIN:<br />

n<br />

∑<br />

j = 0<br />

where:<br />

GET_FULL_MATRIX_DATA<br />

Returns the values entered in a dataset MATRIX statement (C++ or FORTRAN) of type full, given the<br />

statement identifier.<br />

Use<br />

ajTj ( x – x0) Tj( x – x0) =<br />

cos(<br />

j ⋅w ⋅(<br />

x – x0) )<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

MATRIX statement in the dataset<br />

Calling Sequence<br />

GET_FULL_MATRIX_DATA(id, vals, size, ierr)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that specifies the ID of the corresponding MATRIX<br />

statement.<br />

size An integer variable that specifies the size of the MATRIX.<br />

GET_FULL_MATRIX_DATA uses this value <strong>to</strong> compare against the<br />

MATRIX’s true size; a check for a valid call.<br />

Output Arguments<br />

vals A double-precision array of size ‘size’ contains the values from the<br />

MATRIX statement.<br />

ierr An integer variable that indicates the success of the call <strong>to</strong><br />

GET_FULL_MATRIX_DATA:<br />

Extended Definition<br />

GET_FULL_MATRIX_DATA returns the values s<strong>to</strong>red in a dataset MATRIX statement of type full. You<br />

can determine the matrix ordering of the matrix data (row or column ordered), by the type that<br />

GET_MATRIX_INFO returns. The order may not be as entered in the MATRIX statement.<br />

GET_MATRIX_INFO<br />

Returns information about a dataset MATRIX statement given the statement identifier (C++ or<br />

FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

MATRIX statement in the dataset<br />

• ierr=0 Successful<br />

• ierr=1 Failed, no MATRIX having an<br />

identifier of ID exists in the dataset<br />

• ierr=2 Failed, the value of ‘size’ does not<br />

match the size of the MATRIX<br />

• ierr=3 Failed, the MATRIX type is sparse<br />

Tip: Call GET_MATRIX_INFO <strong>to</strong> get the size and type of the MATRIX.<br />

33


34<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Calling Sequence<br />

GET_MATRIX_INFO(id, type, nrows, ncols, size, ierr)<br />

Input Arguments<br />

id An integer variable that specifies the ID of the corresponding MATRIX<br />

statement.<br />

Output Arguments<br />

type An integer value that indicates the MATRIX type as s<strong>to</strong>red by <strong>Adams</strong>/<strong>Solver</strong>.<br />

Extended Definition<br />

GET_MATRIX_INFO is useful when used with the GET_FULL_MATRIX_DATA and<br />

GET_SPARSE_MATRIX_DATA utility subroutines. It returns:<br />

• Matrix type needed <strong>to</strong> determine which utility <strong>to</strong> call <strong>to</strong> get the MATRIX data<br />

• MATRIX size needed in the call <strong>to</strong> GET_FULL_MATRIX_DATA or<br />

GET_SPARSE_MATRIX_DATA<br />

• Number of rows and columns needed <strong>to</strong> interpret the full matrix data.<br />

GET_GRAVITY<br />

• type=1 Sparse<br />

• type=2 Full, row-order<br />

• type=3 Full, column-order<br />

nrows An integer variable that contains the number of rows in the MATRIX.<br />

ncols An integer variable that contains the number of columns in the MATRIX.<br />

size An integer value that contains the <strong>to</strong>tal number of entries in a sparse MATRIX.<br />

For a full matrix, size is ncols*nrows.<br />

ierr An integer variable that indicated the success of the call <strong>to</strong><br />

GET_MATRIX_INFO.<br />

• ierr=0 Successful<br />

• ierr=1 Failed, no MATRIX having an<br />

identifier of id exists in the dataset<br />

Returns the current <strong>Adams</strong>/<strong>Solver</strong> gravity vec<strong>to</strong>r. Specifically this is the gravity vec<strong>to</strong>r that would have<br />

been specified by the ACCGRAV statement or command. See the ACCGRAV documentation for more<br />

details.


Use<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Use this utility subroutine <strong>to</strong> obtain the <strong>Adams</strong> gravity vec<strong>to</strong>r from a user-written subroutine.<br />

Called by<br />

Any user-written subroutine.<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GET_GRAVITY (GX, GY, GX)<br />

Input Arguments<br />

None<br />

Output Arguments<br />

GX A double-precision variable containing the x component of gravitational<br />

acceleration with respect <strong>to</strong> the ground coordinate system (GCS) in model<br />

units.<br />

GY A double-precision variable containing the ycomponent of gravitational<br />

acceleration with respect <strong>to</strong> the ground coordinate system (GCS) in model<br />

units.<br />

GZ A double-precision variable containing the zcomponent of gravitational<br />

acceleration with respect <strong>to</strong> the ground coordinate system (GCS) in model<br />

units.<br />

GET_SPARSE_MATRIX_DATA<br />

Returns the values entered in a dataset MATRIX statement (C++ or FORTRAN) in sparse matrix form<br />

given the statement identifier.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

MATRIX statement in the dataset<br />

35


36<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Calling Sequence<br />

GET_SPARSE_MATRIX_DATA(id, rows, cols, vals, size, ierr)<br />

Input Arguments<br />

id An integer variable that specifies the ID of the corresponding MATRIX<br />

statement.<br />

size An integer variable that specifies the size of the MATRIX.<br />

GET_SPARSE_MATRIX_DATA uses this value <strong>to</strong> compare against the<br />

MATRIX’s true size; a check for a valid call.<br />

Output Arguments<br />

rows An integer array of size size that contains the row indices corresponding <strong>to</strong> the<br />

MATRIX values s<strong>to</strong>red in vals.<br />

cols An integer array of size size that contains the column indices corresponding<br />

<strong>to</strong> the MATRIX values s<strong>to</strong>red in vals.<br />

vals A double-precision array of size size that contains the values from the<br />

MATRIX statement in sparse form.<br />

ierr An integer variable that indicates the success of the call <strong>to</strong><br />

GET_SPARSE_MATRIX_DATA:<br />

Extended Definition<br />

GET_SPARSE_MATRIX_DATA returns the values entered in a dataset MATRIX statement in sparse<br />

matrix form. It can be used with any matrix type, but may be inefficient for a large MATRIX of type full.<br />

Sparse matrix form is a compact way of s<strong>to</strong>ring matrix data when many data entries are zero; only the<br />

non-zero values are s<strong>to</strong>red. The rows and cols arrays provides the row and column matrix locations for<br />

the corresponding data in the vals array. When using GET_SPARSE_MATRIX_DATA <strong>to</strong> get data of a<br />

matrix type full, all values are returned. GET_SPARSE_MATRIX_DATA makes no attempt <strong>to</strong> reduce<br />

the size of the data by eliminating zero entries.<br />

GETCPU<br />

• ierr=0 Successful<br />

• ierr=1 Failed, no MATRIX having an identifier of ID<br />

exists in the dataset<br />

• ierr=2 Failed, the value of size’ does not match the<br />

size of the MATRIX<br />

Tip: Call GET_MATRIX_INFO <strong>to</strong> get the size and type of the MATRIX.


GETCPU retrieves CPU time used so far.<br />

Use<br />

Called by<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GETCPU (value)<br />

Output Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

value Double-precision variable that contains the current CPU time.<br />

GETINM<br />

The GETINM reports whether the current <strong>Adams</strong>/<strong>Solver</strong> command input mode is interactive or<br />

command file-driven.<br />

Use<br />

Called by<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GETINM (value)<br />

Output Argument<br />

value A logical variable that returns true if the <strong>Adams</strong>/<strong>Solver</strong> command input mode<br />

is interactive, and false if it is command file-driven.<br />

GETINT<br />

37


38<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

The GETINT data access subroutine retrieves the type of integra<strong>to</strong>r used for the current simulation. The<br />

strings GETINT returns <strong>to</strong> indicate the integra<strong>to</strong>r type are: ABAM, GSTIFF, GSTIFF_SI2, GSTIFF_SI1,<br />

WSTIFF, WSTIFF_SI2 and WSTIFF_SI1.<br />

Use<br />

Called by<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GETINT (value)<br />

Output Argument<br />

value A character variable of ten characters containing the integra<strong>to</strong>r type.<br />

Extended Definition<br />

GETINT returns the type of integra<strong>to</strong>r used for the current simulation. It can have one of the following<br />

values:<br />

• ABAM - <strong>Adams</strong>-Bashforth-<strong>Adams</strong>-Moul<strong>to</strong>n integra<strong>to</strong>r<br />

• GSTIFF - The fixed coefficient BDF integra<strong>to</strong>r using an index three equation formulation<br />

• GSTIFF_SI2- The fixed coefficient BDF integra<strong>to</strong>r using a stabilized index two equation<br />

formulation<br />

• GSTIFF_SI1- The fixed coefficient BDF integra<strong>to</strong>r using a stabilized index one equation<br />

formulation<br />

• WSTIFF - The variable coefficient BDF integra<strong>to</strong>r<br />

• WSTIFF_SI2 - The fixed coefficient BDF integra<strong>to</strong>r using a stabilized index two equation<br />

formulation<br />

• WSTIFF_SI1- The fixed coefficient BDF integra<strong>to</strong>r using a stabilized index one equation<br />

formulation<br />

• UNDEF - The integra<strong>to</strong>r is undefined<br />

Caution: Value is meaningful only during a simulation, that is, after you have issued a SIMULATE<br />

command.<br />

GETMOD


GETMOD returns the current analysis mode.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Calling Sequence<br />

CALL GETMOD (mode)<br />

Output Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

mode An integer variable that specifies the current analysis mode.<br />

GETSLV<br />

GETSLV returns the name of the active solver, either HARWELL or CALAHAN.<br />

Use<br />

Called by<br />

Any user-written subroutine<br />

Variable: Analysis mode:<br />

mode=1 Kinematics<br />

mode=2 Reserved<br />

mode=3 Initial conditions<br />

mode=4 Dynamics<br />

mode=5 Statics<br />

mode=6 Quasi-statics<br />

mode=7 Linearization<br />

Caution: GETMOD should be called from a user-written subroutine only when iflag is false. (That<br />

is, GETMOD should not be called during the subroutine initialization.) Calls <strong>to</strong> GETMOD<br />

when iflag is true can result in erroneous mode information.<br />

39


40<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GETSLV (value)<br />

Output Argument<br />

value A character*7 variable containing the name of the solver; HARWELL for the<br />

Harwell solver or CALAHAN for the Calahan solver.<br />

Caution: Value is meaningful only during a simulation, that is, after you have issued a SIMULATE<br />

command.<br />

GETSTM<br />

GETSTM returns the current simulation time.<br />

Use<br />

Called by<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GETSTM (VALUE)<br />

Output Argument<br />

value A double-precision variable containing the current simulation time.<br />

Caution: Value is meaningful only during a simulation, that is, after you have issued a SIMULATE<br />

command.<br />

GETVER<br />

GETVER returns the current <strong>Adams</strong>/<strong>Solver</strong> version number as it appears in the <strong>Adams</strong>/<strong>Solver</strong> banner.


Use<br />

Called by<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GETVER (value)<br />

Output Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

value A character*10 variable that contains the <strong>Adams</strong>/<strong>Solver</strong> version number.<br />

GSE<br />

Starting with the 2005r2 release, <strong>Adams</strong>/<strong>Solver</strong> (C++), returns a “+” as<br />

the last character in value. <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN) leaves this<br />

character blank. Among other uses, this permits the user-supplied<br />

subroutine <strong>to</strong> determine which version of the solver, C++ or FORTRAN,<br />

is being used with it.<br />

The following defines a set of utility subroutines which are <strong>to</strong> be used in the GSE_DERIV and<br />

GSE_OUTPUT user subroutines that are associated with the GSE element.<br />

These utilities supplement and enhance the SYSARY and SYSPAR utility subroutines that are used in<br />

<strong>Adams</strong>/<strong>Solver</strong> (FORTRAN) <strong>to</strong> access the input and state arrays of the GSE, and provide the derivatives<br />

of the GSE.<br />

If you are using <strong>Adams</strong>/<strong>Solver</strong> (C++), you should use the utility subroutines described here rather than<br />

SYSARY and SYSPAR because they are more efficient and they permit access <strong>to</strong> enhanced GSE<br />

capabilities (sparse GSE and implicit GSE).<br />

The utility subroutines can be grouped in<strong>to</strong> the following categories:<br />

• Dimension query utilities (GSE_NS, GSE_ND, GSE_NI, GSO_NO)<br />

• Array query utilities (GSE_X, GSE_XDOT, GSE_U, GSE_XD)<br />

• Partial-derivative entry utilities (GSEPAR_X, GSEPAR_U, GSEPAR_XDOT)<br />

• Partial-derivative mapping utilities (GSEMAP_X, GSEMAP_U, GSEMAP_XDOT)<br />

Note that none of the utility subroutines require that the ID of the GSE be provided. <strong>Adams</strong>/<strong>Solver</strong> knows<br />

which GSE is being referred <strong>to</strong>.<br />

41


42<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Dimension Query Utilities: GSE_NS, GSE_ND, GSE_NI, GSE_NO<br />

The dimension query utility subroutines are called <strong>to</strong> obtain information about the dimension of the<br />

various arrays associated with the GSE. Access <strong>to</strong> this information allows proper dimensioning of arrays.<br />

The dimensions obtained from these utilities must be passed <strong>to</strong> other utility subroutines as verification<br />

that the subroutine developer is aware of the required array dimension.<br />

Each of the dimension query utility subroutines takes a single integer argument. After the call <strong>to</strong> the<br />

subroutine, the integer contains the associated dimension.<br />

Called By<br />

GSE_DERIV, GSE_OUTPUT<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GSE_NS(NS)<br />

CALL GSE_ND(ND)<br />

CALL GSE_NI(NI)<br />

CALL GSE_NO(NO)<br />

Arguments<br />

NS Output integer - the number of states<br />

ND Output integer - the number of discrete states<br />

NI Output integer - the number of inputs<br />

NO Output integer - the number of outputs<br />

Array query utility subroutines: GSE_X, GSE_XDOT, GSE_XD, GSE_U<br />

The array query utility subroutines are called <strong>to</strong> obtain information about the values of:<br />

• Continuous states, X<br />

• Time derivative of the continuous states, XDOT<br />

• Discrete states, XD<br />

• GSE inputs, U<br />

Called By<br />

GSE_DERIV and GSE_OUTPUT


Prerequisite<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Require input values, which must be obtained by a previous call <strong>to</strong> the dimension query utility<br />

subroutines.<br />

Calling Sequence<br />

CALL GSE_X(X,NS)<br />

CALL GSE_XDOT(XDOT,ND)<br />

CALL GSE_XD(XD,ND)<br />

CALL GSE_U(U,NI)<br />

Input Arguments<br />

NS Integer - the number of continuous states (used for validation)<br />

ND Integer - the number of discrete states (used for validation)<br />

NI Integer - the number of outputs (used for validation)<br />

Output Arguments<br />

X Double-precision array of dimension NS, the continuous states<br />

XDOT Double-precision array of dimension NS, the time derivative of the<br />

continuous states (IMPLICIT GSE only)<br />

XD Double-precision array of dimension ND, the discrete states<br />

U Double-precision array of dimension NI, the inputs<br />

Caution: • If the incorrect validation integer value is provided, <strong>Adams</strong>/<strong>Solver</strong> (C++) will s<strong>to</strong>p<br />

with an error message.<br />

Partial derivative entry utility subroutines: GSEPAR_X, GSEMAP_XDOT, GSEPAR_U<br />

The partial derivative entry utility subroutines are used <strong>to</strong> provide <strong>Adams</strong>/<strong>Solver</strong> with:<br />

• The partial derivative of the GSE_DERIV and GSE_OUTPUT with respect <strong>to</strong> the continuous<br />

states, X<br />

• The time derivative of the continuous states, XDOT (implicit GSE only)<br />

• The inputs, U<br />

• Calls <strong>to</strong> GSE_XDOT are only appropriate for GSE elements defined with the<br />

IMPLICIT attribute and should only be made from the GSE_DERIV user<br />

subroutine, not from GSE_OUTPUT.<br />

43


44<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

A call <strong>to</strong> GSEPAR_X from GSE_DERIV is unders<strong>to</strong>od <strong>to</strong> provide the partial derivative of GSE_DERIV<br />

with respect <strong>to</strong> X, and so on.<br />

The GSEPAR utility subroutines are assumed <strong>to</strong> provide full partials unless one or more calls were made<br />

<strong>to</strong> the corresponding GSEMAP when the GSE_DERIV or the GSE_OUTPUT user subroutine was called<br />

with IFLAG set. When full partials are provided with the GSEPAR utility subroutines, the order of the<br />

entries should be such that all the partial derivatives with respect <strong>to</strong> the first state or input should be<br />

provided in order before the partial derivatives with respect <strong>to</strong> the second state or input. If sparse partial<br />

derivatives are used, the entries <strong>to</strong> GSEPAR should be in the same order as was defined by GSEMAP.<br />

Called By<br />

GSE_DERIV and GSE_OUTPUT<br />

Prerequisite<br />

Calls may be dependent on calls made <strong>to</strong> GSEMAP utility subroutines when IFLAG was set.<br />

Calling Sequence<br />

CALL GSEPAR_X(D,N)<br />

CALL GSEPAR_XDOT(D,N)<br />

CALL GSEPAR_U(D,N)<br />

Input Arguments<br />

D Double-precision array of partial derivatives in the appropriate order<br />

N Integer - the number of partials being provided (used for validation)<br />

Caution: • If N does not validate, <strong>Adams</strong>/<strong>Solver</strong> (C++) s<strong>to</strong>ps with an error message. For full<br />

partials it is expected <strong>to</strong> be the product of the corresponding dimensions. For<br />

example, the call <strong>to</strong> GSEPAR_X from a GSE_OUTPUT should have N = NI * NS,<br />

where NI and NS are the return values of GSE_NI and GSI_NS respectively. For<br />

sparse partials, the value of N should equal the number of calls made <strong>to</strong> the<br />

corresponding GSEMAP utility subroutine.<br />

• Calls <strong>to</strong> GSEPAR_XDOT are only appropriate for GSE elements defined with the<br />

IMPLICIT attribute and should only be made from the GSE_DERIV user<br />

subroutine, not from GSE_OUTPUT.<br />

Partial derivative mapping utility subroutines: GSEMAP_X, GSE_XDOT, GSEMAP_U<br />

The partial derivative mapping utility subroutines may optionally be used <strong>to</strong> configure the GSE <strong>to</strong> have<br />

sparse entries. For a GSE with a large number of states, inputs and/or outputs, the computational savings<br />

can be significant.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

GSEMAP_X, GSEMAP_XDOT, and GSEMAP_U register dependencies with respect <strong>to</strong> state, the time<br />

derivative of state (implicit GSE only) and input, respectively.<br />

If <strong>Adams</strong>/<strong>Solver</strong> (C++) detects calls <strong>to</strong> the GSEMAP utility subroutines during calls <strong>to</strong> GSE_DERIV or<br />

GSE_OUTPUT, when IFLAG is set, then the corresponding partial derivative is taken <strong>to</strong> be sparse.<br />

GSEMAP utility subroutine calls may be made for one or more of the families of partial derivaties. For<br />

example, if GSEMAP_X is called from GSE_DERIV, this particular partial derivative is taken <strong>to</strong> be<br />

sparse while the other families of partial derivatives, for example the partial derivative of GSE_DERIV<br />

with respect <strong>to</strong> U, is taken <strong>to</strong> be full.<br />

Multiple calls are made <strong>to</strong> GSEPAR utility subroutines, one per dependency. For example, a call<br />

GSEMAP_X(1,1) from GSE_OUTPUT indicates <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> (C++) that the first output depends<br />

on the first state. The order of the calls <strong>to</strong> GSEMAP utility subroutines is significant because entries in<br />

the array subsequently passed <strong>to</strong> the corresponding GSEPAR utility subroutines is assumed <strong>to</strong> be in this<br />

order.<br />

Called By<br />

GSE_DERIV and GSE_OUTPUT<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL GSEMAP_X(I,J)<br />

CALL GSEMAP_XDOT(I,J)<br />

CALL GSEMAP_U(I,J)<br />

Input Arguments<br />

I Integer - the row index (the index of the state derivative or the output which<br />

has a functional dependency)<br />

J Integer - the column index (the index of the state or the input with respect <strong>to</strong><br />

which the functional dependency is being registered)<br />

Caution: Calls <strong>to</strong> GSEMAP_XDOT are only appropriate for GSE elements defined with the<br />

IMPLICIT attribute and should only be made from the GSE_DERIV user subroutine, not<br />

from GSE_OUTPUT.<br />

GSE_SET_IMPLICIT<br />

This subroutine is used <strong>to</strong> specify the implicit/explicit character of the equations governing the GSE.<br />

45


46<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

See the definition of the IMPLICIT attribute in the documentation for the GSE statement.<br />

When the GSE is initialized <strong>Adams</strong>/<strong>Solver</strong> (C++) will look for a GSE_SET_IMPLICIT entry point in the<br />

GSE (if it was not explicitly specified using the ROUTINE=). If GSE_SET_IMPLICIT is present, then<br />

during initialization of the GSE this subroutine will be called.<br />

Note: The value returned by GSE_SET_IMPLICIT will override any IMPLICIT attribute setting<br />

that is specified in the GSE statement<br />

This user-defined subroutine is new for <strong>Adams</strong>/<strong>Solver</strong> (C++) v2006r1 and gives the GSE the ability <strong>to</strong><br />

define the implicit/explicit character of its governing equations. That is, the formulation of a GSE can<br />

be changed without changing the corresponding adams model (.amd).<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_SET_IMPLICIT (ID, IMPLICIT)<br />

Input Arguments<br />

ID An integer variable that gives the identifier of the GSE statement requesting information<br />

from the GSE subroutine. From the identifier, <strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes other<br />

information (such as the Par argument) that is associated with that GSE statement.<br />

Output Arguments<br />

IMPLICIT An integer specifying whether the GSE formulation is implicit or explicit. A nonzero<br />

(true) value for IMPLICIT specifies an implicit formulation.<br />

Example<br />

C<br />

C+===============================================================*<br />

C<br />

SUBROUTINE GSE_SET_IMPLICIT (ID, IMPLICIT)<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

C<br />

C Outputs:<br />

C<br />

INTEGER IMPLICIT<br />

C<br />

C This GSE is formulated implicitly.<br />

IMPLICIT = 1<br />

RETURN<br />

END


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C<br />

C+===============================================================*<br />

C<br />

GSE_SET_ND<br />

This subroutine is used <strong>to</strong> specify the number of discrete internal states the in the GSE.<br />

When the GSE is initialized <strong>Adams</strong>/<strong>Solver</strong> (C++) will look for a GSE_SET_ND entry point in the GSE<br />

(if it was not explicitly specified using the ROUTINE=). If GSE_SET_ND is found, then during<br />

initialization of the GSE this subroutine will be called.<br />

Note: The value, ND, returned by GSE_SET_ND will override any value of ND that is specified<br />

in the GSE statement<br />

This user-defined subroutine is new for <strong>Adams</strong>/<strong>Solver</strong> (C++) v2006r1 and gives the GSE the ability <strong>to</strong><br />

define its own number of discrete states. That is, the number of discrete states in a GSE can be changed<br />

without changing the corresponding adams model (.amd).<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_SET_ND (ID, ND)<br />

Input Arguments<br />

ID An integer variable that gives the identifier of the GSE statement requesting<br />

information from the GSE subroutine. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically recognizes other information (such as the Par argument) that is<br />

associated with that GSE statement.<br />

Output Arguments<br />

ND An integer number giving the number of discrete states that this GSE maintains.<br />

Example<br />

C<br />

C+=================================================================*<br />

C<br />

SUBROUTINE GSE_SET_ND (ID, ND)<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

C<br />

C Outputs:<br />

47


48<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

INTEGER ND<br />

C<br />

C This GSE has two discrete internal states.<br />

ND = 2<br />

RETURN<br />

END<br />

C<br />

C+=================================================================*<br />

C<br />

GSE_SET_NS<br />

This subroutine is used <strong>to</strong> specify the number of internal states the in the GSE.<br />

When the GSE is initialized <strong>Adams</strong>/<strong>Solver</strong> (C++) will look for a GSE_SET_NS entry point in the GSE<br />

(if it was not explicitly specified using the ROUTINE=). If GSE_SET_NS is found, then during<br />

initialization of the GSE this subroutine will be called.<br />

Note: The value, NS, returned by GSE_SET_NS will override any value of NS that is specified<br />

in the GSE statement.<br />

This user-defined subroutine is new for <strong>Adams</strong>/<strong>Solver</strong> (C++) v2006r1 and gives the GSE the ability <strong>to</strong><br />

define its own number of states. That is, the number of states in a GSE can be changed without changing<br />

the corresponding adams model (.amd).<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_SET_NS (ID, NS)<br />

Input Arguments<br />

ID An integer variable that gives the identifier of the GSE statement requesting information<br />

from the GSE subroutine. From the identifier, <strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes<br />

other information (such as the Par argument) that is associated with that GSE statement.<br />

Output Arguments<br />

NS An integer number giving the number of states that this GSE maintains.<br />

Example<br />

C<br />

C+=================================================================*<br />

C<br />

SUBROUTINE GSE_SET_NS (ID, NS)


C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

C<br />

C Outputs:<br />

C<br />

INTEGER NS<br />

C<br />

C This GSE has two internal states.<br />

NS = 2<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

RETURN<br />

END<br />

C<br />

C+=================================================================*<br />

C<br />

GSE_SET_SAMPLE_OFFSET<br />

This subroutine is used <strong>to</strong> specify the simulation time at which the sampling of the discrete states is <strong>to</strong><br />

start.<br />

See the definition of the SAMPLE_OFFSET attribute in the documentation for the GSE statement.<br />

When the GSE is initialized <strong>Adams</strong>/<strong>Solver</strong> (C++) will look for a GSE_SET_SAMPLE_OFFSET entry<br />

point in the GSE (if it was not explicitly specified using the ROUTINE=). If<br />

GSE_SET_SAMPLE_OFFSET is present, then during initialization of the GSE this subroutine will be<br />

called.<br />

Note: The value returned by GSE_SET_SAMPLE_OFFSET will override any<br />

SAMPLE_OFFSET attribute setting that is specified in the GSE statement.<br />

This user-defined subroutine is new for <strong>Adams</strong>/<strong>Solver</strong> (C++) v2006r1 and gives the GSE the ability <strong>to</strong><br />

set the SAMPLE_OFFSET attribute itself. That is, the formulation of a GSE can be changed without<br />

changing the corresponding <strong>Adams</strong> model (.amd).<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_SET_SAMPLE_OFFSET (ID, SAMPLE_OFFSET)<br />

49


50<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

ID An integer variable that gives the identifier of the GSE statement requesting information<br />

from the GSE subroutine.<br />

Output Arguments<br />

SAMPLE_OFFSET A double-precision variable specifying time simulation time at which the<br />

sampling of the discrete states is <strong>to</strong> start.<br />

Example<br />

C<br />

C+=================================================================*<br />

C<br />

SUBROUTINE GSE_SET_SAMPLE_OFFSET (ID, SAMPLE_OFFSET)<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE_PRECISION STATIC_HOLD<br />

C<br />

C Discrete states are <strong>to</strong> be sampled at time at time = 1.23.<br />

C<br />

SAMPLE_OFFSET = 1.23<br />

RETURN<br />

END<br />

C<br />

C+=================================================================*<br />

C<br />

GSE_SET_STATIC_HOLD<br />

This subroutine is used <strong>to</strong> enforce the condition that continuous states are or are not allowed <strong>to</strong> change<br />

during a static or quasi-static simulation.<br />

See the definition of the STATIC_HOLD attribute in the documentation for the GSE statement.<br />

When the GSE is initialized <strong>Adams</strong>/<strong>Solver</strong> (C++) will look for a GSE_SET_STATIC_HOLD entry point<br />

in the GSE (if it was not explicitly specified using the ROUTINE=). If GSE_SET_STATIC_HOLD is<br />

present, then during initialization of the GSE this subroutine will be called.<br />

Note: The value returned by GSE_SET_STATIC_HOLD will override any STATIC_HOLD<br />

attribute setting that is specified in the GSE statement.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

This user-defined subroutine is new for <strong>Adams</strong>/<strong>Solver</strong> (C++) v2006r1 and gives the GSE the ability <strong>to</strong><br />

set the STATIC_HOLD attribute itself. That is, the formulation of a GSE can be changed without<br />

changing the corresponding <strong>Adams</strong> model (.amd).<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_SET_STATIC_HOLD (ID, STATIC_HOLD)<br />

Input Arguments<br />

ID An integer variable that gives the identifier of the GSE statement requesting information<br />

from the GSE subroutine.<br />

Output Arguments<br />

STATIC_HOLD An integer specifying whether the GSE formulation has the STATIC_HOLD<br />

attribute set. A nonzero (true) value for STATIC_HOLD specifies that that GSE has<br />

its STATIC_HOLD attribute set.<br />

Example<br />

C<br />

C+=================================================================*<br />

C<br />

SUBROUTINE GSE_SET_STATIC_HOLD (ID, STATIC_HOLD)<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

C<br />

C Outputs:<br />

C<br />

INTEGER STATIC_HOLD<br />

C<br />

C Continuous variables are held constant during static or<br />

C quasi-static simulations.<br />

C<br />

STATIC_HOLD = 1<br />

RETURN<br />

END<br />

C<br />

C+=================================================================*<br />

C<br />

GTARAY<br />

51


52<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

GTARAY returns the double-precision numbers s<strong>to</strong>red by an IC-type ARRAY statement (C++ or<br />

FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

ARRAY statement in dataset<br />

Calling Sequence<br />

CALL GTARAY (id, array, number, istat)<br />

Input Argument<br />

id An integer variable that specifies the ID of the ARRAY statement.<br />

Output Arguments<br />

array A double-precision array containing the data defined in the ARRAY<br />

statement statement.<br />

istat An integer that indicates the success or the reason for the failure of the<br />

call <strong>to</strong> GTARAY.<br />

number A variable that indicates the number of values returned in the array.<br />

GTCMAT<br />

If: Then:<br />

istat = 0 The call <strong>to</strong> GTARAY was successful.<br />

istat = -1 ARRAY/id is not an IC-type.<br />

istat = -2 <strong>Adams</strong>/<strong>Solver</strong> could not find an ARRAY statement<br />

with the identifier indicated in id.<br />

Caution: • Make sure that array is large enough <strong>to</strong> hold all of the returned values.<br />

• You can only use GTARAY <strong>to</strong> access values for an IC-type ARRAY (the default<br />

type). If you want <strong>to</strong> access values for an X-type, a Y-type, or a U-type ARRAY,<br />

use SYSARY and the ARRAY function, or SYSFNC and the C++ ARYVAL<br />

function or the FORTRAN ARYVAL function.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

GTCMAT computes the compliance matrix for a set of markers in an <strong>Adams</strong>/<strong>Solver</strong> model.<br />

Use<br />

Called By<br />

CONSUB<br />

Prerequisite<br />

Call <strong>to</strong> ANALYS <strong>to</strong> perform a static analysis<br />

Calling Sequence<br />

CALL GTCMAT (nmid, mid, ndim, c, istat)<br />

53


54<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

nmid An integer variable that specifies the number of marker, mid. nmid must<br />

be greater than zero and less than or equal <strong>to</strong> 100.<br />

mid An integer array containing a list of marker identifiers. GTCMAT<br />

computes the compliance matrix for these markers. The markers can be on<br />

any part except ground, and can lie anywhere on the parts. mid can contain<br />

more than one marker on a particular part. Each part with a marker listed<br />

in mid must also have a center-of-mass (CM) marker defined in the<br />

dataset.<br />

ndim An integer variable specifying the number of rows in c. ndim must be at<br />

least 6*nmid, since each marker results in six rows. You must dimension c<br />

in CONSUB with exactly ndim rows (and at least 6*nmid columns).


Output Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

c A double-precision, two-dimensional array containing the compliance<br />

matrix for the markers specified in mid. The compliance terms are in the<br />

following directions: global x, y, and z displacements and small rotations<br />

about the global x-, y-, and z-axes.<br />

Extended Definition<br />

You must dimension c large enough <strong>to</strong> hold six rows and six columns for<br />

each marker, and assign ndim <strong>to</strong> be the number of rows in the matrix. To<br />

compute a matrix for three markers, for example, you should dimension c<br />

<strong>to</strong> be 18 by 18, and set ndim =18. The same matrix could also be used <strong>to</strong><br />

compute a matrix for just one marker. In this case, you would still set ndim<br />

<strong>to</strong> 18, but GTCMAT fills only the elements in the first six rows and<br />

columns.<br />

istat An integer variable containing a status flag. If istat = 0, GTCMAT has<br />

successfully computed the compliance matrix. If istat < 0, GTCMAT has<br />

not computed the compliance matrix because of an error. istat can have<br />

one of the following values:<br />

If: Then:<br />

istat= 0 Normal return<br />

istat= -1 nmid < 0<br />

istat= -2 nmid > maximum number of markers allowed (100)<br />

istat= -3 ndim < 6 * nmid<br />

istat= -6 mid contains an illegal marker<br />

istat= -7 the system has zero degrees-of-freedom<br />

istat= -8 A UCON in the system prevents compliances from<br />

being calculated.<br />

istat= -9 The system Jacobian is singular.<br />

istat= -10 Miscellaneous problems<br />

istat= -11 One of the markers specified is on ground.<br />

istat= -12 Static equilibrium has not been performed.<br />

istat= -13 One of the parts referenced has no cm marker.<br />

The compliance matrix for a system, C, is defined as the partial derivatives of displacements with respect<br />

<strong>to</strong> applied forces:<br />

55


56<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Note that the compliance matrix is the inverse of the stiffness matrix for a system (which is defined as<br />

the partial derivatives of the applied forces with respect <strong>to</strong> the displacements). If a system is assumed <strong>to</strong><br />

be linear, the compliance matrix can be used <strong>to</strong> predict the system movement due <strong>to</strong> force inputs: Dx =<br />

C Df<br />

From this perspective, matrix element cij is the displacement of system degree of freedom i due <strong>to</strong> a unit<br />

force at degree-of-freedom j.<br />

In order for the system <strong>to</strong> have meaningful compliances, it must have one or more degrees of freedom.<br />

A kinematic (zero-degree-of-freedom) model does not move in response <strong>to</strong> applied forces, so by<br />

definition the compliances are zero. GTCMAT returns an error if run on a kinematic model.<br />

GTCMAT returns a matrix containing six columns and six rows for each marker requested. The rows and<br />

columns are in groups of six, appearing in the same order as the markers are listed in mid. The rows<br />

correspond <strong>to</strong> global x, y, and z translations and global AX, AY, AZ rotations. The columns correspond<br />

<strong>to</strong> global x, y, and z forces and <strong>to</strong>rques about the global x, y, and z axes.<br />

If, for example, you specify two marker identifiers in mid, GTCMAT returns a 12 12 matrix. Element<br />

c(2,4) is the change in the global y displacement of the first marker due <strong>to</strong> a unit <strong>to</strong>rque about the global<br />

x-axis applied at the first marker (assuming a linear system). Element c(2,8) is the change in the global<br />

y displacement of the first marker due <strong>to</strong> a global Y force applied at the second marker.<br />

Using <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN)<br />

When using <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN), GTCMAT computes the compliance matrix by inverting the<br />

Jacobian from an <strong>Adams</strong>/<strong>Solver</strong> static solution. Because of this, you must first call ANALYS <strong>to</strong> perform<br />

a static solution, before calling GTCMAT. GTCMAT returns an error if you have not first run a static<br />

analysis.<br />

Using <strong>Adams</strong>/<strong>Solver</strong> (C++)<br />

When using <strong>Adams</strong>/<strong>Solver</strong> (C++), GTCMAT computes the compliance matrix as follows:<br />

1. A linearization of the system is performed (the linearization does not change the current state of<br />

the system) and a standard input-output representation is obtained:<br />

= AX + BU<br />

y = X<br />

where the output y consists of the displacements of the MARKERs and the input U consists of<br />

applied forces at the MARKERs’ locations. For more information on the state vec<strong>to</strong>r X and the<br />

state matrices A,B, , see the LINEAR command.<br />

2. Solving for X we find that<br />

X = A-1-A-1BU<br />

Putting this result in<strong>to</strong> the equation for y we obtain:<br />

y = [-A-1B]U + [-A-1]<br />

3. The compliance matrix C is given by the expression:


C = [-A-1B]<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Notice that the term [-A-1] is due <strong>to</strong> perturbations of the velocities and accelerations of the system<br />

at the operating point, therefore it can be neglected.<br />

The GTCMAT subroutine can be called during a dynamic or a quasi-static simulation.<br />

Caution: If you don't dimension matrix c properly or don't assign the proper value <strong>to</strong> ndim,<br />

GTCMAT can overwrite other memory.<br />

GTCURV<br />

GTCURV evaluates a B-spline or user-written curve created by a CURVE statement (C++ or<br />

FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

CURVE statement in the dataset<br />

Calling Sequence<br />

CALL GTCURV (id, alpha, iord, array, istat)<br />

57


58<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

id An integer variable that specifies the ID of the corresponding CURVE<br />

statement.<br />

alpha A double-precision variable that identifies the value of the independent<br />

parameter, a, at which GTCURV is <strong>to</strong> evaluate the curve. If the curve is a Bspline<br />

computed by the CURVE statement, alpha must be in the domain -1<br />

alpha 1. If the curve is computed by CURSUB, alpha must be in the domain<br />

MINPAR alpha MAXPAR (these are specified in the CURVE statement).<br />

iord An integer variable that specifies the order of the derivative the GTCURV is<br />

<strong>to</strong> return. The legal values are:<br />

• 0 - Returns the curve coordinate.<br />

• 1 - Returns the first derivative with respect <strong>to</strong> a.<br />

• 2 - Returns the second derivative with respect <strong>to</strong> a.


Output Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

array A double-precision array of length three which contains the returned<br />

values of x, y, z.<br />

0<br />

1<br />

2<br />

iord array(1) array(2) array(3)<br />

x( α ) y( α ) z( α )<br />

dx( α )<br />

------------dα<br />

d 2 x( α )<br />

dα 2<br />

-----------------<br />

dy( α )<br />

------------dα<br />

d 2 y( α )<br />

dα 2<br />

-----------------<br />

dz( α )<br />

------------dα<br />

d 2 z( α )<br />

dα 2<br />

----------------<br />

istat An integer variable that indicates either the success or teason for the failure<br />

of the call <strong>to</strong> GTCURV.<br />

If: Then:<br />

istat= -1 Fatal error, invalid id or iord is out of the range.<br />

istat= 0 The call <strong>to</strong> GTCURV was successful.<br />

istat= 1 alpha is less than MINPAR, the curve was evaluated at<br />

MINPAR.<br />

istat= 2 alpha is greater than MAXPAR, the curve was<br />

evaluated at MAXPAR.<br />

59


60<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

array A double-precision array of length three which contains the returned<br />

values of x, y, z.<br />

istat An integer variable that indicates either the success or teason for the<br />

failure of the call <strong>to</strong> GTCURV.<br />

Extended Definition<br />

GTCURV evaluates a B-spline or a user-written curve defined by a CURVE statements and returns one<br />

of the following:<br />

• A value for the dependent variables (x, y, z) for each value it receives for alpha.<br />

• The first partial derivatives of the dependent variable.<br />

• The second partial derivatives of the dependent variable.<br />

GTSTRG<br />

GTSTRG returns the character string s<strong>to</strong>red in a STRING statement.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

0<br />

1<br />

2<br />

iord array(1) array(1) array(1)<br />

x( α ) y( α ) z( α )<br />

dx( α )<br />

------------dα<br />

dx 2 ( α )<br />

dα 2<br />

-----------------<br />

dy( α )<br />

------------dα<br />

dy 2 ( α )<br />

dα 2<br />

-----------------<br />

dxz( α )<br />

---------------dα<br />

dz 2 ( α )<br />

dα 2<br />

----------------<br />

If: Then:<br />

istat= -1 Fatal error, invalid id or iord is out of the range.<br />

istat= 0 The call <strong>to</strong> GTCURV was successful.<br />

istat= 1 alpha is less than MINPAR, the curve was evaluated at<br />

MINPAR.<br />

istat= 2 alpha is greater than MAXPAR, the curve was evaluated<br />

at MAXPAR.


Prerequisite<br />

STRING statement in dataset<br />

Calling Sequence<br />

CALL GTSTRG (id, string, nchars, istat)<br />

Input Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that specifies the ID of the STRING statement.<br />

Output Arguments<br />

istat An integer that indicates the success or failure of the call <strong>to</strong> GTSTRG.<br />

nchars The number of characters in the returned string. Trailing blank spaces are<br />

ignored.<br />

string The requested string.<br />

GTUNTS<br />

GTUNTS returns model unit information from <strong>Adams</strong>/<strong>Solver</strong>.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

If: Then:<br />

istat= 0 The call <strong>to</strong> GTSTRG was successful.<br />

istat= -2 <strong>Adams</strong>/<strong>Solver</strong> could not find a STRING statement with the<br />

identifier indicated in id.<br />

Caution: • Make sure that string is long enough <strong>to</strong> hold all of the string.<br />

• The string is left-justified (that is, <strong>Adams</strong>/<strong>Solver</strong> deletes all blank spaces <strong>to</strong> the left<br />

of the string).<br />

61


62<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Calling Sequence<br />

CALL GTUNTS (exist, scales, units)<br />

Output Arguments<br />

exist A logical variable that, if true, indicates units were set for the model.<br />

scales A double-precision array containing conversion fac<strong>to</strong>rs <strong>to</strong> go from model<br />

units <strong>to</strong> SI for time, length, force, and mass.<br />

units A character*2 array containing two-letter abbreviations for the model units<br />

for time, length, force, and mass.<br />

Example For example, if you have an Aero_Force defined in New<strong>to</strong>ns, and you want <strong>to</strong> convert <strong>to</strong> model<br />

units, you must divide your force by scales(3).<br />

DOUBLE PRECISION SCALES(4)<br />

LOGICAL EXIST<br />

CHARACTER*2 UNITS(4)<br />

INTEGER TIME, LENGTH, FORCE, MASS PARAMETER<br />

(TIME=1,LENGTH=2,FORCE=3, MASS=4)<br />

CALL GTUNTS(EXIST, SCALES, UNITS)<br />

Model_Force = Aero_Force/SCALES(FORCE)<br />

To compute a spring in MKS units, give disp, flen, and K in model units:<br />

MKS_F = ((flen - disp)*K)*SCALES(FORCE) VSIN<br />

Caution: GTUNTS uses the UNITS statement in your dataset <strong>to</strong> determine the units being used in<br />

your model. When a UNITS statement is missing, or if you use a unit consistency fac<strong>to</strong>r<br />

(UCF), GTUNTS is not able <strong>to</strong> determine time, length, mass, or force units. In that case,<br />

GTUNTS returns:<br />

The HAVSIN general subroutine evaluates a haversine function.<br />

Use<br />

Called By<br />

• exist = FALSE<br />

Any user-written subroutine<br />

• scales = 1.0, 1.0, 1.0, 1.0<br />

• units = US


Prerequisites<br />

None<br />

Calling Sequence<br />

CALL HAVSIN (x, x0, h0, x1, h1, iord, value, errflg)<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

63


64<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

h0 A double-precision variable that specifies the value of the function before<br />

the step (x £ x0).<br />

h1 A double-precision variable that specifies the value of the function after the<br />

step (x x1).<br />

iord An integer variable that defines the order of the derivative that HAVSIN is<br />

<strong>to</strong> return. The order is usually zero, but it can be one or two.<br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies the x value at which the haversine<br />

function begins.<br />

x1 A double-precision variable that specifies the value at which the haversine<br />

function ends.<br />

Output Arguments<br />

errflg A logical (true or false) variable that HAVSIN returns <strong>to</strong> the calling<br />

subroutine. If HAVSIN detects an error in the subroutine call<br />

statement, it sets errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling<br />

subroutine.<br />

value A double-precision value the subroutine returns. If iord equals zero,<br />

value is the function evaluated at x. If iord equals one, value is the first<br />

derivative of F(x) with respect <strong>to</strong> the independent variable x. If iord<br />

equals two, value is the second derivative of F(x) with respect <strong>to</strong> the<br />

independent variable x. Value is:<br />

Extended Definition<br />

0<br />

1<br />

2<br />

IORD: Value:<br />

F( x)<br />

∂ F( x)<br />

--------------<br />

∂ x<br />

∂ F 2 ( x)<br />

∂ x 2<br />

----------------<br />

The HAVSIN general subroutine evaluates a haversine function. Figure 1 below illustrates the haversine


function.<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The value x is the independent variable, h0 and h1 are the initial and final values of the haversine<br />

function. The following equation defines HAVSIN:<br />

65


66<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

a<br />

b<br />

c<br />

IMPACT<br />

IMPACT is a simple model for contacts. It evaluates a force that turns on when a distance falls below a<br />

nominal free length (that is, when two parts collide).<br />

Use<br />

( h0 + h1) = ---------------------<br />

2<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

( h1 – h0) = ---------------------<br />

2<br />

( x – x0) = ---------------------<br />

( x1 – x0) HAVSIN<br />

h0 ; x ≤x0<br />

a b c π π<br />

⎧ ⎫<br />

⎪ ⎪<br />

⎪ ⎛ ⋅ – --⎞<br />

⎪<br />

= ⎨ + ⋅sin<br />

; x<br />

⎝ 2⎠<br />

0 < x < x2⎬ ⎪ ⎪<br />

⎪<br />

⎩<br />

h2 ; x ≥ x<br />

⎪<br />

1 ⎭<br />

Caution: • The value x1 must not equal x0. Equal values of x1 and x0 imply a sharp step,<br />

which HAVSIN cannot fit.<br />

• At x0 and x1, the second derivatives of the haversine function do not match the<br />

second derivatives of the constant regions. This discontinuity increases as the<br />

values for x1 and x0 become closer (that is, as the haversine becomes sharper).<br />

Because of the discontinuity, integration problems can arise if the haversine is<br />

sharp.<br />

• The STEP general subroutine (see STEP) is an alternative <strong>to</strong> HAVSIN.


Calling Sequence<br />

CALL IMPACT (x, x', x1, k, e, cmax, d, iord, vec<strong>to</strong>r, errflg)<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

67


68<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

x A double-precision variable that specifies the distance variable you want <strong>to</strong><br />

use <strong>to</strong> compute the force.<br />

x' A double-precision variable that communicates <strong>to</strong> IMPACT the time<br />

derivative of x.<br />

x1 A double-precision variable that specifies the free length of x. If x is less<br />

than x1, <strong>Adams</strong>/<strong>Solver</strong> calculates a positive value for the force. Otherwise,<br />

the force value is zero. The value of x1 must be greater than zero.<br />

k A positive, double-precision variable that specifies the stiffness of boundary<br />

surface interaction.<br />

e A positive, double-precision variable that specifies the exponent of the<br />

force-deformation law. For a stiffening spring characteristic, e > 1.0. For a<br />

softening spring characteristic, 0 < e < 1.0.<br />

cmax A non-negative, double-precision variable that specifies the maximum<br />

damping coefficient.<br />

d A positive, double-precision variable that specifies the boundary pe<strong>net</strong>ration<br />

at which <strong>Adams</strong>/<strong>Solver</strong> applies full damping. For a plot of damping<br />

coefficient versus pe<strong>net</strong>ration, see IMPACT function (C++ or FORTRAN).<br />

iord An integer variable that defines the order of the derivative IMPACT is <strong>to</strong><br />

return. The order is usually zero, but it can be one or two.


Output Arguments<br />

Extended Definition<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

errflg A logical (true or false) variable that IMPACT returns <strong>to</strong> the calling<br />

subroutine. If IMPACT detects an error during its calculations, it sets errflg<br />

<strong>to</strong> true.<br />

vec<strong>to</strong>r A double-precision vec<strong>to</strong>r of length 3, that returns the values calculated by<br />

the subroutine. The following table indicates the information in vec<strong>to</strong>r.<br />

IMPACT models collisions and contact. It evaluates a force that turns on when a distance falls below a<br />

nominal free length (that is, when two parts collide).<br />

The force has two components: a spring or stiffness component and a damping or viscous component.<br />

The stiffness component opposes the pe<strong>net</strong>ration. The damping component of the force is a function of<br />

the speed of pe<strong>net</strong>ration. The damping opposes the direction of relative motion. To prevent a<br />

discontinuity in the damping force at contact, the damping coefficient is, by definition, a cubic step<br />

function of the pe<strong>net</strong>ration. Thus at zero pe<strong>net</strong>ration, the damping coefficient is always zero. The<br />

damping coefficient achieves a maximum, cmax, at a user-defined pe<strong>net</strong>ration, d.<br />

An object colliding with ground is an example of a system that can be modeled with the IMPACT<br />

function.<br />

Let x be the instantaneous distance, x1 be the free length (when x is less than x1, the force turns on), x1<br />

- x be the pe<strong>net</strong>ration, and d be the pe<strong>net</strong>ration at which <strong>Adams</strong>/<strong>Solver</strong> applies full damping (cmax).<br />

• When x x1, force = 0.<br />

(1)<br />

• When x < x1, force is positive.<br />

vec<strong>to</strong>r<br />

returns: For iord values:<br />

(2) 0<br />

• When (x1-d) < x < x1, force is positive; there is damping, but it is less than cmax.<br />

• When x (x1-d), force is positive and damping = cmax.<br />

0 1 2<br />

F( x, x′ )<br />

∂ F( x, x′ )<br />

---------------------<br />

∂ x<br />

∂ F( x, x′ )<br />

---------------------<br />

∂ x′<br />

(3) 0 0 0<br />

∂ 2 F( x, x′ )<br />

∂ x 2<br />

------------------------<br />

∂ 2 F( x, x′ )<br />

------------------------<br />

∂ x′∂ x<br />

69


70<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

The following equation defines IMPACT:<br />

IMPACT<br />

See an explanation of the STEP function (C++ or FORTRAN).<br />

<strong>Adams</strong>/<strong>Solver</strong> never returns a negative force for IMPACT. If the above expression evaluates <strong>to</strong> negative<br />

value, <strong>Adams</strong>/<strong>Solver</strong> returns a zero value.<br />

For an example of an SFOSUB that calls IMPACT, see SFOSUB.<br />

ISTRNG<br />

ISTRNG converts a number from integer format <strong>to</strong> character format. The character string representing<br />

the integer is always left justified.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

Max 0 k( x1x) e<br />

( , ) STEP x x1 ( d, cmax, x1, 0)<br />

x ·<br />

⎧ ⎫<br />

⎪ – ( , – ( ⋅ ) ) ; x < x ⎪<br />

=<br />

1<br />

⎨ ⎬<br />

⎪ 0 ; x ≥ x ⎪ 1<br />

⎩ ⎭<br />

Caution: • IMPACT is only used <strong>to</strong> determine force or <strong>to</strong>rque magnitudes.<br />

• The force value and the distance measure must both be positive in the same<br />

direction.<br />

• When e is less than or equal <strong>to</strong> one, the rate of change of the force is discontinuous<br />

at contact. This may cause convergence problems.<br />

CALL ISTRNG (number, string, length, istat)


Input Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

number An integer variable that specifies the integer <strong>to</strong> be converted.<br />

Output Arguments<br />

istat An integer variable indicating the success or the reason for the failure of the<br />

call <strong>to</strong> ISTRNG.<br />

Extended Definition<br />

One purpose of ISTRNG is <strong>to</strong> provide the CONSUB driver subroutine with a character representation of<br />

an integer. This is necessary because the MODIFY execution control subroutine requires commands in<br />

the form of a character string that may include integers (for example, statement identifiers). The integer<br />

and the character string representing the integer appear identical when printed.<br />

MODIFY<br />

The MODIFY allows execution of any <strong>Adams</strong>/<strong>Solver</strong> command except CONTROL, STOP, from a<br />

CONSUB.<br />

Use<br />

Called By<br />

CONSUB<br />

Prerequisite<br />

None<br />

If: Then:<br />

istat= 0 The call <strong>to</strong> ISTRNG was successful.<br />

istat= -3 There was an error during conversion.<br />

istat= -4 The string was not dimensioned long enough.<br />

length An integer variable that returns the number of nonblank characters in the<br />

converted string.<br />

string A character string that represents the number. <strong>Adams</strong>/<strong>Solver</strong> left justifies<br />

the converted string (that is, it removes all leading blank spaces).<br />

Tip: If the dimension of the string is CHARACTER*12 or longer, the string can hold any<br />

integer defined on a 32-bit machine.<br />

71


72<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Calling Sequence<br />

CALL MODIFY (comand, istat)<br />

Input Argument<br />

comand A character string or variable that corresponds <strong>to</strong> the command<br />

<strong>to</strong> be executed.<br />

Output Argument<br />

istat An integer variable that indicates whether or not the call <strong>to</strong> MODIFY was<br />

successful.<br />

Extended Definition<br />

You must build a character string for the input and pass the string <strong>to</strong> MODIFY as if it were an actual<br />

interactive command. The general subroutines RSTRNG and ISTRNG are available <strong>to</strong> help build these<br />

strings. CONSUB can call MODIFY. Program control returns <strong>to</strong> CONSUB after execution of the<br />

command(s) issued from MODIFY. For an example of a CONSUB driver subroutine that calls MODIFY,<br />

see CONSUB.<br />

MODINF<br />

MODINF returns the original mode numbers and the modal frequencies, in cycles per user-defined time,<br />

of all active modes associated with a FLEX_BODY statement (C++ or FORTRAN).<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

FLEX_BODY statement in dataset<br />

Calling Sequence<br />

CALL MODINF (id, mode, freq, errflg)<br />

If istat = 0, the call <strong>to</strong> MODIFY was successful.<br />

Caution: <strong>Adams</strong>/<strong>Solver</strong> ignores any part of an argument following five blank spaces. Therefore,<br />

when using string concatenation <strong>to</strong> build a command, it is important <strong>to</strong> remove trailing<br />

blanks. Do this by referring only <strong>to</strong> the nonblank portion of the string.


Input Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that specifies the ID of the FLEX_BODY statement.<br />

Output Argument<br />

mode An integer array that contains the original mode numbers of all the active<br />

modes associated with the specified FLEX_BODY.<br />

freq A double-precision array that contains the modal frequencies, in cycles per<br />

user-defined time, of all active modes associated with the specified<br />

FLEX_BODY.<br />

errflg A logical variable that returns true if an error has occurred during the call <strong>to</strong><br />

MODINF.<br />

Caution: You must be sure mode and freq are dimensioned large enough <strong>to</strong> contain all the values<br />

returned by MODINF. You can check the number of active modes using NMODES.<br />

Example<br />

For examples of how MODINF is used, see the following files:<br />

For Windows, in the direc<strong>to</strong>ry /install_dir/solver/samples, where install_dir is the direc<strong>to</strong>ry in which you<br />

installed your <strong>Adams</strong> software.<br />

For UNIX, in the direc<strong>to</strong>ry /install_dir/solver/samples, where install_dir is the direc<strong>to</strong>ry in which you<br />

installed your <strong>Adams</strong> software.<br />

• sysary_sample.acf<br />

• sysary_sample.adm<br />

• sysary_sample.f<br />

• sysary_sample.mtx<br />

NMODES<br />

NMODES returns the number of modal generalized coordinates associated with a FLEX_BODY<br />

statement (C++ or FORTRAN).<br />

Use<br />

Called By<br />

When errflg is true, the values of mode and freq may be wrong.<br />

Any user-written subroutine<br />

73


74<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Prerequisite<br />

FLEX_BODY statement in dataset<br />

Calling Sequence<br />

CALL NMODES (id, nq, errflg)<br />

Input Argument<br />

id An integer variable containing the identifier of the FLEX_BODY<br />

statement for which the number of modal generalized coordinates should<br />

be retrieved.<br />

Output Argument<br />

nq An integer that indicates the number of modal generalized coordinates<br />

associated with the specified FLEX_BODY.<br />

errflg A logical variable that returns true if an error has occurred during the call<br />

<strong>to</strong> NMODES.<br />

Caution: • The value of nq will be zero and errflg will return true if there is no active<br />

FLEX_BODY corresponding <strong>to</strong> id.<br />

Example<br />

For samples of how NMODES is used, see the following files:<br />

For Windows, in the direc<strong>to</strong>ry /install_dir/solver/samples, where install_dir is the direc<strong>to</strong>ry in which you<br />

installed your <strong>Adams</strong> software.<br />

For UNIX, in the direc<strong>to</strong>ry /install_dir/solver/samples, where install_dir is the direc<strong>to</strong>ry in which you<br />

installed your <strong>Adams</strong> software.<br />

POLY<br />

• sysary_sample.acf<br />

• sysary_sample.adm<br />

• sysary_sample.f<br />

• sysary_sample.mtx<br />

• The value of nq may be wrong when is true.<br />

The POLY general subroutine evaluates a polynomial.


Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL POLY (x, x0, par, npar, iord, value, errflg)<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

75


76<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

iord An integer variable that defines the order of the derivative that POLY is<br />

<strong>to</strong> return. The order is usually zero, but it can be one or two.<br />

npar An integer variable that indicates the number of coefficients specified.<br />

The primary purpose of npar is <strong>to</strong> provide POLY with the number of<br />

values s<strong>to</strong>red in the par array.<br />

par A double-precision array of any number of coefficients (a0,...,an).<br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies a shift in the polynomial.<br />

Output Arguments<br />

errflg A logical (true or false) variable that POLY returns <strong>to</strong> the calling<br />

subroutine. If POLY detects an error in the subroutine call statement, it<br />

sets errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

value A double-precision value the subroutine returns. If iord equals zero, value<br />

is the function evaluated at x. If iord equals one, value is the first<br />

derivative of F(x) with respect <strong>to</strong> the independent variable x. If iord<br />

equals two, value is the second derivative of F(x) with respect <strong>to</strong> the<br />

independent variable x. Value is:<br />

Extended Definition<br />

A POLY general subroutine evaluates a polynomial. The following equation defines POLY:<br />

a<br />

∑<br />

j = 0<br />

PUT_SPLINE<br />

aj( x – x0) j<br />

0<br />

1<br />

2<br />

IORD: Value:<br />

F( x)<br />

∂ F( x)<br />

--------------<br />

∂ x<br />

∂ F 2 ( x)<br />

∂ x 2<br />

----------------<br />

PUT_SPLINE is used in conjunction with SPLINE_READ. SPLINE_READ reads in the data points for<br />

a spline from a file. PUT_SPLINE is used <strong>to</strong> s<strong>to</strong>re this data within <strong>Adams</strong>/<strong>Solver</strong>.


Use<br />

Called By<br />

SPLINE_READ<br />

Calling Sequence<br />

CALL PUT_SPLINE (id, nx, nz, x, y, z, errflg)<br />

Input Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable containing the ID of the SPLINE statement.<br />

nx An integer variable that specifies the number of x values contained in the<br />

x array. The number of x values must be at least 4.<br />

nz An integer variable that specifies the number of z values contained in the<br />

z array. The number of z values must be at least 1.<br />

x A double-precision array containing the x values for the spline element.<br />

The number of x values must be at least nx.<br />

y A double-precision array containing the y values for the spline element.<br />

The number of y values must be at least nx · nz.<br />

z A double-precision array containing the z values for the spline element.<br />

The number of z values must be at least nz.<br />

Output Argument<br />

errflg A logical variable that indicates if <strong>Adams</strong> successfully accepts the x, y,<br />

[and z] data. SPLINE_READ checks the value of errflg after calling<br />

PUT_SPLINE.<br />

Extended Definition<br />

PUT_SPLINE transfers spline data <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> from local variables that you define in the<br />

SPLINE_READ user-written subroutine. For an example of a SPLINE_READ subroutine that calls<br />

PUT_SPLINE, see SPLINE_READ.<br />

Cautions<br />

• If there are more than nx values in x, more than nx · nz values in y, or more than nz values in z,<br />

then <strong>Adams</strong>/<strong>Solver</strong> ignores the extra values.<br />

77


78<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

• The z array is not used when nz = 1. The value of z is irrelevant in this case; however, z must<br />

exist.<br />

IORD: Value:<br />

0 Value of the function.<br />

1 Partial derivative of the function with respect <strong>to</strong> x.<br />

2 Second partial derivative of the function with respect <strong>to</strong> x.<br />

• The order of values that are s<strong>to</strong>red in the y array must correspond <strong>to</strong> the order of points in the x<br />

and z arrays as follows:<br />

• The y array must consist of nz consecutive sets of nx values (the values within each set<br />

correspond <strong>to</strong> the values in the x array, and the sets correspond <strong>to</strong> the values in the z array). It is<br />

possible <strong>to</strong> use either a single- or double-dimensioned array for y.<br />

• If a double-dimensioned array is used, the first dimension must be equal <strong>to</strong> nx, not greater, and<br />

the second dimension must be greater or equal <strong>to</strong> nz.<br />

RCNVRT<br />

RCNVRT converts rotational coordinates from one representation <strong>to</strong> another.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL RCNVRT (sys1, coord1, sys2, coord2, istat)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

79


80<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

sys1 A character string specifying the system in which the values passed in<br />

coord1 were determined. The following table shows the possible character<br />

strings and their meanings:<br />

Character<br />

string: Means:<br />

'EULER' <strong>Adams</strong>/<strong>Solver</strong> Euler angles<br />

'EULPAR' Euler parameters PO, P1, P2, P3<br />

'AXAYAZ' Rotational displacements about the x, y, and z axes<br />

'YPR' Yaw-pitch-roll<br />

'COSINES' Directional cosines<br />

'BRYANT' Bryant angles<br />

'B123' Body-three: 1-2-3 (orientation angles)<br />

`B231' Body-three: 2-3-1<br />

`B312' Body-three: 3-1-2<br />

`B132' Body-three: 1-3-2<br />

`B213' Body-three: 2-1-3<br />

`B321' Body-three: 3-2-1<br />

`B121' Body-two: 1-2-1<br />

`B131' Body-two: 1-3-1<br />

`B212' Body-two: 2-1-2<br />

`B232' Body-two: 2-3-2<br />

`B313' Body-two: 3-1-3 (<strong>Adams</strong>/<strong>Solver</strong> Euler angles)<br />

`B323' Body-two: 3-2-3<br />

`S123' Space-three: 1-2-3<br />

`S231' Space-three: 2-3-1<br />

`S312' Space-three: 3-1-2<br />

`S132' Space-three: 1-3-2<br />

`S213' Space-three: 2-1-3<br />

`S321' Space-three: 3-2-1<br />

`S121' Space-two: 1-2-1<br />

`S131' Space-two: 1-3-1<br />

`S212' Space-two: 2-1-2


`S232' Space-two: 2-3-2<br />

`S313' Space-two: 3-1-3<br />

`S323' Space-two: 3-2-3<br />

`RODPAR' Rodrigues parameters<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

sys2 A character string specifying the system in which the values returned as<br />

output in coord2 are <strong>to</strong> be determined. Possible character strings are the<br />

same as those for sys1.<br />

coord1 A double-precision array containing the coordinates <strong>to</strong> be converted.<br />

Angles should be input in radians.<br />

81


82<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Output Arguments<br />

coord2 An array containing the converted coordinates. Angles are output in radians.<br />

istat An integer variable indicating the unqualified success, the qualified success,<br />

or the reason for the failure of the call <strong>to</strong> RCNVRT. The values for istat are<br />

as follows:<br />

Extended Definition<br />

If: Then:<br />

istat= 0 The call <strong>to</strong> RCNVRT was successful without<br />

qualifications.<br />

istat> 0 The call <strong>to</strong> RCNVRT was successful, but there are<br />

nonfatal errors in the input supplied.<br />

istat= +1 The sum of the squares of the Euler parameters is<br />

close <strong>to</strong> (within 0.5), but not exactly, 1.0.<br />

istat= +2 The sum of the squares of a column of the direction<br />

cosines is close <strong>to</strong> (within 0.5), but not exactly, 1.0.<br />

istat< 0 The call <strong>to</strong> RCNVRT was not successful because<br />

there are fatal errors in the input supplied.<br />

istat= -1 The coordinate system for sys1 was not correctly<br />

specified.<br />

istat= -2 The coordinate system for sys2 was not correctly<br />

specified.<br />

istat= -3 The absolute value of an Euler parameter is greater<br />

than 1.5 (<strong>Adams</strong>/<strong>Solver</strong> gives 0.5 <strong>to</strong>lerance).<br />

istat= -4 The sum of the squares of the Euler parameters is not<br />

within 0.5 of 1.0.<br />

istat= -5 The sum of the squares of a column of the direction<br />

cosines is not within 0.5 of 1.0.<br />

istat= -6 The input direction cosine matrix is not orthogonal;<br />

that is, the dot product of any two columns is greater<br />

than 0.5.<br />

istat= -7 The input direction cosine matrix is for left-handed,<br />

In <strong>Adams</strong>/<strong>Solver</strong>, rotational coordinates are often used <strong>to</strong> specify the orientation of a coordinate system.<br />

For example, a DIFSUB, a REQSUB, or an SFOSUB can call RCNVRT <strong>to</strong> change Euler angles <strong>to</strong> Euler<br />

parameters.<br />

Euler parameters are P0, P1, P2, and P3. P0 is the cosine of one-half the angle of rotation of the rotated<br />

frame with respect <strong>to</strong> the reference frame. P1, P2, and P3 are the x, y, and z components, respectively, of<br />

the unit vec<strong>to</strong>r around which the rotation occurs, multiplied by the sine of one-half the angle.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Rodrigues parameters (R1, R2, and R3) define the relative rotation between two frames of reference. The<br />

relationship between Rodrigues parameters and Euler parameters is R1 = P1/P0, R2 = P2/P0, and<br />

R3 = P3/P0. Rodrigues parameters become undefined when P0 = 0, that is, when the angle of rotation<br />

about the vec<strong>to</strong>r is 180 degrees. If the dimension of the string is CHARACTER*12 or longer, the string<br />

can hold any integer defined on a 32-bit machine.<br />

The coord1 and coord2 array length is three, except when the coordinates are in the EULPAR system<br />

(when the array length is four) or in the COSINES system (when the array length is nine). The nine<br />

values of the COSINES system, which forms a three-by-three matrix, are s<strong>to</strong>red in column order in<br />

coord2.<br />

RSTRNG<br />

RSTRNG converts a double-precision variable <strong>to</strong> a character string.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL RSTRNG (reel, string, length, istat)<br />

83


84<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Argument<br />

reel The double-precision number <strong>to</strong> be converted.<br />

Output Arguments<br />

istat An integer variable indicating the success or the reason for the failure of<br />

the call <strong>to</strong> RSTRNG.<br />

length An integer variable that returns the number of nonblank characters in the<br />

converted string.<br />

string A character string that represents the number. <strong>Adams</strong>/<strong>Solver</strong> left justifies<br />

the converted string (that is, removes all leading blank spaces) and retains<br />

all other blank spaces.<br />

Extended Definition<br />

RSTRNG converts a double-precision number <strong>to</strong> the characters representing that number. One purpose<br />

of RSTRNG is <strong>to</strong> provide the CONSUB driver subroutine with a character representation of a real<br />

number. This is necessary because the MODIFY execution control subroutine requires commands in the<br />

form of a character string that can include real numbers (for example, data). The double-precision<br />

variable and the character string representing the number appear identical when printed.<br />

SHF<br />

SHF evaluates a simple harmonic function.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

If: Then:<br />

istat= 0 The call <strong>to</strong> RSTRNG was successful.<br />

istat= -3 There was an error during conversion.<br />

istat= -4 String was not dimensioned long enough.<br />

Tip: If the dimension of the string is CHARACTER*12 or longer, the string can hold any real<br />

number.


Callng Sequence<br />

CALL SHF (x, x0, a, w, phi, b, iord, value, errflg)<br />

Input Arguments<br />

Output Arguments<br />

Extended Definition<br />

The following equation defines SHF:<br />

STEP<br />

STEP approximates a step function with a cubic polynomial.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies a shift in the independent variable.<br />

a A double-precision variable that specifies the amplitude of the harmonic<br />

function.<br />

w A double-precision variable that specifies the frequency of the sine function.<br />

The variable must be in radians per unit of the independent variable.<br />

phi A double-precision variable that specifies a phase shift in the sine function.<br />

The variable phi must be in radians.<br />

b A double-precision variable that specifies the average value of displacement.<br />

iord An integer variable that defines the order of the derivative that SHF is <strong>to</strong><br />

return. The order is usually zero, but it can be one or two.<br />

errflg A logical (true or false) variable that SHF returns <strong>to</strong> the calling subroutine.<br />

If SHF detects an error in the subroutine call statement, it sets errflg <strong>to</strong> true<br />

before it returns errflg <strong>to</strong> the calling subroutine.<br />

value A double-precision value the subroutine returns. The value returned<br />

depends on IORD as follows<br />

a ⋅sin<br />

( w ⋅(<br />

x – x0) – φ ) + b<br />

85


86<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL STEP (x, x0, h0, x1, h1, iord, value, errflg)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies the x value at which the step<br />

function begins.<br />

h0 A double-precision variable that specifies the value of the function before<br />

the step.<br />

x1 A double-precision variable that specifies the x value at which the step<br />

function ends.<br />

h1 A double-precision variable that specifies the value of the function after the<br />

step.<br />

iord An integer variable that defines the order of the derivative that STEP is <strong>to</strong><br />

return. The order is usually zero, but it can be one or two.<br />

Output Arguments<br />

errflg A logical (true or false) variable that STEP returns <strong>to</strong> the calling<br />

subroutine. If STEP detects an error in the subroutine call statement, it sets<br />

errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

value A double-precision value the subroutine returns. The value returned<br />

depends on IORD as follows:<br />

Extended Definition<br />

Figure 1 below demonstrates the step function. For a comparison of STEP and STEP5, and the first<br />

derivatives of STEP and STEP5, see:<br />

• STEP (C++ or FORTRAN) function<br />

• STEP5 (C++ or FORTRAN) function<br />

IORD: Value:<br />

0 Value of the function.<br />

1 Partial derivative of the function with respect<br />

<strong>to</strong> x.<br />

2 Second partial derivative of the function with<br />

respect <strong>to</strong> x.<br />

F( x)<br />

∂ F<br />

-----<br />

∂ x<br />

∂ 2 F<br />

∂ x 2<br />

--------<br />

87


88<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Figure 1. Step Function<br />

The value x is the independent variable, x0 and x1 define the variable values at which the step begins and<br />

ends, h0 and h1 are the initial value and the final value of the step. The equation that defines STEP<br />

follows.<br />

STEP<br />

For an example of a SENSUB evaluation subroutine that calls STEP, see SENSUB.<br />

STEP5<br />

STEP5 approximates a step function with a quintic polynomial.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

⎧ h0 ; x ≤x<br />

⎫<br />

0<br />

⎪ ⎪<br />

⎪ ( x – x0) ( x – x0) ⎪<br />

= ⎨ h0 + ( h1 – h0) ⋅ --------------------- ⋅2 ⋅ 3 – ⎛2 ⋅ --------------------- ⎞ ; x<br />

( x1 – x0) ⎝ ( x1 – x0) ⎠ 0 < x < x1⎬ ⎪ ⎪<br />

⎪ ⎪<br />

⎩ h1 ; x ≥ x1 ⎭<br />

Caution: The value x1 must not equal x0. Equal values of x1 and x0 imply a discontinuous step,<br />

which STEP cannot fit.


Calling Sequence<br />

CALL STEP5 (x, x0, h0, x1, h1, iord, value, errflg)<br />

Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

x A double-precision variable that specifies the independent variable.<br />

x0 A double-precision variable that specifies the x value at which the step<br />

function begins.<br />

h0 A double-precision variable that specifies the value of the function before the<br />

step.<br />

x1 A double-precision variable that specifies the x value at which the step<br />

function ends.<br />

h1 A double-precision variable that specifies the value of the function after the<br />

step.<br />

iord An integer variable that defines the order of the derivative that STEP5 is <strong>to</strong><br />

return. The order is usually zero, but it can be one or two.<br />

Output Arguments<br />

errflg A logical (true or false) variable that STEP5 returns <strong>to</strong> the calling<br />

subroutine. If STEP5 detects an error in the subroutine call statement, it sets<br />

errflg <strong>to</strong> true before it returns errflg <strong>to</strong> the calling subroutine.<br />

value A double-precision value the subroutine returns. The value returned<br />

depends on IORD as follows:<br />

Extended Definition Figure 1 below demonstrates the STEP5 function. For a comparison of STEP and<br />

STEP5, and the first derivatives of STEP and STEP5, see:<br />

• STEP (C++ or FORTRAN) function<br />

• STEP5 (C++ or FORTRAN) function<br />

IORD: Value:<br />

0 Value of the function.<br />

1 Partial derivative of the function with respect<br />

<strong>to</strong> x.<br />

2 Second partial derivative of the function with<br />

respect <strong>to</strong> x.<br />

F( x)<br />

∂ F<br />

-----<br />

∂ x<br />

∂ 2 F<br />

∂ x 2<br />

--------<br />

89


90<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Figure 1. STEP5 Function<br />

The value x is the independent variable, x0 and x1 define the variable values at which the step begins and<br />

ends, h0 and h1 are the initial and values of the step. The equation defining the STEP5 function is:<br />

a = h1 – h0<br />

∆<br />

( x – x0) = ---------------------<br />

( x1 – x0) STEP5<br />

h0 ; x ≤x0<br />

h0 a ∆ 3<br />

10 – 15∆ 6∆ 2<br />

⎧ ⎫<br />

⎪ ⎪<br />

⎪ ⎪<br />

= ⎨ + ( ⋅[<br />

+ ] ) ; x0 < x < x ⎬<br />

1<br />

⎪ ⎪<br />

⎪ h1 ; x ≥ x1 ⎪<br />

⎩ ⎭<br />

The STEP5 subroutine calling sequence is identical <strong>to</strong> the STEP subroutine. For an example of a<br />

SENSUB evaluation subroutine that calls STEP5, see SENSUB.<br />

Caution: The value x1 must not equal x0. Equal values of x1 and x0 imply a discontinuous step,<br />

which STEP5 cannot fit.<br />

SUBTRACT_MASS_PROPERTY


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The SUBTRACT_MASS_PROPERTY utility subroutine accepts the mass properties for two parts or<br />

sets of parts and returns the mass properties of the second set minus the mass properties of the first.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL SUBTRACT_MASS_PROPERTY (cm1, mass1, ip1, cm2, mass2, ip2)<br />

91


92<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

cm1 A double-precision array of length 3 containing the center of mass of the first part or set<br />

of parts expressed in the GCS (Ground/Global Coordinate System).<br />

mass1 A double-precision variable containing the mass of the first part or set of parts.<br />

ip1 A double-precision array of length 6 giving the 6 independent terms in the inertia tensor<br />

for the first part or set of parts. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These inertia terms much be<br />

computed about the center of mass of the part and oriented in GCS.<br />

cm2 A double-precision array of length 3 containing the center of mass of the second part or<br />

set of parts expressed in the GCS.<br />

mass2 A double-precision variable containing the mass of the second set.<br />

ip2 A double-precision array of length 6 giving the 6 independent terms in the inertia tensor<br />

for the second part or set of parts. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These inertia terms much<br />

be computed about the center of mass of the part and oriented in GCS.<br />

Output Arguments<br />

cm2 A double-precision array of length 3 containing the center of mass of the second system<br />

minus the first expressed in GCS.<br />

mass2 A double-precision variable containing the mass of the second system minus the first.<br />

Ip2 A double-precision array of length 6 containing the 6 independent components of in the<br />

inertia tensor for the second system minus the first. (Ixx, Iyy, Izz, Ixy, Ixz, Iyz) These<br />

inertia terms are expressed about the combined center of mass and are oriented in GCS.<br />

Extended Definition<br />

Although not required, the SUBTRACT_MASS_PROPERTY utility subroutine is intended <strong>to</strong> be used<br />

with the BODY_MASS_PROPERTY utility subroutine.<br />

If, for example, the aggregate mass properties of all of the elements of a large model were required, with<br />

the exception of just a few parts, the BODY_MASS_PROPERTY ("Model", … ) utility subroutine could<br />

be used <strong>to</strong> find the aggregate mass of the entire model and then BODY_MASS_PROPERTY and<br />

SUBTRACT_MASS_PROPERTY could be used <strong>to</strong> remove the contributions from the unwanted parts<br />

from the aggregate set.<br />

Specifically, if the mass properties of both the sprung and the unsprung mass of a vehicle were required,<br />

the properties of the unsprung mass (assuming there are fewer unsprung parts than sprung parts) could<br />

be computed as described in the ADD_MASS_PROPERTY documentation, the mass properties of the<br />

entire system could be computed with a single call <strong>to</strong> BODY_MASS_PROPERTY using the 'Model' part<br />

specifier, and the sprung mass could then be obtained with a single call <strong>to</strong><br />

SUBTRACT_MASS_PROPERTY where the unsprung mass properties would be subtracted from the<br />

model mass properties.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The SUBTRACT_MASS_PROPERTY utility subroutine simply calls the ADD_MASS_PROPERTY<br />

utility subroutine with the negative of the mass and inertia values.<br />

The SUBTRACT_MASS_PROPERTY utility subroutine is very similar <strong>to</strong> ADD_MASS_PROPERTY<br />

utility subroutine and the documentation for ADD_MASS_PROPERTY should be referenced for<br />

examples.<br />

SYSARY<br />

The SYSARY data access subroutine provides system state values, such as displacement and velocity, <strong>to</strong><br />

your subroutines, and defines and s<strong>to</strong>res the <strong>Adams</strong>/<strong>Solver</strong> state variables on which the system states are<br />

dependent.<br />

Use<br />

Called By<br />

CONSUB, DIFSUB, GFOSUB, REQSUB, SENSUB, SFOSUB, VARSUB, VFOSUB, and VTOSUB<br />

Calling Sequence<br />

CALL SYSARY (fncnam, ipar, nsize, states, nstates, errflg)<br />

93


94<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

fncnam A character variable that specifies the name of the function whose data is<br />

being requested from SYSARY. The legal values for fncnam are derived<br />

from the list of functions available <strong>to</strong> you in the FUNCTION= expression<br />

construct. Any one of the following character strings is legal.<br />

Displacement Functions:<br />

DISP Returns all six components of displacement.<br />

TDISP Returns three translational components of displacement.<br />

RDISP Returns three B313 Euler rotations<br />

(<strong>Adams</strong>/<strong>Solver</strong> standard rotations).<br />

Q Returns the modal generalized coordinates for<br />

the flex body specified.<br />

UVX Returns the direction cosines of the x-axis of<br />

marker I in the coordinate system of marker J.<br />

UVY Returns the direction cosines of the y-axis of<br />

marker I in the coordinate system of marker J.<br />

UVZ Returns the direction cosines of the z-axis of<br />

marker I in the coordinate system of marker J.<br />

DC Returns the direction cosines of the x-, y-, and<br />

z-axes of marker I in the coordinate system of<br />

marker J.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

95


96<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Velocity Functions:<br />

VEL Returns all six components of velocity.<br />

TVEL Returns three components of translational velocity.<br />

RVEL Returns three components of angular velocity.<br />

QDOT Returns the first time derivative of the modal generalized<br />

coordinates for the flex body specified.<br />

Acceleration Functions:<br />

ACC Returns all six components of acceleration.<br />

TACC Returns three components of translational acceleration.<br />

RACC Returns three components of angular<br />

acceleration.<br />

QDDOT Returns the second time derivative of the<br />

modal generalized coordinates for the flex body<br />

specified.<br />

Generic Force Functions:<br />

FORCE Returns all six components of <strong>net</strong> force (forces<br />

and <strong>to</strong>rques) acting at a marker.<br />

TFORCE Returns three components of <strong>net</strong> translational<br />

force acting at a marker.<br />

RFORCE Returns three components of <strong>net</strong> rotational<br />

force <strong>to</strong>rque) acting at a marker.<br />

System element variables:<br />

PINPUT Returns instantaneous values of all components<br />

of a PINPUT.<br />

POUTPUT Returns instantaneous values of all components<br />

of a POUTPUT.<br />

ARRAY Returns instantaneous values of all components<br />

of an ARRAY.<br />

ipar An integer array of size nsize that contains the parameter list for function<br />

fncnam. The table above defines the appropriate parameter list types and<br />

dimensions for the different functions available.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

nsize An integer variable that gives the number of parameters that the function<br />

fncnam requires. Its value is dependent on the function name. See the table<br />

above for the number of parameters that function fncnam requires.<br />

Output Arguments<br />

errflg A logical variable that returns as true if an error occurred during your call<br />

<strong>to</strong> SYSARY.<br />

nstates An integer variable that returns the number of values <strong>Adams</strong>/<strong>Solver</strong> has<br />

put in states. Note that an integer variable must be used here for<br />

<strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> return the number of states. The value returned in this<br />

variable is as defined in the table above.<br />

states A double-precision array whose size depends on the fncnam (see the table<br />

above) that contains the values that SYSARY returns. When the iflag<br />

argument in the user subroutine is true or when input errors are found,<br />

states contains zeros.<br />

Extended Definition<br />

SYSARY returns a set of system states or s<strong>to</strong>res the dependencies of the user value on the set of system<br />

states. You can use the system state values <strong>to</strong> compute the instantaneous values of a user-defined<br />

function; <strong>Adams</strong>/<strong>Solver</strong> uses the dependency on state variables <strong>to</strong> create the matrix of partial derivatives<br />

(Jacobian) of the system states with respect <strong>to</strong> the <strong>Adams</strong>/<strong>Solver</strong> state variables. <strong>Adams</strong>/<strong>Solver</strong> uses the<br />

Jacobian matrix in several analysis computations.<br />

When called from a force evaluation subroutine or from VARSUB, SYSARY returns the current<br />

predicted values of the state. SENSUB is called only after a completed integration state, so SYSARY<br />

returns the converged values when called from SENSUB. REQSUB is called at output steps and, like<br />

SENSUB, SYSARY returns the converged values when called from REQSUB. Therefore, the values<br />

returned from SYSARY are the current values of the state; whether they are the predicted values, or the<br />

corrected values, depends on where you are when calling SYSARY.<br />

You should use SYSFNC (see SYSFNC) <strong>to</strong> access a single system state corresponding <strong>to</strong> one modeling<br />

element.<br />

Where SYSFNC evaluates one <strong>Adams</strong>/<strong>Solver</strong> function, SYSARY evaluates several with one call. For<br />

example, <strong>to</strong> evaluate DX(12,10,99), DY(12,10,99) and DZ(12,10,99), you call SYSARY with:<br />

• fncnam='TDISP'<br />

• ipar(1)=12<br />

• ipar(2)=10<br />

• ipar(3)=99<br />

• nsize=3<br />

97


98<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

SYSARY would return the requested x, y, and z displacements in states(1), states(2), and states(3), and<br />

return nstates=3. The following table lists the correspondence of other SYSARY fncnam values <strong>to</strong><br />

<strong>Adams</strong>/<strong>Solver</strong> function names.<br />

fncnam: nsize: nstates: states:<br />

DISP 1-3 6 states(1) = DX(i1[,i2,i3])<br />

states(2) = DY(i1[,i2,i3])<br />

states(3) = DZ(i1[,i2,i3])<br />

states(4) = PSI(i1[,i2])<br />

states(5) = THETA(i1[,i2])<br />

states(6) = PHI(i1[,i2])<br />

TDISP 1-3 3 states(1) = DX(i1[,i2,i3])<br />

states(2) = DY(i1[,i2,i3])<br />

states(3) = DZ(i1[,i2,i3])<br />

RDISP 1-2 3 states(1) = PSI(i1[,i2])<br />

Q 1 NMODES* --<br />

UVX** 2 3 --<br />

UVY** 2 3 --<br />

UVZ** 2 3 --<br />

DC** 2 9 --<br />

states(2) = THETA(i1[,i2])<br />

states(3) = PHI(i1[,i2])<br />

VEL 1-4 6 states(1) = VX(i1[,i2,i3,i4])<br />

states(2) = VY(i1[,i2,i3,i4])<br />

states(3) = VZ(i1[,i2,i3,i4])<br />

states(4) = WX(i1[,i2,i3])<br />

states(5) = WY(i1[,i2,i3])<br />

states(6) = WZ(i1[,i2,i3])


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

TVEL 1-4 3 states(1) = VX(i1[,i2,i3,i4])<br />

states(2) = VY(i1[,i2,i3,i4])<br />

states(3) = VZ(i1[,i2,i3,i4])<br />

RVEL 1-3 3 states(1) = WX(i1[,i2,i3])<br />

QDOT 1 NMODES* --<br />

states(2) = WY(i1[,i2,i3])<br />

states(3) = WZ(i1[,i2,i3])<br />

ACC 1-4 6 states(1) = ACCX(i1[,i2,i3,i4])<br />

states(2) = ACCY(i1[,i2,i3,i4])<br />

states(3) = ACCZ(i1[,i2,i3,i4])<br />

states(4) = WDTX(i1[,i2,i3,i4])<br />

states(5) = WDTY(i1[,i2,i3,i4])<br />

states(6) = WDTZ(i1[,i2,i3,i4])<br />

TACC 1-4 3 states(1) = ACCX(i1[,i2,i3,i4])<br />

states(2) = ACCY(i1[,i2,i3,i4])<br />

states(3) = ACCZ(i1[,i2,i3,i4])<br />

RACC 1-4 3 states(1) = WDTX(i1[,i2,i3,i4])<br />

QDDOT 1 NMODES*<br />

states(2) = WDTY(i1[,i2,i3,i4])<br />

states(3) = WDTZ(i1[,i2,i3,i4])<br />

FORCE 1-3 6 states(1) = FX(i1[,i2,i3])<br />

states(2) = FY(i1[,i2,i3])<br />

states(3) = FZ(i1[,i2,i3])<br />

states(4) = TX(i1[,i2,i3])<br />

states(5) = TY(i1[,i2,i3])<br />

states(6) = TZ(i1[,i2,i3])<br />

99


100<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

TFORCE 1-3 3 states(1) = FX(i1[,i2,i3])<br />

states(2) = FY(i1[,i2,i3])<br />

states(3) = FZ(i1[,i2,i3])<br />

RFORCE 1-3 3 states(1) = TX(i1[,i2,i3])<br />

states(2) = TY(i1[,i2,i3])<br />

states(3) = TZ(i1[,i2,i3])<br />

PINPUT 1 n*** states(1) = PINVAL(i1,1)<br />

states(2) = PINVAL(i1,2)<br />

states(3) = PINVAL(i1,3)<br />

.<br />

.<br />

.<br />

states(n) = PINVAL(i1,n)


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

POUTPUT 1 n*** states(1) = POUVAL(i1,1)<br />

states(2) = POUVAL(i1,2)<br />

states(3) = POUVAL(i1,3)<br />

states(n) = POUVAL(i1,n)<br />

ARRAY 1 n*** states(1) = ARYVAL(i1,1)<br />

states(2) = ARYVAL(i1,2)<br />

states(3) = ARYVAL(i1,3)<br />

When the iflag argument in the user subroutine is true, SYSARY sets up the dependencies of the system<br />

states on the <strong>Adams</strong>/<strong>Solver</strong> state variables and sets the states array equal <strong>to</strong> zero. When the iflag<br />

.<br />

.<br />

.<br />

states(n) = ARYVAL(i1,n)<br />

*NMODES (see NMODES) is the number of active modes defined for that flex body. You can use the<br />

utility subroutine NMODES <strong>to</strong> determine the number of active modes. The ipar(1) array must contain<br />

the id of the flex body of interest.<br />

**Assume that the ipar array contains two markers, I and J. You can specify either I or J <strong>to</strong> be zero. In<br />

that case, the marker specified as zero defaults <strong>to</strong> the ground coordinate system.<br />

***Size as specified in the PINPUT, POUTPUT, or ARRAY statement.<br />

101


102<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

argument is false, SYSARY returns the instantaneous values of the system states. You can make several<br />

calls <strong>to</strong> SYSARY, specifying each time the function used, and the parameters of the function.<br />

Tip: 1. Use SYSFNC <strong>to</strong> access individual states. Quite often, user-defined values depend<br />

on a single-system state such as the x component of the displacement between two<br />

markers, or the z component of the velocity between two markers. While you can<br />

use SYSARY <strong>to</strong> access the individual components, a single call <strong>to</strong> SYSFNC is<br />

convenient and more efficient. The use of SYSFNC is therefore recommended<br />

under these circumstances.<br />

Examples<br />

2. Use RCNVRT <strong>to</strong> convert rotational displacements Euler angles <strong>to</strong> any other angle<br />

representation, for example <strong>Adams</strong> AX, AY, AZ projected angles.<br />

CALL SYSFNC (`RDISP', IPAR, 2, ANGLES, NSTATE, ERRFLG)<br />

CALL RCNVRT (`EULER', ANGLES, `AXAYAZ', ANGLES, ISTAT)<br />

Use SYSFNC <strong>to</strong> access individual states.Quite often, user-defined values depend<br />

on a single-system state such as the x component of the displacement between two<br />

markers. While you may use SYSARY <strong>to</strong> access the individual components, a<br />

single call <strong>to</strong> SYSFNC is convenient and more efficient. The use of SYSFNC is<br />

therefore recommended under these circumstances.<br />

Caution: When the iflag argument is true, you must be sure <strong>to</strong> make the same SYSARY calls as when<br />

actually computing the results. <strong>Adams</strong>/<strong>Solver</strong> passes a parameter iflag <strong>to</strong> each user-written<br />

subroutine (xxxSUB). It indicates <strong>to</strong> you whether <strong>Adams</strong>/<strong>Solver</strong> is calling the subroutine<br />

for an initialization pass (iflag = true) or for a function evaluation (iflag =false). You must<br />

construct user-written subroutines such that all calls <strong>to</strong> SYSARY that are made during the<br />

simulation are also invoked when the iflag argument is true. <strong>Adams</strong>/<strong>Solver</strong> uses this<br />

information <strong>to</strong> construct the correct Jacobian matrix.<br />

This example shows properly written calls <strong>to</strong> SYSARY for UVX, UVY, UVE, and DC.<br />

SUBROUTINE VARSUB (ID, TIME, PAR, NPAR, DFLAG, IFLAG, VALUE)<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID, NPAR<br />

DOUBLE PRECISION TIME, PAR(*)<br />

LOGICAL DFLAG, IFLAG<br />

C<br />

C Outputs:<br />

C<br />

LOGICAL VALUE<br />

C<br />

C Local Variables:


C<br />

INTEGER IPAR(2), N_UVX, N_UVY, N_UVZ, N_DC, NSIZE<br />

DOUBLE PRECISION UVX(3), UVY(3), UVZ(3), DC(3,3)<br />

LOGICAL ERRFLG<br />

C<br />

C+-----------------------------------------------------*<br />

C<br />

IPAR(1) = NINT (PAR(1))<br />

IPAR(2) = NINT (PAR(2))<br />

NSIZE = 2<br />

C<br />

C Get the directions of the x axis<br />

C<br />

CALL SYSARY ('UVX', IPAR, NSIZE, UVX, N_UVX, ERRFLG)<br />

C<br />

C Get the directions of the y axis<br />

C<br />

CALL SYSARY ('UVY', IPAR, NSIZE, UVY, N_UVY, ERRFLG)<br />

C<br />

C Get the directions of the z axis<br />

C<br />

CALL SYSARY ('UVZ', IPAR, NSIZE, UVZ, N_UVZ, ERRFLG)<br />

C<br />

C Get the directions of the y axis<br />

C<br />

CALL SYSARY ('DC', IPAR, NSIZE, DC, N_DC, ERRFLG)<br />

C<br />

C Calculate the value of the variable:<br />

C<br />

VALUE = ...<br />

C<br />

RETURN<br />

END<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

This example shows properly written calls <strong>to</strong> SYSARY for Q, QDOT, and QDDOT, as well as an<br />

associated use of the utility subroutines NMODES and MODINF.<br />

SUBROUTINE VARSUB ( ID, TIME, PAR, NPAR, DFLAG,<br />

& IFLAG, VALUE)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C Note: For machines with 60 or more bits per word,<br />

C substitute "REAL" for "DOUBLE PRECISION".<br />

C<br />

C --- External variable definitions -------------------<br />

103


104<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

C<br />

C ID Identifier of calling VARIABLE statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C IFLAG Initialization pass flag<br />

C VALUE The VARIABLE value returned <strong>to</strong> ADAMS<br />

C<br />

C --- Local variables ---------------------------------<br />

C<br />

INTEGER NARG<br />

PARAMETER (NARG = 1)<br />

INTEGER MAXQ<br />

PARAMETER (MAXQ = 100)<br />

C<br />

CHARACTER*60 STRING<br />

CHARACTER*8 FNCNAM<br />

DOUBLE PRECISION MAXFRQ,C1,C2,C3,Q(MAXQ)<br />

DOUBLE PRECISION FREQ(MAXQ)<br />

INTEGER FBDYID,IPAR(NARG),NQ,I<br />

INTEGER OMODE(MAXQ)<br />

LOGICAL ERRFLG<br />

C<br />

C === Executable code =================================<br />

C<br />

IF (NPAR .LT. 5) THEN<br />

STRING = 'Varsub requires 5 parameters'<br />

CALL ERRMES(.TRUE., STRING, ID, 'STOP' )<br />

ELSE<br />

FBDYID = NINT( PAR(1) )<br />

MAXFRQ = PAR(2)<br />

C1 = PAR(3)<br />

C2 = PAR(4)<br />

C3 = PAR(5)<br />

ENDIF<br />

C


CALL NMODES(FBDYID,NQ,ERRFLG)<br />

STRING = 'Cannot get number of modes'<br />

CALL ERRMES(ERRFLG, STRING, ID, 'STOP' )<br />

IF (NQ .GT. MAXQ) THEN<br />

STRING = 'Too many modes, increase MAXQ in varsub'<br />

CALL ERRMES(.TRUE., STRING, ID, 'STOP' )<br />

ENDIF<br />

C<br />

STRING = 'Cannot get frequencies of modes'<br />

CALL MODINF (FBDYID, OMODE, FREQ, ERRFLG)<br />

CALL ERRMES(ERRFLG, STRING, ID, 'STOP' )<br />

C<br />

IPAR(1) = FBDYID<br />

VALUE = 0.0<br />

C<br />

FNCNAM = 'Q'<br />

CALL SYSARY(FNCNAM, IPAR, NARG, Q, NQ, ERRFLG)<br />

STRING = 'Error calling SYSARY for Q.'<br />

CALL ERRMES(ERRFLG, STRING, ID, 'STOP' )<br />

DO 20 I=1,NQ<br />

IF (FREQ(I) .LT. MAXFRQ) VALUE = VALUE + C1*Q(I)<br />

20 CONTINUE<br />

C<br />

FNCNAM = 'QDOT'<br />

CALL SYSARY(FNCNAM, IPAR, NARG, Q, NQ, ERRFLG)<br />

STRING = 'Error calling SYSARY for QDOT.'<br />

CALL ERRMES(ERRFLG, STRING, ID, 'STOP' )<br />

DO 30 I=1,NQ<br />

IF (FREQ(I) .LT. MAXFRQ) VALUE = VALUE + C2*Q(I)<br />

30 CONTINUE<br />

C<br />

FNCNAM = 'QDDOT'<br />

CALL SYSARY(FNCNAM, IPAR, NARG, Q, NQ, ERRFLG)<br />

STRING = 'Error calling SYSARY for QDDOT.'<br />

CALL ERRMES(ERRFLG, STRING, ID, 'STOP' )<br />

DO 40 I=1,NQ<br />

IF (FREQ(I) .LT. MAXFRQ) VALUE = VALUE + C3*Q(I)<br />

40 CONTINUE<br />

C<br />

RETURN<br />

END<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

For other examples that use the SYSARY data access subroutine, see the evaluation subroutines<br />

VFOSUB and VTOSUB.<br />

SYSFNC<br />

105


106<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

The SYSFNC subroutine provides a single-system state value, such as displacement or velocity, <strong>to</strong> your<br />

subroutines, and defines and s<strong>to</strong>res the <strong>Adams</strong>/<strong>Solver</strong> state variables on which the system state is<br />

dependent.<br />

Use<br />

Called By<br />

CONSUB, DIFSUB, GFOSUB, REQSUB, SENSUB, SFOSUB, VARSUB, VFOSUB, and VTOSUB<br />

Calling Sequence<br />

CALL SYSFNC (fncnam, ipar, nsize, state, errflg)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

fncnam A character variable specifying the name of the function whose data is<br />

being requested from SYSFNC. The legal values for fncnam are derived<br />

from the list of functions available <strong>to</strong> you in the FUNCTION= expression<br />

construct. Note that this function requires single quotes. For example,<br />

CALL SYSFNC (`DX', IPAR, 2, DX, ERRFLG)<br />

Here, the DX characters needs <strong>to</strong> be in single quotes.<br />

Any of the following character strings are legal:<br />

Functions/<br />

variables: Character strings: 1<br />

Displacement DM, DX, DY, DZ, AX, AY, AZ, PSI, PHI, THETA,<br />

YAW, PITCH, ROLL<br />

Velocity VM, VR, VX, VY, VZ, WM, WX, WY, WZ<br />

Acceleration ACCM, ACCX, ACCY, ACCZ, WDTM,<br />

WDTX, WDTY, WDTZ<br />

Generic force FM, FX, FY, FZ, TM, TX, TY, TZ<br />

Elementspecific<br />

force<br />

BEAM, BUSH, FIELD, SPDP, SFORCE, VFORCE,<br />

VTORQ, GFORCE, NFORCE*, JOINT, JPRIM,<br />

MOTION, CVCV, PTCV<br />

System element DIF, DIF1, PINVAL, POUVAL, VARVAL, ARYVAL<br />

107


108<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Output Arguments<br />

Extended Definition<br />

Note: <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN) - The NFORCE function is<br />

available only with SYSFNC from the REQSUB and SENSUB<br />

user written subroutines is not accessible from other user written<br />

subroutines.<br />

<strong>Adams</strong>/<strong>Solver</strong> (C++) - does not have support for the NFORCE<br />

measure from the SYSFNC utility subroutine. Instead, you<br />

should use the FX, FY, and FZ, measures. These can either be<br />

used <strong>to</strong> measure the sum of forces on a single marker, or the sum<br />

of forces transmitted by all connec<strong>to</strong>rs connecting a pair of<br />

markers.<br />

Unfortunately, these measures can not directly compute the force<br />

transmitted between two I markers on an NFORCE and<br />

something similar <strong>to</strong> FX(I1,J)-FX(I2,J) may be required.<br />

ipar An integer array containing the parameter list for fncnam. It consists of any<br />

valid list of parameters used in the associated <strong>Adams</strong>/<strong>Solver</strong> function, just<br />

as they would appear in a dataset FUNCTION = expression.<br />

nsize An integer variable specifying the number of values in ipar.<br />

errflg A logical variable that returns true if an error has occurred during your call<br />

<strong>to</strong> SYSFNC.<br />

state A double-precision variable returned by SYSFNC. State is zero when the<br />

iflag argument is set <strong>to</strong> true in the user-written subroutine, or when input<br />

errors are found.<br />

The SYSFNC subroutine provides system-state values (such as displacement and velocity) <strong>to</strong> user<br />

subroutines, and defines and s<strong>to</strong>res the <strong>Adams</strong>/<strong>Solver</strong> state variables on which the system state is<br />

dependent.<br />

SYSFNC returns one system state or s<strong>to</strong>res the dependency of the user value on the system state. You use<br />

the system state values <strong>to</strong> compute the instantaneous value of a user-defined function: <strong>Adams</strong>/<strong>Solver</strong> uses<br />

the dependency on state variables <strong>to</strong> create the matrix of partial derivatives (Jacobian) of the system state<br />

with respect <strong>to</strong> the <strong>Adams</strong>/<strong>Solver</strong> state variables. <strong>Adams</strong>/<strong>Solver</strong> uses the Jacobian matrix in several<br />

analysis computations.<br />

If you need <strong>to</strong> access several system states corresponding <strong>to</strong> one modeling element, you should use<br />

SYSARY (see SYSARY).<br />

SYSFNC requires that you specify system-state information as requested from <strong>Adams</strong>/<strong>Solver</strong> as a series<br />

of function call specifications. This is almost as if you were using the function expression capabilities <strong>to</strong>


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

obtain the system state. For example, <strong>to</strong> request DX(12,10,99), you can call SYSFNC with<br />

fncnam='DX', ipar(1)=12, ipar(2)=10, ipar(3)=99, and nsize=3.<br />

When the iflag argument in the user subroutine is true, SYSFNC sets up the dependencies of the system<br />

states on the <strong>Adams</strong>/<strong>Solver</strong> state variables and sets state equal <strong>to</strong> zero. When the iflag argument is false,<br />

SYSFNC returns the instantaneous values of the system states.<br />

Tip: Use SYSARY <strong>to</strong> simultaneously access several states. Quite often, user-defined values<br />

depend on a set of related system states such as all displacement components between two<br />

markers, or all velocity components between two markers. While SYSFNC can be called<br />

several times <strong>to</strong> access the individual components, a single call <strong>to</strong> SYSARY is not only<br />

more convenient, but more efficient. Therefore, we recommend that you use SYSARY<br />

under these circumstances.<br />

Caution: When the iflag argument is true, you must be sure <strong>to</strong> make the same SYSFNC calls as when<br />

actually computing the results. <strong>Adams</strong>/<strong>Solver</strong> passes a parameter iflag <strong>to</strong> each user-written<br />

subroutine (xxxSUB). It indicates <strong>to</strong> you whether <strong>Adams</strong>/<strong>Solver</strong> is calling the subroutine<br />

for an initialization pass (iflag = true) or for a function evaluation (iflag = false). You must<br />

construct user-written subroutines such that all calls <strong>to</strong> SYSFNC that are made during the<br />

simulation are also invoked when the iflag argument is true. <strong>Adams</strong>/<strong>Solver</strong> uses this<br />

information <strong>to</strong> construct the correct Jacobian matrix.<br />

Examples<br />

For examples using the SYSFNC data access subroutine, see the evaluation subroutines SFOSUB and<br />

VARSUB.<br />

SYSPAR<br />

The SYSPAR subroutine lets you supply the analytical partial derivatives of a subroutine with respect <strong>to</strong><br />

values measured through SYSFNC and SYSARY.<br />

When you supply analytical partial derivatives, <strong>Adams</strong>/<strong>Solver</strong> does not need <strong>to</strong> resort <strong>to</strong> finite<br />

differencing <strong>to</strong> approximate these partial derivatives. Therefore, you potentially improve both accuracy<br />

and speed.<br />

SYSPAR can be used for any number (all, some, or none) of the SYSFNC or SYSARY calls made from<br />

your subroutine.<br />

You can also use SYSPAR intermittently. For example, you can use it only during the first half of the<br />

simulation. <strong>Adams</strong>/<strong>Solver</strong> will use the values you provide, when you provide them, and compute them<br />

au<strong>to</strong>matically when you do not.<br />

Note: SYSPAR works primarily in the <strong>Adams</strong>/<strong>Solver</strong> (C++) or with the GSE statement<br />

in <strong>Adams</strong>/<strong>Solver</strong> FORTRAN.<br />

109


110<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Called By<br />

Any user subroutine that can call SYSFNC and SYSARY.<br />

Calling Sequence<br />

CALL SYSPAR (fncname, iparam, nparam, partl, npartl, errflg)<br />

Input Arguments<br />

fncname A character variable specifying the name of the function corresponding<br />

<strong>to</strong> the partial derivatives that are being provided. The legal values for<br />

fncname are derived from the list of functions available <strong>to</strong> you in the<br />

FUNCTION = expression construct. Depending on the subroutine you<br />

are calling, see either SYSARY or SYSFNC for a list of legal characters.<br />

iparam An integer array containing the parameter list for fncnam. It consists of<br />

any valid list of parameters used in the associated <strong>Adams</strong>/<strong>Solver</strong><br />

function, just as they would appear in a dataset FUNCTION =<br />

expression.<br />

nparam An integer variable specifying the number of values in ipar.<br />

partl Array of partial derivatives that you computed.<br />

npartl Number of partial derivatives in partl. <strong>Adams</strong>/<strong>Solver</strong> compares this<br />

number with the number that it expects, and issues an error message if<br />

you provide an incorrect number of partial derivatives.<br />

Output Arguments<br />

errflg A logical variable that returns true if an error has occurred during your<br />

call <strong>to</strong> SYSPAR.<br />

Extended Definition<br />

<strong>Adams</strong>/<strong>Solver</strong> offers a number of user subroutines that you can use <strong>to</strong> define the value of <strong>Adams</strong><br />

variables, differential equations, forces, and so on. The subroutines return values of dimension 1, 3, or 6.<br />

Usually, the subroutines have a dependency on system states through measurements of the system state<br />

provided by a functional interface, SYSFNC and SYSARY. We define the following nomenclature:<br />

F - The value computed by the user subroutine<br />

Mi - The ith measured value<br />

q - The system generalized coordinates<br />

and observe that, in general:


F(M 1 (q), M 2 (q), ..., M N (q))<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Because the user subroutine is effectively a black box, all that <strong>Adams</strong>/<strong>Solver</strong> knows about this function<br />

is that it depends on the measures, Mi, that you call through SYSFNC/SYSARY.<br />

During its analyses, <strong>Adams</strong>/<strong>Solver</strong> must construct a Jacobian matrix of the system of equations. For this<br />

purpose, <strong>Adams</strong>/<strong>Solver</strong> requires the partial derivatives, , of the function relative <strong>to</strong> the system-<br />

generalized coordinates, q.<br />

The FORTRAN 77 version of <strong>Adams</strong>/<strong>Solver</strong> approaches the problem of computing these partial<br />

derivatives in a direct manner, by altering the system states:<br />

∂ F<br />

-----<br />

∂ q<br />

F( qi + ∆)<br />

– F( qi) = -----------------------------------------<br />

∆<br />

We refer <strong>to</strong> this scheme as finite differencing or, more specifically, forward differencing. This approach<br />

has two main problems:<br />

• Some <strong>Adams</strong> elements, particularly the FLEX_BODY element, can have an extremely large<br />

number of generalized coordinates. Computing the partial derivatives in this way can be quite<br />

time consuming. Note that during finite differencing the user subroutine must be evaluated once<br />

for each state, qi, on which it depends.<br />

• You cannot assist <strong>Adams</strong>/<strong>Solver</strong> in the evaluation of the partial derivatives because you do not<br />

have direct access <strong>to</strong> the generalized coordinates, q, that <strong>Adams</strong> uses.<br />

To address these problems, the C++ version of <strong>Adams</strong>/<strong>Solver</strong> takes a different approach <strong>to</strong><br />

computing the partial derivatives. The C++ version applies the chain rule:<br />

∂ F<br />

-------<br />

∂ qi N<br />

∂ F<br />

-------<br />

∂ M<br />

∂ Mj = ∑ --------- =<br />

∂ qi j = 1<br />

N<br />

∑<br />

j = 1<br />

Note that in keeping with the observation that F is a black box, <strong>Adams</strong>/<strong>Solver</strong> continues <strong>to</strong> rely<br />

on finite differencing <strong>to</strong> compute , where Mj is well known and its partial derivatives can<br />

be evaluated analytically. This scheme solves both problems:<br />

• During finite differencing, the user subroutine only needs <strong>to</strong> be evaluated as many times as the<br />

<strong>to</strong>tal dimension of all the measures.<br />

For example, if F depends on the 3D TDISP measure of a marker on a FLEX_BODY, F must<br />

only be evaluated three times during finite differencing, even if the FLEX_BODY has 200<br />

modal generalized coordinates. This is a remarkable computational savings.<br />

∂ F<br />

-----<br />

∂ q<br />

F( Mj + ∆)<br />

– F( Mj) ----------------------------------------------<br />

∆<br />

∂ Mj ---------<br />

∂ qi ∂ F<br />

---------<br />

∂ Mj 111


112<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Note that the computational savings are not always so generous. Consider a function F that<br />

depends on the two 6D measures, DISP and VEL, of a single PART marker, with respect <strong>to</strong><br />

ground. During finite differencing, F must be evaluated 12 times, once for each dimension of<br />

each measure. Meanwhile, the function only depends on the 12 generalized displacements and<br />

velocities of the PART, so the<br />

FORTRAN 77 <strong>Adams</strong>/<strong>Solver</strong> would also only have needed 12 evaluations of F.<br />

• Because you are aware of the functional dependency of the function, F, on the measured<br />

∂ F<br />

---------<br />

∂ Mj quantities, Mi, computing may be straightforward. <strong>Adams</strong>/<strong>Solver</strong> (C++) provides<br />

SYSPAR: an interface you can use <strong>to</strong> register these partial derivatives, in the cases where they<br />

are known and can be efficiently computed.<br />

Note that the potential of user-provided partial derivatives does not only affect the computational<br />

cost of evaluating the system Jacobian, but can also improve the accuracy of simulations and the<br />

rate of convergence. This is because your analytical derivatives are likely <strong>to</strong> be more accurate<br />

than those obtained using finite differencing. When <strong>Adams</strong>/<strong>Solver</strong> uses the Jacobian directly, as<br />

in <strong>Adams</strong>/Linear, the quality of the solution may also be improved.<br />

When F and M have dimension greater than 1, the partial matrix, should be s<strong>to</strong>red in partl<br />

in FORTRAN 77 style column order. In other words, all the partial derivatives of F with respect<br />

<strong>to</strong> the first component of M come before the partial derivatives of F with respect <strong>to</strong> the second<br />

component of M, and so on.<br />

Each call <strong>to</strong> SYSFNC/SYSARY creates what the previous section refers <strong>to</strong> as a measure. For<br />

each of these measures, the crea<strong>to</strong>r of the user subroutine is allowed <strong>to</strong> register the partials of the<br />

function with respect <strong>to</strong> this measure.<br />

You do not need partial derivatives during every call <strong>to</strong> the user's subroutine, because they are<br />

only needed when the Jacobian is being evaluated. You must request the flag that indicates<br />

whether the partial derivatives are required, by calling the following function:<br />

CALL ADAMS_NEEDS_PARTIALS(PARFLG)<br />

∂ F<br />

---------<br />

∂ Mj Note that, ideally, the PARFLG would have been added <strong>to</strong> the user subroutine call, alongside<br />

IFLAG and DFLAG, but the user subroutines have a standard interface that cannot be changed.


Examples<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

You can make calls <strong>to</strong> SYSPAR only for those SYSFNC/SYSARY for which partials are<br />

conveniently available. As mentioned earlier, you can make SYSPAR calls intermittently. In<br />

other words, you can call SYSPAR only during some period of the simulation when partials can<br />

be easily computed, but skipped during other parts of the simulation. For example, when an<br />

impact force is zero, its partials are trivially zero.<br />

Caution: SYSPAR is optional. You should expect the number of function evaluations and CPU time<br />

<strong>to</strong> decrease. If they do not, you may have made a mistake.<br />

Using an SFOSUB with SYSPAR<br />

The following example shows how a SFOSUB has been modified <strong>to</strong> use SYSPAR. The SFOSUB<br />

computes VALUE = DX(1,2)*VZ(1,2).<br />

Relating this <strong>to</strong> the terminology used earlier, we have:<br />

F = M 1 M 2<br />

where M 1 = DX(1,2) and M 2 = VZ(1,2). Consequently:<br />

∂ F<br />

---------- = VZ( 1, 2)<br />

∂ M1 and<br />

∂ F<br />

---------- =<br />

DX( 1, 2)<br />

∂ M2 When you do not provide partial information, <strong>Adams</strong>/<strong>Solver</strong> fills in the blanks using finite<br />

differencing.<br />

It is, of course, an error <strong>to</strong> call SYSPAR without a matching call <strong>to</strong> SYSFNC or SYSARY.<br />

The SFOSUB implementation follows:<br />

SUBROUTINE SFOSUB (ID, TIME, PAR, NPAR, DFLAG, IFLAG, VALUE)<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

113


114<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

DOUBLE PRECISION DX, VZ<br />

INTEGER NUM, IPAR(2)<br />

LOGICAL ERRFLG<br />

LOGICAL PARFLG<br />

CALL ADAMS_NEEDS_PARTIALS(PARFLG)<br />

IPAR(1) = PAR(1)<br />

IPAR(2) = PAR(2)<br />

CALL SYSFNC('DX', IPAR, 2, DX, ERRFLG )<br />

CALL SYSFNC('VZ', IPAR, 2, VZ, ERRFLG )<br />

VALUE = DX*VZ<br />

IF(PARFLG) THEN<br />

CALL SYSPAR('DX', IPAR, 2, VZ, 1, ERRFLG)<br />

CALL SYSPAR('VZ', IPAR, 2, DX, 1, ERRFLG)<br />

ENDIF<br />

CALL ERRMES(ERRFLG,'ERROR FOR SFORCE ',ID,'STOP')<br />

RETURN<br />

END<br />

Using SYSPAR with Utility <strong>Subroutines</strong><br />

This SFOSUB example shows how you can use SYSPAR in conjunction with utility subroutines. In this<br />

SFOSUB you have:<br />

VALUE = -IMPACT(400-DM(12,9),-VR(12,9))<br />

or, using the nomenclature developed earlier:<br />

F = -IMPACT(400-M 1 ,-M 2 )<br />

where M 1 = DM(12,9) and M 2 = VR(12,9). Here, you must rely on the ability of the IMPACT utility<br />

function <strong>to</strong> provide partial derivatives of its arguments.<br />

∂ F<br />

----------<br />

∂ M1 ∂ F<br />

----------<br />

∂ M2 =<br />

=<br />

∂ IMPACT<br />

-------------------------- ( 400 – M<br />

∂ M 1′ – M2) ( – 1)<br />

1<br />

∂ IMPACT<br />

-------------------------- ( 400 – M<br />

∂ M 1′ – M2) ( – 1)<br />

2<br />

The implementation follows. Pay close attention <strong>to</strong> the use of the IORD argument (argument 8) <strong>to</strong> the<br />

IMPACT function. It controls whether 0th, 1st, or 2nd derivative of the impact is being requested. Learn<br />

more about the IMPACT function (C++ or FORTRAN).


SUBROUTINE SFOSUB (ID, TIME, PAR, NPAR, DFLAG, IFLAG, VALUE)<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

DOUBLE PRECISION DM, VR, V(3)<br />

INTEGER IPAR(2)<br />

LOGICAL ERRFLG, PARFLG<br />

IPAR(1)=12<br />

IPAR(2)=9<br />

CALL ADAMS_NEEDS_PARTIALS(PARFLG)<br />

CALL SYSFNC('DM', IPAR, 2, DM, ERRFLG )<br />

CALL SYSFNC('VR', IPAR, 2, VR, ERRFLG )<br />

IF(PARFLG) THEN<br />

CALL IMPACT(400.D0-DM,-VR,100D0,1.D2,1.5D0, 1D1,1.D0,1,V,ERRFLG)<br />

CALL SYSPAR('DM', IPAR, 2, V(1), 1, ERRFLG )<br />

CALL SYSPAR('VR', IPAR, 2, V(2), 1, ERRFLG )<br />

ENDIF<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

CALL IMPACT(400-DM,-VR,100D0,100.0D0,1.5D0,10D0,1.0D0,0,V,ERRFLG)<br />

VALUE=-V(1)<br />

CALL ERRMES(ERRFLG,'ERROR FOR SFORCE',ID,'STOP')<br />

RETURN<br />

END<br />

Using FIESUB with SYSPAR<br />

This example, involving FIESUB, shows how SYSPAR has closed the functionality gap between<br />

GFOSUB and FIESUB. In the FORTRAN 77 version of <strong>Adams</strong>/<strong>Solver</strong>, the ability <strong>to</strong> define partial<br />

derivatives of the FIELD element in a FIESUB user subroutine gives it a computational advantage over<br />

the GFORCE force element and a GFOSUB user subroutine. The FIESUB user subroutine is defined as<br />

follows:<br />

CALL FIESUB(ID, TIME, PAR, NPAR, DISP, VELO,<br />

DFLAG, IFLAG, FIELD, DFDDIS, DFDVEL)<br />

where DISP and VELO are the displacement and velocity of the I and J markers of the field element that<br />

are input <strong>to</strong> FIESUB. FIESUB computes the 6D value of the force, FIELD. Also, when DFLAG is<br />

TRUE, you must provide the partial derivatives with respect <strong>to</strong> displacement, DFDDIS, and the partial<br />

derivatives with respect <strong>to</strong> velocity, DFDVEL. Learn more about FIELD (C++ or FORTRAN).<br />

115


116<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

The removal of the advantage of FIESUB over GFOSUB is demonstrated by implementing the FIESUB<br />

in a GFOSUB:<br />

SUBROUTINE GFOSUB (ID, TIME, PAR, NPAR, DFLAG, IFLAG, RESULT)<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT(6)<br />

DOUBLE PRECISION DISP(6), VELO(6)<br />

DOUBLE PRECISION DFDDIS(6,6), DFDVEL(6,6)<br />

INTEGER IPAR(4)<br />

LOGICAL ERRFLG, PARFLG<br />

C<br />

C This GFOSUB should never be finite differenced<br />

C<br />

CALL ERRMES(DFLAG,'DFLAG=.TRUE. UNEXPECTED',ID,'STOP')<br />

C<br />

C Check if partials are needed<br />

C<br />

CALL ADAMS_NEEDS_PARTIALS(PARFLG)<br />

C<br />

C Measure displacements, projection angles and velocity<br />

C between markers I and J (PAR(1) and PAR(2)). Note that<br />

C velocity measure takes four marker arguments because<br />

C FIESUB uses velocity of I wrt J in coordinate system<br />

C of J with observer in J.<br />

C<br />

IPAR(1)=NINT(PAR(1))<br />

IPAR(2)=NINT(PAR(2))<br />

IPAR(3)=NINT(PAR(2))<br />

IPAR(4)=NINT(PAR(2))<br />

C<br />

CALL SYSARY('TDISP', IPAR, 3, DISP, 3, ERRFLG )<br />

CALL SYSFNC('AX', IPAR, 2, DISP(4), ERRFLG )<br />

CALL SYSFNC('AY', IPAR, 2, DISP(5), ERRFLG )<br />

CALL SYSFNC('AZ', IPAR, 2, DISP(6), ERRFLG )<br />

CALL SYSARY('VEL', IPAR, 4, VELO, 6, ERRFLG )<br />

IF(PARFLG) THEN<br />

DO 100 I = 1 , 6


DO 100 J = 1 , 6<br />

DFDDIS(I,J)=0.D0<br />

DFDVEL(I,J)=0.D0<br />

100 CONTINUE<br />

ENDIF<br />

C<br />

C Subtract the free length, PAR(3),...,PAR(8)<br />

C<br />

DO 200 I = 1 , 6<br />

DISP(I)=DISP(I)-PAR(I+2)<br />

200 CONTINUE<br />

CALL FIESUB(ID, TIME, PARS, NPAR, DISP, VELO, PARFLG, IFLAG,<br />

+ VALUE, DFDDIS, DFDVEL)<br />

IF (PARFLG) THEN<br />

CALL SYSPAR('TDISP', IPAR, 3, DFDDIS, 18, ERRFLG)<br />

CALL SYSPAR('AX', IPAR, 2, DFDDIS(1,4), 6, ERRFLG)<br />

CALL SYSPAR('AY', IPAR, 2, DFDDIS(1,5), 6, ERRFLG)<br />

CALL SYSPAR('AZ', IPAR, 2, DFDDIS(1,6), 6, ERRFLG)<br />

CALL SYSPAR('VEL', IPAR, 4, DFDVEL, 36, ERRFLG)<br />

ENDIF<br />

RETURN<br />

END<br />

Debugging<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

When modifying a user subroutine by adding SYSPAR calls, you may be concerned about the<br />

correctness of the partial derivatives. In this case, you can define the environment variable<br />

MDI_DEBUG_SYSPAR. When this environment variable is set, <strong>Adams</strong>/<strong>Solver</strong> uses finite differencing<br />

<strong>to</strong> verify the user-provided partial derivative and write debug information <strong>to</strong> the standard output (the<br />

terminal). For example:<br />

SFOSUB(1): DZ(1,11) A: 5.00000E+00 U: 2.06158E+11<br />

which informs you that during the verification of the SFOSUB for SFORCE/1, you provided the value<br />

2.06158E+11 for the partial derivative with respect <strong>to</strong> the DZ(1,11) measure, but <strong>Adams</strong>/<strong>Solver</strong> found,<br />

using finite differencing, that this value should be 5.0. A closer inspection of the source code reveals that<br />

it contained single precision:<br />

CALL SYSPAR('DZ', IPAR, 2, 5., 1, ERRFLG)<br />

rather than double precision:<br />

CALL SYSPAR('DZ', IPAR, 2, 5.D0, 1, ERRFLG)<br />

117


118<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Computing Partial Derivatives<br />

The computation of the partial derivatives of a complicated FORTRAN subroutine can be an<br />

overwhelming task. MSC investigated the software, Au<strong>to</strong>matic Differentiation of FORTRAN<br />

(ADIFOR), that may be able <strong>to</strong> au<strong>to</strong>mate this task.<br />

ADIFOR is a <strong>to</strong>ol for au<strong>to</strong>matic computation of derivatives of function defined in FORTRAN 77<br />

programs.<br />

Au<strong>to</strong>matic differentiation is a technique for computing the derivatives of functions described by<br />

computer programs. ADIFOR implements au<strong>to</strong>matic differentiation by transforming a collection of<br />

FORTRAN 77 subroutines that compute a function f in<strong>to</strong> new FORTRAN 77 subroutines that compute<br />

the derivatives of the outputs of f with respect <strong>to</strong> a specified set of inputs of f.<br />

ADIFOR 2.0 consists of:<br />

• ADIFOR Preprocessor<br />

• ADIntrinsics template expander and library<br />

• SparsLinC library.<br />

Figure 1 shows a block diagram of the ADIFOR 2.0 process, which consists of three steps:<br />

1. Apply the ADIFOR Preprocessor <strong>to</strong> your FORTRAN 77 program <strong>to</strong> produce augmented code for<br />

the computation of derivatives. The preprocessor invokes the ADIntrinsics template expander<br />

directly.<br />

2. Construct a derivative driver code that invokes the generated derivative code and uses the<br />

computed derivatives.<br />

3. Compile the generated derivative code and your derivative driver code, and link these with the<br />

derivative support packages. That is, the ADIntrinsics exception handling package and<br />

(optionally) the SparsLinC sparse derivative package.<br />

Figure 1. Block Diagram of the ADIFOR Process


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

To retrieve the ADIFOR 2.0 au<strong>to</strong>matic differentiation software for educational and non-profit research<br />

use, and for commercial evaluation, visit either of the ADIFOR group Web sites, at:<br />

http://www.mcs.anl.gov/adifor or http://www.cs.rice.edu/~adifor. These pages describe how <strong>to</strong> request<br />

access <strong>to</strong> ADIFOR 2.0 and download the software. The pages also contain links <strong>to</strong> publications related<br />

<strong>to</strong> ADIFOR, as well as legal notices.<br />

TCNVRT<br />

TCNVRT converts translational coordinates from one representation <strong>to</strong> another.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL TCNVRT (sys1, coord1, sys2, coord2, istat)<br />

119


120<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

sys1 A character string specifying the system in which the values passed in<br />

coord1 were determined. The possible character strings and their<br />

meanings are:<br />

Output Arguments<br />

Extended Definition<br />

MOTSUB, REQSUB, or SFOSUB can call TCNVRT <strong>to</strong> change the Cartesian coordinates used <strong>to</strong> specify<br />

a displacement vec<strong>to</strong>r <strong>to</strong> cylindrical coordinates.<br />

TIMGET<br />

CARTESIAN - Cartesian coordinates (x, y, and z).<br />

CYLINDRICAL - Cylindrical coordinates (radius, theta, and z).<br />

SPHERICAL - Spherical coordinates (radius, phi, and theta).<br />

Note: Do not confuse this phi and theta with the Euler angles named<br />

phi and theta.<br />

coord1 A double-precision array containing the coordinates <strong>to</strong> be converted.<br />

Angles should be input in radians.<br />

sys2 A character string specifying the system in which the values returned as<br />

output in coord2 are <strong>to</strong> be determined. Possible character strings are the<br />

same as those for sys1.<br />

coord2 The converted coordinates as output. Angles are output in radians.<br />

istat An integer variable indicating either the success or the reason for the<br />

failure of the call <strong>to</strong> TCNVRT.<br />

If: Then:<br />

istat= 0 The call <strong>to</strong> TCNVRT was successful.<br />

istat= -1 The coordinate system for sys1 was not<br />

correctly specified.<br />

istat= -2 The coordinate system for sys2 was not<br />

correctly specified.<br />

TIMGET returns the simulation time corresponding <strong>to</strong> the last successful simulation step.


Use<br />

Called By<br />

Any user-written subroutine<br />

Calling Sequence<br />

CALL TIMGET (time)<br />

Output Argument<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

time A double-precision scalar that contains the simulation time at the end of the<br />

last successful step.<br />

Extended Definition<br />

TIMGET is primarily useful in situations where past values of system states are <strong>to</strong> be used in defining<br />

the current values of system. In some applications, you need <strong>to</strong> determine when a specific time has been<br />

successfully passed in the simulation. The value of the time argument passed <strong>to</strong> user-written subroutines<br />

is the current simulation time, and is therefore not a reliable indica<strong>to</strong>r of the last successful simulation<br />

time. Moreover, if convergence at the current time is not achieved, <strong>Adams</strong>/<strong>Solver</strong> backs up <strong>to</strong> the last<br />

successful simulation step and tries a new step.<br />

The value of simulation time returned by TIMGET represents a successful simulation time.<br />

<strong>Adams</strong>/<strong>Solver</strong> never backs up over this time again.<br />

Digital control systems are instances where the values provided by TIMGET are useful. Digital control<br />

systems are characterized by the fact that observations of system states are taken at pre-specified regular<br />

intervals named sampling periods. Based on the system states sampled and the governing control laws,<br />

forces acting on the system are defined. These forces are held constant until the next sample period,<br />

regardless of how the system state changed.<br />

Make sure that you only sample converged values of system states when determining the current system<br />

state. TIMGET is useful in this context, because it provides <strong>to</strong> user subroutines a record of when a set of<br />

system states have converged.<br />

Tip: SENSUB has commonly been used <strong>to</strong> identify a successful simulation step. You don't need<br />

<strong>to</strong> rely on TIMGET anymore.<br />

UCOVAR<br />

UCOVAR is used with UCOSUB, <strong>to</strong> tell <strong>Adams</strong>/<strong>Solver</strong> the part states that are used in the user-defined<br />

constraint.<br />

121


122<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Called By<br />

UCOSUB<br />

Prerequisite<br />

UCOSUB iflag parameter equals .TRUE.<br />

Calling Sequence<br />

CALL UCOVAR (id, nparts, lparts, nvars, lvars)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that specifies the ID of the UCON statement for<br />

which you are defining the variables. Use the identifier in the UCOSUB<br />

argument list.<br />

nparts An integer variable that specifies the <strong>to</strong>tal number of elements in the<br />

array lparts. The value of nparts must equal the value of nvars.<br />

123


124<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

lparts An integer array that lists the part identifiers corresponding <strong>to</strong> the<br />

variable types in lvars. The number of part identifiers in lparts must<br />

equal the number of integer codes in lvars. Thus the lparts and lvars<br />

arrays must be equal in length.<br />

nvars An integer value that indicates the <strong>to</strong>tal number of integer codes in lvars.<br />

The value of nvars must equal the value of nparts.<br />

The function: Means that:<br />

11 X displacement of the part center-of-mass with<br />

respect <strong>to</strong> ground<br />

12 Y displacement of the part center-of-mass with<br />

respect <strong>to</strong> ground<br />

13 Z displacement of the part center-of-mass with<br />

respect <strong>to</strong> ground<br />

14 Psi Euler rotation of part principle axis with respect<br />

<strong>to</strong> ground<br />

15 Theta Euler rotation of part principle axis with<br />

respect <strong>to</strong> ground<br />

16 Phi Euler rotation of part principle axis with respect<br />

<strong>to</strong> ground<br />

21 X velocity of the part center-of-mass with respect<br />

<strong>to</strong> ground<br />

22 Y velocity of the part center-of-mass with respect<br />

<strong>to</strong> ground<br />

23 Z velocity of the part center-of-mass with respect <strong>to</strong><br />

ground<br />

24 Psi time derivative<br />

25 Theta time derivative<br />

26 Phi time derivative<br />

Note that the tens digit is one for displacement codes and two for<br />

velocity codes. Also, note that the ones digit indicates a translational or<br />

a rotational component with an integer from one <strong>to</strong> six. All translational<br />

variable values refer <strong>to</strong> the motion of the part center-of-mass, and all<br />

rotational variable values refer <strong>to</strong> the rotation of the principal axes, with<br />

respect <strong>to</strong> the ground reference frame. The number of integer codes in<br />

lvars must equal the number of part identifiers in lparts. Therefore, the<br />

lvars and lparts arrays must be equal in length.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

lvars An integer array that contains the integer codes that identify the variables<br />

involved in the constraint. The table below defines the codes that lvars<br />

can contain.<br />

Extended Definition<br />

UCOVAR tells <strong>Adams</strong>/<strong>Solver</strong> which of the principal axes coordinates are used in the user-defined<br />

constraint. <strong>Adams</strong>/<strong>Solver</strong> subsequently passes these <strong>to</strong> the evaluation subroutine UCOSUB in the array<br />

q. UCOSUB should call UCOVAR in response <strong>to</strong> a true initialization flag (iflag). For an example of a<br />

UCOSUB evaluation subroutine that calls UCOVAR, see UCOSUB.<br />

Caution: • The arrays lparts and lvars can contain as many as thirty values. Don't attempt <strong>to</strong><br />

load and pass these two arrays with more than thirty values in each.<br />

USRMES<br />

USRMES allows you <strong>to</strong> output messages for information or for documenting errors that occur in userwritten<br />

subroutines.<br />

Use<br />

Called By<br />

Any user-written subroutine<br />

• When selecting the displacements or the velocities of the part principal axes for the<br />

constraint, remember that the part principal axes are not always identical <strong>to</strong> those<br />

of the part center-of-mass marker (cm). The following list summarizes the<br />

circumstances in which the part principal axes may differ from those of the part<br />

center-of-mass marker.<br />

• When the PART statement does not include the CM argument, the principal<br />

axes default <strong>to</strong> the body coordinate system.<br />

• Whenever the center-of-mass marker z-axis is parallel <strong>to</strong> the z-axis of the<br />

ground reference frame at time zero, <strong>Adams</strong>/<strong>Solver</strong> permutes the internal<br />

representation of the principal axes by 90-degree rotations, <strong>to</strong> avoid an Euler<br />

matrix singularity.<br />

• If the IP argument in the PART statement includes products of inertia,<br />

<strong>Adams</strong>/<strong>Solver</strong> computes the inertial representation of the principal axes so that<br />

the products of inertia all become zero.<br />

• When specifying an IM marker, <strong>Adams</strong>/<strong>Solver</strong> computes the principal axes,<br />

which may or may not be the axes of the cm marker.<br />

125


126<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Prerequisite<br />

None<br />

Calling Sequence<br />

CALL USRMES (msgflg, mesage, id, msgtyp)<br />

Input Arguments<br />

id An integer variable that specifies the ID of the statement that is currently<br />

invoking the user-written subroutine.<br />

mesage A character string or variable of as many as eighty characters that you<br />

want USRMES <strong>to</strong> document. This character string should be a<br />

descriptive message and should include the name of the subroutine<br />

issuing the message.<br />

msgflg A logical (true or false) variable. When msgflg is true, USRMES<br />

documents a message.<br />

msgtyp A character variable that indicates what type of message is given.<br />

msgtyp can have one of four values:<br />

Extended Definition<br />

INFO - For information messages<br />

WARN - For warnings<br />

ERROR - For error messages<br />

FAULT - For fatal error messages<br />

INFO_NOPAD - Prints out the information message but without the<br />

USRMES:USER1 tag before the message<br />

LOGINF - Writes out the message in the message file but doesn’t print<br />

it out on the screen<br />

If msgtyp has any other value, <strong>Adams</strong>/<strong>Solver</strong> issues an information<br />

message.<br />

USRMES allows you <strong>to</strong> output messages from user-written subroutines. The messages always go <strong>to</strong> the<br />

Message File, and during interactive execution, <strong>Adams</strong>/<strong>Solver</strong> displays them on the screen.


User-Written <strong>Subroutines</strong><br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

User-written subroutines, while a little more difficult <strong>to</strong> use, provide a degree of generality, efficiency<br />

and flexibility that function expressions do not. <strong>Subroutines</strong> allow you <strong>to</strong> use FORTRAN-77 features <strong>to</strong><br />

define functions not otherwise available with <strong>Adams</strong>/<strong>Solver</strong>, and <strong>to</strong> tailor <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> your needs.<br />

By linking in user-written subroutines, you don't lose any efficiency or decrease the simulation speed.<br />

<strong>Subroutines</strong> and function expressions serve essentially the same purpose: they both allow you <strong>to</strong> define<br />

non-standard input <strong>to</strong> <strong>Adams</strong>.<br />

Function expressions are easier <strong>to</strong> work with, because you don't have <strong>to</strong> compile or link programs. Also,<br />

they work on every machine on which <strong>Adams</strong>/<strong>Solver</strong> is available. User-written subroutines, however,<br />

are much more general. The power of the programming language is available <strong>to</strong> define modeling<br />

elements or special output.<br />

On the other hand, function expressions support a limited set of programming constructs. Therefore,<br />

complicated phenomena, especially those involving a lot of logic, cannot be easily described using<br />

function expressions.<br />

You use user-written subroutines when:<br />

• Dataset functions become awkward.<br />

• You need <strong>to</strong> define functions used by a group of users.<br />

• Statements, such as GSE and UCON, require them.<br />

• You want <strong>to</strong> control the running of complex simulations that require decision-making logic.<br />

Write user-written subroutines with care because incorrectly coded subroutines are very difficult <strong>to</strong><br />

debug. Follow a crawl-walk-run approach for developing user subroutines. Start with simple versions of<br />

a user-written subroutine, make sure it works as desired, then gradually increase the complexity of the<br />

subroutine. Make sure that there are no compiler or linker warnings when your subroutine is linked in<strong>to</strong><br />

<strong>Adams</strong>.<br />

The "C" style interface <strong>to</strong> user subroutines has been enhanced <strong>to</strong> replace some of the arguments with a<br />

pointer <strong>to</strong> a structure. This will require changes <strong>to</strong> your user subroutine source code. If you are using the<br />

fortran style interface <strong>to</strong> user subroutines you will not be effected and no changes will be required.<br />

The new argument list <strong>to</strong> the "C" style interface replaces some of the arguments with a pointer <strong>to</strong> a<br />

structure. This structure contains the replaced arguments plus additional information. Old arguments<br />

such as ID, PAR, and NPAR have been incorperated in<strong>to</strong> the structure. New arguments such as marker<br />

id's have been added <strong>to</strong> the structure.<br />

CFFSUB<br />

The CFFSUB evaluation subroutine computes a set of friction force values for a CONTACT statement<br />

(C++ or FORTRAN). You can use a CFFSUB when the default friction force routine is not applicable <strong>to</strong><br />

your model.<br />

127


128<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Calling Sequence<br />

SUBROUTINE CFFSUB (id, time, par, npar, loci, locj, x, xdot, nforce, area, dflag, iflag, result)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

area A double-precision variable that specifies the value of the contact area.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls CFFSUB <strong>to</strong><br />

evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong> false.<br />

id An integer variable that provides the identifier of the CONTACT statement<br />

requesting information from CFFSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically recognizes other information (such as the par argument) that is<br />

available in the corresponding statement.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the functional<br />

dependency information from CFFSUB. Functional dependencies are<br />

established with the same calls <strong>to</strong> SYSARY and SYSFNC that are later used<br />

<strong>to</strong> compute the values of the CONTACT components (see SYSARY and<br />

SYSFNC). If the iflag argument is false, the values of the user-defined<br />

expressions are computed.<br />

loci A double-precision array that specifies the vec<strong>to</strong>r from the reference marker<br />

of the CONTACT I Geometry (IGEOM) <strong>to</strong> the contact point on IGEOM.<br />

Expressed in the coordinate system of the reference marker of IGEOM.<br />

locj A double-precision array that specifies the vec<strong>to</strong>r from the reference marker<br />

of the CONTACT J Geometry (JGEOM) <strong>to</strong> the contact point on JGEOM.<br />

Expressed in the coordinate system of the reference marker of JGEOM.<br />

nforce A double-precision variable that specifies the value of the contact normal<br />

force.<br />

npar An integer variable that indicates the number of constants you specify in the<br />

USER parenthetical list. This variable provides the CFFSUB evaluation<br />

subroutine with the number of values s<strong>to</strong>red in the par array.<br />

par A double-precision array of constants taken in order from the<br />

FRICTION_FUNCTION USER parenthetical list of the CONTACT<br />

statement.<br />

129


130<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the current<br />

simulation time.<br />

x A double-precision array that specifies the values of the contact deformation.<br />

Output Argument<br />

Extended Definition<br />

(1) - Translational deformation since the beginning of contact along the x-axis<br />

of the contact I incident marker.<br />

(2) - Translational deformation since the beginning of contact along the y-axis<br />

of the contact I incident marker.<br />

(3) - Rotational deformation since the beginning of contact about the z-axis of<br />

the contact I incident marker.<br />

xdot A double-precision array that specifies the slip velocities at the contact point.<br />

(1) - Translational slip velocity along the x-axis of the contact<br />

I incident marker.<br />

(2) - Translational slip velocity along the y-axis of the contact<br />

I incident marker.<br />

(3) - Relative angular velocity of contacting surfaces about the<br />

z-axis of the contact I incident marker.<br />

result A double-precision array that returns the three components of the friction force.<br />

(1) - Translational force along the x-axis of the contact I incident marker.<br />

(2) - Translational force along the y-axis of the contact I incident marker.<br />

(3) - Rotational <strong>to</strong>rque about the z-axis of the contact I incident marker.<br />

The default friction model in the CONTACT statement can only model simple dynamic friction. This<br />

means that <strong>to</strong> produce a friction force, contacting bodies must be sliding at the point of contact. Effects<br />

such as static friction and frictional <strong>to</strong>rque are not modeled.<br />

If you require another force model, you can use a CFFSUB. If the algorithms use or consist of alreadyexisting<br />

FORTRAN-77 subroutines, CFFSUB can be made <strong>to</strong> call them. You can call utility subroutines,<br />

such as AKISPL, CUBSPL, SYSARY, and SYSFNC from CFFSUB, <strong>to</strong> obtain information about system<br />

variables, user-defined variables, and splines.<br />

The SYSARY and SYSFNC utility subroutines set functional dependencies when the CFFSUB argument<br />

iflag is true. To compute solutions efficiently, <strong>Adams</strong>/<strong>Solver</strong> must know the other variables on which


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

each user-defined variable depends. <strong>Adams</strong>/<strong>Solver</strong> determines these functional dependencies at the<br />

beginning of the simulation by calling CFFSUB with the argument iflag set <strong>to</strong> true. <strong>Adams</strong>/<strong>Solver</strong> does<br />

this once for each CONTACT statement with a<br />

FRICTION_FUNCTION=USER() argument.<br />

During each call <strong>to</strong> CFFSUB, <strong>Adams</strong>/<strong>Solver</strong> records which calls you make <strong>to</strong> SYSARY and SYSFNC.<br />

<strong>Adams</strong>/<strong>Solver</strong> assumes that the CONTACT components depend on those <strong>Adams</strong>/<strong>Solver</strong> variables that<br />

are accessed through SYSARY and SYSFNC.<br />

Using the DFLAG Variable<br />

The use of the DFLAG variable is optional. Its purpose is <strong>to</strong> simply let you know that CFFSUB is being<br />

called <strong>to</strong> evaluate a partial derivative. One of the states on which the CFFSUB depends has been<br />

perturbed very slightly. In many situations, it is likely that major calculations in the CFFSUB are<br />

insensitive <strong>to</strong> small changes in state, and therefore, need not be recalculated. In such situations, you can<br />

structure the CFFSUB not <strong>to</strong> redo these calculations.<br />

Tip: If the SYSARY or SYSFNC subroutines are called <strong>to</strong> access angular displacements, the<br />

values returned by CFFSUB may contain discontinuities. Discontinuities occur if there is<br />

an Euler singularity. To avoid the Euler singularity (and thus the discontinuities), use the<br />

RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other coordinate system that does not encounter a singularity.<br />

Fortran - Pro<strong>to</strong>type<br />

• If the calculations always use the same SYSARY and SYSFNC calls through the<br />

whole simulation, and you have no initialization <strong>to</strong> do, you do not need <strong>to</strong> check<br />

the flag argument at all. You can just call SYSARY and/or SYSFNC, compute the<br />

user-defined variable value, and return <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN)<br />

Caution: When the iflag argument is true:<br />

• You must make all the calls <strong>to</strong> SYSARY and SYSFNC as they are made <strong>to</strong><br />

compute the component values of the CONTACT statement. This ensures that<br />

<strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies. In general, failure <strong>to</strong><br />

account for dependencies in the CONTACT statement components can make it<br />

difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a solution and/or can force<br />

<strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> take small integration steps, potentially causing large increases in<br />

execution time.<br />

• SYSARY and SYSFNC return zero values for system and user-defined variables.<br />

When you use <strong>Adams</strong>/<strong>Solver</strong>, computations that divide by these values result in<br />

fatal errors. You should check for nonzero values, or ensure the iflag argument is<br />

set <strong>to</strong> false, before dividing by these values.<br />

A sample structure for CFFSUB is shown next. The comments explain how the subroutine works.<br />

131


132<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

SUBROUTINE CFFSUB(ID, TIME,PAR, NPAR, LOCI, LOCJ, X, XDOT,<br />

& NFORCE, DFLAG, IFLAG, FORCE)<br />

C<br />

C === Type and dimension statements ===================<br />

IMPLICIT NONE<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

DOUBLE PRECISION LOCI(3)<br />

DOUBLE PRECISION LOCJ(3)<br />

DOUBLE PRECISION X(3)<br />

DOUBLE PRECISION XDOT(3)<br />

DOUBLE PRECISION NFORCE<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION FORCE(3)<br />

C<br />

C Input parameters<br />

C<br />

C ID Identifier of calling CONTACT statement<br />

C TIME Current timeC PAR Array containing passed parameters<br />

C PAR(1) - stiction coefficient<br />

C PAR(2) - friction coefficient<br />

C PAR(3) - stiction velocity<br />

C PAR(4) - friction velocity<br />

C NPAR Number of passed parameters<br />

C LOCI contact point location on I in I coordinates<br />

C LOCI contact point location on J in J coordinates<br />

C X sliding displacement since the beginning of contact<br />

C X(1) - translational deformation in x<br />

C X(2) - translational deformation in y<br />

C X(3) - rotational deformation about z<br />

C XDOT slip velocity of contact point<br />

C XDOT(1) - slip velocity in x<br />

C XDOT(2) - slip velocity in y<br />

C XDOT(3) - relative angular velocity about z<br />

C NFORCE contact normal force<br />

C<br />

C components returned <strong>to</strong> ADAMS<br />

C<br />

C FORCE Array (dimension 3) of computed CNFORC<br />

C FORCE(1) - force in x direction<br />

C FORCE(2) - force in y direction<br />

C FORCE(3) - <strong>to</strong>rque about z axis<br />

C Local variable and parameter definitions<br />

C<br />

DOUBLE PRECISION US<br />

DOUBLE PRECISION UD<br />

DOUBLE PRECISION VS<br />

DOUBLE PRECISION VD<br />

DOUBLE PRECISION H0, H1, X0, X1, TEMP1, TEMP2<br />

LOGICAL ERRFLG


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C<br />

C ===Executable code ==================================<br />

C<br />

US = PAR(1)<br />

UD = PAR(2)<br />

VS = PAR(3)<br />

VD = PAR(4)<br />

X0 = -VS<br />

H0 = -1<br />

X1 = VS<br />

H1 = 1<br />

CALL STEP(XDOT(1), X0, H0, X1,H1, 0, TEMP1, ERRFLG)<br />

CALL ERRMES(ERRFLG,'ERROR CALLING STEP',ID,'STOP')<br />

X0 = VS<br />

H0 = US<br />

X1 = VD<br />

H1 = UD<br />

CALL STEP(XDOT(1), X0, H0, X1, H1, 0, TEMP2, ERRFLG)<br />

CALL ERRMES(ERRFLG,'ERROR CALLING STEP',ID,'STOP')<br />

FORCE(1) = -NFORCE*TEMP1*TEMP2<br />

FORCE(2) = 0.0<br />

FORCE(3) = 0.0<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_CFFSUB(const struct s<strong>Adams</strong>ContactFriction* fric,<br />

double TIME, const double* LOCI, const double* LOCJ, const double* X,<br />

const double* XDOT, double NFORCE, double AREA, int DFLAG, int IFLAG,<br />

double* VALUES );<br />

typedef void STDCALL adams_f77_CFFSUB(const int* ID, const double*<br />

TIME, const double* PAR, const int* NPAR, const double* LOCI, const<br />

double* LOCJ, const double* X, const double* XDOT, const double*<br />

NFORCE, const double* AREA, const int* DFLAG, const int* IFLAG,<br />

double* VALUES );<br />

struct s<strong>Adams</strong>Contact<br />

{<br />

int ID;<br />

int nIGEOM;<br />

int nJGEOM;<br />

int* IGEOM;<br />

int* JGEOM;<br />

int* IFLIP_GEOM;<br />

int* JFLIP_GEOM;<br />

};<br />

struct s<strong>Adams</strong>ContactFriction<br />

{<br />

struct s<strong>Adams</strong>Contact contact;<br />

int NPAR;<br />

const double* PAR;<br />

133


134<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

};<br />

CNFSUB<br />

The CNFSUB evaluation subroutine computes a set of normal force values for a CONTACT statement<br />

(C++ or FORTRAN). You can use a CNFSUB when the default normal force routine is not applicable <strong>to</strong><br />

your model.<br />

Use<br />

Calling Sequence<br />

SUBROUTINE CNFSUB (id, time, par, npar, loci, ni, locj, nj, gap, gapdot, gapdotdot, area, dflag, iflag,<br />

result)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

area A double-precision variable that specifies the value of the contact area.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls CNFSUB <strong>to</strong><br />

evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong> false.<br />

gap A double-precision variable that specifies the value of the contact pe<strong>net</strong>ration.<br />

gap ≥ no pe<strong>net</strong>ration<br />

gap < 0 pe<strong>net</strong>ration<br />

gapdot A double-precision variable that specifies the first time-derivative of the gap.<br />

gapdot ≥<br />

0 gap is increasing (pe<strong>net</strong>ration is decresing)<br />

gapdot < 0 gap is decreasing (pe<strong>net</strong>ration is increasing)<br />

gapdotdot A double-precision variable that specifies the second time-derivative of the gap.<br />

gapdotdot >= 0 gapdot is increasing<br />

gapdotdot < 0 gapdot is decreasing<br />

id An integer variable that provides the identifier of the CONTACT statement<br />

requesting information from CNFSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically recognizes other information (such as the par argument) that is<br />

available in the corresponding statement.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the functional<br />

dependency information from CNFSUB. Functional dependencies are<br />

established with the same calls <strong>to</strong> SYSARY and SYSFNC that are later used <strong>to</strong><br />

compute the values of the CONTACT components (see SYSARY and<br />

SYSFNC). If the iflag argument is false, the values of the user-defined<br />

expressions are computed.<br />

loci A double-precision array that specifies the vec<strong>to</strong>r from the reference marker of<br />

the CONTACT I Geometry (IGEOM) <strong>to</strong> the contact point on IGEOM. Expressed<br />

in the coordinate system of the reference marker of IGEOM.<br />

locj A double-precision array that specifies the vec<strong>to</strong>r from the reference marker of<br />

the CONTACT J Geometry (JGEOM) <strong>to</strong> the contact point on JGEOM.<br />

Expressed in the coordinate system of the reference marker of JGEOM.<br />

ni A double-precision array that specifies the surface normal vec<strong>to</strong>r of the<br />

CONTACT I Geometry (IGEOM) at the contact location. Expressed in the<br />

coordinate system of the reference marker of IGEOM.<br />

nj A double-precision array that specifies the surface normal vec<strong>to</strong>r of the<br />

CONTACT J Geometry (JGEOM) at the contact location. Expressed in the<br />

coordinate system of the reference marker of JGEOM.<br />

135


136<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

npar An integer variable that indicates the number of constants you specify in the<br />

USER parenthetical list. This variable provides the CNFSUB evaluation<br />

subroutine with the number of values s<strong>to</strong>red in the par array.<br />

par A double-precision array of constants taken in order from the<br />

NORMAL_FUNCTION USER parenthetical list of the CONTACT statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the current<br />

simulation time.<br />

Output Argument<br />

result A double-precision array that returns the value of the normal force.<br />

Extended Definition<br />

The IMPACT and POISSON force types in the CONTACT statement are usually sufficient <strong>to</strong> define the<br />

contact normal force. However, if you require another force model, you can use a CNFSUB. If the<br />

algorithms use or consist of already-existing FORTRAN-77 subroutines, CNFSUB can be made <strong>to</strong> call<br />

them.<br />

You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY, and SYSFNC, from CNFSUB,<br />

<strong>to</strong> obtain information about system variables, user-defined variables, and splines.<br />

The SYSARY and SYSFNC utility subroutines set functional dependencies when the CNFSUB<br />

argument iflag is true. To compute solutions efficiently, <strong>Adams</strong>/<strong>Solver</strong> must know the other variables on<br />

which each user-defined variable depends. <strong>Adams</strong>/<strong>Solver</strong> determines these functional dependencies at<br />

the beginning of the simulation by calling CNFSUB with the argument iflag set <strong>to</strong> true. <strong>Adams</strong>/<strong>Solver</strong><br />

does this once for each CONTACT statement with a<br />

NORMAL_FUNCTION=USER() argument.<br />

During each call <strong>to</strong> CNFSUB, <strong>Adams</strong>/<strong>Solver</strong> records which calls you make <strong>to</strong> SYSARY and SYSFNC.<br />

<strong>Adams</strong>/<strong>Solver</strong> assumes that the CONTACT components depend on those <strong>Adams</strong>/<strong>Solver</strong> variables that<br />

are accessed through SYSARY and SYSFNC.<br />

Using the dflag variable<br />

Only the first value in the array is used by <strong>Adams</strong>/<strong>Solver</strong>.<br />

The use of the dflag variable is optional. Its purpose is <strong>to</strong> simply let you know that CNFSUB is being<br />

called <strong>to</strong> evaluate a partial derivative. One of the states on which the CNFSUB depends has been<br />

perturbed very slightly. In many situations, it is likely that major calculations in the CNFSUB are


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

insensitive <strong>to</strong> small changes in state, and therefore, need not be recalculated. In such situations, you can<br />

structure the CNFSUB not <strong>to</strong> redo these calculations.<br />

Tip: If the SYSARY or SYSFNC subroutines are called <strong>to</strong> access angular displacements, the<br />

values returned by CNFSUB may contain discontinuities. Discontinuities occur if there is<br />

a Euler singularity. To avoid the Euler singularity (and thus the discontinuities), use the<br />

RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other coordinate system that does not encounter a singularity. If the calculations always use<br />

the same SYSARY and SYSFNC calls through the whole simulation, and you have no<br />

initialization <strong>to</strong> do, you do not need <strong>to</strong> check the iflag argument at all. You can just call<br />

SYSARY and/or SYSFNC, compute the user-defined variable value, and return <strong>to</strong><br />

<strong>Adams</strong>/<strong>Solver</strong>.<br />

Caution: When the iflag argument is true:<br />

FORTRAN - Pro<strong>to</strong>type<br />

• You must make all the calls <strong>to</strong> SYSARY and SYSFNC as they are made <strong>to</strong><br />

compute the component values of the CONTACT statement. This ensures that<br />

<strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies. In general, failure <strong>to</strong><br />

account for dependencies in the CONTACT statement components can make it<br />

difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a solution and/or can force<br />

<strong>Adams</strong>/<strong>Solver</strong> (FORTRAN) <strong>to</strong> take small integration steps, potentially causing<br />

large increases in execution time.<br />

• SYSARY and SYSFNC return zero values for system and user-defined variables.<br />

When you use <strong>Adams</strong>/<strong>Solver</strong>, computations that divide by these values result in<br />

fatal errors. You should check for nonzero values, or ensure that the iflag argument<br />

is set <strong>to</strong> false, before dividing by these values.<br />

A sample structure for CNFSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE CNFSUB(ID, TIME,PAR, NPAR, LOCI, NI, LOCJ, NJ,<br />

& GAP, GAPDOT,& GAPDOTDOT, AREA, DFLAG, IFLAG, RESULT)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

IMPLICIT NONE<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

DOUBLE PRECISION LOCI(3)<br />

DOUBLE PRECISION NI(3)<br />

DOUBLE PRECISION LOCJ(3)<br />

DOUBLE PRECISION NJ(3)<br />

DOUBLE PRECISION GAP<br />

DOUBLE PRECISION GAPDOT<br />

137


138<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

DOUBLE PRECISION GAPDOTDOT<br />

DOUBLE PRECISION AREA<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT(3)<br />

C<br />

C Input parameters<br />

C<br />

C ID Identifier of calling CONTACT statement<br />

C TIME Current time<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C LOCI contact point location on I in I coordinates<br />

C NI contact normal on I in I coordinates<br />

C LOCI contact point location on J in J coordinates<br />

C NI contact normal on J in J coordinates<br />

C GAP contact pe<strong>net</strong>ration<br />

C GAPDOT first time derivative of GAP<br />

C GAPDOTDOT second time derivative of GAP CAREA contact area<br />

C<br />

C components returned <strong>to</strong> ADAMSC<br />

C RESULT Array (dimension 3) of computed normal force<br />

C RESULT(1) Normal forceC RESULT(2) not used<br />

C RESULT(3) not used<br />

C<br />

C ---Local variable and parameter definitions ------<br />

C ...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign readable variable names <strong>to</strong> passed parameters<br />

C ...<br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C the following calculations. Note: if IFLAG is<br />

C true, these calls are actually setting functional<br />

C dependencies.<br />

C<br />

CALL SYSFNC (...)<br />

C Check SYSFNC call through ERRMES utility routine<br />

C<br />

CALL ERRMES (...)<br />

C<br />

C Repeat for all required SYSFNC or SYSARY calls<br />

C<br />

...<br />

C<br />

IF (IFLAG) THENC<br />

C - Subroutine initialization -------------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C


C - Evaluate Normal Force components -------------<br />

C<br />

C Your algorithms<br />

C<br />

...<br />

C<br />

C Assign values <strong>to</strong> the RESULT array<br />

C<br />

RESULT(1) = ...<br />

RESULT(2) = ...<br />

RESULT(3) = ...<br />

C<br />

RETURN<br />

END<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_CNFSUB(const struct s<strong>Adams</strong>ContactFriction* fric,<br />

double TIME, const double* LOCI, const double* NI, const double*<br />

LOCJ, const double* NJ, double GAP, double GAPDOT, double GAPDOTDOT,<br />

double AREA, int DFLAG, int IFLAG, double* VALUES );<br />

typedef void STDCALL adams_f77_CNFSUB(const int* ID, const double*<br />

TIME, const double* PAR, const int* NPAR, const double* LOCI, const<br />

double* NI, const double* LOCJ, const double* NJ, const double* GAP,<br />

const double* GAPDOT, const double* GAPDOTDOT, const double* AREA,<br />

const int* DFLAG, const int* IFLAG, double* VALUES );<br />

struct s<strong>Adams</strong>Contact<br />

{<br />

int ID;<br />

int nIGEOM;<br />

int nJGEOM;<br />

int* IGEOM;<br />

int* JGEOM;<br />

int* IFLIP_GEOM;<br />

int* JFLIP_GEOM;<br />

};<br />

struct s<strong>Adams</strong>ContactFriction<br />

{<br />

struct s<strong>Adams</strong>Contact contact;<br />

int NPAR;<br />

const double* PAR;<br />

};<br />

CONSUB<br />

The CONSUB driver subroutine can be used <strong>to</strong> control an <strong>Adams</strong> simulation from within a user<br />

subroutine. Interactively issuing the CONTROL command (C++ or FORTRAN) invokes CONSUB.<br />

Other user-written subroutines cannot call CONSUB.<br />

139


140<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Corresponding Command<br />

CONTROL/ [FUNCTION=USER(r1[,...,r30])[/]]<br />

[[ ]] Optionally select an item combination<br />

Calling Sequence<br />

SUBROUTINE CONSUB (par, npar)<br />

Input Arguments<br />

npar An integer variable that indicates the number of constants specified in the<br />

parenthetical list of the USER keyword. The primary purpose of npar is <strong>to</strong><br />

provide CONSUB with the number of values s<strong>to</strong>red in the par array.<br />

par A double-precision array of constants taken in order from the parenthetical list<br />

in the USER keyword CONTROL command.<br />

Extended Definition<br />

<strong>Adams</strong>/<strong>Solver</strong> passes the parameters in the CONTROL statement FUNCTION=USER() argument as an<br />

array of real numbers <strong>to</strong> the user-written subroutine CONSUB. From CONSUB, any utility subroutines<br />

such as SYSARY, SYSFNC, or AKISPL can be called.<br />

• The MODIFY utility subroutine can be called <strong>to</strong> change an <strong>Adams</strong>/<strong>Solver</strong> statement just as it<br />

would be done interactively.<br />

• The ANALYS utility subroutine can be called <strong>to</strong> invoke one of the <strong>Adams</strong>/<strong>Solver</strong> analysis types.<br />

• The DATOUT utility subroutine can be called <strong>to</strong> process output from the <strong>Adams</strong>/<strong>Solver</strong><br />

simulation(s).<br />

When execution of CONSUB s<strong>to</strong>ps, <strong>Adams</strong>/<strong>Solver</strong> prompts you for another command.<br />

Caution: When program control passes <strong>to</strong> CONSUB, au<strong>to</strong>matic generation of output s<strong>to</strong>ps. If you<br />

want <strong>to</strong> create output, call the DATOUT utility subroutine.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for CONSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE CONSUB ( PAR, NPAR )<br />

C<br />

C === Type and dimension statements ==================<br />

C<br />

C


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C - External variable definitions ---------<br />

C INTEGER NPAR DOUBLE PRECISION<br />

PAR( * )<br />

C<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C<br />

C - Local variable definitions -----------<br />

C ...<br />

C<br />

C === Executable code ================================<br />

C<br />

C - Your commands -----------------<br />

C ...<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_CONSUB(const struct s<strong>Adams</strong>Control* con);<br />

/*<br />

* CONTROL<br />

*/<br />

struct s<strong>Adams</strong>Control<br />

{<br />

int NPAR;<br />

const double* PAR;<br />

};<br />

Examples<br />

For an example of this subroutine, see consub.f.<br />

COUSUB, COUXX, COUXX2<br />

The COUSUB, COUXX, and COUXX2 subroutines define a user-defined COUPLER (C++ or<br />

FORTRAN):<br />

• COUSUB specifies the coupler constraint as a function of the displacements of the joints being<br />

coupled.<br />

• COUXX returns <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> the first partial derivatives of the coupler constraint, with<br />

respect <strong>to</strong> each joint displacement.<br />

• COUXX2 returns the matrix of second partial derivatives of the coupler constraint, with respect<br />

<strong>to</strong> the joint displacements.<br />

141


142<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Corresponding Command<br />

COUPLER/id, JOINTS=id1, id2[,id3]<br />

Calling Sequence<br />

SUBROUTINE COUSUB (id, time, par, npar, disp, ndisp, iflag, phi)SUBROUTINE COUXX (id, time,<br />

par, npar, disp, ndisp, iflag, dfda)SUBROUTINE COUXX2 (id, time, par, npar, disp, ndisp, iflag, dfda2)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that specifies the identifier of the COUPLER statement<br />

whose constraint function is being specified.<br />

time A double-precision variable that contains the current simulation time.<br />

par A double-precision array that contains the constants taken, in order, from the<br />

list of values provided with the USER argument in the COUPLER statement.<br />

npar An integer variable containing the number of entries in the PAR array.<br />

disp A double-precision array containing the instantaneous joint displacements.<br />

Translational displacements are in units of length and rotational displacements<br />

are in radians.<br />

ndisp An integer variable that defines the size of the DISP array. This is equal <strong>to</strong> the<br />

number of joints being coupled in the COUPLER statement.<br />

iflag A logical variable that is set <strong>to</strong> TRUE when COUSUB, COUXX and COUXX2<br />

are being called for an initialization pass. IFLAG is set <strong>to</strong> TRUE once for each<br />

COUPLER statement in a simulation.<br />

Output Arguments<br />

phi A double-precision scalar that contains the value of the coupler constraint<br />

equation.<br />

Extended Definition<br />

The constraint equation must be specified in implicit form. For example, the<br />

equation must be in the form: f (disp) = 0.<br />

dfda A double-precision array of length ndisp that contains the partial derivatives<br />

of phi with respect <strong>to</strong> disp. Therefore, fda(i) = phi / isp(i).<br />

dfda2 A double-precision array of dimensions ndisp that contains the second partials<br />

derivatives of phi with respect <strong>to</strong> disp.<br />

Therefore, dfda2(i) = 2 / disp (i) disp (i)<br />

The COUPLER statement is used <strong>to</strong> relate the motion of two or more joints. If the relationship between<br />

the motion in a set consisting of two or three joints is linear, the scale fac<strong>to</strong>rs relating the motion can be<br />

directly specified in the dataset.<br />

However, when the relationship between the joints is nonlinear in nature, the equation specifying this<br />

relationship must be specified in the user-written subroutines COUSUB, COUXX, and COUXX2.<br />

143


144<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Therefore, if d1, d2, and d3 are displacement/rotations in three translational or revolute joints, the<br />

relationship between them may be written analytically as: ƒ1 (d1) + ƒ2(d2) + ƒ3(d3) = 0<br />

COUSUB, COUXX, and COUXX2 must only be functions of the input variables specified above. You<br />

cannot call SYSFNC or SYSARY <strong>to</strong> access other system states.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for COUSUB, COUXX, and COUXX2 is shown next. The comments explain the<br />

logical structure of each of the subroutines.<br />

COUSUB<br />

SUBROUTINE COUSUB (ID, TIME, PAR, NPAR, DISP, &<br />

NDISP, IFLAG, PHI)<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

C Inputs:<br />

C INTEGER ID DOUBLE PRECISION TIME DOUBLE<br />

PRECISION PAR(*) INTEGER NPAR DOUBLE PRECISION<br />

DISP(*) INTEGER NDISP LOGICAL IFLAGCC<br />

Outputs:<br />

C DOUBLE PRECISION PHICC Local Variables:<br />

C ... ...<br />

C<br />

C+----------------------------------------------------*<br />

C Executable Code<br />

C+----------------------------------------------------*<br />

C<br />

C IF (IFLAG) THEN<br />

C<br />

C+----------------------------------------------------*<br />

C Initialization pass: Initialize necessaryC local<br />

variables<br />

C+----------------------------------------------------*C ...<br />

...<br />

C ELSEC<br />

C+----------------------------------------------------*<br />

C Evaluation pass: Define Phi the<br />

C coupler constraint<br />

C+----------------------------------------------------*<br />

C ... ...<br />

PHI = ...<br />

C<br />

ENDIF<br />

C<br />

C<br />

RETURN<br />

END


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

COUXX<br />

SUBROUTINE COUXX (ID, TIME, PAR, NPAR, DISP,<br />

& NDISP, IFLAG, DFDA)<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

DOUBLE PRECISION DISP(*)<br />

INTEGER NDISP<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION DFDA(*)<br />

C<br />

C Local Variables:<br />

C<br />

...<br />

...<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Executable Code<br />

C+----------------------------------------------------*<br />

C<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Initialization pass: Initialize<br />

C<br />

necessary local variables<br />

C+----------------------------------------------------*<br />

C<br />

...<br />

...C<br />

ELSE<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Evaluation pass: Define the partial<br />

C<br />

derivatives of the coupler constraint<br />

C+----------------------------------------------------*<br />

C<br />

...<br />

...<br />

DFDA(1) = ...<br />

145


146<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

C<br />

C<br />

ENDIF<br />

DFDA(2) = ...<br />

...<br />

RETURN<br />

END<br />

COUXX2<br />

SUBROUTINE COUXX2 (ID, TIME, PAR, NPAR, DISP,<br />

& NDISP, IFLAG, DFDA2)<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

DOUBLE PRECISION DISP(*)<br />

INTEGER NDISP<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION DFDA2(NDISP)<br />

C<br />

C Local Variables:<br />

C<br />

...<br />

...<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Executable Code<br />

C+----------------------------------------------------*<br />

C<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Initialization pass: Initialize<br />

C<br />

necessary local variables<br />

C+----------------------------------------------------*<br />

C<br />

...<br />

...<br />

C<br />

ELSE<br />

C


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C+----------------------------------------------------*<br />

C<br />

Evaluation pass: Define the second partial<br />

C<br />

derivatives of the coupler constraint<br />

C+----------------------------------------------------*<br />

C<br />

...<br />

...<br />

DFDA2(1) = ...<br />

DFDA2(2) = ...<br />

...<br />

...<br />

C<br />

ENDIF<br />

C<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_COUSUB(const struct s<strong>Adams</strong>Coupler* coupler,<br />

double TIME, double*, int IFLAG, double* PHI);<br />

typedef void adams_c_COUXX(const struct s<strong>Adams</strong>Coupler* coupler,<br />

double TIME, double*, int IFLAG, double* dFda);<br />

typedef void adams_c_COUXX2(const struct s<strong>Adams</strong>Coupler* coupler,<br />

double TIME, double*, int IFLAG, double* d2Fda2);<br />

/*<br />

* COUPLER -------------------------------------------------<br />

----------------<br />

*/<br />

struct s<strong>Adams</strong>Coupler<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int NJOINT;<br />

int JOINTS[3];<br />

char TYPE[3];<br />

};<br />

Examples<br />

The mechanical system shown in Figure 1 consists of three rigid bodies and two joints; the first is a<br />

revolute joint and the second translational. The translational joint represents an actua<strong>to</strong>r whose output<br />

displacement controls the angular motion in the revolute joint.<br />

Let the displacement in the translational joint be defined as and the rotation in revolute joint as a.<br />

147


148<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Now assume that the variables s and a are related by the following equation:<br />

s = 10 * Cos (a)<br />

The dataset for this model is:<br />

!Part/1, GroundMarker/11Marker/12Part/2, Mass=10, Ip=10,10,10, Cm=21Marker/21, Qp=0,-5,0,<br />

REU=90d,90d,0Marker/22, REU=90d,0,0Part/3, Mass=25, Ip=75,75,150, Cm=31Marker/31,<br />

Qp=10,20,0, REU=90d,90d,0Marker/32Joint/1, Revolute, I=22, J=11Joint/2, Translational, I=32,<br />

J=12Motion/1, Joint=2, Function = 10*TimeCoupler/1, Joints=1,2, Function=User(10)End<br />

<strong>Subroutines</strong> COUSUB, COUXX, and COUXX2 for this model are:<br />

COUSUB<br />

SUBROUTINE COUSUB (ID, TIME, PAR, NPAR, DISP,<br />

& NDISP, IFLAG, PHI)<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

DOUBLE PRECISION DISP(*)<br />

INTEGER NDISP<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION PHI<br />

C<br />

C Local Variables:<br />

C<br />

DOUBLE PRECISION LENGTH, S, ALPHA<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Executable Code<br />

C+----------------------------------------------------*<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C<br />

there are no variables <strong>to</strong> initialize in this<br />

C<br />

example<br />

C<br />

ELSE<br />

C


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C+----------------------------------------------------*<br />

C<br />

Evaluation pass: Define Phi the coupler<br />

C<br />

constraint<br />

C+----------------------------------------------------*<br />

C<br />

LENGTH = PAR(1)<br />

ALPHA = DISP(1)<br />

S = DISP(2)<br />

PHI = S - LENGTH * COS(ALPHA)<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

COUXX<br />

SUBROUTINE COUXX (ID, TIME, PAR, NPAR, DISP,<br />

& NDISP, IFLAG, DFDA)<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

DOUBLE PRECISION DISP(*)<br />

INTEGER NDISP<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION DFDA(*)<br />

C<br />

C Local Variables:<br />

C<br />

DOUBLE PRECISION LENGTH, S, ALPHA<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Executable Code<br />

C+----------------------------------------------------*C<br />

IF (IFLAG) THEN<br />

C<br />

C<br />

there are no variables <strong>to</strong> initialize in this example<br />

C<br />

ELSE<br />

C<br />

C+----------------------------------------------------*<br />

149


150<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

Evaluation pass: Define the partial derivatives<br />

C<br />

of the coupler constraint<br />

C+----------------------------------------------------*<br />

C<br />

LENGTH = PAR(1)<br />

ALPHA = DISP(1)<br />

S = DISP(2)<br />

C<br />

DFDA(1) = + LENGTH * SIN(ALPHA)<br />

DFDA(2) = 1.0<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

COUXX2<br />

SUBROUTINE COUXX2 (ID, TIME, PAR, NPAR, DISP,<br />

& NDISP, IFLAG, DFDA2)<br />

C<br />

C+----------------------------------------------------*<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

DOUBLE PRECISION DISP(*)<br />

INTEGER NDISP<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION DFDA2(NDISP)<br />

C<br />

C Local Variables:<br />

C<br />

DOUBLE PRECISION LENGTH, ALPHA, S<br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Executable Code<br />

C+----------------------------------------------------*<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C<br />

no variables <strong>to</strong> initialize in this example.<br />

C<br />

ELSE


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C<br />

C+----------------------------------------------------*<br />

C<br />

Evaluation pass: Define the second partial<br />

C derivatives of the coupler constraint<br />

C+----------------------------------------------------*<br />

C<br />

LENGTH = PAR(1)<br />

ALPHA = DISP(1)<br />

S = DISP(2)<br />

DFDA2(1) = LENGTH * COS(ALPHA)<br />

DFDA2(2) = 0.0<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

CURSUB<br />

CURSUB is an evaluation subroutine that computes curve coordinates and their derivatives for a<br />

CURVE statement (C++ or FORTRAN). CURSUB is optional. You can use it <strong>to</strong> define a curve instead<br />

of using control points or data points.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE CURSUB (id, par, npar, alpha, iord, iflag, values)<br />

151


152<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

alpha A double-precision variable that specifies the value of the independent<br />

parameter a which CURSUB uses <strong>to</strong> evaluate a curve. <strong>Adams</strong>/<strong>Solver</strong><br />

restricts a <strong>to</strong> be:<br />

Greater than or equal <strong>to</strong> the MINPAR value on the CURVE statement (-1.0<br />

by default).<br />

Less than or equal <strong>to</strong> the MAXPAR value on the CURVE statement (1.0 by<br />

default).<br />

id An integer variable that provides the identifier of the CURVE statement,<br />

which requests information from the CURSUB. <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically derives additional information (such as the par argument)<br />

from the identifier of the corresponding statement.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> TRUE. for the initial call <strong>to</strong><br />

CURSUB. In general, you do not need <strong>to</strong> check this flag in the subroutine.<br />

However, you can check it if computations occur that require evalution at the<br />

beginning of the simulation. In this case, if iflag is true, then the subroutine<br />

should evaluate the computations.<br />

iord An integer variable that specifies the order of the derivative that CURSUB<br />

returns. The possible values are:<br />

zero (return curve coordinates)<br />

one (return first derivatives with respect <strong>to</strong> a)<br />

two (return second derivatives with respect <strong>to</strong> a).<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide the<br />

CURSUB evaluation subroutine with the number of values s<strong>to</strong>red in the par<br />

array.<br />

par A double-precision array of constants that is taken in order from the USER<br />

parenthetical list of the CURVE statement.


Output Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

values A double-precision array of size three that returns the x, y, and z<br />

coordinates of the curve or their first or second derivatives with respect <strong>to</strong><br />

a. The values the CURSUB should compute and return depend on the<br />

input value of argument iord, as summarized next:<br />

Extended Definition<br />

The CURVE statement lets you define a uniform B-Spline curve using control points or a tensioned B-<br />

Spline curve that is fitted <strong>to</strong> data points. If you cannot represent the curve you want using a uniform or<br />

tensioned B-Spline, you can use the FUNCTION=USER ( ) argument in the CURVE statement and write<br />

a CURSUB evaluation subroutine <strong>to</strong> calculate the curve coordinates and derivatives.<br />

FORTRAN - Pro<strong>to</strong>type<br />

iord:<br />

values (1):<br />

values (2):<br />

values (3):<br />

0<br />

1<br />

2<br />

Caution: Define the curve only as a function of a. Don't make calls <strong>to</strong> the SYSARY and SYSFNC<br />

utility subroutines <strong>to</strong> access other system variables.<br />

A sample structure for CURSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE CURSUB ( ID, PAR, NPAR, ALPHA, IORD,<br />

& IFLAG, VALUES )<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C Note: For machines with 60 or more bits per word,<br />

C substitute "REAL" for "DOUBLE PRECISION".<br />

C<br />

C - External variable definitions ---------<br />

153


154<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

DOUBLE PRECISION ALPHA<br />

INTEGER IORD<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUES( 3 )<br />

C<br />

C ID Identifier of calling CURVE statement<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C ALPHA Curve parameter value<br />

C IORD Derivative order of value <strong>to</strong> be returned<br />

C IFLAG Initialization pass flag<br />

C VALUES Derivative values of CURVE returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variable and parameter definitions ----<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign parameters <strong>to</strong> readable variable names<br />

C...CIF ( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Compute and assign the curve coordinates ----<br />

C<br />

IF ( IORD .EQ. 0 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign values for the X, Y, and Z coordinates<br />

C<br />

VALUES(1) = ...<br />

VALUES(2) = ...<br />

VALUES(3) = ...<br />

C<br />

C - Compute and assign the curve first derivatives -<br />

C<br />

ELSE IF ( IORD .EQ. 1 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C Assign values for the X, Y, and Z first derivatives<br />

C<br />

VALUES(1) = ...<br />

VALUES(2) = ...<br />

VALUES(3) = ...<br />

C<br />

C - Compute and assign the curve second derivatives -<br />

C<br />

ELSE<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign values for the X, Y, and Z second derivatives<br />

C<br />

VALUES(1) = ...<br />

VALUES(2) = ...<br />

VALUES(3) = ...<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_CURSUB(const struct s<strong>Adams</strong>Curve* crv, double<br />

ALPHA, int IORD, int IFLAG, double* VALUES );<br />

/*<br />

* CURVE<br />

*/<br />

struct s<strong>Adams</strong>Curve<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int CLOSED;<br />

int ORDER;<br />

double MINPAR;<br />

double MAXPAR;<br />

};<br />

Examples<br />

For an example of this subroutine, see cursub.f.<br />

DIFSUB<br />

155


156<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

The DIFSUB evaluation subroutine computes a differential-equation value for a DIFF statement (C++ or<br />

FORTRAN). DIFSUB is optional. You only need it if you don't want <strong>to</strong> use a function expression in the<br />

DIFF statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE DIFSUB (id, time, par, npar, dflag, iflag, value)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls DIFSUB <strong>to</strong><br />

evaluate partial derivatives of the function. Otherwise, <strong>Adams</strong>/<strong>Solver</strong> sets<br />

dflag <strong>to</strong> false.<br />

id An integer variable that provides the identifier of the DIFF statement<br />

requesting information from the DIFSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically knows other information (such as the par<br />

argument) available in the corresponding statement.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the<br />

functional dependency of the user-defined variable. The functional<br />

dependencies are set with the same calls <strong>to</strong> the SYSARY and SYSFNC<br />

utility subroutines that are made <strong>to</strong> compute the value of the user-defined<br />

variable. If iflag is false, <strong>Adams</strong>/<strong>Solver</strong> computes the value of the userwritten<br />

variable.<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide the<br />

DIFSUB evaluation subroutine with the number of values s<strong>to</strong>red in the par<br />

array.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the DIFF statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

Output Argument<br />

value A double-precision variable that returns the value of the differential<br />

equation. If the equation is in the explicit form, value contains the<br />

derivative. If the equation is in the implicit form, value contains the residual<br />

(that is, the error relative <strong>to</strong> zero) of the implicit equation. In this case, value<br />

can be a function of the dependent variable and its time derivative.<br />

Extended Definition<br />

A DIFF statement with a function expression is sufficient for defining most user-defined differential<br />

equations. However, if the expression becomes lengthy and awkward or if the definition of the equation<br />

requires additional features of FORTRAN-77, you should use the FUNCTION=USER() argument in the<br />

DIFF statement, and write a DIFSUB evaluation subroutine <strong>to</strong> define the differential equation.<br />

DIFSUB allows you <strong>to</strong> define a differential equation for a variable either explicitly or implicitly:<br />

• In an explicit definition, the derivative of the variable is evaluated on the right side of a<br />

FORTRAN-77 assignment statement.<br />

157


158<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

• In an implicit definition, the right side of the statement is zero.<br />

For further information on implicit and explicit definitions, see the DIFF statement (C++ or FORTRAN).<br />

You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY, and SYSFNC, from DIFSUB <strong>to</strong><br />

obtain information about system variables, other user-defined variables, and splines.<br />

The SYSARY and SYSFNC utility subroutines au<strong>to</strong>matically set functional dependencies when the<br />

DIFSUB argument iflag is true. In order for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> compute solutions efficiently, it must know<br />

on which other variables each user-defined variable directly depends. <strong>Adams</strong>/<strong>Solver</strong> determines these<br />

functional dependencies at the beginning of the simulation by calling a DIFSUB evaluation subroutine<br />

with argument iflag set <strong>to</strong> true. <strong>Adams</strong>/<strong>Solver</strong> does this once for each DIFF statement with a<br />

FUNCTION=USER() argument. During each call <strong>to</strong> the DIFSUB evaluation subroutine, <strong>Adams</strong>/<strong>Solver</strong><br />

records which calls you make <strong>to</strong> SYSARY and SYSFNC. <strong>Adams</strong>/<strong>Solver</strong> assumes that the user-defined<br />

variable depends on those system and user-defined variables, and no others.<br />

Tip: • If the SYSARY or SYSFNC utility subroutine is called <strong>to</strong> access angular<br />

displacements, the values returned by DIFSUB may contain discontinuities. These<br />

discontinuities occur if there is a Euler singularity. To avoid the Euler singularity<br />

(and thus the discontinuities), use the RCNVRT utility subroutine <strong>to</strong> convert the<br />

rotational angles from Euler angles <strong>to</strong> some other coordinate system that does not<br />

encounter a singularity.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for DIFSUB is shown next. The comments explain how the subroutine works.<br />

C<br />

• If the calculations always use the same SYSARY and SYSFNC calls through the<br />

whole simulation, and you have no initialization <strong>to</strong> do, you do not need <strong>to</strong> check<br />

the iflag argument at all. You can just call SYSARY and/or SYSFNC, compute the<br />

user-defined variable value, and return <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong>.<br />

Caution: • When the iflag argument is true, be sure <strong>to</strong> make all the same calls <strong>to</strong> the SYSARY<br />

and SYSFNC utility subroutines that are done when actually computing the value<br />

of the user-defined variable. This ensures that <strong>Adams</strong>/<strong>Solver</strong> has the proper<br />

functional dependencies. In general, failure <strong>to</strong> account for dependencies of the<br />

user-defined variables might make it difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a<br />

solution, and/or might force <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> take small integration steps,<br />

potentially causing large increases in execution time.<br />

• When the iflag argument is true, SYSARY and SYSFNC return zero values for<br />

system and user-defined variables. Computations that divide by these values result<br />

in system errors when <strong>Adams</strong>/<strong>Solver</strong> is executed. Be sure <strong>to</strong> check for nonzero<br />

values, or the iflag argument set <strong>to</strong> false, before dividing by these values.<br />

SUBROUTINE DIFSUB ( ID, TIME, PAR, NPAR, DFLAG,<br />

& IFLAG, VALUE )


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C === Type and dimension statements ==================<br />

C<br />

C Note: For machines with 60 or more bits per word,<br />

C substitute "REAL" for "DOUBLE PRECISION".<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

C<br />

C ID Identifier of calling DIFF statement<br />

C TIME Current time<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C IFLAG Initialization pass flag<br />

C VALUE Computed value of DIFF returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variables and parameters definitions ---<br />

C<br />

...<br />

C<br />

C === Executable code ================================<br />

C<br />

C Assign readable variable names <strong>to</strong> passed parameters<br />

C<br />

...<br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C the following calculations. Note: if IFLAG is<br />

C true, these calls are actually setting<br />

C functional dependencies.<br />

C CALL SYSFNC ( ... )<br />

C<br />

C Check SYSFNC call through ERRMES utility routine<br />

C<br />

CALL ERRMES ( ... )<br />

C<br />

C Repeat for all required SYSFNC or SYSARY calls<br />

C<br />

...<br />

C<br />

IF ( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

159


160<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

C - Evaluate differential equation ---------<br />

C<br />

C Your algorithms<br />

C<br />

...<br />

C<br />

C Assign a value <strong>to</strong> the variable VALUE<br />

C<br />

VALUE = ...<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_DIFSUB(const struct s<strong>Adams</strong>Diff* diff, double<br />

TIME, int DFLAG, int IFLAG, double* RESULT);<br />

struct s<strong>Adams</strong>Diff<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int STATIC_HOLD;<br />

int IMPLICIT;<br />

double IC_R1;<br />

double IC_R2;<br />

};<br />

Examples<br />

For an example of this subroutine, see difsub.f.<br />

DMPSUB<br />

The DMPSUB evaluation subroutine computes the modal damping ratios for a FLEX_BODY statement<br />

(C++ or FORTRAN). DMPSUB is optional. You need it only if you want cus<strong>to</strong>m damping that is not the<br />

same for all modes, or if the modal damping changes with time.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE DMPSUB (id, time, par, npar, freq, nmode, h, cratios)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that provides the identifier of the FLEX_BODY<br />

statement requesting information from the DMPSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically knows other information (such as the par<br />

argument) available in the corresponding statement.<br />

time A double-precision variable containing the current simulation time.<br />

par A double-precision array of constants taken, in order, from the USER<br />

parenthetical list of the FLEX_BODY statement.<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide the<br />

DMPSUB evaluation subroutine with the number of values s<strong>to</strong>red in the par<br />

array.<br />

freq An array of natural frequencies for the modes in cycles per user-defined time.<br />

nmode The <strong>to</strong>tal number of modes associated with the FLEX_BODY statement.<br />

h The current integra<strong>to</strong>r step size. This is useful if you are using damping <strong>to</strong><br />

prevent integration problems.<br />

Output Argument<br />

cratios An array of damping ratios as a fraction of critical damping. There must be<br />

one value computed for each of the modes.<br />

Examples<br />

To control the modal damping of individual modes using a user-written subroutine, use CRATIO=USER<br />

according <strong>to</strong> <strong>Adams</strong> standard practice. The damping ratios for the selected modes are obtained through<br />

a call <strong>to</strong> the DMPSUB subroutine. For a model using units of seconds for time, this example illustrates:<br />

• 1% critical damping for modes less than 100 Hz.<br />

• 10% critical damping for modes greater or equal <strong>to</strong> 100 Hz but less than 1 kHz.<br />

• 100% critical damping for modes greater than or equal <strong>to</strong> 1 kHz.<br />

The following statement defines the constants <strong>Adams</strong>/<strong>Solver</strong> is <strong>to</strong> pass <strong>to</strong> the DMPSUB evaluation<br />

subroutine:<br />

FLEX_BODY/1, I=101, J=201<br />

, CRATIO=USER(.01,100,.1,1000,1)<br />

For the current example of this subroutine, see dmpsub.f.<br />

161


162<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_DMPSUB(const struct s<strong>Adams</strong>Cratio* flex, double<br />

TIME, const double* FREQS, int NMODE, double STEPSIZE, double*<br />

CRATIOS);<br />

/*<br />

* FLEX_BODY -------------------------------------------------<br />

----------------<br />

*/<br />

struct s<strong>Adams</strong>FlexBody<br />

{<br />

int ID;<br />

/* int NMAT;<br />

const int* MATRICES;<br />

int VM;<br />

int WM; */<br />

};<br />

struct s<strong>Adams</strong>Cratio<br />

{<br />

struct s<strong>Adams</strong>FlexBody FlexBody;<br />

int NPAR;<br />

const double* PAR;<br />

};<br />

FIESUB<br />

The FIESUB evaluation subroutine computes the force and <strong>to</strong>rque components and their derivatives for<br />

a FIELD statement (C++ or FORTRAN). FIESUB is optional. You only need it if you don't want <strong>to</strong> use<br />

the constant stiffness and damping matrices in the FIELD statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE FIESUB (id, time, par, npar, disp, velo,& dflag, iflag, field, dfddis, dfdvel)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that provides the identifier of the FIELD statement<br />

requesting information from FIESUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically knows other information (such as the par argument) available<br />

in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

par A double-precision array of constants taken, in order, from the USER<br />

parenthetical list of the FIELD statement.<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide FIESUB<br />

with the number of values s<strong>to</strong>red in the par array.<br />

disp A six-element, double-precision array that provides the x, y, and z<br />

translational displacements and the AX, AY, and AZ rotational<br />

displacements that <strong>Adams</strong>/<strong>Solver</strong> measures at the I marker with respect <strong>to</strong><br />

the J marker, resolved in the coordinate system of the J marker. For more<br />

information, see AX function (C++ or FORTRAN), AY function (C++ or<br />

FORTRAN), and AZ function (C++ or FORTRAN).<br />

velo A six-element, double-precision array that provides the x, y, and z<br />

translational velocities and the x, y, and z rotational velocities that<br />

<strong>Adams</strong>/<strong>Solver</strong> measures at the I marker with respect <strong>to</strong> the J marker,<br />

resolved in the coordinate system of the J marker.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs derivatives<br />

from FIESUB. FIESUB needs <strong>to</strong> evaluate dfddis and dfdvel only when the<br />

dflag argument is true. Otherwise, <strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong><br />

false.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true for the initial call <strong>to</strong><br />

FIESUB. In general, this flag does not need <strong>to</strong> be checked in the subroutine.<br />

If there are computations that need <strong>to</strong> be evaluated at the beginning of the<br />

simulation, you can check the iflag argument. In this case, if the iflag<br />

argument is true, the subroutine should evaluate the computations.<br />

163


164<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Output Arguments<br />

field A six-element, double-precision array that returns the x, y, and z<br />

translational forces and the x, y, and z rotational forces that <strong>Adams</strong>/<strong>Solver</strong><br />

applies at the I marker with respect <strong>to</strong> the J marker, resolved in the<br />

coordinate system of the J marker.<br />

dfddis A six-by-six, double-precision array that returns the derivatives of the six<br />

field components with respect <strong>to</strong> the six displacement values in the disp<br />

array. For example, the derivative of the fourth FIELD component (TX)<br />

with respect <strong>to</strong> the second displacement variable (y) is dfddis (4,2). You<br />

only need <strong>to</strong> define dfddis when dflag is set <strong>to</strong> true.<br />

dfdvel A six-by-six, double-precision array of the derivatives of the six field<br />

components with respect <strong>to</strong> the six velocity values in the velo array. For<br />

example, the derivative of the first FIELD component (FX) with respect <strong>to</strong><br />

the sixth velocity variable (WZ) is dfdvel(1,6). You need <strong>to</strong> define dfdvel<br />

only when dflag is set <strong>to</strong> true.<br />

Extended Definition<br />

The FIELD statement with KMATRIX and CMATRIX/CRATIO arguments specified may be used for<br />

defining six-component forces whose stiffness and damping matrices have constant entries. If, however,<br />

the force components are nonlinear functions of the relative displacements and the relative velocities of<br />

the FIELD I and J markers, then use a FIELD statement with FUNCTION=USER() and write a FIESUB<br />

<strong>to</strong> calculate the six FIELD components. These components and their derivatives can be functions of time<br />

and of the FIELD I marker component displacements and component velocities, with respect <strong>to</strong> the J<br />

marker. <strong>Adams</strong>/<strong>Solver</strong> resolves the components in the J marker coordinate system.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

FIESUB output must be strictly a function of the values in arrays disp and velo. Consequently, FIESUB<br />

may not call the SYSARY or SYSFNC utility subroutine. FIESUB may call other utility subroutines,<br />

such as AKISPL, and CUBSPL, that do not introduce a dependency on <strong>Solver</strong> states.<br />

Caution: • The dfddis and dfdvel arrays must always be positive semidefinite. <strong>Adams</strong>/<strong>Solver</strong><br />

does not warn you if the dfddis array, the dfdvel array, or both, are not positive<br />

semidefinite. An array A is positive semidefinite if xT A x > 0 for all x ¹ 0.<br />

FORTRAN - Pro<strong>to</strong>type<br />

• Don't attempt <strong>to</strong> make any of the six field components dependent on system<br />

variables other than those FIESUB passes through the arguments disp, velo, and<br />

time. This rule prohibits calls <strong>to</strong> the utility subroutines SYSARY and SYSFNC.<br />

Failure <strong>to</strong> comply with this rule does not produce error messages, but greatly<br />

reduces the integration step sizes, increases the CPU time, and decreases the<br />

probability of convergence <strong>to</strong> a solution.<br />

• If FIESUB returns the six field components without their correct derivatives,<br />

simulation times may correspondingly increase, and the probability of<br />

convergence <strong>to</strong> a solution decreases.<br />

• If AKISPL, CUBSPL, or any of the <strong>Adams</strong>/<strong>Solver</strong> utility subroutines are used,<br />

don't forget <strong>to</strong> involve the derivatives returned by these subroutines when the<br />

FIESUB derivatives are evaluated.<br />

• Field components with continuous derivatives are desirable. Discontinuous<br />

derivatives cause a reduction of integration step size at the discontinuity, and may<br />

cause <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> fail <strong>to</strong> converge <strong>to</strong> a solution.<br />

• When the iflag argument is true, <strong>Adams</strong>/<strong>Solver</strong> sets the disp and velo arguments <strong>to</strong><br />

zeros. When you execute <strong>Adams</strong>/<strong>Solver</strong>, computations that divide by these values<br />

result in fatal errors. You should check for nonzero values, or ensure the iflag<br />

argument is false, before dividing by disp or velo values.<br />

A sample structure for FIESUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE FIESUB (ID, TIME, PAR, NPAR, DISP,<br />

& VELO, DFLAG, IFLAG, FIELD,<br />

& DFDDIS, DFDVEL )<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

DOUBLE PRECISION DISP( 6 )<br />

DOUBLE PRECISION VELO( 6 )<br />

LOGICAL DFLAG<br />

165


166<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

LOGICAL IFLAG<br />

DOUBLE PRECISION FIELD( 6 )<br />

DOUBLE PRECISION DFDDIS( 6, 6 )<br />

DOUBLE PRECISION DFDVEL( 6, 6 )<br />

C<br />

C ID Identifier of calling FIELD statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C DISP Array of I with respect <strong>to</strong> J displacements<br />

C VELO Array of I with respect <strong>to</strong> J velocities<br />

C DFLAG Differencing flag<br />

C IFLAG Initialization pass flag<br />

C FIELD Array of field values<br />

C DFDDIS Displacement partial derivatives<br />

C DFDVEL Velocity partial derivatives<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign readable variable names <strong>to</strong> passed parameters<br />

C<br />

...<br />

C<br />

IF ( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Calculate field component forces --------<br />

C<br />

C X translation field force<br />

C<br />

...<br />

FIELD(1) = ...<br />

C<br />

C Y translation field force<br />

C<br />

...<br />

FIELD(2) = ...<br />

C<br />

C Z translation field force<br />

C<br />

...<br />

FIELD(3) = ...<br />

C<br />

C - Calculate field component <strong>to</strong>rques -------<br />

C


C X rotational field <strong>to</strong>rque<br />

C<br />

...<br />

FIELD(4) = ...<br />

C<br />

C Y rotational field <strong>to</strong>rque<br />

C<br />

...<br />

FIELD(5) = ...<br />

C<br />

C Z rotational field <strong>to</strong>rque<br />

C<br />

...<br />

FIELD(6) = ...<br />

C<br />

C - Assign returned partial derivatives if this --<br />

C is a differencing pass (DFLAG=.TRUE.)<br />

C<br />

IF ( DFLAG ) THEN<br />

C<br />

C Assign displacement partials for X force<br />

C<br />

DFDDIS(1,1) = ...<br />

...<br />

DFDDIS(1,6) = ...<br />

C<br />

C Assign displacement partials for Y force<br />

C<br />

DFDDIS(2,1) = ...<br />

...<br />

DFDDIS(2,6) = ...<br />

C<br />

C Assign displacement partials for Z force<br />

C<br />

DFDDIS(3,1) = ...<br />

...<br />

DFDDIS(3,6) = ...<br />

C<br />

C Assign displacement partials for X <strong>to</strong>rque<br />

C<br />

DFDDIS(4,1) = ...<br />

...<br />

DFDDIS(4,6) = ...<br />

C<br />

C Assign displacement partials for Y <strong>to</strong>rque<br />

C<br />

DFDDIS(5,1) = ...<br />

...<br />

DFDDIS(5,6) = ...<br />

C<br />

C Assign displacement partials for Z <strong>to</strong>rque<br />

C<br />

DFDDIS(6,1) = ...<br />

...<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

167


168<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

DFDDIS(6,6) = ...<br />

C<br />

C Assign velocity partials for X force<br />

C<br />

DFDVEL(1,1) = ...<br />

...<br />

DFDVEL(1,6) = ...<br />

C<br />

C Assign velocity partials for Y force<br />

C<br />

DFDVEL(2,1) = ...<br />

...<br />

DFDVEL(2,6) = ...<br />

C<br />

C Assign velocity partials for Z force<br />

C<br />

DFDVEL(3,1) = ...<br />

...<br />

DFDVEL(3,6) = ...<br />

C<br />

C Assign velocity partials for X <strong>to</strong>rque<br />

C<br />

DFDVEL(4,1) = ...<br />

...<br />

DFDVEL(4,6) = ...<br />

C<br />

C Assign velocity partials for Y <strong>to</strong>rque<br />

C<br />

DFDVEL(5,1) = ...<br />

...<br />

DFDVEL(5,6) = ...<br />

C<br />

C Assign velocity partials for Z <strong>to</strong>rque<br />

C<br />

DFDVEL(6,1) = ...<br />

...<br />

DFDVEL(6,6) = ...<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_FIESUB(const struct s<strong>Adams</strong>Field* fie, double<br />

TIME, double* DISP, double* VELO, int DFLAG, int IFLAG, double*<br />

FIELD, double* DFDDIS, double* DFDVEL);<br />

/*<br />

* FIELD -------------------------------------------------<br />

----------------<br />

*/<br />

struct s<strong>Adams</strong>Field<br />

{<br />

int ID;


};<br />

int NPAR;<br />

const double* PAR;<br />

int I;<br />

int J;<br />

Examples<br />

For an example of this subroutine, see fiesub.f.<br />

GFOSUB<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The GFOSUB evaluation subroutine computes a set of six force values applied by a GFORCE statement<br />

(C++ or FORTRAN). You can use a GFOSUB when the functions are <strong>to</strong>o cumbersome or complex <strong>to</strong><br />

enter as expressions in a GFORCE statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE GFOSUB(id, time, par, npar, dflag, iflag, result)<br />

169


170<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

id An integer variable that provides the identifier of the GFORCE statement<br />

requesting information from GFOSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes other information (such as the<br />

par argument) that is available in the corresponding statement.<br />

time A double-precision variable containing the current simulation time.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the GFORCE statement.<br />

npar An integer variable that indicates the number of constants you specify in<br />

the USER parenthetical list. This variable provides the GFOSUB<br />

evaluation subroutine with the number of values s<strong>to</strong>red in the par array.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls GFOSUB<br />

<strong>to</strong> evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong> false.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the<br />

functional dependency information from GFOSUB. Functional<br />

dependencies are established with the same calls <strong>to</strong> SYSARY, and<br />

SYSFNC that are later used <strong>to</strong> compute the values of the GFORCE<br />

components. If the iflag argument is false, the values of the user-defined<br />

expressions are computed.<br />

Output Argument<br />

result A double-precision array that returns the six values of the GFORCE<br />

components.<br />

Extended Definition<br />

The GFORCE statement with a function expression is usually adequate for defining functions that<br />

represent the three translational and three rotational vec<strong>to</strong>r components of a force at a point. However, if<br />

the force and <strong>to</strong>rque expressions become lengthy and awkward, you can use a GFOSUB.<br />

You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY, and SYSFNC, from GFOSUB,<br />

<strong>to</strong> obtain information about system variables, user-defined variables, and splines.<br />

The SYSARY and SYSFNC utility subroutines set up functional dependencies when the GFOSUB<br />

argument iflag is true. In order for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> compute solutions efficiently, it must know the<br />

<strong>Solver</strong> states on which the GFORCES depend. <strong>Adams</strong>/<strong>Solver</strong> determines these functional dependencies<br />

at the beginning of the simulation by calling GFOSUB with the argument iflag set <strong>to</strong> true. <strong>Adams</strong>/<strong>Solver</strong><br />

does this once for each GFORCE statement with a FUNCTION=USER() argument. During each call <strong>to</strong><br />

GFOSUB, <strong>Adams</strong>/<strong>Solver</strong> records the calls you make <strong>to</strong> SYSARY and SYSFNC. <strong>Adams</strong>/<strong>Solver</strong> assumes<br />

that the GFORCE components depend on those <strong>Adams</strong>/<strong>Solver</strong> states that are accessed through SYSARY<br />

and SYSFNC.


Using the DFLAG Variable<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The use of the DFLAG variable with a GFOSUB is optional. It merely identifies that GFOSUB is being<br />

called <strong>to</strong> evaluate a partial derivative. One of the states on which the GFOSUB depends has been<br />

perturbed very slightly. In many situations, it is likely that major calculations in the GFOSUB are<br />

insensitive <strong>to</strong> small changes in state, and therefore, need not be recalculated.<br />

In such situations, you can structure the GFOSUB not <strong>to</strong> redo these calculations. For example, assume<br />

you are using a GFOSUB <strong>to</strong> model tire and terrain interactions. The terrain is modeled as a set of<br />

triangular patches, and the tire forces as a GFOSUB. A labor-intensive calculation in the problem is <strong>to</strong><br />

identify the patch that is in contact with the tire. Because pertubations of system states are always small<br />

when DFLAG is true, it is not necessary <strong>to</strong> recalculate the patch that is in contact with the tire.<br />

Caution: • Euler angles calculated by SYSARY or SYSFNC subroutines may be<br />

discontinuous. To avoid discontinuity, use the RCNVRT utility subroutine <strong>to</strong><br />

convert the rotational angles from Euler angles <strong>to</strong> some other rotational scheme<br />

that does not encounter discontinuity.<br />

FORTRAN - Pro<strong>to</strong>type<br />

• When the iflag argument is true, you must make all the calls <strong>to</strong> SYSARY and<br />

SYSFNC as are made <strong>to</strong> compute the component values of the GFORCE<br />

statement. This ensures that <strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies.<br />

In general, failure <strong>to</strong> account for dependencies in the GFORCE components can<br />

make it difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a solution and/or can force<br />

<strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> take small integration steps. It may increase simulation time<br />

dramatically.<br />

• When the iflag argument is true, SYSARY and SYSFNC return zero values for<br />

system and user-defined variables. Computations that divide by these values will<br />

result in fatal errors. You should check for nonzero values, or ensure the iflag<br />

argument is set <strong>to</strong> false, before dividing by these values.<br />

A sample structure for GFOSUB is shown next. The comments explain how the subroutine works.<br />

&<br />

SUBROUTINE GFOSUB(ID, TIME, PAR, NPAR, DFLAG,<br />

IFLAG, RESULT)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C Note: For a machine with 60 or more bits per word,<br />

C<br />

C<br />

substitute "REAL" for "DOUBLE PRECISION".<br />

C - External variable definitions -----------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

171


172<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT( 6 )<br />

C<br />

C ID Identifier of calling GFORCE statement<br />

C TIME Current time<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C IFLAG Initial pass flag<br />

C RESULT Array (dimension 6) of computed GFORCE<br />

C components returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variable and parameter definitions -----<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign readable variable names <strong>to</strong> passed parameters<br />

C<br />

...<br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C the following calculations. Note: if IFLAG is<br />

C true, these calls are actually setting functional<br />

C dependencies.<br />

C<br />

CALL SYSFNC (...)<br />

C<br />

C Check SYSFNC call through ERRMES utility routine<br />

C<br />

CALL ERRMES (...)<br />

C<br />

C Repeat for all required SYSFNC or SYSARY calls<br />

C<br />

...<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C - Subroutine initialization -------------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Evaluate GFORCE components -------------<br />

C<br />

C Your algorithms<br />

C<br />

...<br />

C<br />

C Assign values <strong>to</strong> the RESULT array<br />

C<br />

RESULT(1) = ...


C<br />

RESULT(2) = ...<br />

RESULT(3) = ...<br />

RESULT(4) = ...<br />

RESULT(5) = ...<br />

RESULT(6) = ...<br />

RETURN<br />

END<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_GFOSUB(const struct s<strong>Adams</strong>Gforce* gfo, double<br />

TIME, int DFLAG, int IFLAG, double* RESULT);<br />

/*<br />

* GFORCE<br />

*/<br />

struct s<strong>Adams</strong>Gforce<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int I;<br />

int RM;<br />

int JFLOAT;<br />

};<br />

Examples<br />

For an example of this subroutine, see gfosub.f.<br />

GSE_DERIV, GSE_UPDATE, GSE_OUTPUT, GSE_SAMP<br />

These four subroutines are used <strong>to</strong> completely define a GSE (C++ or FORTRAN). Recall that the<br />

constitutive equations for a GSE have the form:<br />

• GSE_DERIV defines the function fc(), shown in Equation 1 above. GSE_DERIV also returns<br />

the partial derivatives:<br />

• GSE_UPDATE defines the function fd(), shown in Equation 2 above. It defines the derivative of<br />

the states that the GSE introduces. GSE_UPDATE does not return any partial derivatives.<br />

• GSE_OUTPUT defines the function g(), shown in Equation 3 above. GSE_OUTPUT also<br />

returns the partial derivatives:<br />

• GSE_SAMP defines the sampling period associated with Equation 2. The sampling period is the<br />

time between two consecutive updates. It does not need <strong>to</strong> be a constant.<br />

173


174<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Corresponding Statement<br />

GSE_DERIV<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_DERIV (ID, TIME, PAR, NPAR, DFLAG, IFLAG, NS, XDOT)<br />

Input Arguments<br />

id An integer variable containing the ID of the GSE statement requesting<br />

information from the GSE subroutine. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically recognizes other information (such as the PAR argument)<br />

that is associated with that GSE statement.<br />

time A double-precision variable containing the current simulation time.<br />

par A double-precision array containing the constant parameters taken in<br />

order from the USER parenthetical list in the GSE statement.<br />

npar An integer variable containing the number of constants in the<br />

Function=USER(...) parenthetical list in the GSE statement. The primary<br />

purpose is <strong>to</strong> provide the subroutine with the number of entries in the par<br />

array.<br />

dflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine <strong>to</strong> obtain partial derivatives of the function fc().<br />

iflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine during the code initialization pass. For other evaluation<br />

subroutines, the flag is used when <strong>Adams</strong>/<strong>Solver</strong> needs functional<br />

dependency information and normally controls calls <strong>to</strong> the SYSFNC and<br />

SYSARY utility subroutines. You can use the IFLAG argument <strong>to</strong> control<br />

any other initialization you might need <strong>to</strong> do in the GSE evaluation<br />

subroutine.<br />

ns An integer variable containing the number of continuous states in the<br />

GSE; taken from the NS argument <strong>to</strong> the GSE statement.<br />

Output Arguments<br />

xdot A double-precision array of dimension NS, containing the derivatives of<br />

the state Xc.<br />

Examples<br />

For an example of this subroutine, see gse_deriv.f


GSE_UPDATE<br />

Calling Sequence<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

SUBROUTINE GSE_UPDATE (ID, TIME, PAR, NPAR, DFLAG, IFLAG, ND, XDplus1)<br />

Input Arguments<br />

id An integer variable containing the ID of the GSE statement requesting<br />

information from the GSE subroutine. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes other information (such as the<br />

PAR argument) that is associated with that GSE statement.<br />

time A double-precision variable containing the current simulation time.<br />

par A double-precision array containing the constant parameters taken in<br />

order from the USER parenthetical list in the GSE statement.<br />

npar An integer variable containing the number of constants in the<br />

Function=USER(...) parenthetical list in the GSE statement. The<br />

primary purpose is <strong>to</strong> provide the subroutine with the number of entries<br />

in the Par array.<br />

dflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine <strong>to</strong> obtain partial derivatives of the function fc().<br />

iflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine during the code initialization pass. For other evaluation<br />

subroutines, the flag is used when <strong>Adams</strong>/<strong>Solver</strong> needs functional<br />

dependency information and normally controls calls <strong>to</strong> the SYSFNC and<br />

SYSARY utility subroutines. Although you cannot call these routines<br />

from any of the GSE evaluation subroutines, you can use the IFLAG<br />

argument <strong>to</strong> control any other initialization you might need <strong>to</strong> do in the<br />

GSE evaluation subroutine.<br />

nd An integer variable containing the number of discrete states in the GSE;<br />

taken from the ND argument <strong>to</strong> the GSE statement.<br />

Output Arguments<br />

XdPlus1 A double-precision array of dimension ND, containing the value of the<br />

GSE discrete states at time T=Tn+1.<br />

Examples<br />

For an example of this subroutine, see gse_update.f.<br />

GSE_OUTPUT<br />

175


176<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_OUTPUT (ID, TIME, PAR, NPAR, DFLAG, IFLAG, NO, Y)<br />

Input Arguments<br />

id An integer variable containing the ID of the GSE statement requesting<br />

information from the GSE subroutine. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically recognizes other information (such as the par argument) that<br />

is associated with that GSE statement.<br />

time A double-precision variable containing the current simulation time.<br />

par A double-precision array containing the constant parameters taken in<br />

order from the USER parenthetical list in the GSE statement.<br />

npar An integer variable containing the number of constants in the<br />

Function=USER(...) parenthetical list in the GSE statement. The primary<br />

purpose is <strong>to</strong> provide the subroutine with the number of entries in the PAR<br />

array.<br />

dflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine <strong>to</strong> obtain partial derivatives of the function g().<br />

iflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine during the code initialization pass. For other evaluation<br />

subroutines, the flag is used when <strong>Adams</strong>/<strong>Solver</strong> needs functional<br />

dependency information and normally controls calls <strong>to</strong> the SYSFNC and<br />

SYSARY utility subroutines. Although you cannot call these routines<br />

from any of the GSE evaluation subroutines, you can use the IFLAG<br />

argument <strong>to</strong> control any other initialization you might need <strong>to</strong> do in the<br />

GSE evaluation subroutine.<br />

no An integer variable containing the number of outputs in the GSE; taken<br />

from the NO argument <strong>to</strong> the GSE statement.<br />

Output Arguments<br />

Y A double-precision array of dimension NO, containing the value of the GSE<br />

at the current simulation time.<br />

Example<br />

For an example of this subroutine, see gse_output.f.<br />

GSE_SAMP<br />

Calling Sequence and Structure<br />

SUBROUTINE GSE_SAMP (ID, TIME, PAR, NPAR, IFLAG,Sample_Step)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that gives the identifier of the GSE statement<br />

requesting information from the GSE subroutine. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes other information (such as the<br />

Par argument) that is associated with that GSE statement.<br />

time A double-precision variable containing the current simulation time.<br />

par A double-precision array containing the constant parameters taken in<br />

order from the USER parenthetical list in the GSE statement.<br />

npar An integer variable containing the number of constants in the<br />

Function=USER(...) parenthetical list in the GSE statement.<br />

The primary purpose is <strong>to</strong> provide the subroutine with the number of<br />

entries in the Par array.<br />

iflag A logical variable that is set <strong>to</strong> true when <strong>Adams</strong>/<strong>Solver</strong> calls the<br />

subroutine during the code initialization pass. For other evaluation<br />

subroutines, the flag is used when <strong>Adams</strong>/<strong>Solver</strong> needs functional<br />

dependency information and normally controls calls <strong>to</strong> the SYSFNC and<br />

SYSARY utility subroutines. Although you cannot call these routines<br />

from any of the GSE evaluation subroutines, you can use the IFLAG<br />

argument <strong>to</strong> control any other initialization you might need <strong>to</strong> do in the<br />

GSE evaluation subroutine.<br />

Output Arguments<br />

sample_step A double-precision scalar, containing the sample step (that is, the<br />

difference between the next sample time, and the current simulation).<br />

Example<br />

For an example of this subroutine, see gse_samp.f.<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_GSESUB(const struct s<strong>Adams</strong>GSE* gse, double TIME,<br />

int DFLAG, int IFLAG, int NSTATE, const double* STATES, int NINPUT,<br />

const double* INPUTS, int NPUTPUT, double* STATED, double* OUTPUT);<br />

typedef void adams_c_GSEXU(const struct s<strong>Adams</strong>GSE* gse, double TIME,<br />

int IFLAG, int NSTATE, const double* STATES, int NINPUT, const<br />

double* INPUTS, int NOUTPUTS, double* DERIVS);<br />

typedef void adams_c_GSEXX(const struct s<strong>Adams</strong>GSE* gse, double TIME,<br />

int IFLAG, int NSTATE, const double* STATES, int NINPUT, const<br />

double* INPUTS, int NOUTPUTS, double* DERIVS);<br />

typedef void adams_c_GSEYU(const struct s<strong>Adams</strong>GSE* gse, double TIME,<br />

int IFLAG, int NSTATE, const double* STATES, int NINPUT, const<br />

double* INPUTS, int NOUTPUTS, double* DERIVS);<br />

177


178<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

typedef void adams_c_GSEYX(const struct s<strong>Adams</strong>GSE* gse, double TIME,<br />

int IFLAG, int NSTATE, const double* STATES, int NINPUT, const double*<br />

INPUTS, int NOUTPUTS, double* DERIVS);<br />

typedef void STDCALL adams_f77_GSESUB(const int* ID, const double*<br />

TIME, const double* PAR, const int* NPAR, const int* DFLAG, const int*<br />

IFLAG, const int* NSTATE, const double* STATES, const int* NINPUT,<br />

const double* INPUTS, const int* NOUTPUT, double* STATED, double*<br />

OUTPUT);<br />

typedef void adams_c_GSEDERIV(const struct s<strong>Adams</strong>GSE* gse, double<br />

TIME, int DFLAG, int IFLAG, int, double*);<br />

typedef void adams_c_GSEOUTPUT(const struct s<strong>Adams</strong>GSE* gse, double<br />

TIME, int DFLAG, int IFLAG, int, double*);<br />

typedef void adams_c_GSEUPDATE(const struct s<strong>Adams</strong>GSE* gse, double<br />

TIME, int DFLAG, int IFLAG, int, double*);<br />

typedef void adams_c_GSESAMPLE(const struct s<strong>Adams</strong>GSE* gse, double<br />

TIME, int IFLAG, double* OUTPUT);<br />

typedef void adams_c_GSESETNS(int NS, int* ERR);<br />

typedef void adams_c_GSESETND(int ND, int* ERR);<br />

typedef void adams_c_GSESETIMPLICIT(int FLAG, int* ERR);<br />

typedef void adams_c_GSESETSTATICHOLD(int FLAG, int* ERR);<br />

typedef void adams_c_GSESETSAMPLEOFFSET(int UNTNUM, double* LOGERR);<br />

/*<br />

* GSE<br />

*/<br />

struct s<strong>Adams</strong>GSE<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int NI;<br />

int NO;<br />

int U;<br />

int Y;<br />

int NS;<br />

int X;<br />

int IC;<br />

int STATIC_HOLD;<br />

int IMPLICIT;<br />

int ND;<br />

int XD;<br />

int ICD;<br />

double SAMPLE_OFFSET;<br />

};<br />

MFOSUB<br />

MFOSUB is an evaluation subroutine that computes the modal force corresponding <strong>to</strong> an MFORCE<br />

statement (C++ or FORTRAN). MFOSUB is optional. You need it only if you don't want <strong>to</strong> use a function<br />

expression in the MFORCE statement, or if you need the added capabilities of the USER form of the<br />

MFORCE statement.


Use<br />

Corresponding Statement<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

You invoke the MFOSUB by using either the FUNCTION or FORCE option in the MFORCE statement.<br />

The MFOSUB output arguments are interpreted differently depending on the form used. <strong>Adams</strong>/<strong>Solver</strong><br />

(C++) can invoke the MFOSUB using either form. <strong>Adams</strong>/<strong>Solver</strong> (FORTRAN) can only invoke the<br />

MFOSUB using FUNCTION.<br />

Calling Sequence<br />

SUBROUTINE MFOSUB (id, time, par, npar, dflag, iflag,$modloads, nmodes, ncases,$scale, case,<br />

loadvec)<br />

179


180<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

id An integer variable that provides the identifier of the MFORCE statement<br />

that is requesting information from the MFOSUB.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the MFORCE statement.<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> enable<br />

MFOSUB <strong>to</strong> correctly dimension the par array.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when calling MFOSUB<br />

<strong>to</strong> evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets dflag <strong>to</strong> false.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when determining the<br />

functional dependency information from MFOSUB. You establish the<br />

functional dependencies with the same calls <strong>to</strong> SYSARY and SYSFNC<br />

that <strong>Adams</strong>/<strong>Solver</strong> later uses <strong>to</strong> compute the values of the MFORCE<br />

components (see SYSARY and SYSFNC). If the iflag argument is false,<br />

you must compute the value of the user-written MFORCE.<br />

modloads A double-precision array containing the values of the modal load cases that<br />

are defined for the FLEX_BODY and that the MFORCE is acting on. The<br />

modload array has the dimensions modload (6+nmodes, ncases).<br />

nmodes An integer variable that indicates the number of modes in the associated<br />

FLEX_BODY. The value of nmodes provides MFOSUB with a way <strong>to</strong><br />

correctly dimension the modloads and loadvec arrays.<br />

ncases An integer variable that indicates the number of load cases available in the<br />

associated FLEX_BODY. The value of ncases provides MFOSUB with a<br />

means <strong>to</strong> correctly dimension the modloads array. If ncases=0, then the<br />

contents of modloads are undefined because no user-defined load cases are<br />

available for the FLEX_BODY.


Output Arguments<br />

scale A double-precision variable.<br />

If MFOSUB is called with the FUNCTION form:<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

This output argument contains the scale fac<strong>to</strong>r that is <strong>to</strong> be applied <strong>to</strong> the<br />

modal load vec<strong>to</strong>r. The value of scale can depend on the values<br />

<strong>Adams</strong>/<strong>Solver</strong> calls from SYSFNC and SYSARY (see SYSARY and<br />

SYSFNC).<br />

If MFOSUB is called with the FORCE form:<br />

<strong>Adams</strong>/<strong>Solver</strong> ignores this output argument.<br />

case An integer, in the range 0 <strong>to</strong> ncases.<br />

If MFOSUB is called with the FUNCTION form:<br />

This output argument denotes a user-defined modal load case that is<br />

multiplied by the scale output argument <strong>to</strong> produce the modal load on the<br />

FLEX_BODY. If case=0, then <strong>Adams</strong>/<strong>Solver</strong> looks for a modal load case in<br />

the loadvec array.<br />

If MFOSUB is called with the FORCE form:<br />

This output argument must be set <strong>to</strong> zero and <strong>Adams</strong>/<strong>Solver</strong> extracts the<br />

modal load directly from the loadvec array.<br />

loadvec A double-precision array of dimension loadvec(6+nmodes) that MFOSUB<br />

generates itself or generates based on the load cases it receives from the<br />

modloads array.<br />

If MFOSUB is called with the FUNCTION form:<br />

If the output variable case is zero, <strong>Adams</strong>/<strong>Solver</strong> computes the modal force<br />

by multiplying the output array loadvec by the output variable scale. The<br />

values of loadvec can be a function of time, but not a function of the model<br />

response. For example, they must not depend on values obtained by calling<br />

SYSFNC and SYSARY. If case>0, then <strong>Adams</strong>/<strong>Solver</strong> ignores the contents<br />

of loadvec.<br />

If MFOSUB is called with the FORCE form:<br />

<strong>Adams</strong>/<strong>Solver</strong> applies the contents of the loadvec array directly <strong>to</strong> the<br />

FLEX_BODY without scaling it. Each component of loadvec can depend on<br />

time and model response. That is, you can use the values obtained from<br />

SYSFNC and SYSARY <strong>to</strong> compute entries in the loadvec array.<br />

181


182<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Examples<br />

A sample for MFOSUB is shown next. In this example, MFOSUB is invoked using the FUNCTION form<br />

and uses load case 3 and scales it with 10.<br />

C<br />

C<br />

C<br />

SUBROUTINE MFOSUB(ID, TIME, PAR, NPAR, DFLAG, IFLAG,<br />

$ MODLOADS, NMODES, NCASES,<br />

$ SCALE, CASE, LOADVEC)<br />

INTEGER ID, NPAR, NMODES, NCASES<br />

LOGICAL DFLAG<br />

LOGICAL ERRFLG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION TIME, PAR(NPAR), MODLOADS(6+NMODES, NCASES)<br />

INTEGER CASE<br />

DOUBLE PRECISION SCALE, LOADVEC(6+NMODES)<br />

CASE = 3<br />

SCALE = 10.<br />

ERRFLG = NCASES.LT.CASE<br />

CALL ERRMES(ERRFLG, 'Trying <strong>to</strong> use an invalid load case.',<br />

& ID, 'STOP' )<br />

RETURN<br />

END<br />

In this next example, the MFOSUB is called with the FORCE form of the MFORCE statement. The<br />

MFOSUB applies a critical modal damping force <strong>to</strong> the FLEX_BODY identified by the first entry in the<br />

USER parenthetical list. Note that the user-written subroutine assumes the generalized mass matrix is the<br />

identity matrix.<br />

SUBROUTINE MFOSUB(ID, TIME, PAR, NPAR, DFLAG, IFLAG, MODLOADS,<br />

& NMODS, NCASES, SCALE, CASE, LOADVEC)<br />

C<br />

IMPLICIT NONE<br />

C<br />

C... ARGUMENTS:<br />

C<br />

INTEGER ID<br />

INTEGER NPAR<br />

INTEGER NMODS<br />

INTEGER NCASES<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(NPAR)<br />

DOUBLE PRECISION MODLOADS(6+NMODS, NCASES)<br />

C<br />

C... RETURNS<br />

C


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

INTEGER CASE<br />

DOUBLE PRECISION SCALE, LOADVEC(6+NMODS)<br />

C<br />

C... PARAMETERSC<br />

INTEGER MAXN<br />

PARAMETER (MAXN = 100 )<br />

DOUBLE PRECISION ZERO<br />

PARAMETER (ZERO = 0.0D+00)<br />

DOUBLE PRECISION ONE<br />

PARAMETER (ONE = 1.0D+00)<br />

DOUBLE PRECISION TWO<br />

PARAMETER (TWO = 2.0D+00)<br />

DOUBLE PRECISION PI<br />

PARAMETER (PI = 3.141592653589793D+00)<br />

C<br />

C... LOCALSC<br />

LOGICAL ERRFLG<br />

INTEGER I, NQ, FBYID<br />

INTEGER MNUM(MAXN)<br />

DOUBLE PRECISION GSTF, GMAS<br />

DOUBLE PRECISION MFRQ(MAXN), QDOT(MAXN)<br />

C<br />

C===================== EXECUTABLE CODE<br />

==============================<br />

C FBYID = NINT(PAR(1))<br />

C<br />

C... GET MODE NUMBERS AND FREQUENCIES FOR ALL ACTIVE MODES<br />

C<br />

CALL MODINF (FBYID, MNUM, MFRQ, ERRFLG)<br />

CALL ERRMES(ERRFLG, 'FAILED CALL TO MODINF', ID, 'STOP')<br />

C<br />

C... GET TIME DERIVATIVE OF MODAL COORDINDATES<br />

CALL SYSARY('QDOT', FBYID, 1, QDOT, NQ, ERRFLG)<br />

CALL ERRMES(ERRFLG, 'FAILED CALL TO SYSARY', ID, 'STOP')<br />

C<br />

C... CASE MUST BE SET TO ZEROC<br />

CASE = 0CC... BUILD MODAL LOAD AND RETURN IN LOADVEC ARRAY<br />

C<br />

DO I = 1, 6<br />

LOADVEC(I) = ZERO<br />

END DO<br />

C<br />

DO I = 1, NMODS<br />

GMAS = ONE<br />

GSTF = (TWO * PI * MFRQ(I)) ** 2<br />

183


184<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

LOADVEC(I+6) = -TWO * DSQRT(GSTF * GMAS) * QDOT(I)<br />

END DO<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_MFOSUB(const struct s<strong>Adams</strong>Mforce* mforce, double<br />

TIME, int DFLAG, int IFLAG, const double* MODLOADS, int NMODES, int<br />

NCASES, double* SCALE, int* CASE, double* LOADVEC);<br />

/*<br />

* MFORCE<br />

*/<br />

struct s<strong>Adams</strong>Mforce<br />

{<br />

struct s<strong>Adams</strong>FlexBody FlexBody;<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int JFLOAT;<br />

};<br />

MOTSUB<br />

The MOTSUB evaluation subroutine computes the joint displacement, velocity, or acceleration for a<br />

MOTION statement (C++ or FORTRAN). MOTSUB is optional. You only need it if you don't want <strong>to</strong><br />

use a function expression in the MOTION statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE MOTSUB(id, time, par, npar, iord, iflag,value)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that provides the identifier of the MOTION statement<br />

requesting information from MOTSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically knows other information (such as the par<br />

argument) available in the corresponding statement.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true for the initial call <strong>to</strong><br />

MOTSUB. In general, you do not need <strong>to</strong> check this flag in the<br />

subroutine. If there are computations that need <strong>to</strong> be evaluated once at the<br />

beginning of the simulation, you can check the iflag argument. In this<br />

case, if the iflag argument is true, the subroutine should evaluate the<br />

computations.<br />

iord An input integer variable indicating the order of the time derivative that<br />

<strong>Adams</strong>/<strong>Solver</strong> requires at different points in the analysis.<br />

Output Arguments<br />

When the motion is a displacement, <strong>Adams</strong>/<strong>Solver</strong>, at various times, calls<br />

MOTSUB with IORD set <strong>to</strong> 0, 1, or 2, requesting the displacement value<br />

and its first and second time derivatives, respectively.<br />

When the motion is a velocity, <strong>Adams</strong>/<strong>Solver</strong> only calls MOTSUB with<br />

IORD set <strong>to</strong> 0 or 1, and returns the velocity value and its time derivative,<br />

respectively. The second time derivative, a velocity motion, is never<br />

required.<br />

When the motion is an acceleration, <strong>Adams</strong>/<strong>Solver</strong> only uses IORD set <strong>to</strong><br />

0. No time derivatives of the function used in the MOTSUB for an<br />

acceleration motion are needed.<br />

npar An integer variable that indicates the number of constants specified in<br />

the USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide<br />

MOTSUB with the number of values s<strong>to</strong>red in the par array.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the MOTION statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

value A double-precision variable that returns the zeroth, first, or second<br />

derivative of the motion of the I marker with respect <strong>to</strong> the J marker.<br />

These derivatives represent the displacement, velocity, and acceleration<br />

of the motion, respectively. The value of IORD indicates which derivative<br />

of motion value must return.<br />

185


186<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Extended Definition<br />

In most cases, the MOTION statement with a function expression is adequate for defining the motion<br />

input. However, if the expression becomes lengthy and awkward, you should use the<br />

FUNCTION=USER() argument in the MOTION statement, and write a MOTSUB <strong>to</strong> calculate the<br />

displacement.<br />

MOTSUB measures translational displacements from the origin of the J marker <strong>to</strong> the origin of the I<br />

marker. The positive z-axis of the J marker defines the positive direction. MOTSUB measures rotational<br />

displacements from the x-axis of the J marker <strong>to</strong> the x-axis of the I marker. The right-hand rule defines a<br />

positive angle with respect <strong>to</strong> the positive z-axis of the J marker.<br />

MOTSUB output must be strictly a function of time. Consequently, MOTSUB must not call the<br />

SYSARY and SYSFNC utility subroutines. To describe discrete time-dependent functions, MOTSUB<br />

may call the CUBSPL utility subroutine.<br />

Caution: • Define the motion only as a function of time. Don't make calls <strong>to</strong> the SYSARY and<br />

SYSFNC utility subroutines <strong>to</strong> access other system variables or <strong>to</strong> access userdefined<br />

variables.<br />

FORTRAN - Pro<strong>to</strong>type<br />

• Make sure the first and second derivatives MOTSUB returns for displacement are<br />

correct.<br />

• If the CUBSPL utility subroutine or any of the <strong>Adams</strong>/<strong>Solver</strong> utility subroutines<br />

are used, do not forget <strong>to</strong> involve the derivatives returned by these subroutines<br />

when the MOTSUB derivatives are evaluated.<br />

• Avoid conditional branching that results in discontinuous accelerations, velocities,<br />

or displacements.<br />

• Make sure MOTSUB uses length units <strong>to</strong> define translational displacements and<br />

their derivatives, and radians <strong>to</strong> define rotational displacements and their<br />

derivatives.<br />

A sample structure for MOTSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE MOTSUB ( ID, TIME, PAR, NPAR, IORD,<br />

& IFLAG, VALUE )<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C Note: For machines with 60 or more bits per word,<br />

C substitute "REAL" for "DOUBLE PRECISION".<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

INTEGER IORD<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

C<br />

C ID Identifier of calling MOTION statement<br />

C TIME Current time<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C IORD Derivative order of value <strong>to</strong> be returned<br />

C IFLAG Initialization pass flag<br />

C VALUE Derivative value of MOTION returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variable and parameter definitions ----<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign parameters <strong>to</strong> readable variable names<br />

C<br />

...<br />

C<br />

IF ( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Compute and assign the motion displacement ---<br />

C<br />

IF ( IORD .EQ. 0 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign a value <strong>to</strong> VALUE for the motion displacement<br />

C<br />

VALUE = ...<br />

C<br />

C - Compute and assign the motion velocity -----<br />

C<br />

ELSE IF ( IORD .EQ. 1 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign a value <strong>to</strong> VALUE for the motion velocity<br />

C<br />

VALUE = ...<br />

C<br />

187


188<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C - Compute and assign the motion acceleration ---<br />

C<br />

ELSE<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign a value <strong>to</strong> VALUE for the motion acceleration<br />

C<br />

VALUE = ...<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>ype<br />

typedef void adams_c_MOTSUB(const struct s<strong>Adams</strong>Motion* motion, double<br />

TIME, int DFLAG, int IFLAG, double* RESULT);<br />

/*<br />

* MOTION<br />

*/<br />

struct s<strong>Adams</strong>Motion<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int JOINT;<br />

const char* Type;<br />

int I;<br />

int J;<br />

char Which[2];<br />

const char* DVA;<br />

};<br />

Examples<br />

For an example of this subroutine, see motsub.f.<br />

RELSUB<br />

The RELSUB restart subroutine allows you <strong>to</strong> reload any information needed <strong>to</strong> restart user-written<br />

subroutines. <strong>Adams</strong>/<strong>Solver</strong> calls SAVSUB during a SAVE command <strong>to</strong> write user data. RELSUB can<br />

then read the data during a RELOAD command.<br />

SAVSUB and RELSUB are optional. You only need them if you want the SAVE and RELOAD<br />

commands <strong>to</strong> save and reload user data, in addition <strong>to</strong> internal <strong>Adams</strong>/<strong>Solver</strong> data.


Use<br />

Corresponding Command<br />

Calling Sequence<br />

SUBROUTINE RELSUB(iunit, errflg)<br />

Input Argument<br />

Output Argument<br />

Structure<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

iunit An integer variable that contains the FORTRAN IO unit of the<br />

<strong>Adams</strong>/<strong>Solver</strong> save file. <strong>Adams</strong>/<strong>Solver</strong> opens the save file as sequential<br />

and unformatted. If SAVSUB has written data <strong>to</strong> the save file, the RELSUB<br />

may read it from this unit with an unformatted FORTRAN READ<br />

statement.<br />

errflg A logical variable that indicates <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> that an error has occurred<br />

while reading user data. If you set errflg <strong>to</strong> true, <strong>Adams</strong>/<strong>Solver</strong> writes an<br />

error message <strong>to</strong> the screen and <strong>to</strong> the message file.<br />

Tip: The most straightforward way <strong>to</strong> reinitialize user-written subroutines may be <strong>to</strong> collect the<br />

necessary variables in a COMMON block, use SAVSUB <strong>to</strong> write them <strong>to</strong> the save file, and<br />

RELSUB <strong>to</strong> read them back from the save file.<br />

Caution: RELSUB must read data from the save file in the same order in which SAVSUB wrote the<br />

data.<br />

A sample structure for RELSUB is shown next. The comments describe how the subroutine works.<br />

SUBROUTINE RELSUB(IUNIT, ERRFLG)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C --- External variable definitions -------------------<br />

C<br />

INTEGER IUNIT<br />

LOGICAL ERRFLG<br />

C<br />

C IUNIT FORTRAN IO unit attached <strong>to</strong> Save File<br />

C ERRLFG used <strong>to</strong> signal problems back <strong>to</strong> ADAMS<br />

C<br />

189


190<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C --- COMMON Blocks -----------------------------------<br />

C<br />

COMMON ...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Read in the information which appears in the COMMON<br />

C blocks, through which this routine shares information<br />

C with other user-written subroutines.<br />

C<br />

READ (IUNIT) ...<br />

C<br />

RETURN<br />

END<br />

Example<br />

For an example of this subroutine, see relsub.f.<br />

REQSUB<br />

The REQSUB evaluation subroutine computes the output values for a REQUEST statement (C++ or<br />

FORTRAN). REQSUB is optional. You only need it if you do not want <strong>to</strong> use the standard requests or<br />

F1,F2,...,F8 expressions in the REQUEST statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE REQSUB (id, time, par, npar, iflag, result)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that provides the identifier of the REQUEST<br />

statement requesting information from REQSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically knows other information (such as the par<br />

argument) available in the corresponding statement.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true for the initial call <strong>to</strong><br />

REQSUB. In general, you do not need <strong>to</strong> test this flag in the subroutine.<br />

But if there are computations that need <strong>to</strong> be evaluated once at the<br />

beginning of the simulation, you can test the iflag argument. In this case,<br />

if the iflag argument is true, the subroutine should evaluate the<br />

computations.<br />

npar An integer variable that indicates the number of constants specified in<br />

the USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide<br />

REQSUB with the number of values s<strong>to</strong>red in the par array.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the REQUEST statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

Output Argument<br />

result A double-precision array of eight values that contains the values you<br />

calculate in the REQSUB. <strong>Adams</strong>/<strong>Solver</strong> sends all the values and the<br />

current time <strong>to</strong> the tabular output file.<br />

Extended Definition<br />

If the dataset contains an OUTPUT statement with the REQSAVE<br />

argument, <strong>Adams</strong>/<strong>Solver</strong> s<strong>to</strong>res values two through four, and six through<br />

eight in the request file for subsequent plotting in the postprocessor (see<br />

the C++ OUTPUT command or the FORTRAN OUTPUT command).<br />

<strong>Adams</strong>/<strong>Solver</strong> does not s<strong>to</strong>re columns one and five in the request file.<br />

These columns usually contain translational and rotational magnitude<br />

values for the request. If the dataset contains a RESULTS statement<br />

without the NODATASTRUCTURES argument, <strong>Adams</strong>/<strong>Solver</strong> s<strong>to</strong>res<br />

all eight values in the results file for subsequent postprocessing. If fewer<br />

than eight values are used in the result array, <strong>Adams</strong>/<strong>Solver</strong> sets the<br />

remaining values <strong>to</strong> zero.<br />

The REQUEST and MREQUEST statements are usually adequate for outputting displacement, velocity,<br />

acceleration, or force data between two markers in the system. But if you want <strong>to</strong> output other quantities,<br />

191


192<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

include the FUNCTION=USER() argument in the REQUEST statement and define the request output in<br />

a REQSUB.<br />

REQSUB passes back an array of eight values. You can call any utility subroutine from REQSUB <strong>to</strong><br />

make any element in the result array functionally dependent on system displacements, velocities,<br />

accelerations, forces, user-defined differential variables, or on-spline data.<br />

Tip: If the SYSARY or SYSFNC utility subroutine is called <strong>to</strong> access angular displacements,<br />

the values returned by them may contain discontinuities. To avoid the discontinuities, use<br />

the RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other set of rotational coordinates that does not encounter a singularity.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for REQSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE REQSUB ( ID, TIME, PAR, NPAR, IFLAG,<br />

& RESULT )<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT( 8 )<br />

C<br />

C ID Identifier of calling REQUEST statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C IFLAG Initialization pass flag<br />

C RESULT Array of values returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign parameter values <strong>to</strong> readable variable names<br />

C<br />

...<br />

C<br />

IF( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...


C<br />

ENDIF<br />

C<br />

C - Create request information -----------<br />

C<br />

C Your algorithms<br />

C<br />

...<br />

C<br />

C Assign values <strong>to</strong> the result array<br />

C<br />

RESULT(1) = ...<br />

...<br />

RESULT(8) = ...<br />

C<br />

RETURN<br />

END<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_REQSUB(const struct s<strong>Adams</strong>Request* req, double<br />

TIME, int IFLAG, double* OUTPUT);<br />

/*<br />

* REQUEST -------------------------------------------------<br />

----------------<br />

*/<br />

struct s<strong>Adams</strong>Request<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

const char* COMMENT;<br />

const char* TITLE[8];<br />

};<br />

Examples<br />

For an example of this subroutine, see reqsub.f.<br />

SAVSUB<br />

The SAVSUB restart subroutine allows you <strong>to</strong> s<strong>to</strong>re any information needed <strong>to</strong> later restart user-written<br />

subroutines. <strong>Adams</strong>/<strong>Solver</strong> calls SAVSUB during a SAVE command <strong>to</strong> write user data. The RELSUB<br />

restart subroutine can then read the data during a RELOAD command.<br />

SAVSUB and RELSUB are optional. You only need them if you want <strong>to</strong> use the SAVE and RELOAD<br />

commands <strong>to</strong> save and reload user data, in addition <strong>to</strong> internal <strong>Adams</strong>/<strong>Solver</strong> data.<br />

193


194<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Corresponding Command<br />

Calling Sequence<br />

SUBROUTINE SAVSUB(iunit, errflg)<br />

Input Arguments<br />

iunit An integer variable that contains the FORTRAN IO unit of the<br />

<strong>Adams</strong>/<strong>Solver</strong> save file. <strong>Adams</strong>/<strong>Solver</strong> opens the save file as sequential and<br />

unformatted. You may s<strong>to</strong>re data in the save file by writing it <strong>to</strong> this unit<br />

with an unformatted FORTRAN WRITE statement.<br />

Output Argument<br />

errflg A logical variable that indicates <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> that an error has<br />

occurred while saving user data. If you set errflg <strong>to</strong> true, <strong>Adams</strong>/<strong>Solver</strong><br />

writes an error message <strong>to</strong> the screen and <strong>to</strong> the message file.<br />

Tip: The most straightforward way <strong>to</strong> reinitialize user-written subroutines might be <strong>to</strong> collect<br />

the necessary variables in a COMMON block, use SAVSUB <strong>to</strong> write them <strong>to</strong> the save file,<br />

and RELSUB <strong>to</strong> read them back from the save file.<br />

Caution: RELSUB must read data from the save file in the same order in which SAVSUB wrote the<br />

data.<br />

Structure<br />

A sample structure for SAVSUB is shown next. The comments describe how the subroutine works.<br />

SUBROUTINE SAVSUB(IUNIT, ERRFLG)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C --- External variable definitions -------------------<br />

C<br />

INTEGER IUNIT<br />

LOGICAL ERRFLG<br />

C<br />

C IUNIT FORTRAN IO unit attached <strong>to</strong> Save File<br />

C ERRLFG used <strong>to</strong> signal problems back <strong>to</strong> ADAMS<br />

C


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C --- COMMON Blocks -----------------------------------<br />

C<br />

COMMON...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Write out the information which appears in the COMMON<br />

C blocks, through which this routine shares information<br />

C with other user-written subroutines.<br />

C<br />

WRITE (IUNIT) ...<br />

C<br />

RETURN<br />

END<br />

Example<br />

For an example of this subroutine, see savsub.f.<br />

SENSUB<br />

The SENSUB evaluation subroutine computes the values sensed by a SENSOR statement (C++ or<br />

FORTRAN). SENSUB is optional. You only need it if you do not want <strong>to</strong> use a function expression in<br />

the SENSOR statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE SENSUB (id, time, par, npar, iflag, value)<br />

195


196<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

id An integer variable that contains the ID of the SENSOR statement that<br />

requests information from SENSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically knows other information (such as the par argument) available<br />

in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time <strong>to</strong> SENSUB.<br />

par A double-precision array of constants taken, in order, from the USER<br />

parenthetical list of the SENSOR statement.<br />

npar An integer variable that indicates the number of constants specified in<br />

the USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide<br />

SENSUB with the number of values s<strong>to</strong>red in the par array.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true for the initial call <strong>to</strong><br />

SENSUB. If there are computations that need <strong>to</strong> be evaluated once at the<br />

beginning of the simulation, you can check the iflag argument. In this case, if<br />

the iflag argument is true, the subroutine should evaluate the computations.<br />

Output Argument<br />

value A double-precision variable that contains the value of the function that<br />

SENSUB evaluates.<br />

Extended Definition<br />

The SENSOR statement with a function expression is usually adequate for most sensing requirements.<br />

However, if the expression becomes lengthy and awkward, you should use the FUNCTION=USER()<br />

argument in the SENSOR statement, and write a SENSUB <strong>to</strong> define the function you want <strong>to</strong> sense.<br />

To access information on which the function depends, you can use the utility subroutines such as<br />

AKISPL, CUBSPL, SYSARY, and SYSFNC in SENSUB.<br />

Tip: If the SYSARY or SYSFNC utility subroutines are called <strong>to</strong> access angular displacements,<br />

the values returned by them may contain discontinuities. To avoid the discontinuities, use<br />

the RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other rotational representation that does not encounter a singularity.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for SENSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE SENSUB ( ID, TIME, PAR, NPAR, IFLAG,<br />

& VALUE )<br />

C<br />

C === Type and dimension statements ===================


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

C<br />

C ID Identifier of calling SENSOR statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C IFLAG Initialization pass flag<br />

C VALUE The returned value of the sensor<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign parameter values <strong>to</strong> readable variables<br />

C<br />

...<br />

C<br />

IF( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIFCC - Evaluate sensor ----------------<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign the returned value<br />

C<br />

VALUE = ...<br />

C<br />

RETURN<br />

END<br />

C Style - pro<strong>to</strong>type<br />

typedef void adams_c_SENSUB(const struct s<strong>Adams</strong>Sensor* sensor, double<br />

TIME, int IFLAG, double* OUTPUT);<br />

/*<br />

* SENSOR -------------------------------------------------<br />

----------------<br />

197


198<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

struct s<strong>Adams</strong>SensorEval<br />

{<br />

int NPAR;<br />

const double* PAR;<br />

};<br />

*/<br />

struct s<strong>Adams</strong>Sensor<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

double VALUE;<br />

double Error;<br />

char Logic[2];<br />

/* struct s<strong>Adams</strong>SensorEval Eval; */<br />

};<br />

Examples<br />

For an example of this subroutine, see sensub.f.<br />

SEVSUB<br />

The SEVSUB evaluation subroutine computes a scalar value that a SENSOR statement (C++ or<br />

FORTRAN) s<strong>to</strong>res and is available through the SENVAL function expression. SEVSUB is evaluated<br />

only when the event defined by the SENSOR occurs. SEVSUB is optional. You only need it if you do<br />

not want <strong>to</strong> use a function expression in the EVALUATE argument of the SENSOR statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE SEVSUB (id, time, par, npar, iflag, result)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that contains the ID of the SENSOR statement that<br />

requests information from SEVSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically knows other information (such as the par argument)<br />

available in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time <strong>to</strong> SEVSUB.<br />

par A double-precision array of constants taken, in order, from the USER<br />

parenthetical list of the SENSOR statement.<br />

npar An integer variable that indicates the number of constants specified in<br />

the USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide<br />

SEVSUB with the number of values s<strong>to</strong>red in the par array.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true for the initial call <strong>to</strong><br />

SEVSUB. If there are computations that need <strong>to</strong> be evaluated once at the<br />

beginning of the simulation, you can check the iflag argument. In this case,<br />

if the iflag argument is true, the subroutine should evaluate the<br />

computations.<br />

Output Argument<br />

result A double-precision variable that returns the value of the EVALUATE<br />

function for the SENSOR.<br />

Extended Definition<br />

Defining the EVALUATE argument of SENSOR with a function expression is usually sufficient for must<br />

users. If the expression becomes lengthy and awkward, however, you can use SEVSUB. If the algorithms<br />

for computing the EVALUATE function use or consist of existing subroutines, SEVSUB can be made <strong>to</strong><br />

call them.<br />

SEVSUB is only called by <strong>Adams</strong>/<strong>Solver</strong> when the event defined by the SENSOR occurs. <strong>Adams</strong>/<strong>Solver</strong><br />

evaluates whether a SENSOR event has occurred only when it has determined the state of the system for<br />

the current time step.<br />

Once the EVALUATE function has been evaluated, <strong>Adams</strong>/<strong>Solver</strong> s<strong>to</strong>res the result until the SENSOR<br />

event reoccurs. The most recent value of the EVALUATE function is available through the SENVAL<br />

function expression.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for SEVSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE SEVSUB ( ID, TIME, PAR, NPAR, IFLAG,<br />

& RESULT )<br />

199


200<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C<br />

C --- External variable definitions -------------------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT<br />

C<br />

C ID Identifier of calling SENSOR statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C IFLAG Initialization pass flag<br />

C RESULT Scalar value returned <strong>to</strong> ADAMS<br />

C<br />

C --- Local variable definitions ----------------------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C --- Assign parameter values <strong>to</strong> readable variable names<br />

C<br />

...<br />

C IF( IFLAG ) THEN<br />

C<br />

C --- Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C --- Compute the result<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C --- Assign the return value<br />

C<br />

RESULT = ...<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_SEVSUB(const struct s<strong>Adams</strong>Sensor* sensor, double<br />

TIME, int IFLAG, double* OUTPUT);


*<br />

* SENSOR<br />

struct s<strong>Adams</strong>SensorEval<br />

{<br />

int NPAR;<br />

const double* PAR;<br />

};<br />

*/<br />

struct s<strong>Adams</strong>Sensor<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

double VALUE;<br />

double Error;<br />

char Logic[2];<br />

/* struct s<strong>Adams</strong>SensorEval Eval; */<br />

};<br />

Examples<br />

For an example of this subroutine, see sevsub.f.<br />

SFOSUB<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The SFOSUB evaluation subroutine computes the force magnitude for an SFORCE statement. SFOSUB<br />

is optional. You only need it if you don't want <strong>to</strong> use a function expression in the SFORCE statement<br />

(C++ or FORTRAN).<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE SFOSUB (id, time, par, npar, dflag, iflag, value)<br />

201


202<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

id An integer variable that contains the ID of the SFORCE statement that<br />

requests information from SFOSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically knows other information (such as the par argument)<br />

available in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the SFORCE statement.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls SFOSUB<br />

<strong>to</strong> evaluate partial derivatives of the function. Otherwise, <strong>Adams</strong>/<strong>Solver</strong><br />

sets dflag <strong>to</strong> false. See Using the DFLAG Variable.<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide<br />

SFOSUB with the number of values s<strong>to</strong>red in the par array.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the<br />

functional dependency of the user-defined SFORCE. Set functional<br />

dependencies by making the same calls <strong>to</strong> SYSARY and SYSFNC that<br />

you make <strong>to</strong> compute the value of the user-defined SFORCE (see<br />

SYSARY and SYSFNC). If the iflag argument is false, compute the value<br />

of the user-written SFORCE.<br />

Output Argument<br />

value A double-precision variable that contains the force value that SFOSUB<br />

computes.<br />

Extended Definition<br />

The SFORCE statement (C++ or FORTRAN) with a function expression is usually adequate for defining<br />

most single-component forces. If the expression becomes lengthy and awkward, however, you should use<br />

the FUNCTION=USER() argument in the SFORCE statement, and write an SFOSUB <strong>to</strong> calculate the<br />

single-component force.<br />

You can call utility subroutines, such as SYSARY, SYSFNC, AKISPL, and CUBSPL, from SFOSUB <strong>to</strong><br />

obtain information about system variables, user-defined variables, and splines.<br />

The SYSARY and SYSFNC utility subroutines au<strong>to</strong>matically set functional dependencies when the<br />

SFOSUB argument iflag is true. For <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> compute solutions efficiently, it must know<br />

on which other variables each user-defined SFORCE directly depends. <strong>Adams</strong>/<strong>Solver</strong> determines these<br />

functional dependencies at the beginning of the simulation by calling SFOSUB evaluation subroutine<br />

with argument iflag set <strong>to</strong> true. <strong>Adams</strong>/<strong>Solver</strong> does this once for each SFORCE statement with a<br />

FUNCTION=USER() argument. During each call <strong>to</strong> SFOSUB, <strong>Adams</strong>/<strong>Solver</strong> records which calls you


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

make <strong>to</strong> SYSARY and SYSFNC. <strong>Adams</strong>/<strong>Solver</strong> assumes the SFORCE depends on those system<br />

variables, and no others.<br />

Tip: If the SYSARY or SYSFNC utility subroutines are called <strong>to</strong> access angular displacements,<br />

the values they return may contain discontinuities. To avoid the discontinuities, use the<br />

RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other rotational representation that does not encounter a singularity.<br />

Caution: • Force attributes (such as translational, rotational, action-reaction, and action-only)<br />

influence the definition of positive and of negative forces. Review attribute<br />

influences in the SFORCE statement (C++ or FORTRAN).<br />

FORTRAN - Pro<strong>to</strong>type<br />

• The function you choose <strong>to</strong> define a force must be both continuous and<br />

differentiable. Forces with discontinuous derivatives cause a reduction of the<br />

integration step size at the discontinuity. As a result, simulation time may<br />

drastically increase and <strong>Adams</strong>/<strong>Solver</strong> may fail <strong>to</strong> converge <strong>to</strong> a solution.<br />

• When the iflag argument is true, be sure <strong>to</strong> make all the same calls <strong>to</strong> SYSARY<br />

and SYSFNC that are made when actually computing the value of the user-defined<br />

SFORCE. This ensures that <strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies.<br />

In general, failure <strong>to</strong> account for dependencies of the user-defined SFORCE might<br />

make it difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a solution and/or might force<br />

<strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> take small integration steps. Both of these usually cause large<br />

increases in execution time.<br />

• When the iflag argument is true, SYSARY and SYSFNC return zero values for<br />

system and user-defined variables. Computations that divide by these values result<br />

in system errors when <strong>Adams</strong>/<strong>Solver</strong> is executed. Be sure <strong>to</strong> check for nonzero<br />

values, or the iflag argument set <strong>to</strong> false, before dividing by these values.<br />

A sample structure for SFOSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE SFOSUB ( ID, TIME, PAR, NPAR, DFLAG,<br />

& IFLAG, VALUE )<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C Note: For machines with 60 or more bits per word,<br />

C substitute "REAL" for "DOUBLE PRECISION".<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

203


204<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

C<br />

C ID Identifier of calling SFORCE statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C IFLAG Initialization pass flag<br />

C VALUE The SFORCE value returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign parameters <strong>to</strong> readable variable names<br />

C<br />

...<br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C calculations below. Note: if IFLAG is true, these<br />

C calls are actually setting functional dependencies.<br />

C<br />

CALL SYSFNC ( ... )<br />

C<br />

CALL ERRMES ( ... )<br />

C<br />

C Repeat for all required SYSFN<br />

C or SYSARY calls<br />

C<br />

...<br />

C<br />

IF( IFLAG ) THEN<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Evaluate force -----------------<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign the returned value<br />

C<br />

VALUE = ...<br />

C<br />

RETURN<br />

END


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_SFOSUB(const struct s<strong>Adams</strong>Sforce* sforce, double<br />

TIME, int DFLAG, int IFLAG, double* RESULT);<br />

/*<br />

* SFORCE<br />

*/<br />

struct s<strong>Adams</strong>Sforce<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int I;<br />

int J;<br />

int ACTION_ONLY;<br />

const char* Type;<br />

};<br />

Examples<br />

For an example of this subroutine, see sfosub.f.<br />

SPLINE_READ<br />

SPLINE_READ reads x, y, [and z] data from a file <strong>to</strong> a SPLINE statement. The SPLINE_READ<br />

subroutine is optional. You use it only if you do not want <strong>to</strong> use the X and Y arguments in the SPLINE<br />

statement (C++ or FORTRAN).<br />

Use<br />

Corresponding Statement<br />

SPLINE/id<br />

, X=x1, x2, x3, x4 [, . . . , xn]<br />

, Y=y1, y2, y3, y4 [, . . . , yn]<br />

[,LINEAR_EXTRAPOLATE]<br />

or<br />

SPLINE/id<br />

, X=x1, x2, x3, x4 [, . . . , xn]<br />

, Y=z1, y11, y12, y13, y14 [, . . . ,y1n]<br />

, Y=z2, y21, y22, y23, y24 [, . . . ,y2n]<br />

, Y=z3, y31, y32, y33, , LINEAR_EXTRAPOLATE y34 [, . . . ,y3n]<br />

, Y=z4, y41, y42, y43, y44 [, . . . ,y4n]<br />

[, . . . , Y=zm, ym1, ym2, ym3, ym4,[, . . . ,ymn]]<br />

[, LINEAR_EXTRAPOLATE]<br />

or<br />

205


206<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

SPLINE/id<br />

, FILE=filename<br />

[, BLOCK=blockname]<br />

[, LINEAR_EXTRAPOLATE]<br />

[ ] Optionally select the item.<br />

Calling Sequence<br />

SUBROUTINE SPLINE_READ (id, file_name, block_name, status)<br />

Input Arguments<br />

id An integer variable that indicates the identifier of the corresponding<br />

SPLINE statement.<br />

file_name A character array of dimension 132 that contains the FILE name that<br />

you specify using the FILE argument in the corresponding SPLINE<br />

statement.<br />

block_name A character array of dimension 132 that contains the BLOCK name (if<br />

any) that you specify using the BLOCK argument of the corresponding<br />

SPLINE statement.<br />

Output Argument<br />

status A logical variable that indicates if SPLINE_READ successfully reads<br />

and passes the x, y, [and z] data from the file <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong>. If the<br />

SPLINE data does not pass correctly, you can set the status <strong>to</strong> .TRUE.<br />

using PUT_SPLINE, which s<strong>to</strong>ps the appropriate operations in<br />

<strong>Adams</strong>/<strong>Solver</strong>. Otherwise, set the status <strong>to</strong> .FALSE.<br />

Extended Definition<br />

If you are a novice <strong>Adams</strong>/SOLVER user, you can use the X and Y arguments in the SPLINE statement<br />

<strong>to</strong> define the spline elements. If you are an expert user and a sizeable amount of data is required <strong>to</strong> define<br />

the spline elements, you might prefer <strong>to</strong> use the FILE argument in the SPLINE statement in conjunction<br />

with the SPLINE_READ user-written subroutine.<br />

<strong>Adams</strong>/<strong>Solver</strong> calls SPLINE_READ during the model-input phase. At this point, the model is not fully<br />

defined, and consequently, SPLINE_READ may not call most utility subroutines. SPLINE_READ must<br />

call the PUT_SPLINE utility subroutine in order <strong>to</strong> pass <strong>Adams</strong>/<strong>Solver</strong> the x, y, [and z] data that it reads<br />

from the file (see PUT_SPLINE).


FORTRAN - Pro<strong>to</strong>type<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

A sample structure for the SPLINE_READ subroutine follows next. The comments explain the activities<br />

that the subroutine performs.<br />

SUBROUTINE SPLINE_READ (ID, FILE_NAME, BLOCK_NAME, STATUS)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C Note: For machines with 60 or more bits per word,<br />

C substitute "REAL" for "DOUBLE PRECISION".<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGERID<br />

CHARACTER*132FILE_NAME<br />

CHARACTER*132BLOCK_NAME<br />

LOGICALSTATUS<br />

C<br />

C IDIdentifier of calling SPLINE statement<br />

C FILE_NAMEName of file containing data <strong>to</strong> define spline<br />

C BLOCK_NAMEName of named block within the file <strong>to</strong> be<br />

C used for this spline<br />

C STATUS Error status flag<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C open file, check validity, type... and read data in<strong>to</strong> local<br />

variables<br />

C<br />

...<br />

CALL PUT_SPLINE(ID,NX,NZ,X,Y,Z,ERRFLG)<br />

C<br />

C check ERRFLG, clean-up (release memory if necessary, close<br />

file...), and set STATUS<br />

C<br />

...<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_SPLINE_READ(const struct s<strong>Adams</strong>Spline* spline,<br />

int* IERR);<br />

/*<br />

* SPLINE -------------------------------------------------<br />

----------------<br />

*/<br />

struct s<strong>Adams</strong>Spline<br />

207


208<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

{<br />

};<br />

int ID;<br />

const char* FILENAME;<br />

const char* BLOCKNAME;<br />

Examples<br />

For an example of this subroutine, see spline_read.f.<br />

SURSUB<br />

SURSUB is an evaluation subroutine that computes surface coordinates and their derivatives for a<br />

SURFACE element (C++). The use of SURSUB is optional; it is not required when a Parasolid file is<br />

provided as input for the surface definition.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

For FORTRAN use:<br />

SUBROUTINE SURSUB (ID, PAR, NPAR, U, V, IORD, IFLAG, VALUES, IERR)For C++ use:<br />

SURSUB (int ID, double* PAR, int NPAR, double U, double V, int IORD, int IFLAG, double* VALUES,<br />

int* IERR)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that provides the identifier of the SURFACE statement<br />

that is being defined by SURSUB.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> TRUE for the initial call <strong>to</strong><br />

SURSUB. Computations that should be done only once during an analysis<br />

should be performed and s<strong>to</strong>red when IFLAG is true.<br />

iord An integer variable that specifies the order of the derivative that SURSUB<br />

returns. The possible values are:<br />

zero - Return surface coordinates.<br />

one - Return first derivatives with respect <strong>to</strong> u, v.<br />

two - Return second derivatices with respect <strong>to</strong> u, v.<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The purpose of npar is <strong>to</strong> provide SURSUB with<br />

the number of values s<strong>to</strong>red in the par array.<br />

par A double-precision array of constants that is taken in order from the USER<br />

parenthetical list of the SURFACE statement.<br />

u A double-precision variable that specifies the value of the independent<br />

parameter u, which SURSUB uses <strong>to</strong> evaluate coordinates of a point on the<br />

surface. <strong>Adams</strong>/<strong>Solver</strong> restricts u <strong>to</strong> be:<br />

Greater than or equal <strong>to</strong> the MINPAR[1] value on the SURFACE statement<br />

(-1.0 by default).<br />

Less than or equal <strong>to</strong> the MAXPAR[1] value on the SURFACE statement<br />

(1.0 by default).<br />

v A double-precision variable that specifies the value of the independent<br />

parameter v which SURSUB uses <strong>to</strong> evaluate coordinates of a point on the<br />

surface. <strong>Adams</strong>/<strong>Solver</strong> restricts v <strong>to</strong> be:<br />

Greater than or equal <strong>to</strong> the MINPAR[2] value on the SURFACE statement<br />

(-1.0 by default).<br />

Less than or equal <strong>to</strong> the MAXPAR[2] value on the SURFACE statement<br />

(1.0 by default).<br />

209


210<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Output Arguments


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

values A double-precision array that contains the output data. The data are<br />

dependent on IORD and IERR. This is elaborated below.<br />

Note: All data are <strong>to</strong> be returned, column ordered, in a single array.<br />

IORD=0,<br />

IERR=0<br />

IORD=0,<br />

IERR=1<br />

IORD=1,<br />

IERR=0 or<br />

IERR=1<br />

IORD=2,<br />

IERR=0 or<br />

IERR=1<br />

(3x1 array)<br />

(5x1 array)<br />

(3x2 array)<br />

(3x3 array)<br />

211


212<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

IERR An integer variable that specifies whether or not the [u,v] provided as<br />

input is on the surface.<br />

Extended Definition<br />

IERR=0 implies the point is on the SURFACE<br />

IERR=1 implies the point is not on the SURFACE<br />

IERR should be set only when IORD=0.<br />

IF IERR=0, then SURSUB should just return the x ,y ,z coordinates of the<br />

point on the SURFACE. The first three components of the output array<br />

VALUES should contain this data. The last two components of VALUES<br />

can remain undefined.<br />

IF IERR=1, then SURSUB is required <strong>to</strong> extrapolate the SURFACE<br />

definition and return the x, y, z coordinates of the point on the<br />

extrapolated SURFACE. The first three components of the output array<br />

VALUES should contain this data. In addition, SURSUB is also expected<br />

<strong>to</strong> return the u,v values of the point on the surface closest <strong>to</strong> the x, y, z<br />

coordinates that were calculated. These values, u* and v*, are returned in<br />

components 4,5 of the output array VALUES.<br />

SURSUB is a user-written subroutine that allows you <strong>to</strong> define a SURFACE. The x, y, and z coordinates<br />

of a point on a parametric surface are functions of independent parameters, (u,v). As (u,v) vary from their<br />

minimum <strong>to</strong> maximum values, the functions x(u,v), y(u,v), and z(u,v) sweep out points on the surface.<br />

A surface can be open or closed in both u and v. A surface closed in u (UCLOSED) meets along the edges<br />

defined by the maximum and minimum values of u. A surface closed in v (VCLOSED) meets along the<br />

edges defined by the maximum and minimum values of v.<br />

Surfaces can be used in <strong>Adams</strong> constraints. A surface marker allowed <strong>to</strong> only move on the surface is<br />

provided for this purpose. Any valid constraint (joint, jprim, and so on) can be constructed using the<br />

surface marker.<br />

A surface has parameterization limits as prescribed by MINPAR and MAXPAR. It is likely, however, that<br />

there are regions within the parameter space where the surface is not defined. The finiteness of the surface<br />

(including holes) are modeled using a penalty approach. The penalty approach applies a force <strong>to</strong> prevent<br />

the surface marker from moving off the edge of an open surface, or from moving in<strong>to</strong> a hole in the<br />

surface. This approach necessarily requires that the surface marker move off the surface for a short<br />

duration. In such a situation, the surface descrip<strong>to</strong>r is provided with [u,v] values outside the domain of<br />

the surface. The descrip<strong>to</strong>r is expected <strong>to</strong> extrapolate the surface definition <strong>to</strong> provide an estimated<br />

location of the surface marker at these [u,v] points. Linear extrapolation is adequate for most purposes.<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically extrapolates the surface as needed when the surface description is provided<br />

as a Parasolid geometry file. You are required <strong>to</strong> perform such extrapolation when you provide the<br />

surface definition through a SURSUB user-written subroutine.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

If [u,v] are the parameters corresponding <strong>to</strong> the current point on the surface, and [u*, v*] are the<br />

parameters for the closest material point on the surface <strong>to</strong> [u,v], the penalty force that is applied in the<br />

[u,v] domain is:<br />

F = -K * [(u-u)2 + (v-v*)2]<br />

K = 108<br />

At this time, you have no control over the stiffness parameter, K.<br />

Caution: Define the SURFACE only as a function of u, v. Do not make calls <strong>to</strong> the SYSARY and<br />

SYSFNC utility subroutines <strong>to</strong> access other system variables.<br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for SURSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE SURSUB ( ID, PAR, NPAR, U, V, IORD, IFLAG,<br />

& VALUES, IERR )<br />

C<br />

C Inputs:<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

DOUBLE PRECISION U,V<br />

INTEGER IORD<br />

LOGICAL IFLAG<br />

C<br />

C Outputs:<br />

C<br />

DOUBLE PRECISION VALUES( * )<br />

INTEGER IERR<br />

C<br />

C+---------------------------------------------------------------*<br />

C<br />

C ID<br />

Identifier of calling CURVE statement<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C U,V Curve parameter value<br />

C IORD Derivative order of value <strong>to</strong> be returned<br />

C IFLAG Initialization pass flag<br />

C VALUES Derivative values of CURVE returned <strong>to</strong> ADAMS<br />

C IERR Return flag; 0 =(U,V) on surface<br />

1 =(U,V) outside surface<br />

C<br />

C+---------------------------------------------------------------*<br />

C<br />

C Local Variables:<br />

C<br />

...<br />

C<br />

213


214<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C External Functions:(Note : This function must be written by you)<br />

C<br />

EXTERNAL UV_IS_OUTSIDE_SURFACE<br />

LOGICAL UV_IS_OUTSIDE_SURFACE<br />

C<br />

C+---------------------------------------------------------------*<br />

C<br />

IF ( IFLAG ) THEN<br />

C<br />

C<br />

Initialization call:<br />

C<br />

...<br />

<br />

<br />

...<br />

RETURN<br />

ENDIF<br />

C<br />

C<br />

Computation call:<br />

C<br />

IERR = 0<br />

IF ( IORD .EQ. 0 ) THEN<br />

C<br />

C<br />

Check whether [u,v] lie on the surface:<br />

C<br />

IF ( UV_IS_OUTSIDE_SURFACE(...) ) THEN<br />

...<br />

<br />


C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

C<br />

VALUES(2) = y...<br />

VALUES(3) = z...<br />

ENDIF<br />

ELSEIF ( IORD .EQ. 1 ) THEN<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Need matrix of 1st partial derivatives wrt. Parameters u,v:<br />

...<br />

<br />

...<br />

Return the 3x2 matrix of partials, sorted by column<br />

VALUES(1) = dx_du... VALUES(2) = dy_du...<br />

VALUES(3) = dz_du... VALUES(4) = dx_dv...<br />

VALUES(5) = dy_dv... VALUES(6) = dz_dv...<br />

ELSEIF ( IORD .EQ. 2 ) THEN<br />

Need matrix of 2nd partial derivatives wrt. Parameters u,v:<br />

...<br />

<br />

...<br />

Return the 3x3 matrix of partials, sorted by column<br />

VALUES(1) = d2x_dudu...<br />

VALUES(2) = d2y_dudu...<br />

VALUES(3) = d2z_dudu...<br />

VALUES(4) = d2x_dudv...<br />

VALUES(5) = d2y_dudv...<br />

VALUES(6) = d2z_dudv...<br />

VALUES(7) = d2x_dvdv...<br />

VALUES(8) = d2y_dvdv...<br />

VALUES(9) = d2z_dvdv...<br />

ELSECC<br />

Error - Should not be here:<br />

CALL ERMESS (...)<br />

ENDIF<br />

RETURN<br />

END<br />

C Style Pro<strong>to</strong>type<br />

typedef void adams_c_SURSUB(const struct s<strong>Adams</strong>Surface* srf, double<br />

ALPHA, double BETA, int IORD, int IFLAG, double* VALUES, int* IERR );<br />

/*<br />

* SURFACE<br />

215


216<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

*/<br />

struct s<strong>Adams</strong>Surface<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

/* const char* FILENAME; */<br />

int ORDER[2];<br />

int CLOSED[2];<br />

double MINPAR[2];<br />

double MAXPAR[2];<br />

};<br />

Examples<br />

The figure below illustrates a circular surface S with a hole H at its very center. The surface S belongs <strong>to</strong><br />

a body A. A point P, belonging <strong>to</strong> a different body B, is required <strong>to</strong> move on the surface S. The bounds<br />

of the parameterization are the outer perimeter of the circular suface A circular surface with a hole in its<br />

center.<br />

A circular surface with a hole in its center.<br />

For an example of this subroutine, see sursub.c.<br />

UCOSUB<br />

The UCOSUB evaluation subroutine computes a constraint value and its derivatives for a UCON<br />

statement. You must write a UCOSUB whenever one or more UCON statements are used in a dataset.<br />

Use<br />

Corresponding Statement<br />

UCON/id, FUNCTION=USER(r1[,...,r30])<br />

[ ] Optionally select the item.<br />

Calling Sequence<br />

SUBROUTINE UCOSUB (id, time, q, par, npar, idrsel,& iflag, scalar, array, xmatrx)


Input Arguments<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

id An integer variable that contains the ID of the UCON statement requesting<br />

information from UCOSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically knows other information (such as the par argument) available<br />

in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

q A double-precision array (of as many as thirty elements) that contains the<br />

current values of the part principal axes variables. These values are in the<br />

order specified by the call <strong>to</strong> UCOVAR.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the UCON statement; r1[,...,r30].<br />

npar An integer variable that indicates the number of constants specified in the<br />

USER parenthetical list. The primary purpose of npar is <strong>to</strong> provide<br />

UCOSUB with the number of values s<strong>to</strong>red in the par array.<br />

idrsel A three-element integer array containing control values for returning the<br />

proper information through scalar, array, and xmatrx.<br />

iflag A logical variable used as a switch <strong>to</strong> call UCOVAR for initial definition of<br />

the principal axes variables. If the iflag argument is true, UCOVAR should<br />

be called (see UCOVAR).<br />

217


218<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Output Arguments


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

array A thirty-element double-precision array that returns <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> the<br />

first derivatives of the constraint relationship with respect <strong>to</strong> the principal<br />

axes variables or through which the second partials of the constraint<br />

relationship are returned with respect <strong>to</strong> time and the principal axes<br />

variables. The set of derivatives UCOSUB returns depends on the value<br />

of idrsel(2). In this table, q represents the variables, t stands for time, and<br />

F refers <strong>to</strong> the constraint equation.<br />

If idresel (2) is:<br />

array is:<br />

0<br />

No evaluation<br />

1<br />

array (m) =<br />

2<br />

array (m) =<br />

If any of the elements of array are symbolically zero, they don't need <strong>to</strong><br />

be defined.<br />

219


220<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

scalar A double-precision variable for returning the residue (the error relative <strong>to</strong><br />

zero) of the implicit constraint expression, the nonprincipal axes variabledependent<br />

portion of the constraint expression (the value of the constraint<br />

expression if all principal axes variables are zero), or the various time<br />

derivatives of the constraint expression.<br />

The value UCOSUB returns <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> depends on the value of<br />

idrsel(1). In the following table, q represents the variables, t stands for<br />

time, F refers <strong>to</strong> the constraint equation, and f refers <strong>to</strong> the equation when<br />

all variables (q) are set equal <strong>to</strong> zero.<br />

If idresel (1) is:<br />

scalar is:<br />

0<br />

No evaluation<br />

1<br />

scalar =<br />

2<br />

scalar =<br />

3<br />

scalar =<br />

4<br />

scalar =


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

xmatrx A double-precision thirty-by-thirty array that returns <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> the<br />

second derivatives of the constraint expression with respect <strong>to</strong> the<br />

principal axes variables. The second derivatives UCOSUB returns the<br />

value of idrsel(3):<br />

Extended Definition<br />

If idresel (3) is:<br />

xmatrx is:<br />

0<br />

No evaluation<br />

1<br />

xmatrx(m,n) =<br />

The letter q represents the variables, t stands for time, and F refers <strong>to</strong> the<br />

constraint equation. If any of the elements of xmatrx are symbolically<br />

zero, they need not be defined.<br />

The standard constraint statements are usually adequate for defining commonly occurring displacement<br />

constraints between marker pairs. For displacement constraint combinations not available through these<br />

statements or for constraints involving velocity variables, you should use the FUNCTION=USER()<br />

argument in the UCON statement, and write a UCOSUB <strong>to</strong> define the constraint. The constraints defined<br />

in the subroutine can incorporate velocity variables. You can select as many as thirty displacements<br />

and/or velocities of part principal axes <strong>to</strong> be the variables in the constraint relationship for a UCON<br />

statement. Each UCON statement removes one degree of freedom from the system.<br />

At every evaluation step, <strong>Adams</strong>/<strong>Solver</strong> evaluates UCOSUB <strong>to</strong> determine the value of the constraints.<br />

During the initialization of UCOSUB, the utility subroutine UCOVAR should be called <strong>to</strong> declare the<br />

variables used in the relationship. PART statement identifiers and type codes identify the variables. To<br />

preserve the generality of UCOSUB, the identifiers and the type codes can be passed through the<br />

parameter list of the UCON statement.<br />

For the formulation of constraints, you cannot access information with SYSARY or SYSFNC. You can,<br />

however, access information with AKISPL or CUBSPL (see AKISPL, CUBSPL, and UCOVAR). You<br />

must set up UCOSUB system dependencies using UCOVAR, and use system information from the q<br />

parameter only.<br />

For each system constraint, <strong>Adams</strong>/<strong>Solver</strong> formulates a governing constraint equation. For standard<br />

<strong>Adams</strong>/<strong>Solver</strong> constraint statements, symbolic partial derivatives of the constraint equation with respect<br />

221


222<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

<strong>to</strong> the system variables have been pre-computed and s<strong>to</strong>red in the program for use in the system Jacobian<br />

when the particular constraint is involved.<br />

When you write a UCOSUB, equations of motion are added <strong>to</strong> the set of equations <strong>Adams</strong>/<strong>Solver</strong><br />

generates for the standard constraint statements. You must provide the first and second derivatives of the<br />

constraint relationship with respect <strong>to</strong> the set of variables. You must code the constraint relationship in<br />

the implicit form. For information on implicit forms, see DIFF statement (C++ or FORTRAN).<br />

Caution: • When selecting the displacements or the velocities of the part principal axes for the<br />

constraint, remember that the part principal axes are not always identical <strong>to</strong> those<br />

of the part center-of-mass marker (CM). The following list summarizes the<br />

circumstances in which the part principal axes may differ from those of the part<br />

center-of-mass marker.<br />

Structure<br />

• When the PART statement does not include the CM argument, the principal<br />

axes default <strong>to</strong> the body coordinate system.<br />

• Whenever the center-of-mass marker z-axis is parallel <strong>to</strong> the z-axis of the<br />

ground reference frame at time zero, <strong>Adams</strong>/<strong>Solver</strong> permutes the internal<br />

representation of the principal axes by 90-degree rotations <strong>to</strong> avoid an Euler<br />

matrix singularity.<br />

• If the IP argument in the PART statement includes products of inertia,<br />

<strong>Adams</strong>/<strong>Solver</strong> computes the inertial representation of the principal axes so that<br />

the products of inertia become zero.<br />

• When specifying an IM marker, <strong>Adams</strong>/<strong>Solver</strong> computes the principal axes,<br />

which may or may not be the axes of the CM marker.<br />

• When the iflag argument is true, <strong>Adams</strong> sets q <strong>to</strong> zero. When you execute<br />

<strong>Adams</strong>/<strong>Solver</strong>, computations that divide by these values result in fatal errors.<br />

Before dividing by q values, you should check for nonzero values or ensure the<br />

iflag argument is false.<br />

A sample structure for UCOSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE UCOSUB (ID, TIME, Q, PAR, NPAR,<br />

& IDRSEL, IFLAG, SCALAR, ARRAY,<br />

& XMATRX)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION Q( 30 )<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

INTEGER IDRSEL( 3 )<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION SCALAR<br />

DOUBLE PRECISION ARRAY( 30 )<br />

DOUBLE PRECISION XMATRX( 30, 30 )<br />

C<br />

C ID Identifier of calling UCON statement<br />

C TIME Current time<br />

C Q Array of part state variables<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C IDRSEL UCON values selection control flag<br />

C IFLAG Initialization pass flag<br />

C SCALAR Scalar value returned <strong>to</strong> ADAMS<br />

C ARRAY Partial derivatives<br />

C XMATRX Second partial derivatives<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C - Assign parameters <strong>to</strong> readable variable names --<br />

C<br />

...<br />

C<br />

C - Subroutine initialization -----------<br />

C<br />

IF( IFLAG ) THEN<br />

C<br />

C Declare principal axis variables<br />

C<br />

CALL UCOVAR ( ... )<br />

C<br />

ENDIF<br />

C<br />

C - Find implicit constraint relation -------<br />

C<br />

IF ( IDRSEL(1) .EQ. 1 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign scalar<br />

C<br />

SCALAR = ...<br />

C<br />

C - First time derivative of constraint relation --<br />

C<br />

ELSE IF ( IDRSEL(1) .EQ. 2 ) THEN<br />

C<br />

C Your algorithm<br />

223


224<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

...<br />

C<br />

C Assign first time derivative <strong>to</strong> scalar<br />

C<br />

SCALAR = ...<br />

C<br />

C - Second time derivative of constraint ------<br />

C<br />

relation<br />

C<br />

ELSE IF ( IDRSEL(1) .EQ. 3 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign second time derivative <strong>to</strong> scalar<br />

C<br />

SCALAR = ...<br />

C<br />

C - Nonprincipal-axes-dependent portion of ----<br />

C<br />

constraint relation<br />

C<br />

ELSE IF ( IDRSEL(1) .EQ. 4 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign nonprincipal-axes-dependent portion <strong>to</strong> scalar<br />

C<br />

SCALAR = ...<br />

C<br />

ENDIF<br />

C<br />

C - Evaluate array -----------------<br />

C<br />

C - First derivative of constraint relationship with<br />

C respect <strong>to</strong> the variables<br />

C<br />

IF ( IDRSEL(2) .EQ. 1 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign array values<br />

C<br />

ARRAY(1) = ...<br />

...<br />

ARRAY(30) = ...<br />

C


C - Derivatives of prior first derivatives with --<br />

C respect <strong>to</strong> time<br />

C<br />

ELSE IF ( IDRSEL(2) .EQ. 2 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign array values<br />

C<br />

ARRAY(1) = ...<br />

...<br />

ARRAY(30) = ...<br />

C<br />

ENDIF<br />

C<br />

C - Derivatives of prior first derivatives with --<br />

C respect <strong>to</strong> the variables<br />

C IF ( IDRSEL(3) .EQ. 1 ) THEN<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign matrix values<br />

C<br />

XMATRX(1, 1) = ...<br />

...<br />

XMATRX(30, 30) = ...<br />

C<br />

ENDIF<br />

C<br />

RETURN<br />

END<br />

Examples<br />

For an example of this subroutine, see ucosub.f.<br />

VARSUB<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The VARSUB evaluation subroutine computes an algebraic value for a VARIABLE statement (C++ or<br />

FORTRAN). VARSUB is optional. You only need it if you don't want <strong>to</strong> use a function expression in the<br />

VARIABLE statement.<br />

225


226<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

CALL VARSUB(id, time, par, npar, dflag, iflag, value)<br />

Input Arguments<br />

id An integer variable that contains the ID of the VARIABLE statement<br />

requesting information from VARSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes other information (such as the<br />

par argument) that is available in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the VARIABLE statement.<br />

npar An integer variable that indicates the number of constants you specify in<br />

the USER parenthetical list. The primary purpose of the npar argument is<br />

<strong>to</strong> provide VARSUB with the number of values s<strong>to</strong>red in the par array.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls VARSUB<br />

<strong>to</strong> evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong> false.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the<br />

functional dependency of the user-defined VARIABLE statement.<br />

<strong>Adams</strong>/<strong>Solver</strong> usually does this during the first pass through each<br />

VARIABLE statement that is calling the subroutine. You set functional<br />

dependencies with the same calls <strong>to</strong> SYSARY and SYSFNC that you use<br />

<strong>to</strong> compute the value of the user-defined VARIABLE statement (see<br />

SYSARY and SYSFNC). If the iflag argument is false, you should<br />

compute the value of the user-written VARIABLE statement.<br />

Output Arguments<br />

value A double-precision variable that returns the value of the variable.<br />

Extended Definition<br />

You can use the VARIABLE statement with the function expression <strong>to</strong> define most user-defined<br />

VARIABLE statements. However, if the expression becomes lengthy and awkward, you should use the<br />

FUNCTION=USER() argument in the VARIABLE statement, and write a VARSUB <strong>to</strong> define the<br />

VARIABLE statement.


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY, and SYSFNC, from VARSUB,<br />

<strong>to</strong> obtain information about system variables, user-defined variables, and splines (see AKISPL,<br />

CUBSPL, SYSARY, and SYSFNC).<br />

The SYSARY and SYSFNC utility subroutines au<strong>to</strong>matically set functional dependencies when the<br />

VARSUB argument iflag is true. To compute solutions efficiently, <strong>Adams</strong>/<strong>Solver</strong> must know the other<br />

variables on which each user-defined variable depends. <strong>Adams</strong>/<strong>Solver</strong> determines these functional<br />

dependencies at the beginning of the simulation by calling VARSUB with the argument iflag set <strong>to</strong> true.<br />

<strong>Adams</strong>/<strong>Solver</strong> does this once for each VARIABLE statement with a FUNCTION=USER() argument.<br />

During each call <strong>to</strong> VARSUB, <strong>Adams</strong>/<strong>Solver</strong> records which calls you make <strong>to</strong> SYSARY and SYSFNC.<br />

<strong>Adams</strong>/<strong>Solver</strong> assumes the user-defined variable depends on those system and user-defined variables,<br />

and no others.<br />

Tip: If the SYSARY or SYSFNC utility subroutines are called <strong>to</strong> access angular displacements,<br />

the values returned by them may contain discontinuities. To avoid the discontinuities, use<br />

the RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other rotational representation that does not encounter a singularity.<br />

Caution: • When the iflag argument is true, you should make the same calls <strong>to</strong> SYSARY and<br />

SYSFNC as you do <strong>to</strong> compute the value of the user-defined VARIABLE<br />

statement. This ensures that <strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies.<br />

In general, <strong>Adams</strong>/<strong>Solver</strong> may have difficulty converging <strong>to</strong> a solution and/or may<br />

take small integration steps if you fail <strong>to</strong> account for dependencies of the userdefined<br />

VARIABLE statement. These results usually cause large increases in<br />

execution time.<br />

• When the iflag argument is true, SYSARY and SYSFNC return zero values for<br />

system and user-defined variables. Computations that divide these values result in<br />

system errors when you execute <strong>Adams</strong>/<strong>Solver</strong>. You should check for nonzero<br />

values or ensure that the iflag argument is set <strong>to</strong> false before dividing by these<br />

values.<br />

• You must be careful when defining a VARIABLE statement dependent on another<br />

VARIABLE statement, or on other <strong>Adams</strong>/<strong>Solver</strong> statements that contain<br />

functions. If you define a system of equations without a stable solution, the<br />

convergence may fail for the entire <strong>Adams</strong>/<strong>Solver</strong> model. The following example<br />

refers <strong>to</strong> this type of VARIABLE statement:<br />

VARIABLE/1,FUNCTION=VARVAL(1)+1<br />

When looked at as an algebraic equation, it looks like the following:<br />

V=V+1<br />

However, when <strong>Adams</strong>/<strong>Solver</strong> tries <strong>to</strong> solve this equation using the New<strong>to</strong>n-Raphson<br />

iteration, the solution diverges and a message indicates that the correc<strong>to</strong>r has failed <strong>to</strong><br />

converge.<br />

227


228<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

FORTRAN - Pro<strong>to</strong>type<br />

A sample structure for VARSUB is shown next. The comments explain how the subroutine works.<br />

SUBROUTINE VARSUB ( ID, TIME, PAR, NPAR, DFLAG,<br />

& IFLAG, VALUE )<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C<br />

C - External variable definitions ---------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR( * )<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION VALUE<br />

C<br />

C ID Identifier of calling VARIABLE statement<br />

C TIME Current time<br />

C PAR Array of passed statement parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C IFLAG Initialization pass flag<br />

C VALUE The VARIABLE value returned <strong>to</strong> ADAMS<br />

C<br />

C - Local variable definitions -----------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign parameters <strong>to</strong> readable variable names<br />

C<br />

...<br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C calculations below. Note: if IFLAG is true, these<br />

C calls are actually setting functional dependencies.<br />

C<br />

CALL SYSFNC ( ... )<br />

C<br />

CALL ERRMES ( ... )<br />

C<br />

C Repeat for all required SYSFN<br />

C or SYSARY calls<br />

C<br />

...<br />

C<br />

IF( IFLAG ) THEN


C<br />

C - Subroutine initialization -----------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Evaluate variable----------------<br />

C<br />

C Your algorithm<br />

C<br />

...<br />

C<br />

C Assign the returned value<br />

C<br />

VALUE = ...<br />

C<br />

RETURN<br />

END<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_VARSUB(const struct s<strong>Adams</strong>Variable* variable,<br />

double TIME, int DFLAG, int IFLAG, double* RESULT);<br />

/*<br />

* VARIABLE<br />

*/<br />

struct s<strong>Adams</strong>Variable<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

double IC;<br />

};<br />

Examples<br />

For an example of this subroutine, see varsub.f.<br />

VFOSUB<br />

The VFOSUB evaluation subroutine computes force components for a VFORCE (C++ or FORTRAN).<br />

VFOSUB is optional. You only need it if you don't want <strong>to</strong> use function expressions in the VFORCE<br />

statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE VFOSUB (id, time, par, npar,dflag, iflag, result)<br />

229


230<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

Input Arguments<br />

id An integer variable that contains the ID of the VFORCE statement<br />

requesting information from VFOSUB. From the identifier,<br />

<strong>Adams</strong>/<strong>Solver</strong> au<strong>to</strong>matically recognizes other information (such as the<br />

par argument) that is available in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the VFORCE statement.<br />

npar An integer variable that indicates the number of constants you specify in<br />

the USER parenthetical list. The primary purpose of the npar argument<br />

is <strong>to</strong> provide <strong>to</strong> VFOSUB the number of values s<strong>to</strong>red in the par array.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls VFOSUB<br />

<strong>to</strong> evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong> false. See Using the DFLAG<br />

Variable.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs<br />

functional dependency information from VFOSUB. Functional<br />

dependencies are established with the same calls <strong>to</strong> SYSARY and<br />

SYSFNC that are later used <strong>to</strong> compute the values of the VFORCE<br />

components (see SYSARY and SYSFNC). If the iflag argument is false,<br />

the values of the user-defined expressions are computed.<br />

Output Arguments<br />

result A double-precision array that returns the three values of the VFORCE<br />

components, in x-y-z order.<br />

Extended Definition<br />

You can usually use the VFORCE statement with function expressions <strong>to</strong> define the three components of<br />

a translational vec<strong>to</strong>r force at a point. However, if the force expressions become lengthy and awkward or<br />

require external computations, it may be necessary <strong>to</strong> use a VFOSUB. If the algorithms use or consist of<br />

already-existing FORTRAN-77 subroutines, VFOSUB can be made <strong>to</strong> call them.<br />

You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY, and SYSFNC, from VFOSUB <strong>to</strong><br />

obtain information about system variables, user-defined variables, and splines. (See AKISPL, CUBSPL,<br />

SYSARY, and SYSFNC).<br />

The SYSARY and SYSFNC utility subroutines au<strong>to</strong>matically set functional dependencies when the<br />

VFOSUB argument iflag is true. For <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> compute solutions efficiently, it must know<br />

on which other variables each user-defined variable depends directly. <strong>Adams</strong>/<strong>Solver</strong> determines these<br />

functional dependencies at the beginning of the simulation by calling VFOSUB with the argument iflag


<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

set <strong>to</strong> true. During each call <strong>to</strong> VFOSUB, <strong>Adams</strong>/<strong>Solver</strong> records which calls you make <strong>to</strong> SYSARY and<br />

SYSFNC and assumes that the resulting values are dependent only on those <strong>Adams</strong>/<strong>Solver</strong> variables<br />

accessed through the SYSARY and SYSFNC calls.<br />

Tip: If the SYSARY or SYSFNC utility subroutines are called <strong>to</strong> access angular displacements,<br />

the values returned by them may contain discontinuities. To avoid the discontinuities, use<br />

the RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other rotational representation that does not encounter a singularity.<br />

Caution: • When the iflag argument is true, you must make all the calls <strong>to</strong> SYSARY and<br />

SYSFNC as are made <strong>to</strong> compute the component values of the VFORCE. This<br />

ensures that <strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies. In general,<br />

failure <strong>to</strong> account for dependencies in the VFORCE components can make it<br />

difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a solution and/or can force<br />

<strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> take small integration steps. Both of these effects usually cause<br />

large increases in execution time.<br />

FORTRAN - Pro<strong>to</strong>type<br />

• When the iflag argument is true, SYSARY and SYSFNC return zero values.<br />

Computations that divide by these values result in fatal errors when you execute<br />

<strong>Adams</strong>/<strong>Solver</strong>. You should check for nonzero values or ensure that the iflag<br />

argument is set <strong>to</strong> false before dividing by these values.<br />

A sample structure for VFOSUB is shown next. The comments explain how the subroutine works.<br />

&<br />

SUBROUTINE VFOSUB(ID, TIME, PAR, NPAR, DFLAG,<br />

IFLAG, RESULT)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C - External variable definitions -----------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT(3)<br />

C<br />

C ID Identifier of calling VFORCE statement<br />

C TIME Current time<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C<br />

C<br />

IFLAG<br />

RESULT<br />

Initial pass flag<br />

Array (dimension 3) of computed VFORCE<br />

C components returned <strong>to</strong> ADAMS<br />

231


232<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

C - Local variable and parameter definitions ------<br />

C ...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign readable variable names <strong>to</strong> passed parameters<br />

C<br />

...<br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C the calculations below. Note: if IFLAG is true, these<br />

C calls are actually setting functional dependencies.<br />

C<br />

CALL SYSFNC (...)<br />

C<br />

C Check SYSFNC call through ERRMES utility routine<br />

C<br />

CALL ERRMES (...)<br />

C<br />

C Repeat for all required SYSFNC or SYSARY calls<br />

C<br />

...<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C - Subroutine initialization -------------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Evaluate VFORCE components ------------<br />

C<br />

C Your algorithms<br />

C<br />

...<br />

C<br />

C Assign values <strong>to</strong> the RESULT array<br />

C<br />

RESULT(1) = ...<br />

RESULT(2) = ...<br />

RESULT(3) = ...<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_VFOSUB(const struct s<strong>Adams</strong>Vforce* vfo, double<br />

TIME, int DFLAG, int IFLAG, double* RESULT);<br />

/*<br />

* VFORCE -------------------------------------------------<br />

----------------


*/<br />

struct s<strong>Adams</strong>Vforce<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int I;<br />

int JFLOAT;<br />

int RM;<br />

};<br />

Examples<br />

For an example of this subroutine, see vfosub.f.<br />

VTOSUB<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

The VTOSUB evaluation subroutine computes <strong>to</strong>rque components for a VTORQUE statement (C++ or<br />

FORTRAN). VTOSUB is optional. You only need it if you don't want <strong>to</strong> use function expressions in the<br />

VTORQUE statement.<br />

Use<br />

Corresponding Statement<br />

Calling Sequence<br />

SUBROUTINE VTOSUB(id, time, par, npar, dflag, iflag, result)<br />

Input Arguments<br />

id An integer variable that contains the ID of the VTORQUE statement<br />

requesting information from VTOSUB. From the identifier, <strong>Adams</strong>/<strong>Solver</strong><br />

au<strong>to</strong>matically recognizes other information (such as the par argument) that is<br />

available in the corresponding statement.<br />

time A double-precision variable through which <strong>Adams</strong>/<strong>Solver</strong> conveys the<br />

current simulation time.<br />

par A double-precision array of constants taken in order from the USER<br />

parenthetical list of the VTORQUE statement.<br />

233


234<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

npar An integer variable that indicates the number of constants you specify in the<br />

USER parenthetical list. The primary purpose of the npar argument is <strong>to</strong><br />

provide VTOSUB with the number of values s<strong>to</strong>red in the par array.<br />

dflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it calls VTOSUB <strong>to</strong><br />

evaluate the partial derivatives of the specified functions. Otherwise,<br />

<strong>Adams</strong>/<strong>Solver</strong> sets the dflag argument <strong>to</strong> false.<br />

iflag A logical variable that <strong>Adams</strong>/<strong>Solver</strong> sets <strong>to</strong> true when it needs the functional<br />

dependency of the user-defined expressions. You set functional<br />

dependencies with the same calls <strong>to</strong> the SYSARY and SYSFNC utility<br />

subroutines that are made <strong>to</strong> compute the values of the user-defined<br />

expressions (see SYSARY and SYSFNC). If the iflag argument is false, the<br />

values of the user-defined expressions are computed.<br />

Output Arguments<br />

result A double-precision array of length 3 that returns the x-, y-, and z-components<br />

of the VTORQUE.<br />

Extended Definition<br />

You can often use the VTORQUE statement with function expressions sufficient <strong>to</strong> define the three<br />

rotational vec<strong>to</strong>r components of a <strong>to</strong>rque at a point. However, if the <strong>to</strong>rque expressions become lengthy<br />

and awkward, you can use a VTOSUB evaluation subroutine. If the algorithms use or consist of already<br />

existing FORTRAN-77 subroutines, VTOSUB can be made <strong>to</strong> call them.<br />

You can call utility subroutines, such as AKISPL, CUBSPL, SYSARY and SYSFNC, from VTOSUB <strong>to</strong><br />

obtain information about system variables, user-defined variables, and splines. See AKISPL, CUBSPL,<br />

SYSARY, and SYSFNC.<br />

The SYSARY and SYSFNC utility subroutines au<strong>to</strong>matically set functional dependencies when the<br />

VTOSUB argument iflag is true. In order for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> compute solutions efficiently, it must<br />

know on which other variables each user-defined variable depends directly. <strong>Adams</strong>/<strong>Solver</strong> determines<br />

these functional dependencies at the beginning of the simulation by calling VTOSUB with the argument<br />

iflag set <strong>to</strong> true. <strong>Adams</strong>/<strong>Solver</strong> does this once for each VTORQUE statement with a<br />

FUNCTION=USER() argument.<br />

During each call <strong>to</strong> the VTOSUB evaluation subroutine, <strong>Adams</strong>/<strong>Solver</strong> records which calls you make <strong>to</strong><br />

SYSARY and SYSFNC and assumes that the resulting values are dependent on only those <strong>Adams</strong>/<strong>Solver</strong><br />

variables accessed through the SYSARY and SYSFNC calls.<br />

Tip: If the SYSARY or SYSFNC utility subroutines are called <strong>to</strong> access angular displacements,<br />

the values returned by these may contain discontinuities. To avoid the discontinuities, use<br />

the RCNVRT utility subroutine <strong>to</strong> convert the rotational angles from Euler angles <strong>to</strong> some<br />

other coordinate system that does not encounter a singularity.


FORTRAN - Pro<strong>to</strong>type<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

Caution: • When the iflag argument is true, you must make all the same calls <strong>to</strong> SYSARY and<br />

SYSFNC as are made <strong>to</strong> compute the component values of VTORQUE. This<br />

ensures that <strong>Adams</strong>/<strong>Solver</strong> has the proper functional dependencies. In general,<br />

failure <strong>to</strong> account for dependencies in the VTORQUE components may make it<br />

difficult for <strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> converge <strong>to</strong> a solution and/or may force<br />

<strong>Adams</strong>/<strong>Solver</strong> <strong>to</strong> take small integration steps, potentially causing large increases in<br />

execution time.<br />

• When the iflag argument is true, SYSARY and SYSFNC return zero values for<br />

system and user-defined variables. When you execute <strong>Adams</strong>/<strong>Solver</strong>,<br />

computations that divide by these values result in fatal errors. You should check<br />

for nonzero values or ensure the iflag argument is set <strong>to</strong> false before dividing by<br />

these values.<br />

A sample structure for VTOSUB is shown next. The comments explain how the subroutine works.<br />

&<br />

SUBROUTINE VTOSUB(ID, TIME, PAR, NPAR, DFLAG,<br />

IFLAG, RESULT)<br />

C<br />

C === Type and dimension statements ===================<br />

C<br />

C - External variable definitions -----------<br />

C<br />

INTEGER ID<br />

DOUBLE PRECISION TIME<br />

DOUBLE PRECISION PAR(*)<br />

INTEGER NPAR<br />

LOGICAL DFLAG<br />

LOGICAL IFLAG<br />

DOUBLE PRECISION RESULT(3)<br />

C<br />

C ID Identifier of calling VTORQUE statement<br />

C TIME Current time<br />

C PAR Array containing passed parameters<br />

C NPAR Number of passed parameters<br />

C DFLAG Differencing flag<br />

C IFLAG Initial pass flag<br />

C RESULT Array (dimension 3) of computed VTORQUE<br />

C<br />

C<br />

components returned <strong>to</strong> ADAMS<br />

C - Local variable and parameter definitions ------<br />

C<br />

...<br />

C<br />

C === Executable code =================================<br />

C<br />

C Assign readable variable names <strong>to</strong> passed parameters<br />

C<br />

...<br />

235


236<br />

<strong>Adams</strong>/<strong>Solver</strong><br />

C<br />

C Call SYSFNC and/or SYSARY <strong>to</strong> collect information for<br />

C the following calculations. Note: if IFLAG is true, these<br />

C calls are actually setting functional dependencies.<br />

C<br />

CALL SYSFNC (...)<br />

C<br />

C Check SYSFNC call through ERRMES utility routine<br />

C<br />

CALL ERRMES (...)<br />

C<br />

C Repeat for all required SYSFNC or SYSARY calls<br />

C<br />

...<br />

C<br />

IF (IFLAG) THEN<br />

C<br />

C - Subroutine initialization -------------<br />

C<br />

...<br />

C<br />

ENDIF<br />

C<br />

C - Evaluate VTORQUE components ------------<br />

C<br />

C Your algorithms<br />

C<br />

...<br />

C<br />

C Assign values <strong>to</strong> the RESULT array<br />

C<br />

RESULT(1) = ...<br />

RESULT(2) = ...<br />

RESULT(3) = ...<br />

C<br />

RETURN<br />

END<br />

C Style - Pro<strong>to</strong>type<br />

typedef void adams_c_VTOSUB(const struct s<strong>Adams</strong>V<strong>to</strong>rque* v<strong>to</strong>, double<br />

TIME, int DFLAG, int IFLAG, double* RESULT);<br />

/*<br />

* VTORQUE -------------------------------------------------<br />

----------------<br />

*/<br />

struct s<strong>Adams</strong>V<strong>to</strong>rque<br />

{<br />

int ID;<br />

int NPAR;<br />

const double* PAR;<br />

int I;<br />

int JFLOAT;<br />

int RM;<br />

};


Examples<br />

For an example of this subroutine, see v<strong>to</strong>sub.f.<br />

(1)<br />

(2) 0<br />

0 1 2<br />

F( x, x′ )<br />

0 Value of the function<br />

1 Partial derivative of the function with respect <strong>to</strong> x.<br />

<strong>Welcome</strong> <strong>to</strong> <strong>Adams</strong>/<strong>Solver</strong> <strong>Subroutines</strong><br />

∂<br />

F( x, x′ )<br />

∂ x<br />

∂<br />

F( x, x′ )<br />

∂ x<br />

2 Second partial derivative of the function with respect <strong>to</strong> x.<br />

2<br />

x2 ∂<br />

F( x, x′ )<br />

∂<br />

2<br />

∂<br />

F( x, x′ )<br />

∂ x′ ∂ x<br />

237


238<br />

<strong>Adams</strong>/<strong>Solver</strong>

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!