Befor finding an answer for the quesion I asked before, I wrote very simple code for very sime mesh(there are just two triangles) as below to call C function in fortran. For the simplicity of code. Neither interface module here nor iso_c_binding(as possible as) isn't used here. It is very similar to this post, There is another error.
program METIS_NoInterface
implicit none
integer :: ne, nn
integer, dimension(:), allocatable :: eptr, eind
integer, pointer :: vwgt=>null(), vsize=>null()
integer :: nparts
real, pointer :: tpwgts=>null()
integer, dimension(0:39) :: opts
integer :: objval
integer, dimension(:), allocatable :: epart, npart
! Input => 2 tri: too small mesh
!ne = 2
!nn = 4
!nparts = 2
!allocate(eptr(0:2), eind(0:5))
!eptr=[0, 3, 4]
!eind=[0,1,3,1,2,3]
! Output
!allocate(epart(0:1), npart(0:4))
! Input => 4 quad : reasonable result
ne = 4
nn = 9
nparts = 2
allocate(eptr(0:ne), eind(0:15))
eptr=[0,4,8,12,16]
eind=[0,1,8,7,1,2,3,8,3,4,5,8,5,6,7,8]
! Output
allocate(epart(0:ne-1), npart(0:nn-1))
! METIS function call
call METIS_SetDefaultOptions(opts)
!call METIS_PartMeshNodal(ne,ne,eptr,eind,vwgt,vsize,nparts,tpwgts,& !<=syntax error
call METIS_PartMeshNodal(ne,nn,eptr,eind,vwgt,vsize,nparts,tpwgts,&
opts,objval,epart,npart)
! Result print
write(*,*) epart
write(*,*) ''
write(*,*) npart
write(*,*) ''
end program
It gives access violation error because of eind. It runs anyway if c_null_ptr are passed instead of eind. The size of array eind and number of elements are coincident. How can it be fixed? => resolved. Thank you!
The problem I had was systax error on calling METIS_PartMeshNodal, the 2nd argument was ne which is the same the 1st argument ne. It should have been nn.
Solution was to replace the 2nd argument to nn. Above code can be compiled and executed.
NOTE: Too small mesh may not have reasonable solution due to METIS' scheme.
Please refer another post in order to use interface module.
Related
I am trying to code a computationally efficient PACK operation over a polymorphic array and I am running on issues with gfortran 9.2.0:
The PACK operation has to work on a polymorphic array of a derived type quantity, and return a result on itself
For reasons I'm not explaining here, this array should not be reallocated
In general, there is overlap between the locations of the returned indices, and those of the original array: something like array(1:5) = array([2,4,6,8,10])
I'm having problems, as the only version of the assigment I've tried with gfortran is with a loop - all array-based version either produce compiler or runtime segfaults.
An example is reported in this program:
module m
implicit none
type, public :: t
integer :: i = 0
contains
procedure, private, pass(this) :: t_assign => t_to_t
generic :: assignment(=) => t_assign
end type t
type, public, extends(t) :: tt
integer :: j = 0
contains
procedure, private, pass(this) :: t_assign => t_to_tt
end type tt
contains
elemental subroutine t_to_t(this,that)
class(t), intent(inout) :: this
class(t), intent(in ) :: that
this%i = that%i
end subroutine t_to_t
elemental subroutine t_to_tt(this,that)
class(tt), intent(inout) :: this
class(t ), intent(in ) :: that
this%i = that%i
select type (thatPtr=>that)
type is (t)
this%j = 0
type is (tt)
this%j = thatPtr%j
class default
! Cannot stop here
this%i = -1
this%j = -1
end select
end subroutine t_to_tt
end module m
program test_poly_pack
use m
implicit none
integer, parameter :: n = 100
integer :: i,j
class(t), allocatable :: poly(:),otherPoly(:)
allocate(t :: poly(n))
allocate(t :: otherPoly(10))
! Assign dummy values
forall(i=1:n) poly(i)%i = i
! Array assignment with indices => ICE segfault:
! internal compiler error: Segmentation fault
otherPoly(1:10) = poly([10,20,30,40,50,60,70,80,90,100])
! Scalar assignment with loop -> OK
do i=1,10
otherPoly(i) = poly(10*i)
end do
! Array assignment with PACK => Compiles OK, Segfault on runtime. GDB returns:
! Thread 1 received signal SIGSEGV, Segmentation fault.
! 0x000000000040163d in m::t_to_t (this=..., that=...) at test_poly_pack.f90:31
! 31 this%i = that%i
otherPoly(1:10) = pack(poly,mod([(j,j=1,100)],10)==0)
do i=1,10
print *, ' polymorphic(',i,')%i = ',otherPoly(i)%i
end do
end program test_poly_pack
Am I doing anything wrong, and/or is this only a compiler bug or there is any best practices I should be following?
The crashes are compiler bugs. When the compiler says internal compiler error ... Please submit a full bug report, you really can trust it and you should act accordingly (and submit the bug report). The runtime crash is a compiler bug as well (wrong code).
If you know the actual types at the time of the assignment, you can use type guards
select type (p => poly)
type is (t)
select type(op => otherpoly)
type is (t)
op(1:10) = pack(p,mod([(j,j=1,100)],10)==0)
end select
end select
If you need it to be polymorphic - you probably have to reallocate
allocate(otherPoly(1:10),source = pack(poly,mod([(j,j=1,100)],10)==0))
until the bugs you hopefully reported are fixed.
I am trying to implement a python-type in operator that checks whether a 1D array contains a certain element. In principle I got this to work, but I'm having trouble covering both types of arrays that I want to work with, namely fixed-size arrays and allocatable arrays. Below I have a code that almost does what I want:
MODULE operator_in
IMPLICIT NONE
INTERFACE OPERATOR(.IN.)
MODULE PROCEDURE in_integer_list
! MODULE PROCEDURE in_integer_list_alloc
END INTERFACE OPERATOR(.IN.)
CONTAINS
FUNCTION in_integer_list(key, list) RESULT(res)
IMPLICIT NONE
INTEGER, INTENT(IN) :: key
INTEGER, INTENT(IN) :: list(:)
LOGICAL :: res
INTEGER :: ii
res = .FALSE.
DO ii = 1,SIZE(list)
IF (key == list(ii)) THEN
res = .TRUE.
RETURN
END IF
END DO
END FUNCTION in_integer_list
FUNCTION in_integer_list_alloc(key, list) RESULT(res)
IMPLICIT NONE
INTEGER, INTENT(IN) :: key
INTEGER, ALLOCATABLE, INTENT(IN) :: list(:)
LOGICAL :: res
IF (ALLOCATED(list)) THEN
res = in_integer_list(key, list)
ELSE
res = .FALSE.
END IF
END FUNCTION in_integer_list_alloc
END MODULE operator_in
PROGRAM test
USE operator_in
INTEGER :: list1(5) = (/1, 4, 6, 3, 8/)
INTEGER, ALLOCATABLE :: list2(:), list3(:)
INTEGER :: ii
ALLOCATE(list2(7))
list2(:) = (/8,7,6,5,4,2,1/)
DO ii = 1,5
IF (ii .IN. list1) THEN
WRITE (*,'(I3,A,5I3)') ii, ' is in ', list1
END IF
IF (ii .IN. list2) THEN
WRITE (*,'(I0.3,A,7I3)') ii, ' is in ', list2
END IF
! IF (ii .IN. list3) THEN
! WRITE (*,'(I3,A,7I3)') ii, ' is in ', list3
! END IF
END DO
END PROGRAM test
As is, the code produces the following output:
1 is in 1 4 6 3 8
1 is in 8 7 6 5 4 2 1
2 is in 8 7 6 5 4 2 1
3 is in 1 4 6 3 8
4 is in 1 4 6 3 8
4 is in 8 7 6 5 4 2 1
5 is in 8 7 6 5 4 2 1
However, if I un-comment the last three lines,
IF (ii .IN. list3) THEN
WRITE (*,'(I0.3,A,7I3)') ii, ' is in ', list3
END IF
the code crashes with a segmentation fault, because list3 is not allocated:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x10925ebe4
#1 0x10925e306
#2 0x7fff5e878b5c
#3 0x1092547da
#4 0x109254bc5
#5 0x109254cce
Segmentation fault: 11
I tried to fix this by writing a second function (in_integer_list_alloc) that allows for allocatable arrays, but declaring both functions in my interface:
INTERFACE OPERATOR(.IN.)
MODULE PROCEDURE in_integer_list
MODULE PROCEDURE in_integer_list_alloc
END INTERFACE OPERATOR(.IN.)
gives me an ambiguity error:
FUNCTION in_integer_list(key, list) RESULT(res)
1
user-defined_operator.f90:27:2:
FUNCTION in_integer_list_alloc(key, list) RESULT(res)
2
Error: Ambiguous interfaces in operator interface 'in' for 'in_integer_list' at (1) and 'in_integer_list_alloc' at (2)
And if I comment out the first procedure in the interface:
INTERFACE OPERATOR(.IN.)
! MODULE PROCEDURE in_integer_list
MODULE PROCEDURE in_integer_list_alloc
END INTERFACE OPERATOR(.IN.)
I of course get problems with the fixed-size array, list1:
IF (ii .IN. list1) THEN
1
Error: Operands of user operator 'in' at (1) are INTEGER(4)/INTEGER(4)
So: Is there a clever way to achieve what I want or at least get a proper error message when the code crashes because the passed array is not allocated?
Ideally, redesign your code such that there is no need to deal with an unallocated array. If you want to represent an empty list, use a allocated zero size array.
(An unallocated object is a better conceptual fit to "there is no list", rather than an "the list is empty". Conceptually, you should not be querying something that doesn't exist.)
If you must, you could write a single argument adapter function along the line of the following:
FUNCTION foo(arg)
INTEGER, INTENT(IN), OPTIONAL:: arg(:)
INTEGER, ALLOCATABLE :: foo(:)
IF (PRESENT(arg)) THEN
foo = arg
ELSE
foo = [INTEGER ::]
END IF
END FUNCTION foo
The adapter could then be used:
IF (item .in. foo(list)) THEN
...
Appropriate naming of the adapter function is left to the reader.
(The adapter has been written with the dummy argument OPTIONAL, to accommodate actual argument not present, actual argument not allocated and actual argument dissociated. This is a Fortran 2008 feature.)
NB: This answer has a flaw, as pointed out in the comments. I will leave it here so that other readers might avoid making the same mistake.
Being a Python user, I can also appreciate the syntactic sugar that an .in. operator could provide. That said, standard Fortran is also quite concise:
if (any(items==value)) then
...
endif
However, here is one way to implement .in. that should handle both fixed-size and allocatable arrays:
module operator_in
implicit none
interface operator(.in.)
module procedure operatorin
end interface operator(.in.)
contains
logical function operatorin(v,lst) result(found)
implicit none
integer, intent(in) :: v
integer, intent(in) :: lst(:)
integer, allocatable :: temp(:)
found = .false.
allocate(temp,source=lst)
if (size(temp)>0) then
if (any(temp == v)) found=.true.
endif
end function operatorin
end module operator_in
Notes: I use the allocatable temp array so that if compiled with check:all (or similar) the code will run without error messages. Also, I use any to avoid manually looping over the list of items. Try it out, it's nice.
I am having a problem trying to use subsets of an array containing instances of a type in Fortran. Creating the subset renders the contents garbage. Essentially it boils down to:
class(myType), allocatable :: instances(:)
...allocate/initialize instances here...
doSomethingWithInstances( instances ) ! Works
doSomethingWithInstances( instances((/1,2/)) ) ! Doesn't work
Here is a complete code that reproduces the problem, in this code the correct output is the values of the integers assigned to each of the instances i.e "3, 8, 16", when the subroutine is called on the subset (/1,2/) of the array it should therefore print "3, 8" however it instead prints "3, 192552":
module test
! Simple type contains integer
type :: myType
integer :: n
end type
contains
! Output the integer for myType t
subroutine saySomething(t)
class(myType) :: t
print *, t%n
end subroutine
end module
program main
use test
type(myType), allocatable :: instances(:)
! Declare an array of myType
allocate(instances(3))
instances(1) = myType(3)
instances(2) = myType(8)
instances(3) = myType(16)
! call saySomething for each element
! on the direct array and on the subset
! elements 1 and 2
print *, "Working:"
call saySomethingArray(instances)
print *, "Broken:"
call saySomethingArray(instances((/1,2/))) ! Here is the problem
contains
! Call saySomething on each element of the input array
subroutine saySomethingArray(instances)
class(myType) :: instances(:)
integer :: i
do i=1,size(instances)
call saySomething(instances(i))
enddo
end subroutine
end program
I wondered if it wasn't copying things correctly or something when it creates the subset, but I couldn't figure it out. Any help would be greatly appreciated :) cheers
In these cases please always tell us what is your compiler, its version and all flags used for compiling. This is a compiler bug. I can reproduce it with GCC 7. It runs correctly with Intel Fortran 16.
As a workaround, the error will go away if you declare instances in saySomethingArray as type instead of class. Also, printing the array as an array expression works correctly.
The problem also appears for other kinds of array expressions, not just vector subscripts.
Reported to GCC as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84074. Maybe it will turn up to be a duplicate of some earlier bug. This is the MCVE ([mcve]):
type :: t
integer :: n
end type
type(t) :: array(2) = [t(1),t(2)]
call sub(array((/1,2/)))
contains
subroutine sub(a)
class(t) :: a(:)
integer :: i
print *, "loop a(i) :"
do i=1,size(a)
print *,a(i)%n
enddo
print *, "a%n :",a%n
print *, "a(1:size(a))%n :",a(1:size(a))%n
end subroutine
end program
Output:
> gfortran-7 vecsubs2.f90
> ./a.out
loop a(i) :
2
0
a%n : 1 2
a(1:size(a))%n : 1 2
I am trying to write a program where I want the allocatable array A to be of either rank 1, 2, or 3, depending on my input at run-time. I want to do this since the subsequent operations on A are similar, and I have defined in a module an interface work with module procedures that when acted on A, gives the desired result.
What I am doing currently is this:
program main
implicit none
integer :: rank,n=10
real*8, allocatable :: A1(:)
real*8, allocatable :: A2(:,:)
read (*,*) rank
if (rank.eq.1) then
allocate (A1(n))
else if (rank.eq.2) then
allocate (A2(n,n))
end if
! operate on the array
if (rank.eq.1) then
call work(A1)
else if (rank.eq.2) then
call work(A2)
end if
end program
Things would be much easier if somehow I could choose the rank of A, as then the if statements are not needed. Maybe this is not possible, but all help are appreciated.
The next Fortran standard (2015) has the select rank construct similar to select case. My example uses the select case construct on the rank intrinsic of an assumed-rank dummy variable.
module my_type
use, intrinsic :: iso_fortran_env, &
ip => INT32, &
wp => REAL64
implicit none
private
public :: MyType
type MyType
real (wp) :: rank0
real (wp), allocatable :: rank1(:)
real (wp), allocatable :: rank2(:,:)
real (wp), allocatable :: rank3(:,:,:)
contains
procedure :: create => create_my_type
procedure :: destroy => destroy_my_type
end type MyType
contains
subroutine create_my_type(this, array)
! calling arguments
class (MyType), intent (in out) :: this
real (wp), intent (in) :: array(..) !! Assumed-rank dummy variable
! local variables
integer (ip), allocatable :: r(:)
select case(rank(array))
case (0)
return
case (1)
r = shape(array)
allocate( this%rank1(r(1)) )
case (2)
r = shape(array)
allocate( this%rank2(r(1), r(2)) )
case (3)
r = shape(array)
allocate( this%rank3(r(1), r(2), r(3)) )
case default
error stop 'array must have rank 0,1,2, or 3'
end select
! Release memory
if (allocated(r)) deallocate( r )
end subroutine create_my_type
subroutine destroy_my_type(this)
! calling arguments
class (MyType), intent (in out) :: this
if (allocated(this%rank1)) deallocate( this%rank1 )
if (allocated(this%rank2)) deallocate( this%rank2 )
if (allocated(this%rank3)) deallocate( this%rank3 )
end subroutine destroy_my_type
end module my_type
program main
use, intrinsic :: iso_fortran_env, only: &
ip => INT32, &
wp => REAL64
use my_type, only: &
MyType
implicit none
type (MyType) :: foo
real (wp) :: a0, a1(42), a2(42,42), a3(42,42,42)
print *, rank(a0)
print *, rank(a1)
print *, rank(a2)
print *, rank(a3)
! Allocate array of rank 3
call foo%create(a3)
print *, rank(foo%rank3)
print *, shape(foo%rank3)
print *, size(foo%rank3)
! Release memory
call foo%destroy()
end program main
Declare the array to be rank three. If a lower rank array is required, allocate the relevant trailing dimensions to be of size one.
real, allocatable :: array(:,:,:)
...
select case (desired_rank)
case (1) ; allocate(array(n,1,1))
case (2) ; allocate(array(n,n,1))
case (3) ; allocate(array(n,n,n))
case default ; error stop 'bad desired rank'
end select
You can then use an array section to get a contiguous slice of array that is consistent with your desired rank. Alternatively, write the relevant procedures that operate on array to take a rank three argument, and make them aware of the meaning of a size one extent for the higher dimensions.
I want to write something like :
b=0e0
do j=1,n
b(j,j) = f(x)*real(j)
end do
in an impicit way like, say
b=0e0
(b(j,j)=f(x)*real(j),j=1,n)
which isn't working. If the r.h.s. of the expression doesn't depend on j, I can of course do this:
b=0e0
c([(k,k=1,n*n,n+1)])=f(x)
b=reshape(c,shape(b))
but I'd love to have a more elegant and flexible one lined way, like a FORALL statement, e.g.
b=0e0
FORALL (j=1:n) b(j,j)=f(x)*real(j)
, but this is unfortunately a bit too restricted for the case where I need it. For the purpose of initialization there is something called DATA statement, which so far also didn't help me.
Thanks in advance!
You can define a subroutine that sets the diagonal of a matrix to a vector, as shown below.
program xdiag
implicit none
integer, parameter :: n = 3
real :: xmat(n,n) = 0.0
integer :: i
call set_diag([1.0,4.0,9.0],xmat)
do i=1,n
print*,xmat(i,:)
end do
contains
subroutine set_diag(diag,xmat)
real, intent(in) :: diag(:)
real, intent(in out) :: xmat(:,:)
integer :: i,n
n = size(diag)
if (any(shape(xmat) /= n)) then
print*,"in set_diag, size(diag) =",size(diag)," shape(xmat)=",shape(xmat)," should all be equal, STOPPING"
stop
end if
forall (i=1:n) xmat(i,i) = diag(i)
end subroutine set_diag
end program xdiag
! output:
! 1. 0. 0.
! 0. 4. 0.
! 0. 0. 9.