Using Dymola 2017.
Case A) Calling an external c-script
I have had success implementing simple external c functions that have no “# include <-->” statements:
Modelica Function:
function chirp
input Modelica.SIunits.AngularVelocity w_start;
input Modelica.SIunits.AngularVelocity w_end;
input Real A;
input Real M;
input Real t;
output Real u "output signal";
external "C" u=chirp(w_start,w_end,A,M,t)
annotation(IncludeDirectory="modelica://ExternalFuncTest/Resources/Source/", Include="#include \"chirp.c\"");
end chirp;
C-script:
double chirp(double w1, double w2, double A, double M, double time)
{
double res;
res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
return res;
}
Case B) Calling an external function in a .dll file
I also have had success in calling external functions within a compiled dll:
Modelica Function:
function bessel_Jn
"Bessel function of the 1st kind (regular cylindrical) of order n"
extends Modelica.Icons.Function;
input Integer n;
input Real x;
output Real y;
external "C" y=gsl_sf_bessel_Jn(n,x) annotation(LibraryDirectory="modelica://ExternalFuncTest/Resources/Source/gsl-1.8/", Library="libgsl");
end bessel_Jn;
Case C) Calling an external c-script which uses functions from an external .dll via headers
What I want to do now is create a c function that does more interesting things. My current approach is to include header files in the c function that references the compiled dll (in this case a compiled version of the GNU scientific library). This example has the header (although it does not do anything for the moment).
Modelica Function:
function chirp
input Modelica.SIunits.AngularVelocity w_start;
input Modelica.SIunits.AngularVelocity w_end;
input Real A;
input Real M;
input Real t;
output Real u "output signal";
external "C" u=chirp(w_start,w_end,A,M,t)
annotation(LibraryDirectory="modelica://ExternalFuncTest/Resources/Source/gsl-1.8/", Library="libgsl",
IncludeDirectory="modelica://ExternalFuncTest/Resources/Source/", Include="#include \"chirp.c\"");
end chirp;
C-cript:
#include <gsl/gsl_sf_bessel.h> //<-- note the additional header
double chirp(double w1, double w2, double A, double M, double time)
{
double res;
res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
return res;
}
When attempting to call the function above the error indicates failure to translate and nothing else due to the existence of the header file. If the header file is commented out the function will run as expected.
Please let me know if you have any insight as to how to properly go about implementing this feature. Thank you.
For reference: The image below is the path to the external c-script and .dll.
Wrong Path: Note gsl header folder is within gsl-1.8 folder
Correct Path: Note gsl header folder is at the same level as gsl-1.8 folder
UPDATE: Header works but function call causes translation to fail
I have updated the c-script to now call a function that should be handeled by the header. In its current state it won't work. Perhaps it can't find the .dll file although its specified in the modelica code? Do I have to include a load .dll command in the c-scripts?
#include <gsl/gsl_sf_bessel.h>
double chirp(double w1, double w2, double A, double M, double time)
{
double res;
double y;
res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
y = gsl_sf_bessel_j0(time); // <-- Calls a function from the .dll file using the header
return res;
}
Referencing compiled library headers from c-scripts that are called by a Modelica external function call is possible.
However, it is still not determined if there is an efficient method to access the .dll. This is discussed in a follow up question External Functions: Alternative Method to use .dll from a C-script.
The solution that allowed the header files to be recognized is presented. Thanks to all who responded in helping figure this out.
Step 1) Create Folder Structure
Modelica looks in default directories automatically for external function dependencies. Section 12.9.4 of modelica.org/documents/ModelicaSpec33Revision1.pdf
The default location that Modelica looks for compiled libraries is a folder called Library
within the Resources folder of your project:
LibraryDirectory="modelica://LibraryPackageName/Resources/Library"
For header files and c-scripts the default location is a folder called Include
within the Resources folder of your project:
IncludeDirectory="modelica://LibraryPackageName/Resources/Include"
To specify alternative directories follow the modelica spec document. As of Modelica Specification 3.3 Rev 1 you can only specify one LibraryDirectory
and one IncludeDirectory
. Though this may be addressed in the future https://trac.modelica.org/Modelica/ticket/2103.
Summary of Overall Folder Structure
Step 2) Create Modelica Function and C-Scripts in locations specified in above image
Below are examples that can be used for reference.
Modelica Function
function chirp
input Modelica.SIunits.AngularVelocity w_start;
input Modelica.SIunits.AngularVelocity w_end;
input Real A;
input Real M;
input Real t;
output Real u "output signal";
external "C" u=chirp(w_start,w_end,A,M,t)
annotation(Library="libgsl",Include="#include \"chirp.c\"");
end chirp;
C-Script
#include <gsl/gsl_sf_bessel.h>
double chirp(double w1, double w2, double A, double M, double time)
{
double res;
res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
return res;
}