Skip to content

Conversation

@AlexBuccheri
Copy link

This MR does two separate things:

  • Several commits, removing several gfortran compiler warnings
  • One commit replacing MPI_INIT with MPI_Init_thread, where I request the maximum threading support

W.r.t. compiler warnings, most of the changes silence false positives resulting from implicit LHS allocation. In these cases, I've just added explicit allocate statements. A couple others are from unused arguments. In one instance, I've removed an argument (see the logger) and in the other I'm assigned a dummy attribute.

W.r.t. replacing MPI_INIT with MPI_Init_thread. There's no obvious reason (to me) not to do this, and if a consumer/client code initialises with anything other than MPI_THREAD_SINGLE, this is required. As such, I initialise with MPI_THREAD_MULTIPLE, which should maximise support.

It is still the client code's responsibility to check what's actually provided by the MPI library, and handle appropriately:

    call MPI_Query_thread(provided)
    if (provided < required) then
      call MPI_Comm_rank(MPI_COMM_WORLD, rank)
      if (rank == 0) write(*, '(a)') 'MPI library threading support is less than required by <MY CODE>'
      call MPI_Abort(MPI_COMM_WORLD, 1, ierr)
    end if
``





 

Copy link
Member

@aradi aradi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the PR! This PR should be split into 2 separate ones:

  • Compiler warning workarounds
  • MPI-initialization
    as the two features are completely unrelated.

As for the compiler warnings: I am not a big fan of writing workarounds to avoid false positive compiler warnings. I am fine with the explicit allocate() statements (to avoid automatic lhs-(re)allocation), but I would not prefer to incorporate the other changes (the string addition and the placeholder local instance variable.)

For the MPI initialization, see the detailed comment below, I think the solution proposed there would be more elegant and robust.

.gitignore Outdated
/_*
/build
*.mod
/cmake-*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How and why are files matching this pattern generated during code development or build? (The .gitignore of the repository should only contain patterns, which are generated during the common development workflow.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a Jetbrains convention for cmake build folder names. It's relatively common, but not defacto. I can drop the commit if you prefer.

Comment on lines 29 to 30
!> State of global random number
integer :: rn = 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this example is there to demonstrate the usage of module variables to pass initialization information. We should, therefore, explicitly do not create a variable within the type, in order to make the example clearer. (What is the actual reason for adding this (unused) instance variable?)

Copy link
Author

@AlexBuccheri AlexBuccheri Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've got a type-bound procedure that does not use this.

Happy to roll back the change

Comment on lines 169 to 170
allocate(match(size(value1, dim=1), size(value1, dim=2)))
match = value1 == value2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
allocate(match(size(value1, dim=1), size(value1, dim=2)))
match = value1 == value2
allocate(match(size(value1, dim=1), size(value1, dim=2)))
match(:,:) = value1 == value2

Whenever lhs reallocation is not wanted (because lhs had been already allocated) or not possible (because lhs is not allocatable), the placeholder indices should be used for arrays on the lhs. This makes the intention of assigning into more pronounced.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this only occur when the LHS is an allocatable variable being assigned a value whose shape/length doesn’t match its current allocation (like, the LHS not being allocated)? In this case, a shape mismatch is impossible because you have if-statements guarding against it.

But happy to make the change

Comment on lines 47 to 48
allocate(match(size(value1, dim=1)))
match = value1 == value2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
allocate(match(size(value1, dim=1)))
match = value1 == value2
allocate(match(size(value1, dim=1)))
match(:) = value1 == value2


! Note: factorial(n) with n > 13 overflows with 32 bit integers
nn = int(13 * rand) + 1
this%rn = nn
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed, as we do not want to use variables within the type instance in this example.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Comment on lines 205 to 206
allocate(match(size(value1, dim=1), size(value1, dim=2)))
match = is_close_elem(value1, value2, atol=atol, rtol=rtol)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
allocate(match(size(value1, dim=1), size(value1, dim=2)))
match = is_close_elem(value1, value2, atol=atol, rtol=rtol)
allocate(match(size(value1, dim=1), size(value1, dim=2)))
match(:,:) = is_close_elem(value1, value2, atol=atol, rtol=rtol)

Comment on lines 241 to 242
allocate(match(size(value2, dim=1), size(value2, dim=2)))
match = is_close_elem(value1, value2, atol=atol, rtol=rtol)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
allocate(match(size(value2, dim=1), size(value2, dim=2)))
match = is_close_elem(value1, value2, atol=atol, rtol=rtol)
allocate(match(size(value2, dim=1), size(value2, dim=2)))
match(:,:) = is_close_elem(value1, value2, atol=atol, rtol=rtol)

Comment on lines +173 to +175
! & helpmsg="list of tests and suites to include or to exclude when prefixed with '~' (e.g. " //&
! & "'somesuite ~somesuite/avoidedtest' would run all tests except 'avoidedtest' in the test " //&
! & "suite 'somesuite')")&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we use sting addition, if Fortran has a perfect feature of breaking strings into continuation lines? I don't see the point for this change...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it makes no sense, but GCC with warnings enabled will catch what you currently have. Unlike most of the warning fixes, which affect fortuno's test cases (we don't build by default), this one gets caught by Octopus's CI.

So the point is either client codes are forced into disabling specific warnings or one does a trivial patch upstream. Alternatively, we discussed scoping compiler flags on a per library basis some time ago, but since Cristian's left, this is a non-starter.

Comment on lines +183 to +185
& helpmsg="list of tests and suites to include or to exclude when prefixed with '~' (e.g. " // &
& "'somesuite ~somesuite/avoidedtest' would run all tests except 'avoidedtest' in the test " // &
& "suite 'somesuite')")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment just above. Let's keep the original form, unless there is a really convincing argument for the change.


call MPI_Init(ierror)
if (ierror /= 0) error stop "MPI_Init failed in init_mpi_env"
call MPI_Init_thread(MPI_THREAD_MULTIPLE, provided)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with this approach is, that if the client is using the high level runner routine execute_mpi_cmd_app(), it has no way to check before the tests start, whether the MPI framework provides the necessary level of thread support. So, it is safer here to use the lowest possible threading level (MPI_THREAD_SINGLE, which must work, if the MPI framework works at all). This is also the level of threading support Fortuno requires.

In order to allow codes to use a more advanced threading support, we should allow clients to initialize the MPI-framework before calling execute_mpi_cmd_app() and pass then the global communicator (as optional argument) to execute_mpi_cmd_app(). Fortuno should then just use the provided communicator without initializing or finalizing the MPI framework. The client would then also be responsible for the finalization of the MPI framework after the call.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it has no way to check before the tests start, whether the MPI framework provides the necessary level of thread support.

How does this prevent the caller from calling execute_mpi_cmd_app , followed by a setup that calls MPI_Query_thread?

Fortuno should then just use the provided communicator without initializing or finalizing the MPI framework. The client would then also be responsible for the finalization of the MPI framework after the call.

As discussed over email, I'm fine with this idea. I'll open a separate PR for it

@AlexBuccheri
Copy link
Author

For the MPI initialization, see the detailed comment below, I think the solution proposed there would be more elegant and robust.

I'll drop the commit and open a separate PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants