chintanp

30 Reputation

3 Badges

9 years, 20 days

MaplePrimes Activity


These are questions asked by chintanp

Dear all, 

I am using a custom wrapper to access the subroutines defined in a fortran DLL. The fortran code is pretty basic: it takes three arguments, a, b, mult. Being a subroutine. it returns the result in 'mult'.

Currently, I can get the result from fortran DLL in my wrapper code. I am not able to get it back in Maple. 

My fortran code is as under: 

      subroutine multiply(a1,b1, mult1) bind (C, name="multiply")

        use iso_c_binding
        implicit none

        real (c_double), intent(in), VALUE :: a1
        real (c_double), intent(in), VALUE :: b1
        real (c_double), intent(out) :: mult1

        mult1 = a1*b1

        return
      end subroutine multiply

I tried using this subroutine from a regular C file and it works, so this code works the way it should. 

Now the custom wrapper that I use (obtained by editing the auto-generated wrapper)

/* MWRAP_multiply Wrapper
   Generated automatically by Maple 2015.0.
   Do not edit this file. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mplshlib.h>

#include <maplec.h>

typedef void *MaplePointer;
static MKernelVector mapleKernelVec;
static ALGEB *args;

/* main - MWRAP_multiply */
//ALGEB M_DECL MWRAP_multiply( MKernelVector kv,
//	void (M_DECL *fn) ( FLOAT64 a1, FLOAT64 a2, FLOAT64 a3 ),
//	ALGEB fn_args )

ALGEB mmultiply(MKernelVector kv, ALGEB fn_args)

{
    FLOAT64 a1;
    FLOAT64 a2;
    FLOAT64 a3;

    int i;
    mapleKernelVec = kv;
    args = (ALGEB*) fn_args;

    if( MapleNumArgs(mapleKernelVec,(ALGEB)args) != 3 )
        MapleRaiseError(mapleKernelVec,"Incorrect number of arguments");

     /* float[8] */
    a1 = MapleToFloat64(mapleKernelVec,args[1]);

    /* float[8] */
    a2 = MapleToFloat64(mapleKernelVec,args[2]);

    /* float[8] */
    a3 = MapleToFloat64(mapleKernelVec,args[3]);

    //(*fn)(a1, a2, a3);
    multiply(a1, a2, &a3);

    MaplePrintf(kv, "Output from multiply %f", a3);

    return( ToMapleNULL(mapleKernelVec) );
}

Since the fortran subroutine calls are call by reference, we need to pass the address of a3, (&a3). Then I compile this to create the DLL using: 

gcc -shared -fPIC -o libmmultiply.so mult.f90 mwrap_multiply.c -I /opt/maple2015/extern/include/ -L /opt/maple2015/bin.X86_64_LINUX/ -lmaplec -lgfortran

And then copying the resulting DLL (libmmultiply.so) to the Maple/bin folder. 

Then in Maple : 

mult := define_external("mmultiply",MAPLE,LIB="libmmultiply.so");

mult1 := 0.01;

mult(2., 3., mult1);
### Printed in Maple: Output from multiply 6.000000

mult1;
### Still 0.01 (we want this to be 6.0)

So, it can be seen that the fortran subroutine is successfully executed, so we get 6.0 as the output. However, this does'nt get assigned to 'mult1. The reason for this, I feel, is that the reference to the original variable 'mult1' in Maple is lost in the wrapper, and so the resulting value doesn't update 'mult1'. 

How can I get the resulting value back in Maple ? I want to get this in 'mult1', as most fortran legacy codes use the subroutine method of returning results by updating the arguments. 

Thanks 

Chintan Pathak 

Dear All, 

I am trying to use define_external to use a C dll from inside MAPLE. The C dll exports a function that has a argument of type function pointer which has a return type of pointer. The function itself returns pointers.  

Pointers are needed as return types as the C function needs to return arrays. 

When I try to pass the C function, as maple procedure as the argument, it errs saying "Error, (in rk4_vec) number expected for float[8] parameter, got proc () option remember; table( [( 1 ) = HFloat(1.0), ( 2 ) = HFloat(-0.0) ] ) 'procname(args)' end proc"

rk4_vec is as follows: 

