1

This is my code:

Program Arrays

Implicit none

Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,3)::V_cvo
Complex,dimension(7,3)::V_cvo_temp


Do concurrent(i=0:7,j=1:3)

   V_cvo(i,j)=cmplx(i+j,2*i-j)

End Do

V_cvo_temp=V_cvo(1:,:)
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))

Stop
End Program Arrays

After compiling I got a this message:

Error: Different shape for array assignment  on dimension 1 (2 and 1)|

What is wrong here? If I want to find location of minimal element in some array in specific sector of that array how it is possible?

This could be one of the possible solution for the problem:

Program Arrays

Implicit none

Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,2)::V_cvo
Logical,dimension(0:7,2) :: lmask = .FALSE.

forall(i=2:5,j=1:2)lmask(i,j) = .TRUE.

Do concurrent(i=0:7,j=1:2)

   V_cvo(i,j)=cmplx(i+j,2*i-j)

End Do

V_Max = Maxloc(abs(V_cvo),mask=lmask)-(/1,0/)

Open(1,File='Output.txt',Status='Unknown')

Write(1,'(2x,i0,2x,i0)') V_max
Write(1,*)

Do concurrent(i=2:5,j=1:2)

   Write(1,'(1x,i0,1x,i0,2x,f7.4)')i,j,abs(V_cvo(i,j))

End Do

Close(1)

Stop
End Program Arrays

Output file is:

 5  1

 2 1   4.2426
 3 1   6.4031
 4 1   8.6023
 5 1  10.8167
 2 2   4.4721
 3 2   6.4031
 4 2   8.4853
 5 2  10.6301

Opinions about this?

3 Answers3

3

This expression

minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))

returns a rank-1 array with 1 element. The lhs of the assignments is a rank-1 array with 2 elements. Fortran won't assign incompatible arrays -- hence the compiler error message.

(@gdlmx's answer is subtly wrong in its diagnosis, if the expression returned a scalar Fortran would happily broadcast its value to every element of an array.)

If the expression did return a scalar it would still not return the location of the minimum element in that section of V_cvo. The sub-expression

(/((V_cvo_temp(i,j),j=1,3),i=2,5)/)

produces a rank-1 array containing the specified elements of V_cvo_temp, it essentially flattens the array into a vector and loses their locations along the way. This is why the first expression returns a rank-1 array with 1 element - it's the location of an element in a rank-1 array.

The problem with this solution

V_Min=minloc(abs(V_cvo(2:5,1:3)))

is that the expression abs(V_cvo(2:5,1:3)) will return a (temporary) array indexed, as Fortran arrays are by default, from 1 on each rank. When I try the code it returns the location (1,1) which appears to be outside the section considered. That's the location of the minimum element of the temporary array.

The problem with the 'clever' solutions I've tried has been that abs(V_cvo(2:5,1:3)) always returns, even if hidden from view, a temporary array indexed from 1 on each rank. Any application of minloc or similar functions uses those indices, not the indices that v_cvo uses. The best solution might be to make an explicit temporary array (suitably declared) like this:

allocate(abstemp(LBOUND(v_cvo,1):UBOUND(v_cvo,1),LBOUND(v_cvo,2):UBOUND(v_cvo,2)))

then

v_min = minloc(abstemp(2:5,1:3))

and

deallocate(abstemp)
High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
  • I understand.Definitly, your answer was correct but a can not find right solution for this problem.How to find minimal element in some section of array if array was indexed by o for first index?! –  Apr 24 '16 at 11:08
  • Great.Working with one little correction: `V_Min = MINLOC(ABS(V_cvo),mask=lmask)-1` Now he back a correct result. –  Apr 24 '16 at 12:23
  • With this steps code works fine so: First: `Logical,dimension(0:7,2) :: lmask = .FALSE.` Second: `forall(i=2:5,j=1:2)lmask(i,j) = .TRUE.` Third: `V_Min = Maxloc(abs(V_cvo),mask=lmask)-(/1,0/) ` After this shanges to the code I got right indexes. What is your opininion about this way? –  Apr 24 '16 at 15:50
1

It seems that the right side of

V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))

returns a scalar instead of a vector of 2 components. What you need is array slicing: V_cvo_temp(1:3,2:5)

V_Min=minloc(abs(V_cvo_temp(2:5,1:3)))

or simpler

V_Min=minloc(abs(V_cvo(2:5,1:3))) ! without temp array 

Also you don't need the stop at the end.

Edit1:

minloc returns the index relative to (1,1). To understand this behavior, try this example:

Program Hello
Implicit none
Integer,dimension(2)::V_Min
Complex,dimension(0:7,3)::V_cvo
V_cvo = cmplx(10,10)
V_cvo(3,2) = cmplx(0,0) ! the minimum index = [3,2]
V_Min=minloc(abs(V_cvo))
print *, 'minloc for whole array: ', V_Min
V_Min=minloc(abs(V_cvo(3:,2:)))
print *, 'minloc for sub-array:   ', V_Min
End Program Hello

It outputs:

minloc for whole array:            4           2 ! base index=[-1,0]
minloc for sub-array:              1           1 ! base index=[2,2]

So if passing a sub-array to minloc, you need to add your base index to get the 'correct' answer.

gdlmx
  • 6,479
  • 1
  • 21
  • 39
  • Thank you.This solution works well.How to do same thing with `V_cvo` without this step `V_cvo_temp=V_cvo(1:,:)`? –  Apr 24 '16 at 01:08
  • Glad that helps, please don't forget to approve the answer and cast your vote. – gdlmx Apr 24 '16 at 01:10
  • How to do same thing directly with `V_cvo` without this step `V_cvo_temp=V_cvo(1:,:)`? Result of this was wrong:`V_Min=minloc(abs(V_cvo(2:5,1:3)))` –  Apr 24 '16 at 01:15
  • But I want to find miniml in range from 2 to te 5 for first index and in range from 1 to 3 for second index of array `V_cvo`.Your last solution did not bring good result. –  Apr 24 '16 at 01:23
  • Sorry, you're right. I mix up the order. Since `V_cvo_temp` and `V_cvo` have different lower bound in dimension 1, you will probably get different index numbers – gdlmx Apr 24 '16 at 01:33
  • How to do this with array constructor? When I try with this:`V_Min=minloc(abs((/((V_cvo(i,j),j=1,3t),i=2,5)/)))` agot this message: `Error: Different shape for array assignment on dimension 1 (2 and 1)|` –  Apr 24 '16 at 01:39
  • Inline construction of 2d array is alittle tricky, pls refer to this [post](http://stackoverflow.com/questions/3708307/how-to-initialize-two-dimensional-arrays-in-fortran) But I suggest you to avoid it if there is other altenatives – gdlmx Apr 24 '16 at 01:42
0

This solution also works fine (best maybe):

forall(i=1:7,j=1:3) V_cvo_temp(i,j)=abs(V_cvo(i,j))
V_Min = MINLOC(V_cvo_temp(m:n,:))+(/m-1,0/)

Code are correct for every m and n if they are in interval 1:7 for this case or in some other interval.