Search code examples
modelicadymola

External Functions: Reference headers in C-script to compiled dll


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 Resources Source Folder

Correct Path: Note gsl header folder is at the same level as gsl-1.8 folder Corrected Resources Source 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;
}

Solution

  • 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 Required 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;
    }