Trouble understanding listing 7.2 and 7.3 in modern Fortran book

Hi @milancurcic
I am on page 185 and 186 of the Modern Fortran book, and I can’t understand how the Coarrays work exactly.

  1. If the Coarray is shared between all images, why do we need to gather the data from all images into one gather variable ? Doesn’t the data synchronize ?
  2. If we have a large set of data for example, is it advisable to pack it all on one image ?

Thanks

1 Like

Hi @Aurelius_Nero, I’ll write more when I have the book in front of me (I don’t remember what I wrote there), but just short comments for now:

  1. Every image has its own, independent, copy of every variable. Coarrays are variables whose values can be copied between the images using the coarray syntax (square brackets for indexing). The data won’t synchronize automatically–you need to do that explicitly in the code.
  2. In general, yes, you would gather on one image only the data that you need on that image. This could be for I/O, further calculations, or other reasons.
1 Like

Here’s the complete program from the listings 7.2-7.3 from GitHub (helper modules not included):

program weather_stats_parallel

  use mod_arrays, only: denan, mean
  use mod_io, only: read_buoy
  use mod_parallel, only: tile_indices

  implicit none

  character(len=5), allocatable :: ids(:)
  character(len=20), allocatable :: time(:)
  real, allocatable :: wind_speed(:)
  real, allocatable :: max_wind(:), mean_wind(:)
  real, allocatable :: gather(:)[:]
  integer :: is, ie, indices(2)
  integer :: i

  real :: min_mean_wind, max_mean_wind, max_max_wind

  ids = ['42001', '42002', '42003', '42020', '42035',&
    '42036', '42039', '42040', '42055']

  if (num_images() > size(ids)) error stop 'Error: Too many images'

  indices = tile_indices(size(ids))
  is = indices(1)
  ie = indices(2)

  allocate(max_wind(is:ie), mean_wind(is:ie))

  do i = is, ie
    call read_buoy('data/buoy_' // ids(i) //  '.csv', time, wind_speed)
    wind_speed = denan(wind_speed)
    max_wind(i) = maxval(wind_speed)
    mean_wind(i) = mean(wind_speed)
  end do

  allocate(gather(size(ids))[*])

  gather(is:ie)[1] = max_wind 
  sync all 
  if (this_image() == 1) then
    print *, 'Maximum wind speed measured is ', maxval(gather), &
      'at station ', ids(maxloc(gather))
  end if

  gather(is:ie)[1] = mean_wind
  sync all
  if (this_image() == 1) then
    print *, 'Highest mean wind speed is ', maxval(gather), &
      'at station ', ids(maxloc(gather))
    print *, 'Lowest mean wind speed is ', minval(gather), &
      'at station ', ids(minloc(gather))
  end if

end program weather_stats_parallel

@Aurelius_Nero please let me know your specific questions in reference to the code, or if you’d like to go through it together step by step, either here or on a video call.

1 Like

So my whole confusion was understanding how Coarrays work in general.

I was under the impression that When you declare an array as a Coarray, all images have a shared access to it and it’s a single sort of memory tray, that all images can alter or change it.
I didn’t realize that a copy is made across all images.

I am also confused about the next section where we need a “Halo” variable.

The code is quite clear to me so far :slight_smile:

If you put some of the dimensions (or part of one dimension) of an array into co-dimensions, this is what you effectively have. You can arrange that each image’s local array is a piece (slice) of the entire (distributed) array. That is the closest you will get to a “shared” array. It was done like that so that references to data in other images is manifest in the source (for the benefit of the programmer as well as the compiler).

E.g., a shared (1000,1000) array can be implemented on 10 images as dimensions (1000,100) and codimensions (10).

1 Like

Thank you !