To develop an integration model or an substructure model in Matlab for communication, the developer needs to provide the explicit linkage to the DataExchange DLL in the code. This document assumes that the develoepr is familiar with Matlab.
Link with DataExchange library (Matlab)¶
To explicitly link with the DLL in Matlab, the DataExchange.dll and corresponding header file (DataExchange.h) should be loaded to Matlab using the following command.
% load DataExchange library
loadlibrary('./DataExchange.dll', './DataExchange.h');
Then use the following calllib function to call the DLL functions in the matlab script.
Syntax: [x1,...,xN] = calllib(libname,function,arg1,...,argN)
where
- x1,...,xN: return variables of the DLL function
- libname: the name of the dll file
- function: the name of the DLL function
- arg1,...,argN: input variables of the DLL function
For example, the way to use the setupconnection()
function to establish the connection is shown below
iResult = calllib('DataExchange', 'setupconnection', PortNumber, sockfdPtr, flag, machineInetAddr, TCP_IP);
Integration Model (Matlab)¶
In addition to the above code to link with the DataExchange.dll, the integration model starts with declaring variables required for communication.
PortNumber = 8090; % port number
machineInetAddr = libpointer('cstring','127.0.0.1'); % IP address
sockfd = 0; % initialize socket number
flag = 1; % 1 - integration module; 2 - substructure module
numdofs = 3; % total interface DOFs
where
- PortNumber: port number. This number should be consistent with the port number specified in the substructure model below.
- machineInetAddr - IP address of machine with the substructure model. For the case that the integration and substructure models are modelled in the same Windows machine, the standard IP address of "127.0.0.1" can be used.
- sockfd: a SOCKET type variable for a newly generated socket
- flag: a variable to be used in the DataExchange.dll functions to indicate the model is a integration model or a substructure model.
- numdofs: a variable defines the total number of degrees of freedom at the interface nodes.
Communication Initialization¶
Then, three DLL functions are called to initialize the data exchange format, set up the connection with the substructure model, and send the initialized data exchange format to the substructure model.
% initialize data exchange format
calllib('DataExchange', 'updatemessageheader', 2, 0, Software_only, 1, Double_precision, numdofs);
% setup connection
sockfdPtr = libpointer('uint64Ptr', sockfd); % pointer to sockfd
iResult = calllib('DataExchange', 'setupconnection', PortNumber, sockfdPtr, flag, machineInetAddr, TCP_IP);
if iResult ~= 0
disp('Connection failed.');
else
disp('Connection done');
end
% send the data exchange format to the substructure model
sockfd1 = get(sockfdPtr, 'value');
iResult = calllib('DataExchange', 'initialization', sockfd1, flag, TCP_IP);
if iResult ~= 0
disp('Initialization failed.');
else
disp('Initialization done');
end
where UpdateMessageHeader(version, command, testtype, subtype, precision, numdofs) function is used to initialize the following information defined in the header block of the data exchanged through UTNP (see here for more details).
- version: this parameter corresponds to the Version parameter in the data exchange format. It is 2 for the current release version.
- command: this parameter corresponds to the Command parameter in the data exchange format. It can be defined as zero at this initialization stage.
- testtype: this parameter corresponds to thie Test type parameter in the data exchange format. Depending on the simulation methods, one of the following values can be used to initialize the parameter.
- 1 - Pseudo-dynamic (ramp-hold) simulation
- 2 - Pseudo-dynamic (continuous) simulation
- 4 - Numerical multi-platform simulation
- subtype: this parameter corresponds to the Substructure type parameter in the data exchange format. Depending on the substructure modules, one of the following values can be used to initialize the parameter
- 1 - OpenSees
- 2 - Zeus-NL
- 3 - ABAQUS
- 4 - VecTor2
- 5 - NICON-AIO or NICON-NIO
- 6 - VecTor4
- 7 - LS-Dyna
- precision: this parameter corresponds to the Precision parameter in the data exchange format. It can be defined as 1 for single precision and 2 for double precision
- numdofs: this parameter corresponds to the Number of DOFs parameter in the data exchange format. It is equal to the total number of effective DOFs at the interface nodes for communication.
Sending Data¶
Once communication is established and the data format parameters are initialized, the integration module starts with sending displacement command to the substructure.
%------------------------------------------------------------------------------------
% send trial displacement to substructure module
%------------------------------------------------------------------------------------
% update the command in the message header block for imposing target displacement
calllib('DataExchange', 'updatecommand', Impose_TargetValues);
% define the type of data to be appended to the message header
% updatesubtype (disp, vel, accel, force, stiff, mass,temperature)
% use 1 and 0 to enable and disable the data in the function.
calllib('DataExchange', 'updatesubtype', 1, 0, 0, 0, 0, 0, 0);
% send the updated data header to the substructure module
action = calllib('DataExchange', 'command', sockfd1, flag, TCP_IP);
% calculate the data size to be appended to the message header
lens = calllib('DataExchange', 'indicator');
% send trial disp to substructure module
sdata = unn(:,i);
sdataPtr = libpointer('doublePtr', sdata);
iResult = calllib('DataExchange', 'senddata', sockfd1, sdataPtr, lens, TCP_IP);
if iResult ~= 0
disp('Failed to send disp.');
else
disp('Disp sent');
end
Receiving Data¶
Once the restoring force is computed in the substructure module, the integration module sends another command to receive the computed force from the substructure module.
%------------------------------------------------------------------------------------
% receive restoring force from substructure module
%------------------------------------------------------------------------------------
% update the command in the message header for receiving data from the substructure module
calllib('DataExchange', 'updatecommand', Report_Values);
% define the type of data to be appended to the message header
% UpdateSubtype (disp, vel, accel, force, stiff, mass,temperature)
% use 1 and 0 to enable and disable the data in the function.
calllib('DataExchange', 'updatedatatype', 0, 0, 0, 1, 0, 0, 0);
% send the updated message header to the substructure module
action = calllib('DataExchange', 'command', sockfd1, flag, TCP_IP);
% calculate the data size to be appended to the message header
lens = calllib('DataExchange', 'indicator');
% receive the computed restoring force from substructure module
forcePtr = libpointer('doublePtr', zeros(1,lens));
iResult = calllib('DataExchange', 'recvdata', sockfd1, forcePtr, lens, TCP_IP);
if iResult ~= 0
disp('Failed to receive force.');
else
disp('Force received');
end
%Formulate the equivalent force to solve the system's motion equation
force = get(forcePtr,'value');
Pe = P(:,i) - force';
The above sending and receving data steps are repeated until the end of the simulation.
Disconnection¶
Once the simulation is done, the following is included in the code to disconnect the integration module from the substructure module.
%------------------------------------------------------------------------------------
% terminate communication
%------------------------------------------------------------------------------------
%update the command in the message header
calllib('DataExchange', 'updatecommand', Terminate);
% send the updated message header to the substructure module
action = calllib('DataExchange', 'command', sockfd1, flag, TCP_IP);
% disconnect and close socket
iResult = calllib('DataExchange', 'close', sockfdPtr);
disp('Simulation done.')
% unload dataexchange library
unloadlibrary DataExchange;
Substructure Model (C/C++)¶
Similar to the above integration module, the variables for port number, IP address, socket number, and indicator of module type should be defined after the program is linked with the DataExchange.dll.
PortNumber = 8090; % port number
machineInetAddr = libpointer('cstring','0.0.0.0'); % IP address
sockfd = 0; % variable for new created socket id
flag = 2; % 1 - integration module; 2 - substructure module
Communication Initialization¶
The same updatemessageheader, setupconnection, initialization are used in the substructure module to initialize the message header and connect with the integration module. The only difference is the value of flag which indicates that the dll functions are being called by a substructure module.
%------------------------------------------------------------------------------------
% Initialize data exchange format and setup connection
%------------------------------------------------------------------------------------
% declare data exchange format
calllib('DataExchange', 'updatemessageheader', 2, 0, 0, 0, Double_precision, 0);
% setup connection
sockfdPtr = libpointer('uint64Ptr', sockfd); % pointer to sockfd
iResult = calllib('DataExchange', 'setupconnection', PortNumber, sockfdPtr, flag, machineInetAddr, TCP_IP);
if iResult ~= 0
disp('Connection failed.');
else
disp('Connection done');
end
% receive data exchange format from the integration module
sockfd1 = get(sockfdPtr, 'value');
iResult = calllib('DataExchange', 'initialization', sockfd1, flag, TCP_IP);
if iResult ~= 0
disp('Initialization failed.');
else
disp('Initialization done');
end
After the connection is built, a switch statement is included, which defines different actions based on the received command values in the message header.
% receive data format from integration module
action = calllib('DataExchange', 'command', sockfd1, flag, TCP_IP);
switch action
case Impose_TargetValues
% // code to receive data from the integration module (see below)
case Report_Values
% // code to send computed data to the integration module (see below)
case Terminate
% // exit the switch statement
exitFlag = 0;
otherwise
disp('Invalid action received');
end
Receiving Data¶
In the above case of Impose_TargetValues, the substructure module receives the displacement from the integration module. Detailed code is shown below:
% calculate the size to be appended to the message header
lens = calllib('DataExchange', 'indicator');
% receive displacement from the integration module
TdispPtr = libpointer('doublePtr', zeros(1,lens));
iResult = calllib('DataExchange', 'recvdata', sockfd1, TdispPtr, lens, TCP_IP);
if iResult ~= 0
disp('Failed to receive trial displacement.');
else
disp('Trial displacement received');
end
% save the displacement for analysis
Tdisp = get(TdispPtr,'value');
Sending Data¶
In the case of Report_Values, the substructure module sends the computed restoring force back to the integration module. Detailed code is shown below:
% calculate the size to be appended to the message header
lens = calllib('DataExchange', 'indicator');
% calculate the restoring force with respect to the received displacement
RF = K * Tdisp';
RFPtr = libpointer('doublePtr', RF);
% send the computed force to integration module
iResult = calllib('DataExchange', 'senddata', sockfd1, RFPtr, lens, TCP_IP);
if iResult ~= 0
disp('Failed to send restoring force.');
else
disp('Restoring force sent');
end
Disconnection¶
At the end of the simulation, the communication is disconnected.
%------------------------------------------------------------------------------------
% Disconnect communication and close socket
%------------------------------------------------------------------------------------
% disconnect and close socket
iResult = calllib('DataExchange', 'close', sockfdPtr);
disp('Simulation done.')
% unload DataExchcange library
unloadlibrary DataExchange;
Source Code Downloading¶
The source code the above communication example in Matlab can be downloaded from here.