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.


Anmelden zum Antworten