Engee 文档
Notebook

Fortran和Engee集成

这个项目解决了集成遗留Fortran和Engee代码的问题.

目前正在考虑两种情况:
*融入技术计算环境
*集成到仿真环境中

假设你需要集成这样的代码:
``'fortran
子程序vect_add(a,b,res,len)

整数len
整数i

真实的,意图(inout)::res(len)
真正的a(len)
真正的b(len)

做并发(i=1:len)
    res(i)=a(i)+b(i)
结束做

回来吧

结束子程序vect_add

该子程序将两个向量相加。 我们的任务是在我们的计算中使用这个子程序。

## 工作准备

在开始工作之前,我们注意到以下几点:
我们将需要修改子例程的代码,以便它可以正确绑定到名称C或C++。:

`subroutine vect_add(a,b,res,len) bind ( C, name="vect_add" )`

为了正确使用我们的子例程,它必须编译成共享库。
为此,我们将使用gfortran编译器。


In [ ]:
run(`gfortran vect_add.f90 -shared -fPIC -o vect_add.so`)
Out[0]:
Process(`gfortran vect_add.f90 -shared -fPIC -o vect_add.so`, ProcessExited(0))

让我们通过运行以下命令来确保我们可以使用已编译的过程:

In [ ]:
run(`objdump -x vect_add.so`)
vect_add.so:     file format elf64-x86-64
vect_add.so
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000000000

Program Header:
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**12
         filesz 0x0000000000000420 memsz 0x0000000000000420 flags r--
    LOAD off    0x0000000000001000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2**12
         filesz 0x00000000000001e9 memsz 0x00000000000001e9 flags r-x
    LOAD off    0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 2**12
         filesz 0x00000000000000a8 memsz 0x00000000000000a8 flags r--
    LOAD off    0x0000000000002e80 vaddr 0x0000000000003e80 paddr 0x0000000000003e80 align 2**12
         filesz 0x00000000000001a0 memsz 0x00000000000001a8 flags rw-
 DYNAMIC off    0x0000000000002e90 vaddr 0x0000000000003e90 paddr 0x0000000000003e90 align 2**3
         filesz 0x0000000000000150 memsz 0x0000000000000150 flags rw-
    NOTE off    0x0000000000000238 vaddr 0x0000000000000238 paddr 0x0000000000000238 align 2**2
         filesz 0x0000000000000024 memsz 0x0000000000000024 flags r--
EH_FRAME off    0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 2**2
         filesz 0x0000000000000024 memsz 0x0000000000000024 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000002e80 vaddr 0x0000000000003e80 paddr 0x0000000000003e80 align 2**0
         filesz 0x0000000000000180 memsz 0x0000000000000180 flags r--

Dynamic Section:
  INIT                 0x0000000000001000
  FINI                 0x00000000000011dc
  INIT_ARRAY           0x0000000000003e80
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000000003e88
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000000260
  STRTAB               0x0000000000000318
  SYMTAB               0x0000000000000288
  STRSZ                0x000000000000005e
  SYMENT               0x0000000000000018
  PLTGOT               0x0000000000004000
  RELA                 0x0000000000000378
  RELASZ               0x00000000000000a8
  RELAENT              0x0000000000000018
  RELACOUNT            0x0000000000000003

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .note.gnu.build-id 00000024  0000000000000238  0000000000000238  00000238  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .gnu.hash     00000024  0000000000000260  0000000000000260  00000260  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .dynsym       00000090  0000000000000288  0000000000000288  00000288  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynstr       0000005e  0000000000000318  0000000000000318  00000318  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .rela.dyn     000000a8  0000000000000378  0000000000000378  00000378  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .init         0000001b  0000000000001000  0000000000001000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  6 .plt          00000010  0000000000001020  0000000000001020  00001020  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  7 .plt.got      00000008  0000000000001030  0000000000001030  00001030  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  8 .text         0000019a  0000000000001040  0000000000001040  00001040  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  9 .fini         0000000d  00000000000011dc  00000000000011dc  000011dc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 10 .eh_frame_hdr 00000024  0000000000002000  0000000000002000  00002000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .eh_frame     00000080  0000000000002028  0000000000002028  00002028  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 12 .init_array   00000008  0000000000003e80  0000000000003e80  00002e80  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 13 .fini_array   00000008  0000000000003e88  0000000000003e88  00002e88  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 14 .dynamic      00000150  0000000000003e90  0000000000003e90  00002e90  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 15 .got          00000020  0000000000003fe0  0000000000003fe0  00002fe0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 16 .got.plt      00000018  0000000000004000  0000000000004000  00003000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 17 .data         00000008  0000000000004018  0000000000004018  00003018  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .bss          00000008  0000000000004020  0000000000004020  00003020  2**0
                  ALLOC
 19 .comment      0000002b  0000000000000000  0000000000000000  00003020  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 crtstuff.c
