Fortran, array change their Values - arrays

i have a very odd problem, it seems that, somehow some of my reals are getting changed.
i've got a Modul:
c\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
module Koordinaten
implicit none
save
real(kind=8),allocatable,dimension(:) :: xi, yi, zi
integer,allocatable,dimension(:) :: setnodes, st
real(8),allocatable, dimension(:) :: sx,sy,sz
Integer :: setdaten
end
c/////////////////////////////////////////////////////////
which is used in most of the suroutines and the main subroutine (this subroutine is called and the end of each simulation Increment, an does nothing but my code.). There, in the main program, all are allocated.
SUBROUTINE UEDINC (INC,INCSUB)
use Koordinaten
implicit none
c ** Start of generated type statements **
include 'dimen'
include 'jname'
include 'statistics'
include 'spaceset'
integer inc, incsub
integer :: i, nsets,k
character(265), dimension(ndset) :: setname
c ** End of generated type statements **
write(0,*)"NUMNP: ",NUMNP
allocate(xi(NUMNP))
allocate(yi(NUMNP))
allocate(zi(NUMNP))
allocate(setnodes(NUMNP))
allocate(st(NUMNP))
allocate(sx(NUMNP))
allocate(sy(NUMNP))
allocate(sz(NUMNP))
allocate(ri(NUMNP))
allocate(delta_r(NUMNP))
allocate(dummy(NUMNP))
Where NUMNP comes from 'dimen'. (Creating the dimensions with NUMNP as size in the Modul doesn't work, i dont know why, but thats not my problem for now)
next a subroutine is called doing this:
c#########################################################
subroutine einlesen ()
use Koordinaten
use zyl_para
implicit none
c ** Start of generated type statements **
include 'dimen'
integer :: i, j
integer :: token1, token2
real(8), dimension(3) :: nodein, nodedis
c ** End of generated type statements **
write(0,*)"--- lese Koordinaten ein ---"
write(0,*)"Anzahl der Datenpunkte: ", NUMNP
do i=1,NUMNP
call NODVAR(0,i,nodein,token1,token2)
call NOdVAR(1,i,nodedis,token1,token2)
xi(i)=nodein(1)+nodedis(1)
yi(i)=nodein(2)+nodedis(2)
zi(i)=nodein(3)+nodedis(3)
end do
write(0,*)"--- Koordinaten eingelesen ---"
do i=1, NUMNP
write(0,*)xi(i),yi(i),zi(i)
end do
write(0,*)"§§§§§§§§§§§§§§§§§"
write(0,*)xi(i),yi(i),zi(i)
return
end subroutine einlesen
c#########################################################
Here is the strange part: Thr subroutine 'NODVAR' gives back the Koordinates and the Displacement of a node; calling it works just fine and the values are stored correct in nodein(1:3) and nodedis(1:3).
But
write(0,*)xi,yi,zi
gives out 3 columns of the values stored in xi, so basically yi and zi have the values of xi
Update
The Values are not exact equal, they differ a bit:
....
-20.0000765815728 -20.0000760759377 -20.0000751985753
-20.0000726178150 -20.0000671623785 -20.0000576162833
-20.0000427864046 -20.0000214978710 -19.9999932382105
-19.9999590389013 -18.9999215100902 -18.9998779514709
-18.9998277903388 -18.9997725557635 -18.9997146854248
-18.9996577298267 -18.9996059540004 -18.9995633069003
-18.9995325241422 -18.9995144999731 -18.9995087694121
-18.9995144999742 -18.9995325241444 -18.9995633069036
-18.9996059540045 -18.9996577298314 -18.9997146854297
-18.9997725557682 -18.9998277903431 -18.9998779514747
-18.9999215100934 -18.9999598955851 -18.9999939247953
-19.0000218363084 -19.0000426285757 -19.0000570432278
-19.0000664612509 -19.0000719811992 -19.0000746027515
-19.0000754299370 -19.0000747701169 -19.0000754299373
-19.0000746027519 -19.0000719811998 -19.0000664612514
-19.0000570432280 -19.0000426285755 -19.0000218363074
-18.9999939247935 -18.9999598955826 -17.9999226880232
-17.9998792166917 -17.9998290553161 -17.9997737084839
-17.9997156002768 -17.9996582203842 -17.9996058186853
....
END update
do i=1, NUMNP
write(0,*)xi(i),yi(i),zi(i)
end do
prints the values for xi, yi, and zi.
I do not deallocate the array till the end of the main subroutine
The printing is not the Problem, the Problem is, that the next subroutines uses this koordinates, but seem to have the same Problem.
The subroutine worked fine as i gave the xi,yi and zi as parameters during calling, but now i have to work with subroutins where i cannot pass them during calling.
So, why does this happen?
Thanks you for your time... and sorry for my errors.
UPDATE
I use the Subruotine 'UEDINC' euqivalent to a main Program. It works like an API to the FEM-Programm i use. This subroutine is called at the end of each increment and all my code and my subroutines are within this subroutine / called in this subroutine.
'NODVAR' is provided by the FEM-Program and dokumented. It is called for each node i and gives back the values in an arry of dim(3), here nodein and nodedis, the 0/1 indicates what is given back: koordinates or their displacement, token1 and token2 give back some Information i do not need.
I verified, that the values given back form 'NODVAR' are the ones i expect by printing them out. I also printetd out the values during the loop where they are stored vom 'NODVAR' to my array, by printing the values storred in my arry, here they where also right.
I know, that Kind=8 isn't portable, but it works for ifort, and the code doesn't have to be portable at all.
Further investigation
I modifed my code some bit, i now have the following subroutine:
c##########################################################
implicit none
c ** Start of generated type statements **
integer :: ndaten, i, j
integer :: token1, token2
real(8), dimension(3) :: nodein, nodedis
real(8), dimension(ndaten) :: x,y,z
c ** End of generated type statements **
write(0,*)"--- lese Koordinaten ein ---"
write(0,*)"Anzahl der Datenpunkte: ", ndaten
do i=1,ndaten
call NODVAR(0,i,nodein,token1,token2)
call NOdVAR(1,i,nodedis,token1,token2)
x(i)=nodein(1)+nodedis(1)
y(i)=nodein(2)+nodedis(2)
z(i)=nodein(3)+nodedis(3)
write(0,*)x(i),y(i),z(i) ***(1)
end do
write(0,*)"*****************"
write(0,*)x,y,z ***(2)
write(0,*)"--- Koordinaten eingelesen ---"
return
end subroutine einlesen
c#########################################################
The arrys x,y,z have the dim(NUMNP) and are basically empty, i do nothing with them beofre calling this subroutine, ndaten=NUMNP
(1) gives me, as i expect:
-19.9999205042055 4.174743870006559E-005 -2.49993530375797
-19.9998768725013 0.362341804670311 -2.47354036781631
-19.9998267169371 0.734574978337486 -2.38959111446343
-19.9997716931358 1.10321804323537 -2.24337882624597
-19.9997141644151 1.45282900896610 -2.03451636821160
-19.9996575908584 1.76783665097058 -1.76773205553564
-19.9996061583064 2.03464970008098 -1.45274943026036
-19.9995638755175 2.24353899096506 -1.10315640708085
-19.9995334705205 2.38977079851914 -0.734524030614783
-19.9995156926493 2.47372965346901 -0.362296534411106
-19.9995100448173 2.50012385767524 4.865608618193709E-010
....
(2) gives me:
-19.9999205042055 -19.9998768725013 -19.9998267169371
-19.9997716931358 -19.9997141644151 -19.9996575908584
-19.9996061583064 -19.9995638755175 -19.9995334705205
-19.9995156926493 -19.9995100448173 -19.9995156926504
-19.9995334705227 -19.9995638755208 -19.9996061583105
-19.9996575908630 -19.9997141644199 -19.9997716931404
-19.9998267169414 -19.9998768725051 -19.9999205042086
-19.9999590389038 -19.9999932382123 -20.0000214978720
-20.0000427864049 -20.0000576162831 -20.0000671623780
-20.0000726178145 -20.0000751985748 -20.0000760759375
-20.0000765815728 -20.0000760759378 -20.0000751985753
-20.0000726178150 -20.0000671623785 -20.0000576162833
-20.0000427864046 -20.0000214978710 -19.9999932382105
-19.9999590389013 -18.9999215100902 -18.9998779514709
-18.9998277903388 -18.9997725557635 -18.9997146854248
-18.9996577298267 -18.9996059540004 -18.9995633069003
-18.9995325241422 -18.9995144999731 -18.9995087694121
-18.9995144999742 -18.9995325241444 -18.9995633069036
-18.9996059540045 -18.9996577298314 -18.9997146854297
-18.9997725557682 -18.9998277903431 -18.9998779514747
-18.9999215100934 -18.9999598955851 -18.9999939247953
-19.0000218363084 -19.0000426285757 -19.0000570432278
...
['(1)', and '(2)' are obviously not in the code i compile and only some Markers for demonstration]

In your second output read the values across then down, in your first read the values down then across and you will find that they are the same numbers. This statement
write(0,*)x,y,z
writes vector x, then vector y, then vector z. The format clause (ie the *) tells the compiler to write the numbers as it sees fit. By lucky chance it has chosen to write 3 values on each line, in the order x(1),x(2),x(3),newLine,x(4),...,y(1),y(2),... This has tricked you into thinking that it is writing (incorrectly) x(i),y(i),z(i) but it is your thinking which is incorrect here, not the program.
If you want the values written x(1),y(1),z(1),newLine,x(2),... you have to write the statements to do that, as your first output statement does.

I find your question a rather confusing. Are you saying that you find the values in the arrays xi, yi, zi to be unexpected? What is your evidence that the values have changed?
If values of a variable are changing outside of your expectations, in Fortran there are two likely errors to cause such a problem: 1) array subscripts out of bounds, or 2) disagreement between actual and dummy procedure arguments. The easiest and first step and hunting down such errors and turning on all error and warning options of your compiler, especially run-time subscript bounds checking. Also be sure to place all procedures (subroutines and functions) in modules and use them so that the compiler can check argument consistency.
What compiler are you using?
P.S. real (kind=8) is not guaranteed to be an 8-byte real. Numeric values of kinds are not portable and differ between compilers.

