What is wrong with array(2:)(::2) in fortran? - arrays

I am learning Fortran08 and am puzzled as to why I cannot execute the following
integer :: array(8)
READ(*, *) array
array(2:)(::2)
, but the following works fine
integer :: array(8)
integer :: temp(7)
READ(*, *) array
temp = array(2:)
temp(::2)

The answer is simple, but I don't know if that much useful. It simply is not legal Fortran syntax.
Why is it so? Because the standard says so. And why? Because the committee designed it that way. Why? You have to ask them, but note that there may be a clash with string array indexing.
Fortran simply does not use consecutive array indexing parentheses, unlike C. The array syntax of Fortran and C is very different in multiple aspects.
Doesn't array(2::2) achieve what you need?

Related

Native Fortran type signature for "list of variable length strings"?

In Fortran, is there any way to declare an "array of allocatable arrays", that doesn't require wrapping the allocatable arrays into a derived type?
My main use-case would be to allow invoking a function with an array of variable-length strings, i.e. I am looking for a type signature matching the literal
["Hello", &
"World.", &
"How are you?"]
Motivation
In Fortran strings are natively represented as fixed-size character arrays, padded with blanks on the right. Arrays of strings are normally represented as arrays of (equal-length) character arrays, which I assume is in order to make them behave like a matrix of characters.
However, this also means that doing something like
CALL mySubroutine(["Hello","World.","How are you?"])
will result in a compiler error like
Error: Different CHARACTER lengths (5/4) in array constructor at (1)
A commonly suggested workaround (see e.g. Return an array of strings of different length in Fortran) is to use an array of derived types instead, e.g.
TYPE string
CHARACTER(LEN=:), ALLOCATABLE :: chars
END type string
! ...
CALL myStringSubroutine([string("Hello"), &
string("World."), &
string("How are you?")])
However, since there is no standardized string type of this kind, I am much more frequently seeing APIs using natively supported "workarounds" such as using fixed-size character strings, and trimming them when used. In this case the invocation would look like
CALL myFixedSubroutine(["Hello ", &
"World. ", &
"How are you?"])
While this is no problem in principle, it can become awkward and inefficient, if one of the strings is much longer than the others. It also has implications for version control, where now changing "... you?" to "... you??" means that the padding of the other lines has to be changed, creating spurious diffs.
(In the comments, a suggestion was given that at least automates the whitespace-padding.)
No, there is no way bar the wrapper type.
A fundamental concept in the language is that elements within an array may only vary in value. The allocation status of an object is not part of the value of that object.
(The allocation status of a component is part of the value of the object that has the component.)
A varying length string type is described in Part 2 of the Fortran standard.

Is possible to convert a string from array of pointers to variable names?

I'm looking to solve a math equation given as string to array of pointers like
char* equations = {"n+1", "n+2", "n*n+3"}
I want the compiler to consider strings inside the above character array as variables e.g "n" is a variable. So, when I assign this string to an 'int' so they will act like a mathematical operation like this:
int a = n+1;
I was thinking the below method could work, but it is definitely not working because we can't assign a pointer's array to int. Even it did, but it's taking just the codes of it like A=65, but this is not my requirement:
a = equations[0]; //(compiler assume it like a = n+1)
The compiler cannot do that for you, you will have to parse the strings into their components (variables, constants, operators) and then apply the appropriate operations yourself.
there are many ways to do this, for example you could parse each expression do some pattern matching and then create and expression from this, which is of course much easier said than done.
But I've found a library that I've not tested yet that do what you want(Or promise to do so), here is the link:
http://partow.net/programming/exprtk/index.html
No, what you want is not possible, because, in a compiled version of a C code, the notion of a "variable name" does not exist.
If you want to achieve this sort of things, you have to do this before you head into the compilation part, i.e, during the pre-processing part.
Otherwise, a more flexible way of achieving what you "probably" want is to make use of function pointers (as "callbacks", if you prefer). You can have different functions defined to do certain jobs and then, at run-time, you can choose any of the already defined functions to be called / invoked and collect the result in the desired variable.

Define array from a bigger one in Fortran

