In [1]:
io = open("C/skel.c","w")
write(io, "int ajoute2(int x) { return x+2; }")
close(io)
run(`gcc -o C/ajoute2.so --shared C/skel.c`);
In [2]:
w = ccall((:ajoute2, "ajoute2.so"), Int32, (Int32,), 12)
run(`rm C/ajoute2.so C/skel.c`)
println("w = $w")
#include <inttypes.h>
double mysum(int64_t m, int64_t n, double *x)
{
double s = 0.;
int i,j;
for(i = 0; i < m; ++i)
for(j = 0; j < n; ++j)
s += x[i * n + j];
return s;
}
a = reshape(collect(1.:10.), 5, 2)
s = ccall((:mysum, "libmysum.so"), Float64, (Int64, Int64, Ptr{Float64}), size(a, 1), size(a, 2), a)
println("s = $s")
In [7]:
include("C/test_mysum.jl")
#include <inttypes.h>
double apply_f(double (*fun)(double), int64_t x_n , double *x, double * y)
{
int64_t i;
for(i = 0; i < x_n; ++i)
i[y] = (*fun)(i[x]);
}
and the @cfuntion
julia macro as in
a = collect(1.:10.)
fun = @cfunction(x->x*x, Float64, (Float64,))
b = zeros(10)
s = ccall((:apply_f, "libjuliafun.so"), Cvoid, (Ptr{Cvoid}, Cint, Ptr{Cdouble}, Ptr{Cdouble}), fun, 10, a, b)
println("b = $b")
one could call julia function into the C code
In [3]:
include("C/test_apply_f.jl")
extern "C"
interface for the entry function #include <cinttypes>
#include <vector>
#include <numeric>
extern "C" {
double mysum2(int64_t n, double *x);
};
double mysum2(int64_t n, double *x)
{
double s = 0;
std::vector<double> t(x, x + n);
for(auto & z : t) s+= z;
return s;
}
a = collect(1.:10.)
s = ccall((:mysum2, "libmysum2.so"), Float64, (Int64, Ptr{Float64}), size(a, 1), a)
println("s = $s")
In [4]:
include("C/test_mysum2.jl")
#define ALLOC_MAX 4
double *table[ALLOC_MAX];
int64_t compteur = 0;
int64_t my_alloc(int64_t size) {
double * p;
printf("comp = %d\n", compteur);
if (compteur < ALLOC_MAX )
{
p = (double*) (calloc(size, sizeof(double)));
if (p)
{
table[compteur] = p;
return compteur++;
}
else
return -1; // bad calloc
}
else
return -2; // allocation table is full
}
void my_free(int64_t num)
{
if (table[num]) { free(table[num]); table[num] = NULL; }
}
int64_t set_values(int64_t size, int64_t num, double * val)
{
if (table[num])
memcpy((void*)(table[num]), (void*)(val), sizeof(double)*size);
else
return -1;
}
int64_t get_values(int64_t size, int64_t num, double * val)
{
if (table[num])
memcpy((void*)(val), (void*)(table[num]), sizeof(double)*size);
else
return -1;
}
using Libdl: dlopen, dlsym
lib_alloc = dlopen("libmyalloc")
all_ptr, fre_ptr, set_ptr, get_ptr = map(x->dlsym(lib_alloc, x), [:my_alloc, :my_free, :set_values, :get_values])
function alloc(n::Int)
ret = ccall(all_ptr, Int64, (Int64, ), n)
if (ret == -2) println("allocation table is full") end
if (ret == -1) println("calloc could not allocate another bloc") end
return ret
end
function free(num::Int)
ccall(fre_ptr, Int64, (Int64, ), num)
end
function set_values(num::Int, vals::Array{Float64, 1})
ret = ccall(set_ptr, Int64, (Int64, Int64, Ptr{Float64}), size(vals, 1), num, vals)
return ret
end
function get_values(num::Int, vals::Array{Float64, 1})
ret = ccall(get_ptr, Int64, (Int64, Int64, Ptr{Float64}), size(vals, 1), num, vals)
return ret
end
h1 = alloc(10); h2 = alloc(5)
a = collect(1.:10.)
set_values(h1, a)
b = zeros(3)
ret2 = get_values(h1, b)
println("b = $b")
free(h1)
h3 = alloc(1); h4 = alloc(1); h5 = alloc(1)
In [5]:
include("C/test_myalloc.jl")
Out[5]:
module heat
use iso_c_binding, only: c_int32_t, c_double
public :: kernel
contains
subroutine kernel(m, n, u_in, u_out, error) bind( C, name="heatKernel" )
implicit none
integer(c_int32_t), intent(in) :: m, n
real(c_double), dimension( 1:m, 1:n ), intent(in) :: u_in
real(c_double), dimension( 1:m, 1:n ), intent(out) :: u_out
real(c_double), intent(out) :: error
integer(c_int32_t) :: i, j
error = 0.d0
u_out(2:m-1,2:n-1) = 4.d0 * u_in(2:m-1, 2:n-1) &
- u_in(1:m-2, 2:n-1) &
- u_in(3:m, 2:n-1) &
- u_in(2:m-1,1:n-2) &
- u_in(2:m-1,3:n)
error = sum((u_out(:,:) - u_in(:,:))**2)
end subroutine kernel
end module heat
function heat(src::Array{Float64,2}, dest::Array{Float64,2})
@assert size(dest) == size(src)
(size_x, size_y) = size(dest)
size_x = Int32(size_x) # could overflows
size_y = Int32(size_y)
err = Ref{Float64}(0.) # ✏️ VERY IMPORTANT ✏️
ccall((:heatKernel, "./libheatKernel.so"), Cvoid, (Ref{Int32}, Ref{Int32}, Ptr{Float64}, Ptr{Float64}, Ref{Float64}), size_x, size_y, src, dest, err)
return err[]
end
subroutine solve(n_x, n_y, p_x, p_y, snapshot_step, snapshot_size, iter_max, solution) bind( C, name="solve" )
use iso_c_binding, only: c_int32_t, c_double
use communications
use heat
use mpi
implicit none
integer(c_int32_t), intent(in) :: n_x, n_y ! sizes of the global matrix
integer(c_int32_t), intent(in) :: p_x, p_y ! nb of processes (in each dimensions)
integer(c_int32_t), intent(in) :: snapshot_step, snapshot_size
integer(c_int32_t), intent(inout) :: iter_max ! max number of iterations
real(c_double), intent(inout) :: solution(1:n_x, 1:n_y, 1:snapshot_size)
! (...)
call set_bounds( coords, p_x, p_y, u_in)
call set_bounds( coords, p_x, p_y, u_out)
do i=1, iter_max
call stencil_4( h_x, h_y, d_t, u_in, u_out, error_loc )
call MPI_ALLREDUCE( error_loc, error, 1, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_WORLD, ierr )
error = sqrt( error )
if (mod( i, snapshot_step ) == 0) then
!(...)
call gather_solution( sol_space, n_x, n_y, u_in, ndims, comm2D, is_master )
if (is_master) solution(:, :, i / snapshot_step) = sol_space(:, :)
!(...)
end if
call ghosts_swap( comm2D, type_row, neighbour, u_in )
u_in = u_out
if (error <= prec) exit
end do
if (i < iter_max ) iter_max = i ! to know if we do all loops
!(...)
end subroutine solve
import MPI
function main()
MPI.Init()
comm = MPI.COMM_WORLD
commSize = MPI.Comm_size(comm)
commRank = MPI.Comm_rank(comm)
nArg = size(ARGS, 1)
# (..) some checks about nargs
nX, nY, pX, pY, iterMax, snapshotStep = map(x->parse(Int32, x), ARGS)
# (...) some checks than pX*pY == commSize
@assert snapshotStep < iterMax
snapshotSize = max(iterMax ÷ snapshotStep, 1)
iter = Ref{Int32}(iterMax) # very important !!
solution = zeros(nX, nY, snapshotSize)
ccall((:solve, "./libheat_solve.so"), Cvoid,
(Ref{Int32}, Ref{Int32}, Ref{Int32}, Ref{Int32}, Ref{Int32}, Ref{Int32}, Ref{Int32}, Ptr{Float64}),
nX, nY, pX, pY, snapshotStep, snapshotSize, iter, solution
)
iter = iter[] # very important !!
if (commRank == 0)
indexToDisplay = (iter == iterMax ? snapshotSize : (iter ÷ snapshotStep))
show(IOContext(stdout, :limit=>true), "text/plain", solution[:, : , indexToDisplay]);
end
MPI.Finalize()
end
main()
mpirun -np 4 julia heat_solve.jl 6 6 2 2 30 10
@pyimport
and julia will convert the result
In [2]:
using PyCall
@pyimport numpy
a = transpose(numpy.arange((5)))
Out[2]:
In [3]:
py"""2 in range(10)"""
Out[3]:
["name_field"]
for methods or members
In [4]:
so = pyimport("scipy.optimize")
filter(x->occursin("newton", x),convert(Array{String}, so["__all__"]))
Out[4]:
In [6]:
so["newton"](x->log(x) - 1 , 1)
Out[6]:
struct Mesh
points::Array{Float64,2}
cells::Array{Array{Int}}
end
using PyCall
@pyimport vtk
@pyimport vtk.util as vu
@pyimport vtk.util.numpy_support as vuns
function readMeshFromFileVtk(fileName::String)
reader=vtk.vtkUnstructuredGridReader()
reader["SetFileName"](fileName)
reader["Update"]()
out = reader[:GetOutput]()
pts = out[:GetPoints]()
pointsData = pts[:GetData]()
points = convert(Array{Float64,2}, vuns.vtk_to_numpy(pointsData))
nbPoints = size(points, 1)
clls = out[:GetCells]()
cllData = clls[:GetData]()
cellsRaw = vuns.vtk_to_numpy(cllData)
i = Int32(1)
nbCells = out[:GetNumberOfCells]()
cellIdx = 1
cells = fill(Int32[], nbCells) # beware 32 bits cast
while i < size(cellsRaw,1)
currentCellSize = cellsRaw[i]
cells[cellIdx] = cellsRaw[i+1:i+currentCellSize]
i += currentCellSize+1
cellIdx += 1
end
return Mesh(points, cells)
end
Ref{T}
when Julia variables are modify by the routineRCall