Related

.C() returns me an empty list

I'm a beginner in R and I'm trying to load a .dll file, named dll.dll, that's written in C, into R. It seems to work, now I want to use the functions that are stored in the .dll file and I encounter problems.
I've searched for a solution or other method in manuals, here and on google. Would be very thankful if I could get a suggestion of what to use or any idea!
My code:
setwd("C:/Users/MyUser/R")
dyn.load("dll.dll")
is.loaded("DLL_FUNK")
# For some reason True with capital letters, not in lower case
output <- .C("DLL_FUNK", in9 = as.integer(7))
#output # R Crashes before I can write this.
# R Crashes
# In outdata.txt: "in-value= 139375128"
The function should return a number, 1955. But I can't seem to get to that value. What am I doing wrong?
Update with code (Fortran runned as C), this is the code in dll.dll:
subroutine dll_funk(in9)
implicit none
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!*** Declarations: variables, functions
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
integer(4) :: in9
!integer :: in9
! Definitions of variables in the external function calls
!!dec$ attributes c,alias :'dll_funk' :: dll_funk
!dec$ attributes dllexport :: dll_funk
!dec$ attributes value :: in9
open(194,file='outdata.txt')
write(194,*) 'in-value=', in9
! in9 = 1955
close(194)
end subroutine
!end function
So now when it runs, R crashes but before it writes to my file (outdata.txt) but it't not my number, maybe some kind of address...
Another question, do you recommend me to run the code with .C and from C run the Fortran code or is it better to run it with .Fortran with only Fortran code?
It seems like .Fortran have problem handling strings, or that's what I understood from: Interface func .C and .Fortran
Why did not you pass any arguments to your C function dll_function? When you use .C(), you have to pass function arguments as a list. .C() will return modified list. So, If you pass in nothing, you get nothing.
What does your C function dll_function looks like? Note that:
dll_function must be a void C function, with no return values. If this function should return something, it must return by modifying function arguments;
all function arguments of dll_function must be pointers.
Follow-up
The dll_function is only to test if I can get access to it.
You can use is.loaded() after dyn.load() to test whether you have access to the C function:
dyn.load("dll.dll")
is.loaded("dll_function") ## TRUE
Note that, is.loaded takes C function name, while dyn.load() takes .dll name. In general you can have multiple functions in a single .dll file. You can use is.loaded() to check either of them, to test whether shared library has been loaded successfully.
So if I want it to return something, I should give it an argument (of same type?)?
Yes. The other answer here does give a toy example. You can have a look at this answer I made half a month ago. At the bottom there is a summary of variable type.
When using .C, the extra arguments passed to .C are copied and passed on as pointers to the called c-function. This function can then modify the data pointer to by the pointers. The return value of the function is ignored by .C. So, you c-function should look something like:
void dll_function(int* result) {
/* Do some complicated computation that results in 1955 */
(*result) = 1955;
}
And your call from R:
.C("dll_function", integer(1))
An example with input (this calculates the sum of an integer vector; this example assumes that there are no missing values in vector):
void dll_function2(int* result, int* vector, int* length) {
int sum = 0;
for (int i = 0; i < (*length); ++i, ++vector) {
sum += (*vector)
}
(*result) = sum;
}
Called from R:
x <- c(1000, 900, 55)
.C("dll_function2", integer(1), as.integer(x), length(x))[[1]]