0000000000001040 l     F .text	0000000000000000 deregister_tm_clones
0000000000001070 l     F .text	0000000000000000 register_tm_clones
00000000000010b0 l     F .text	0000000000000000 __do_global_dtors_aux
0000000000004020 l     O .bss	0000000000000001 completed.0
0000000000003e88 l     O .fini_array	0000000000000000 __do_global_dtors_aux_fini_array_entry
00000000000010f0 l     F .text	0000000000000000 frame_dummy
0000000000003e80 l     O .init_array	0000000000000000 __frame_dummy_init_array_entry
0000000000000000 l    df *ABS*	0000000000000000 vect_add.f90
0000000000000000 l    df *ABS*	0000000000000000 crtstuff.c
00000000000020a4 l     O .eh_frame	0000000000000000 __FRAME_END__
0000000000000000 l    df *ABS*	0000000000000000 
0000000000003e90 l     O .dynamic	0000000000000000 _DYNAMIC
0000000000004020 l     O .data	0000000000000000 __TMC_END__
0000000000004018 l     O .data	0000000000000000 __dso_handle
0000000000001000 l     F .init	0000000000000000 _init
0000000000002000 l       .eh_frame_hdr	0000000000000000 __GNU_EH_FRAME_HDR
00000000000011dc l     F .fini	0000000000000000 _fini
0000000000004000 l     O .got.plt	0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000  w      *UND*	0000000000000000 __cxa_finalize
00000000000010f9 g     F .text	00000000000000e1 vect_add
0000000000000000  w      *UND*	0000000000000000 _ITM_registerTMCloneTable
0000000000000000  w      *UND*	0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000  w      *UND*	0000000000000000 __gmon_start__


Out[0]:
Process(`objdump -x vect_add.so`, ProcessExited(0))

此命令输出二进制文件中的字符,我们看到vect_add字符存在于我们的库中。:

00000000000010f9g F.文本000000000000000e1vect_add

融入技术计算环境

为了正确集成,我们将使用动态链接器。 这将允许我们根据需要上传和下载我们的共享库。

In [ ]:
using Pkg; Pkg.add("Libdl")
using Libdl
   Resolving package versions...
   Installed MPItrampoline_jll ─ v5.5.1+2
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`

下载我们的图书馆:

In [ ]:
lib = Libdl.dlopen("./vect_add.so");
foo = Libdl.dlsym(lib, :vect_add);

让我们创建测试数据并使用ccall函数调用我们的例程。

Ccall与fortran的工作的一个特点是Fortran例程的所有参数都通过引用传递。

朱莉娅有一个特殊的类型。 Ref.

In [ ]:
Vect_in = Vector{Float32}([1.0,2.0,3.0,4.0,5.0])
Vect_out = copy(Vect_in);
ccall(foo,Nothing,(Ref{Float32},Ref{Float32},Ref{Float32},Ref{Int}), Vect_in, Vect_in, Vect_out, 5)
println("Результат работы кода Fortran : $Vect_out")
Результат работы кода Fortran : Float32[2.0, 4.0, 6.0, 8.0, 10.0]

在我们完成库的工作后,我们需要下载它。:

In [ ]:
Libdl.dlclose(lib)
Out[0]:
true

集成到仿真环境中

要将编译后的库集成到仿真环境中,我们将使用C功能块。
与任何库一样,使用库函数需要头文件。 很容易看出,我们没有。 但是,gfortran允许您自动生成它。 为此,我们将重新编译我们的代码,另外指定密钥 -fc-prototypes 并通过将输出写入文件 vect_add.h

In [ ]:
res = read(`gfortran vect_add.f90 -shared -o libvect_add.so -fPIC -fc-prototypes`,String);
write("vect_add.h",res);

打开模型 fort_integration:

In [ ]:
demoroot = @__DIR__
demo = joinpath("$demoroot","fortran_caller.engee");
mdl = engee.load(demo)
Out[0]:
Model(
	name: fortran_caller
	id: 953bdeb1-1e6b-46a7-b5b4-f6b171e07232
)

此外,我们将配置c函数块的头文件和库的路径。:

In [ ]:
engee.set_param!("fortran_caller/Fortran_is_Here","IncludeDirectories"=>demoroot)
engee.set_param!("fortran_caller/Fortran_is_Here","LibraryDirectories"=>demoroot)

对我们过程的调用包含在输出代码部分的C函数块中。 由于指针应用于其输入,我们必须传输输入信号的地址。

image.png

此外,您需要将生成的头文件和库添加到构建信息中。:

image_2.png

让我们运行模拟并查看结果。:

In [ ]:
engee.run(mdl);
In [ ]:
println("Входной вектор: $(simout["fortran_caller/V_in"].value[1])")
println("Результаты работа Fortran: $(simout["fortran_caller/res"].value[1])")
Входной вектор: Float32[1.0, 2.0, 3.0, 4.0, 5.0]
Результаты работа Fortran: Float32[2.0, 4.0, 6.0, 8.0, 10.0]

结论

Fortran代码集成是通过首先将此代码编译到共享库中并从模拟环境或交互式脚本调用此库来执行的。 这种方法允许您使用以前的开发,而无需用Julia语言重写代码。

示例中使用的块