rk4_vec := define_external("rk4vec", 't0' :: float[8], 'm' :: integer[4], 'u0' :: ARRAY(1..2,datatype=float[8]), 'dt' :: float[8], 'f' :: PROC('t' :: float[8], 'm' :: integer[4], 'u' :: ARRAY(1..2,datatype=float[8]), 'RETURN' :: REF(float[8])), 'RETURN' ::REF(float[8]), "WRAPPER", LIB="rk4.dll");

rk4vec in C looks like this: 

double *rk4vec ( double t0, int m, double u0[], double dt, 
  double *f ( double t, int m, double u[] ) )

I am passing as :

rk4vec_test_f := proc(t, n, u)
local uprime :: REF(float[8]);
#uprime := Array(n);
uprime(1) := u(2);
uprime(2) := -u(1);
return uprime;
end proc;

I have tried the RETURN type on the define_external call as : float[8], ARRAY(1..2, datatype=float[8]) , but that didnt work either. I got the idea of using REF from times2 example on this link.

Any guidance in this matter is highly appreciated. 

Attached are the C file, the dll, maple worksheet. Tested on Windows, with 64-bit, Maple 2016 standard. rk4.zip

 

Dear all, 

We are trying to use a fortran subroutine in maple using external calling. I was able to get the 'multiply' example working. i.e. through the steps descibed here: http://www.mapleprimes.com/questions/203646-External-Calling-FORTRAN-Dll--Error 

My mult.f looks like this: 

    subroutine multiply(a,b)
    real a,b,mult
    mult=a*b
    return 
    end

It simply takes two arguments (Real), and returns the product. I used the following commands to build the dll: 

1. gfortran -c mult.f        ## This creates the object file mult.o, which is used later. 

2. gfortran -shared -mrtd -o mult.dll mult.o ## This creates the dll and can be used in maple. 

The command in maple looks like this : 

mult := define_external("multiply",LIB="C:/shared/mult.dll",FORTRAN,'a'::(float[4]),'b'::(float[4]), RETURN::(float[4]));

And finally, 

mult(3., 3.) ## works, if it gives the correct output. 

Few things to note here are: 

1. The dll has to be generated from inside the Cygwin64 shell, with cygwin64/bin in the system path. 

2. This only worked for (some) 64-bit Maple version (Maple 2016 Standard). 

The reason, I repeated a working example, was because I tried following the same steps for the more complicated case, however without success so far.  This post explains an approach on how to pass a subroutine as an argument to a fortran subroutine in the dll. http://www.mapleprimes.com/posts/37031-Calling-An-External-Routine-That-Needs However the post is old and the steps did not work for me. 

My system is as follows: 

1. Fortran file to generate the dll, takefunc.f , takes a subroutine as an argument and calls it. 

    subroutine take(func)
    external func
    call func()
    end

2. Fortran driver file to verify that the dll generated through this program works: 

    PROGRAM main
    external take, fun
    call take(fun)
    END
    
    SUBROUTINE fun()
    PRINT *, "This is a nice one"
    END

I want the step 2 to be performed in maple, i.e. fun() should be a maple procedure, and we should be able to use either WRAPPER or second dll to use take() in maple. 

I want the process to work with latest maple versions and compilers, Windows7 64-bit or 32-bit (and hopefully later). F77 is fine. 

Regret the long post, will keep this post updated if I make any progress. Any guidance in this matter is highly appreciated. Anyway to make define_external spew more debug information will also help. 

- Chintan Pathak 

Research Scientist,

ChemE, University of Washington. 

Dear Forum, 

 

I am a new Maple user, and its symbolic prowess is really amazing. So we are trying to interface it with a C library. I want to generate some C code through Maple, and am trying the CodeGeneration package. 

But the default conversion of C(a, b) is b = C language equivalent of expression a.

Now this should be fine for most purposes, but the C library that we are working with, "ACADOToolkit" in this case, requires the equations to be formatted in a certain way. So, I need the following equation in C:

 

f << dot(v) == (u-0.2*v*v)/m

 

Now the LHS part of == is to be hard-coded, but we want to generate the equation on the right using maple. Even if I define an equation as 

eq1:= diff(v(t),t)=(u(t)-0.2*v(t)*v(t))/m(t) and then use C(rhs(eq1)), I get the result in the form of cg = u - 0.2 ...., whereas I want this to be assigned to something else, in this case - "f << dot(v)= ".

 

How can I achieve this ?

 

Thanks 

Chintan Pathak 

Research Scholar, 

University of Washington

 

Page 1 of 1