Propagate error string: Fortran > C

Problem statement
The main part of my code is in C (called from Python). The C-part calls functions written in Fortran. Possible errors are propagated using an error-code and an error-string with a description of the error.
The problem is that I cannot seem to get the correct interface to write the string in Fortran and read/copy/manipulate it in C. The code below outlines what I want to do, the comments with marked with * ... * indicate where extensions are needed.
C
// global variable: read from Python if an error is encountered
char* error_string;
// template for the Fortan-subroutine
void fortran_calculation_( double* , int* );
int heavy_calculation( double* x )
{
int error_code;
// ... some code ...
// * should accept and write "error_string" *
fortran_calculation_( x , &error_code );
if ( error_code )
{
error_string = "TO BE WRITTEN BY FORTRAN > REMOVE!!";
return 1;
}
// ... some code ...
return 0;
}
Fortran
subroutine fortran_calculation_(x,error_code)
implicit none
! * include "error_string" as argument *
real*8 :: x
integer :: error_code
! ... some code ...
if ( ... ) then
! * write "error_string" *
error_code = 1
return
end if
return
end subroutine
I've tried many things, but I cannot seem to get it working...
You have two problems. One, how to access a C global variable from Fortran. This one is relatively straightforward, create an interface in a module with iso_c_binding. See https://gcc.gnu.org/onlinedocs/gfortran/Interoperable-Global-Variables.html for an example.
However, the trickier problem is that you have defined your error_string as a pointer to char. That means that your Fortran code must allocate the string before writing to it. The Fortran allocatable and pointer variables work with descriptors, not raw pointers, so you must first create an interface to the C malloc function. Only after that you can write to it. Something like:
module my_error_string
use iso_c_binding
interface
type(c_ptr) function c_malloc(size) bind(C, name="malloc")
use iso_c_binding
integer(kind=c_size_t), value :: size
end function c_malloc
end interface
type(c_ptr), bind(C) :: error_string
contains
subroutine write_error(str)
character(len=*) :: str
character, pointer :: fstr(:)
integer(c_size_t) :: strlen
integer :: i
strlen = len(str, kind=c_size_t) + 1_c_size_t
error_string = c_malloc(strlen)
if (.not. c_associated(error_string)) then
call perror("error_string is a null pointer => malloc failed?!")
stop 1
end if
call c_f_pointer(error_string, fstr, shape=[strlen])
do i = 1, len(str)
fstr(i) = str(i:i)
end do
fstr(strlen) = c_null_char
end subroutine write_error
end module my_error_string
(It might be simple to change the interface such that you instead pass an allocated C string to the Fortran function to fill in, or perhaps use a callback function. But the above works, if that's what you want.)
Here is a shamefully ugly "solution" to your problem, based on the design you provided.
main.c:
#include <stdio.h>
#include <string.h>
char error_string_[512];
void fortan_calculation_( double*, int*, int* );
int main() {
double d = 2.5;
int l, i = 3;
memset( error_string_, 0, 512 );
fortan_calculation_( &d, &i, &l );
error_string_[l] = 0;
printf( "After call: '%s'\n", error_string_ );
}
error.f90:
subroutine fortan_calculation( d, i, l )
implicit none
character(512) str
common /error_string/ str
double precision d
integer i, l
str = "Hello world!"
l = len_trim( str )
end subroutine fortan_calculation
Compilation and test:
$ gcc -c main.c
$ gfortran -c error.f90
$ gcc main.o error.o -lgfortran
$ ./a.out
After call: 'Hello world!'
But that is just disgusting code: it assumes a lot of (arguably) common practices for Fortran compilers, whereas it exists some ways of linking properly C and Fortran using the iso_c_binding Fortran module.
I'll have a look and see if I can come up with a proper solution to that.
EDIT: actually, there's a nice SO page about that available.

Matlab: For loop with window array

This is my one dimensional array A, containing 10 numbers:
A = [-8.92100000000000 10.6100000000000 1.33300000000000 ...
-2.57400000000000 -4.52700000000000 9.63300000000000 ...
4.26200000000000 16.9580000000000 8.16900000000000 4.75100000000000];
I want the loop to go through like this; (calculating mean interval wise) - Interval length of 2,4,8
(a(1)+a(2))/2 - value stored in one block of a matrix say m= zeros(10)
then (a(1)+a(2)+a(3)+a(4))/4 ------ mean-----
then (a(1)+a(2)..... a(8))/8
Then shift indexes:
(a(2)+a(3))/2; - mean
(a(2)+a(3)+a(4)+a(5))/4
(a(2)+a(3)...a(9))/8
SO basically 2^n length interval
%____ my code _____%
A= newArrayy;
sum=0;
storeD = zeros(3,9);
flag=true;
for k=1:9
n=1;
while(true)
if(k+(2^n-1)<10)
meanSum= mean(A(k):A(k+2^n-1))
storeD(n,k)= meanSum;
n=n+1;
else
flag=false;
end
end
end
I need to find standard deviation, covariance and mean for each interval, but I get an error on the meanSum line.
In the meanSum line, you should write
A(k:k+2^n-1)
You want to access the elements ranging from k to k+2^n-1. Therefore you have to provide the range to the selection operation.
A few suggestions:
Use a search engine or a knowlegde base to gather information on the error message you received.
Try to understand which operation failed, and how it should work in principle (in your case: the colon operator, e.g. http://de.mathworks.com/help/matlab/ref/colon.html)
If your own efforts don't lead to success, at least post the error message you get to make the question more clear. Better yet, provide a minimal working example. In your case one or two lines of code would suffice.
A = [-8.92100000000000 10.6100000000000 1.33300000000000 ...
-2.57400000000000 -4.52700000000000 9.63300000000000 ...
4.26200000000000 16.9580000000000 8.16900000000000 4.75100000000000];
sum=0;
storeD = zeros(3,9);
for k=1:9
n=1;
while(1==1)
if(k+(2^n-1)<=10)
meanSum= mean(A(k:k+2^n-1));
storedD(n,k)= meanSum
covVar= cov(A(k:k+2^n-1));
storedC(n,k)= covVar
stdDev= std(A(k:k+2^n-1));
storedS(n,k)= stdDev
n=n+1;
else
break;
end
end
end
So this worked :D Thanks for the help! There was an error in while loop as i didn't use a break to exit the loop.

Fortran: segmentation fault when trying to update particle position in 3-d array

I've written a program to move around particles in a 3-D field based on a 3-D velocity field. However, I get a segmentation fault at the line when I update the particle positions, and I have no idea why! I wrote this program previously in a single file, and it worked fine. But now I'm getting the segmentation fault error when I have all the functions/subroutines in a module.
Edit: I implemented the suggestions below, and now the segmentation fault has moved from the update particle line to the line where I call writeResults. Any help is still appreciated!
Main Program:
program hw4Fortran
use hw4_module
implicit none
!Define types
integer::i ,j, k, num_ts, num_particles, field_size_x, field_size_y, &
field_size_z, num_arguments
type(vector),allocatable::vfield(:,:,:)
type(vector),allocatable::parray(:)
character(30)::out_file_basename, vel_file, part_file, filename, string_num_ts
!Read command line
num_arguments = NARGS()
if (num_arguments > 1) then
call GETARG(1, string_num_ts)
read(string_num_ts, *) num_ts
else
num_ts = 50
end if
if (num_arguments > 2) then
call GETARG(2, out_file_basename)
else
out_file_basename = "results"
end if
if (num_arguments > 3) then
call GETARG(3, vel_file)
else
end if
if (num_arguments > 4) then
call GETARG(4, part_file)
else
part_file = "particles.dat"
end if
!Open files
open(unit=1, file=vel_file)
open(unit=2, file=part_file)
!Read number of particles
num_particles = readNumParticles(2)
!Adjust for zero index
num_particles = num_particles - 1
!Allocate and read particle array
parray = readParticles(2, num_particles)
!Read field size
field_size_x = readFieldSize(1)
field_size_y = readFieldSize(1)
field_size_z = readFieldSize(1)
!Adjust for zero index
field_size_x = field_size_x - 1
field_size_y = field_size_y - 1
field_size_z = field_size_z - 1
!Allocate and read vector field
vfield = readVectorField(1, field_size_x, field_size_y, field_size_z)
!Move particles and write results
do i=0,num_ts
if (mod(i,10) == 0) then
write(filename, fmt = "(2A, I0.4, A)") trim(out_file_basename), "_", i, ".dat"
open(unit = 3, file=filename)
end if
do j=0, num_particles
if (i > 0) then
parray(j) = updateParticle(vfield(INT(FLOOR(parray(j)%x)),INT(FLOOR(parray(j)%y)),INT(FLOOR(parray(j)%z))), parray(j))
end if
if (mod(i,10) == 0) then
call writeResults(3, parray(j))
end if
end do
if (mod(i,10) == 0) then
close(3)
end if
end do
!Close files
close(1)
close(2)
!Deallocate arrays
deallocate(vfield)
deallocate(parray)
end program hw4Fortran
Module:
module hw4_module
implicit none
type vector
real::x,y,z
end type
contains
function readNumParticles(fp) result(num_particles)
integer::fp, num_particles
read(fp, *) num_particles
end function
function readParticles(fp, num_particles) result(parray)
integer::fp, num_particles, i
type(vector),allocatable::parray(:)
allocate(parray(0:num_particles))
do i=0, num_particles
read(fp, *) parray(i)
end do
end function
function readFieldSize(fp) result(field_size)
integer::fp, field_size
read(fp, *) field_size
end function
function readVectorField(fp, field_size_x, field_size_y, &
field_size_z) result(vfield)
integer::fp, field_size_x, field_size_y, field_size_z, i, j
type(vector),allocatable::vfield(:,:,:)
allocate(vfield(0:field_size_x,0:field_size_y,0:field_size_z))
do i=0, field_size_x
do j=0, field_size_y
read(fp, *) vfield(i,j,:)
end do
end do
end function
function updateParticle(velocity, old_particle) result(new_particle)
type(vector)::new_particle,old_particle,velocity
new_particle%x = old_particle%x + velocity%x
new_particle%y = old_particle%y + velocity%y
new_particle%z = old_particle%z + velocity%z
end function
subroutine writeResults(fp, particle)
integer::fp
type(vector)::particle
write(fp, *) particle%x, " ", particle%y, " ", particle%z
end subroutine
end module
This function
function readParticles(fp, num_particles) result(parray)
integer::fp, num_particles, i
type(vector),allocatable::parray(:)
allocate(parray(0:num_particles))
do i=0, num_particles
read(fp, *) parray(i)
end do
end function
allocates parray with index values 0:num_particles. Unfortunately, and this trips up many a newcomer to Fortran (some oldcomers too), those array bounds are not passed out to the calling code which will blithely assume an index range starting at 1. And then the code goes on to access parray(0) ... and the problem that John B warns of arises.
Fortran's capability of indexing arrays from an arbitrary integer value is never quite as useful as it seems. You can pass the bounds into and out of procedures, but who can be bothered ? Easier just to pretend that Fortran arrays index from 1 and apply that consistently throughout a program.
here is a simple version of what the OP is doing with allocate
module altest
contains
function setarray(n) result(x)
implicit none
integer, intent(in) :: n
integer , allocatable :: x(:)
allocate(x(n))
x(1)=1
end function
end module
program Console6
use altest
implicit none
integer,allocatable :: m(:)
m=setarray(2)
write(*,*)'m1',m(1)
end program Console6
It "appears" to be allocating an array x in the function and assigning that to an allocatable array m in the calling program. This compiles but throws a subscript out of bounds error on the write. (note this would likely be a seg fault if bounds checking is not enabled )
This can be fixed by separately allocating the array in the calling routine, or by passing the allocatable array as an argument:
module altest
contains
subroutine setarray(n,x)
implicit none
integer, intent(in) :: n
integer , allocatable :: x(:)
allocate(x(n))
x(1)=1
end subroutine
end module
program Console6
use altest
implicit none
integer,allocatable :: m(:)
call setarray(2,m)
write(*,*)'m1',m(1)
end program Console6
Edit - somewhat to my surprise, the second case works fine if we allocate with a zero lower bound in the sub allocate(x(0:n)) , the calling routine 'knows' the subscript starts at zero. ( Works with intel fortran v13 -- I have no Idea if this is a safe thing to do.. )
A segmentation fault normally indicates that your program is trying to access memory that does not belong to it.
When you say the error occurs "when I update the particle positions", I take it you mean this line:
updateParticle(vfield(INT(FLOOR(parray(j)%x)),INT(FLOOR(parray(j)%y)),INT(FLOOR(parray(j)%z))), parray(j))
An array-bounds violation in that statement seems entirely plausible, as I don't see anything in your code that would prevent the array indexes INT(FLOOR(parray(j)%x)) et al from falling outside the allocated dimensions of array vfield. Even if they are all in bounds at the initial step of the simulation, they may go out of bounds as the simulation proceeds.
Whether such a result in fact occurs appears to be data-dependent, not related to whether your functions appear in a module.
It looks like you have a C background. Could this be an off-by-one error? When looping in Fortran, the loop index goes all the way to the upper bound. Your Fortran loop:
do j=0, num_particles
! ...
end do
is equivalent to this C loop:
for (int j = 0; j <= num_particles; j++)
{
// ...
}
Note the <= sign, instead of <.
You may want to change your Fortran upper bound to num_particles - 1.

Error of mexfunction variables in an array of a structure variable

Recently, I tried to write mexfunctions using structure variables.
I watched the tutorial but got confused because of how the variable values are passed.
The following example (mexfunction_using_ex_wrong.m & mexfunction_using_ex_wrong.cpp) demonstrates how to fetch the variables passed from matlab in mexfunction.
However, in this case, the result is:
address i_c1=2067094464 i_c2=2067094464
i_c1=10 i_c2=10
address i_c1=1327990656 i_c2=2067100736
i_c1=2 i_c2=20
address i_c1=2067101056 i_c2=2067063424
i_c1=3 i_c2=30
As can be seen, the 1st element of the c1 & c2 array of a structure variable is accidentally the same.
But, in another example (mexfunction_using_ex_correct.m & mexfunction_using_ex_correct.cpp), the elements of array 1 (b1) and array 2(b2) of a structure variable are unrelated as I expect.
The result is:
address i_b1=1978456576 i_b2=1326968576
i_b1=1 i_b2=10
address i_b1=1978456584 i_b2=1326968584
i_b1=2 i_b2=20
address i_b1=1978456592 i_b2=1326968592
i_b1=3 i_b2=30
However, it's more common to use the 1st example in programming. so could anybody explain why in the 1st example the addresses of i_c1 & i_c2 are the same?
The following code is mexfunction_using_ex_wrong.m
clc
clear all
close all
mex mexfunction_using_ex_c_wrong.cpp;
a.b(1).c1=double(1);
a.b(2).c1=double(2);
a.b(3).c1=double(3);
a.b(1).c2=double(1);
a.b(2).c2=double(2);
a.b(3).c2=double(3);
mexfunction_using_ex_c_wrong(a);
The following code is mexfunction_using_ex_c_wrong.cpp
#include "mex.h"
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
int i, j, k;
double *i_c1;
double *i_c2;
// for struct variables(pointers) inside fcwcontext
mxArray *mx_b, *mx_c1, *mx_c2;
mx_b=mxGetField(prhs[0], 0, "b");
for(i = 0;i < 3;i=i+1)
{
mx_c1=mxGetField(mx_b, i, "c1");
mx_c2=mxGetField(mx_b, i, "c2");
i_c1=mxGetPr(mx_c1);
i_c2=mxGetPr(mx_c2);
*i_c2=(*i_c2)*10;
printf("address i_c1=%d i_c2=%d\n", i_c1, i_c2);
printf(" i_c1=%g i_c2=%g\n", *i_c1, *i_c2);
}
}
The following code is mexfunction_using_ex_c_correct.m
clc
clear all
close all
mex mexfunction_using_ex_correct.cpp;
a.b1(1)=double(1);
a.b1(2)=double(2);
a.b1(3)=double(3);
a.b2(1)=double(1);
a.b2(2)=double(2);
a.b2(3)=double(3);
mexfunction_using_ex_correct(a);
The following code is mexfunction_using_ex_c_correct.cpp
#include "mex.h"
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
int i, j, k;
double *i_b1;
double *i_b2;
mxArray *mx_b1, *mx_b2;
mx_b1=mxGetField(prhs[0], 0, "b1");
mx_b2=mxGetField(prhs[0], 0, "b2");
for(i = 0;i < 3;i=i+1)
{
i_b1=mxGetPr(mx_b1);
i_b2=mxGetPr(mx_b2);
i_b2[i]=i_b2[i]*10;
printf("address i_b1=%d i_b2=%d\n", &i_b1[i], &i_b2[i]);
printf(" i_b1=%g i_b2=%g\n", i_b1[i], i_b2[i]);
}
}
The addresses are not "accidentally the same" - they're intentionally the same, due to MATLAB's internal copy-on-write optimisations. If you look at the MEX documentation, you'll see warnings scattered around...
Do not modify any prhs values in your MEX-file. Changing the data in these read-only mxArrays can produce undesired side effects.
...in various forms...
Note Inputs to a MEX-file are constant read-only mxArrays. Do not modify the inputs. Using mxSetCell* or mxSetField* functions to modify the cells or fields of a MATLAB® argument causes unpredictable results.
...trying to make it very clear that you should absolutely not modify anything you recieve as an input. By calling mxGetPr() on input data and writing back to that pointer as you do with i_b2 and i_c2, you're getting right into that "unpredictable results" territory - if you look at a.b(1).c1 in the MATLAB workspace after the call, it'll really be 10 even though you "only" changed c2.
From MEX, you're looking at the raw data storage without any knowledge of, or access to, MATLAB's internal housekeeping, so the only safe way to modify anything is to use the mxCreate* or mxDuplicate* functions to get your own safe arrays you can then do whatever you want with, and pass back to MATLAB via plhs.
That said, I will admit to having abused in-place modification for a significant performance gain in one instance where I could guarantee my data was unique and unshared, but it's at best unsupported and at worst downright perilous.

Resources