Selected oSP3D features can be exported to a dynamic linked library with the C Application Programming Interface (API).
The C API documentation for the FMOPSolver
dynamic linked
library is available on the Ansys
API Documentation site. With this C API, you can only query and evaluate an already created field-MOP. Hence,
reference mesh definition, data input, and field-MOP creation all must be done within
the oSP3D main executable. Once created, the oSP3D database can be exported and used
within this dynamic linked library.
Installation Directories
On Linux, the FMOPSolver
integration gets unpacked
automatically during installation. The Windows installation is optional and must be
selected explicitly during setup.
If successfully installed, you can find the following FMOPSolver subdirectories within the oSP3D installation directory:
- FMOPSolver/share/
Demonstration examples in C, C++, python, and MATLAB languages as well as developer documentation in HTML and PDF format. To read the documentation in HTML format, open share/doc/html/index.html.
- FMOPSolver/lib/
The dynamic link library itself, without any dependency.
- FMOPSolver/include/
The C/C++-API header file.
Linkage to Other Shared Libraries and Compatibility Notes
The installation subdirectory share contains some demonstration examples. These examples gets compiled and tested in the oSP3D build and test environments on a regular basis, using tools of the GNU Compiler Collection (GCC) for programming languages and python 2.7.x for the scripting example.
To use the C and C++ examples in a custom environment, compile the respective source
code unit and link to the FMOPSolver
dynamic linked library.
Because the FMOPSolver
library depends on several other
libraries, you must further ensure that the loader executable finds them. Because a
typical oSP3D installation is not located in any default search paths, you must add the
${SoS_install_dir}/sos directory to the list of search
paths.
On most Linux systems, you can do this either by using the
LD_LIBRARY_PATH
environment variable or by adding the search
path to the /etc/ld.so.conf file. Windows follows different
strategies with different search orders, depending on operating system settings. In most
cases, the directory from which the application was loaded, the current directory, and
the directories that are listed in the PATH
environment variable
are scanned. For more information, refer to the manual for your operating system.
The python example is written for version 2.7.x. It uses the
ctypes
module to access the FMOPSolver
dynamic linked library API. Due to its dependencies to other libraries, you mus ensure
that the loader executable can find these dependencies. Refer to the previous paragraph
for help.
The next two sections introduce the FMOPSolver
API using a
general workflow example and a Python example.
General Workflow Example
A typical FMOPSolver
dynamic linked library workflow executes
API calls in the following order:
Add an additional license search path if your license file is not placed at a default location. Default locations are listed in the developer documentation. For more information, search the developer documentation for
FMOP_appendLicenseSearchPath
.Acquire a license. The library cannot be used without a valid license.
Load the oSP3D database containing the field-MOP of interest.
Get a handle to the field-MOP in question.
Get the parameters and evaluate the field-MOP, repeating this step as needed
Release the field-MOP handle.
Release the database handle.
Release all licenses. You cannot release acquired licenses until all
fmop_handle_*t
handles are successfully released.
On the Ansys API Documentation site, the C API documentation for the
FMOPSolver
dynamic linked library provides demonstration
examples that show this workflow for C, C++, and Python code.
Note:
Be sure to load oSP3D databases only once. Because a database file is usually quite large, loading it requires a significant amount of time and resources. Therefore, you should keep the database file handler open as long as one of its field-MOP models is needed. If you only need one field-MOP handle from a specific database, you can release this database handle immediately after loading it. However, because this field-MOP handle stores a reference on its parent object, resources are not released until the last child object is released.
Be sure to release your license if no longer needed. Licenses are not released automatically. Licenses are guaranteed to be returned only at program or process termination.
Python Example
The installed version 2.7.x Python
example follows in principal
the suggestions of the general workflow
example. To use the C-API, import the ctypes module:
import ctypes
In the Variables
section, you must define the system
environment, which is where the FMOPSolver
dynamic linked library
can be found: CDLL_lib_path = C:\your\path\FMOPSolver0.dll. The
python example assumes that library dependencies are located in one of the default
search paths, next to the FMOPSolver
dynamic linked library.
Furthermore, you must define the path to the oSP3D field-MOP demo or any other oSP3D
field-MOP database, the number of field-MOP input parameters, and some parameter values
set within their DOE (Design of Experiments) boundaries.
Using the following code, the current working directory gets set to the path of the
FMOPSolver
library and loaded into the oSP3D handle:
os.chdir ( os.path.dirname( CDLL_lib_path ) ) sos = ctypes.CDLL ( os.path.basename( CDLL_lib_path ) )
Because the ctypes
module assumes that
int
data is to be returned by default, the subsequent line
declares some other return types:
sos.FMOP_getLastLogString.restype = ctypes.c_char_p
Enum variable definitions are not known by python and are therefore redefined for
convenience. Furthermore, the function CheckError
and the class
LicManager
are also for convenience only. The first one
checks the FMOPSolver
API returned error code and throws an
error. The latter one closes all open handles and returns the license on error.
To acquire a license:
sos.FMOP_appendLicenseSearchPath ( user_lic_path ) sos.FMOP_acquireLicenses ( FMOP_MESH_ALL )
To load the database of interest into the database handle:
database = ctypes.c_void_p() sos.FMOP_loadDbFile ( ctypes.byref( database ), db_path )
As noted in the general workflow example, you should keep the database handle in scope as long as its field-MOP models get used. You should not load and unload the oSP3D database for each FMOP handle.
To get a list of known field-MOP identifiers:
Call
sos.FMOP_getModelIdents ( database, FMOP_NODE_DATA, ctypes.byref( fmop_idents ), ctypes.byref( num_idents ) )
.Print the
fmop_idents
array:fmop = ctypes.c_void_p() sos.FMOP_getModel ( database, FMOP_ELEMENT_DATA, fmop_ident, ctypes.byref( fmop ) )
An element field-MOP handle with the given fmop_ident
is loaded
into your prepared fmop
variable.
At this point, you can query some interesting properties, like the
FCOP[total]
value or the number of active parameters and the
model dimension. The latter two parameters are of special interest because they are
needed to prepare input arrays for a field-MOP evaluation call. For example, the
following code queries the needed field-MOP input array sizes and evaluates the
fmop
handle at the given param_values
point:
param_idents = ctypes.POINTER( ctypes.c_char_p )() num_idents = ctypes.c_ulonglong(0) sos.FMOP_getModelParamIdents ( fmop, ctypes.byref( param_idents ), ctypes.byref ( num_idents ) ) num_mesh_items = ctypes.c_ulonglong(0) sos.FMOP_getModelDim ( fmop, ctypes.byref ( num_mesh_items ) ) param_values = ( ctypes.c_double * num_idents ) ( 1., 2., 3., 4., 5., 6. ) approx_field = ( ctypes.c_double * num_mesh_items.value ) () sos.FMOP_approxField ( fmop, param_values, ctypes.byref( approx_field ) )
This can be done as often as a different param_values
combination of interest exists and these parameters are within their DOE
boundaries.
Finally, to release all handles and licenses:
sos.FMOP_releaseModel ( ctypes.byref ( fmop ) ) sos.FMOP_releaseDb ( ctypes.byref ( database ) ) sos.FMOP_releaseLicenses ()
MATLAB Example
The FMOPSolver
shared library can be used inside
MATLAB™. The provided example was tested on Microsoft Windows using MATLAB R2015b
with MinGW64/GCC4.9 as the MEX compiler.
MATLAB provides a simple mechanism for binding external libraries. It parses the API
and links against the dynamic library by declaring the API through the ANSI C header
file. The command loadlibrary
is used to import the
library:
loadlibrary ( CDLL_lib_file ,'fmop_solver.h')
You can call functions in the dynamic library:
calllib ( CDLL_lib_file, function_name, parameter_1, parameter_2, ... )
To acquire a license:
calllib ( CDLL_lib_file, 'FMOP_appendLicenseSearchPath', user_lic_path ); errno = calllib ( CDLL_lib_file, 'FMOP_acquireLicenses', feature ); FMOPSolver_checkError ( errno, 'Error acquiring licenses', calllib( CDLL_lib_file, 'FMOP_getLastErrorString' ) );
The function FMOPSolver_checkError
is a MATLAB function
provided in a separate example file for convenience.
To load the database of interest into the database
handle:
database = libpointer( 'voidPtr' ); errno = calllib ( CDLL_lib_file, 'FMOP_loadDbFile', database, db_path );
You should keep the database
handle in scope as long as its
field-MOP models get used. You should not load and unload the oSP3D database for each
field-MOP handle. To get a list of known field-MOP identifiers:
num_idents = uint64 (0); [errno, ~, num_idents] = calllib ( CDLL_lib_file, 'FMOP_getModDim', database, 'fmop_node_data', num_idents );
To get the number of identifiers and then access the string identifier of each field-MOP:
ident = calllib ( CDLL_lib_file, 'FMOP_getModelIdent', database, 'fmop_element_data', uint64(i) );
fmop = libpointer( 'voidPtr' ); calllib ( CDLL_lib_file, 'FMOP_getModel', database, 'fmop_element_data', fmop_ident, fmop )
An element field-MOP handle is loaded with the given fmop_ident
into your prepared fmop
variable. At this point, you can query
some interesting properties, like the FCoP[Total]
value or the
number of active parameters and the model dimension. The latter two parameters are of
special interest because they are needed to prepare input arrays for a field-MOP
evaluation call.
For example, the following code queries the needed field-MOP input array sizes and
evaluates the fmop
handle at the given
param_values
point:
[errno, ~, num_idents] = calllib ( CDLL_lib_file, 'FMOP_getModelParamIdentsDim', fmop, num_idents ); for i = 1 : num_idents-1 param_ident = calllib ( CDLL_lib_file, 'FMOP_getModelParamIdent', fmop, uint64(i) ); ... end num_mesh_items = uint64 (0); [errno, ~, num_mesh_items] = calllib ( CDLL_lib_file, 'FMOP_getModelDim', fmop, num_mesh_items ); param_values = [ 43341.092 134.12064 0.093418892 0.042747076 2.7525392e-09 58.798039 ]; approx_field = libpointer( 'doublePtr', zeros ( num_mesh_items, 1 ) ); calllib ( CDLL_lib_file, 'FMOP_approxField', fmop, param_values, approx_field ); % approx_field.Value ( 1:10, 1 )
This can be done as often as a different param_values
combination of interest exists and these parameters are within their DOE
boundaries.
Finally, to release all handles and licenses:
calllib ( CDLL_lib_file, 'FMOP_releaseModel', fmop ); calllib ( CDLL_lib_file, 'FMOP_releaseDb', database ); calllib ( CDLL_lib_file, 'FMOP_releaseLicenses' );