I have a 4-dimensional array in Fortran called covi It is declared as:
real, dimension(10,10,2,2) :: covi
and computed in a certain way.
At some point, I need to take 2-dimensional slices of that array, lke for example covi(1,1,:,:), covi(3,4,:,:),covi(7,5,:,:), etc.
I have declared another variable real, dimension(2,2) :: cov and written cov=covi(7,5,:,:) but this is not working. It gives the following error message:
error #6366: The shapes of the array expressions do not conform. [COVI]
covi = cov(i1,i2,:,:)
In Matlab this notation works perfectly. It is pretty intuitive. How does one achieve this in Fortran?
Thanks

How to concatenate two arrays in Fortran 90

I have an original array called pres_lev3d, whose size is defined by pres_lev3d(im*jm, levsi), where im*jm is 72960 and levsi is 64. This corresponds to global atmospheric data, thus the size. The array is allocatable: real (kind=kind_io8), allocatable :: pres_lev3d(:, :). I have a second array, press_1d, whose size is also defined in a similar fashion pres_1d(im*jm, levsi), but in this array levsi is 1.
I need to concatenate both arrays (technically a 2d and 1d array) to an array of the shape (/72960, 65/). In MATLAB this seems like a very simple process, however, I can't seem to find an easy way to go around it in Fortran 90.
I have tried to create a third array
pres_lev=(/pres_lev3d, pres_1d/)
and also tried to use merge, but none of these approaches seem to work out.
I am fairly new to Fortran.
If I've followed your explanation correctly this would probably work
real(kind_io8), dimension(72960,65) :: out_array
...
out_array(:,1:64) = pres_lev3d
out_array(:,65) = pres_1d
If that's not easy enough, or if I've misunderstood your question, explain further. To allocate out_array to conform to your input arrays, try something like
real(kind_io8), dimension(:,:), allocatable :: out_array
...
allocate(out_array(size(pres_lev3d,1),size(pres_lev3d,2)+1))
...
out_array(:,1:64) = pres_lev3d
out_array(:,65) = pres_1d

Passing c arrays into fortran as a variable sized matrix

So, i've been commissioned to translate some fortran subroutines into C. These subroutines are being called as part of the control flow of a large porgram based primarily in C.
I am translating the functions one at a time, starting with the functions that are found at the top of call stacks.
The problem I am facing is the hand-off of array data from C to fortran.
Suppose we have declared an array in c as
int* someCArray = (int*)malloc( 50 * 4 * sizeof(int) );
Now, this array needs to be passed down into a fortran subroutine to be filled with data
someFortranFunc( someCArray, someOtherParams );
when the array arrives in fortran land, it is declared as a variable sized matrix as such:
subroutine somefortranfunc(somecarray,someotherparams)
integer somefarray(50,*)
The problem is that fortran doesn't seem to size the array correctly, becuase the program seg-faults. When I debug the program, I find that indexing to
somefarray(1,2)
reports that this is an invalid index. Any references to any items in the first column work fine, but there is only one available column in the array when it arrives in fortran.
I can't really change the fact that this is a variable sized array in fortran. Can anyone explain what is happening here, and is there a way that I can mitigate the problem from the C side of things?
[edit]
By the way, the fortran subroutine is being called from the replaced fortran code as
integer somedatastorage(plentybignumber)
integer someindex
...
call somefarray(somedatastorage(someindex))
where the data storage is a large 1d array. There isn't a problem with overrunning the size of the data storage. Somehow, though, the difference between passing the C array and the fortran (sub)array is causing a difference in the fortran subroutine.
Thanks!
Have you considered the Fortran ISO C Binding? I've had very good results with it to interface Fortran and C in both directions. My preference is to avoid rewriting existing, tested code. There are a few types that can't be transferred with the current version of the ISO C Binding, so a translation might be necessary.
What it shouldn't be that others suggested:
1. Size of int vs. size of Integer. Since the first column has the right values.
2. Row vs. column ordering. Would just get values in wrong order not segmentation faulted.
3. Reference vs value passing. Since the first column has the right values. Unless the compiler is doing something evil behind your back.
Are you sure you don't do this in some secret way?:
someCArray++
print out the value of the someCArray pointer right after you make it and right before you pass it. You also should print it out using the debugger in the fortran code just to verify that the compiler is not generating some temporary copies to help you.

Resources