#1
  1. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Posts
    7
    Rep Power
    0

    Unhappy I need help with my C++ 2-d vector I'm passing to Fortran


    Hi. I got stuck in this problem since yesterday and I'm not getting anywhere near solving it. I need help with my 2-d vector of double I created from C++ which I'm passing to F90 as a 2-d array of real*8.

    The 1-d vector transferred to F90 is okay. The 2-d is not. I'm aware of the row-column difference of order in C++ and Fortran. The specific problem is that the 1st column of the vector/array is the only column which is okay in F90 (which is the first row in C++). F90 retrieved that row in C++ successfully, but not the 2nd row (which is the 2nd column in Fortran).

    Specifically, in the code below, vCalFile in C++ is the 2-d vector I'm trying to pass to F90 by reference.

    Code:
    //C++ code
    //Fortran Programs Called By C++
    extern "C" {
    	//function to process meter values		
    	void __stdcall MILLIGAL(int& row, int& col, const double* vCalFile, 
    				int& readingvsize, double* readingvec,
    				int& metervsize, int* metervec,
    				char* FNSUM, int num_chars); 
    }
    //Function to pass FLD Data to F90 subroutines for processing	
    void FldGrav::PassFldGrav(char FNFLD[20], char FNSUM[20], int mark, int nfix, 
    			const std::vector <std::vector <double> >& vCalFile) {
    	ifstream fldfile(FNFLD, ios::in);
    	assert(fldfile);		
    
    	fldfile.seekg(mark);
    	std::string line;
    
    	getline(fldfile, line);
    	
    	while (getline(fldfile, line)) {
    	   if (!line.empty())  {					
    			stringstream ss(line);				
    			ss>>reading;	readingvec.push_back(reading);
    			ss>>meter;		metervec.push_back(meter);
    			if (ss.fail()) {				
    				meter = 1;				
    				metervec.pop_back();			
    				metervec.push_back(meter);		
    			}
    	   }
    	}
    	
    	fldfile.close();
    
    	int readingvsize = readingvec.size();
    	int metervsize = metervec.size();
    	
    	int row = vCalFile.size();
    	int col = nmtr_const;
    	int num_chars = strlen(FNSUM);
    	
    	//display vectors for testing purposes only	
    	printf("size of vCalFile: %d", row);
    	for (int i=0; i<row; i++) {		
    		printf("\n");
    		for (int j=0; j<col; j++) 		
    			printf("%f\t", vCalFile[i][j]);
    	}
    
    	MILLIGAL (row, col, &vCalFile[0][0],
    			readingvsize, &readingvec[0],
    			metervsize, &metervec[0],
    			FNSUM, num_chars);
    
    	readingvec.clear();
    	metervec.clear();
    	D.vCalFile.clear();
    
    }
    
    !F90 Code
    subroutine Milligal (col, row, calfilevec, readingvsize, mtrrdg, metervsize, imeter, FNSUM)
    	implicit none
    	
    	interface
    		  subroutine ForReading(readingvsize,mtrrdg, FNSUM)
    	!MS$ATTRIBUTES C,REFERENCE, ALIAS:'_ForReading' :: ForReading
    		  integer	readingvsize
    		  real*8	mtrrdg(readingvsize)
    		  character*24 FNSUM
    
    		  end subroutine ForReading
    	end interface
    	
    	character*24 FNSUM
    	integer calmtrvsize, readingvsize, metervsize
    	integer i, j, col, row, textlen
    	integer imeter(metervsize)
    	real*8 calfilevec(row, col), mtrrdg(readingvsize)
    	
    	write(*,*) row, col
    	write(*,*)
    	write(*,*) calfilevec(1,1)
    	write(*,*) calfilevec(2,1)
    	write(*,*) calfilevec(3,1)
    	write(*,*) calfilevec(1,2)
    	write(*,*) calfilevec(2,2)
    	write(*,*) calfilevec(3,2)
    	write(*,*)
    	write(*,*) 
    
    	do i = 1,row
    		do j = 1, col
    			write(*,*) i, j, calfilevec(i,j)
    		end do
    	end do
    	
    	
    	textlen = len(FNSUM)
    	FNSUM(textlen:textlen) = char(0)		
    
    	call ForReading(readingvsize, mtrrdg, FNSUM)
    	return
    end subroutine Milligal
    Thanks in advance for your help.
    Last edited by C++ Padua; July 23rd, 2003 at 09:38 PM.
  2. #2
  3. Left due to despotic ad-min
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jun 2003
    Posts
    1,044
    Rep Power
    14
    Your problem is that std::vector is more than just a contiguous array. It is actually a data structure that contains a contiguous array.

    The reason that your 1-D array transferred to F90 OK is that &yourvector[0] is the address of the first element in the vector, and the elements are guaranteed to be contiguous.

    The reason that your 2-D array does not get passed satisfactorily is that the F90 requires the data in columns to be contiguous. As in a 2-D array in F90 is effectively a 1D array with the columns of data laid end to end. A std::vector<std::vector<double> > is actually a structure containing a vector of data structures laid end to end. That difference causes your incompatibility: the actual data contained in a 2D array is not quite contiguous.

    What you need to do is something like;

    // warning: untested code to illustrate idea.
    // I may be transposing the 2D array by copying it.

    int rows = vCalFile.size();
    int cols = 0;
    if (rows > 0) cols = vCalFile[0].size();

    std::vector<double> temp(rows*cols);
    for (int i = 0; i < rows; ++i)
    {
    for (int j = 0; j < cols; ++j)
    {
    temp[i*rows + j] = vCalFile[i][j];
    }
    }

    MILLIGAL (row, col, &temp[0],
    readingvsize, &readingvec[0],
    metervsize, &metervec[0],
    FNSUM, num_chars);

IMN logo majestic logo threadwatch logo seochat tools logo