C++ Objekt in Fortran initialisieren und an C++ Routine übergeben
-
Hallo ihr Lieben,
in meinem letzten Thread war ich beeindruckt, wie einfach die Kommunikation zwischen Fortran und C++ (zumindest für meine Anforderungen) doch ist.
Jetzt möchte ich das einen Schritt weitertreiben durch folgende Problemstellung:
Die aufgerufene C++ Funktion initialisiert einen Zufallsgenerator (RNG) für meine parallelisierte C++ Routine. Das ist zum Einen sehr zeitintensiv und zum Anderen 'falsch', dass der RNG jedes Mal neu initialisiert wird. Denn bei gleichem seed liefert das jedes Mal die gleiche Folge von Zufallszahlen.
Aus diesem Grund würde ich gerne den Zufallsgenerator in Fortran initialisieren (als C++ Objekt?) und dann jedes Mal übergeben, wenn die C++ Funktion aufgerufen wird.
Der Pseudocode sieht grob so aus:
// Fortran Code program me implicit none // C++ RNG initialisieren do n = 1, length // C++ Funktion aufrufen und RNG verwenden end do end program me
Geht das? Oder lässt sich der RNG unabhängig vom Fortran Code initialisieren und wird dann jedes Mal in der C++ Funktion verwendet.
Gruß,
-- Klaus.
-
wie einfach die Kommunikation zwischen Fortran und C++
Du hast einen C-Wrapper geschrieben.
als C++ Objekt?
Nein.
Lagere die Initialisierung des RNGs aus und rufe sie einmal explizit im Fortran-Programm auf.
-
knivil schrieb:
Lagere die Initialisierung des RNGs aus und rufe sie einmal explizit im Fortran-Programm auf.
Äh, wie meinen?
Also in einem C++ Pseudo Code hätte ich z.B. folgendes
class dummy { // Inhalt }; void function(dummy& d) { // Inhalt } int main() { // klasse initialisieren dummy d; // Übergabe an funktion f(d); return 0; }
Und das Initialisieren soll ich nun auslagern? Wie würde das denn in C++ aussehen?
Gruß,
-- Klaus.
-
Du rufst
main
aus Fortran auf?Und das Initialisieren soll ich nun auslagern? Wie würde das denn in C++ aussehen?
dummy d; void init_d() { d = dummy("wohouw"); } void use_d() { // hey i can use d }
Das ist nur eine Moeglichkeit. Nein, ich gebe keine Beispiele fuer andere.
-
Okay,
scheinbar kann ich es auch anders lösen. Ich muss nicht ein Objekt initialisieren, sondern kann auch eine Klasse schreiben und lediglich eine Funktion davon aufrufen.
Ich bin diesem Beispiel gefolgt und habe eine kleine Klasse geschrieben, die lediglich
hello from foo
ausgibt:#include <iostream> class foo { public: void hello(){ std::cout << "Hello from foo" << std::endl; } }; /* C wrapper interfaces to C++ routines */ extern "C" { foo *foo__new(){ return new foo(); } void foo__hello(foo *This){ This->hello(); } void foo__delete(foo *This){ delete This; } }
Der Code in fortran 90 sieht dann etwas aufwendiger aus, auch wenn ich den Eindruck habe, dass viel technisches dabei ist, um eben die Schnittstellen bereit zu stellen.
module foo_module use, intrinsic :: ISO_C_BINDING, only: C_ptr, C_NULL_ptr implicit none private type foo_type private type(C_ptr) :: object = C_NULL_ptr end type foo_type interface function C_foo__new() result(this) bind(C,name="foo__new") import type(C_ptr) :: this end function C_foo__new subroutine C_foo__delete(this) bind(C,name="foo__delete") import type(C_ptr), value :: this end subroutine C_foo__delete subroutine C_foo__hello(this) bind(C,name="foo__hello") import type(C_ptr), value :: this end subroutine C_foo__hello end interface interface new module procedure foo__new end interface new interface delete module procedure foo__delete end interface delete interface hello module procedure foo__hello end interface hello public :: new, delete, hello, foo_type contains ! Fortran wrapper routines to interface C wrappers subroutine foo__new(this) type(foo_type), intent(out) :: this this%object = C_foo__new() end subroutine foo__new subroutine foo__delete(this) type(foo_type), intent(inout) :: this call C_foo__delete(this%object) this%object = C_NULL_ptr end subroutine foo__delete subroutine foo__hello(this) type(foo_type), intent(inout) :: this call C_foo__hello(this%object) end subroutine foo__hello end module foo_module program main use foo_module type(foo_type) :: foo call new(foo) call hello(foo) call delete(foo) end program main
Gruß,
-- Klaus.
-
Also ich nochmal,
ich verstehe es einfach nicht, wenn ich jetzt Arrays übergeben möchte, wie z.B. in diesem Minifortranprogramm:program main use foo_module implicit none integer, parameter :: n = 4 real(8), dimension(1:n) :: x, y type(foo_type) :: foo x = (/ 1,2,3,4 /) y = (/ 1,4,9,16 /) call new(foo) call show(foo,x,y,n) call delete(foo) end program main
Das zugehörige
foo_module
sieht wie folgt aus und dabei klappt die Übergabe nicht. Ich verstehe das so, dass in den Zeilen 37 bis 51 seitens Fortran definiert wird, was die subroutinen zu erwarten haben und darüber Zeile 9 bis 24 findet die Konvertierung nach C statt?module foo_module use, intrinsic :: ISO_C_BINDING, only: C_int, C_ptr, C_NULL_ptr implicit none private type foo_type private type(C_ptr) :: object = C_NULL_ptr end type foo_type interface function C_foo__new() result(this) bind(C,name="foo__new") import type(C_ptr) :: this end function C_foo__new subroutine C_foo__delete(this) bind(C,name="foo__delete") import type(C_ptr), value :: this end subroutine C_foo__delete subroutine C_foo__show(this,x,y,n) bind(C,name="foo__show") import type(C_ptr), value :: this integer(C_int), value :: n type(C_ptr), value :: x,y end subroutine C_foo__show end interface interface new module procedure foo__new end interface new interface delete module procedure foo__delete end interface delete interface show module procedure foo__show end interface show public :: new, delete, show, foo_type contains ! Fortran wrapper routines to interface C wrappers subroutine foo__new(this) type(foo_type), intent(out) :: this this%object = C_foo__new() end subroutine foo__new subroutine foo__delete(this) type(foo_type), intent(inout) :: this call C_foo__delete(this%object) this%object = C_NULL_ptr end subroutine foo__delete subroutine foo__show(this,x,y,n) type(foo_type), intent(in) :: this integer, parameter :: n real(8), dimension(1:n) :: x,y call C_foo__show(this%object,x,y,n) end subroutine foo__show end module foo_module
Der zugehöirge C Wrapper sieht so aus:
#include <iostream> #include <vector> class foo { public: void show(double*, double*, int); private: std::vector<double> _x, _y; }; auto foo::show(double* x, double* y, int n) -> void { for(int i = 0; i < n; ++i) { _x.push_back( x[i] ); _y.push_back( y[i] ); } for(unsigned int i = 0; i < _x.size(); ++i) std::cout << _x[i] << "\t" << _y[i] << std::endl; } /* C wrapper interfaces to C++ routines */ extern "C" { foo *foo__new(){ return new foo(); } void foo__show(foo *This, double* x, double* y, int n){ This->show(x,y,n); } void foo__delete(foo *This){ delete This; } }
Kann mir jemand trotz C++ Forum bei der Sache mit Fortran weiterhelfen?
Gruß,
-- Klaus.