@@ -28,7 +28,7 @@ module m_data_output
2828
2929 private
3030 public :: s_write_serial_data_files, s_write_parallel_data_files, s_write_data_files, s_initialize_data_output_module, &
31- & s_finalize_data_output_module, s_write_ib_state_0
31+ & s_finalize_data_output_module, s_write_ib_state_0_file
3232
3333 type(scalar_field), allocatable, dimension (:) :: q_cons_temp
3434
@@ -733,35 +733,186 @@ contains
733733
734734 end subroutine s_initialize_data_output_module
735735
736- !> @brief Writes restart_data/ ib_state_0.dat: the initial IB layout (namelist patch_ib entries, then any generated
737- !! particle- cloud beds). Rank-0 - only. Read back by simulation at startup via s_read_ib_restart_data(0 , ...)
738- !! (src/ simulation/ m_start_up.fpp). Uses the same 20 - field record layout s_write_serial_ib_state
739- !! (src/ simulation/ m_data_output.fpp) writes, so simulation' s own writers can freely overwrite this file later at t_step_start
740- !! == 0 without changing its layout - only position (fields 17:19) and radius (field 20) are populated here; everything else
741- !! (time, force, torque, vel, angular_vel, angles) is zero for a freshly generated IB.
742- impure subroutine s_write_ib_state_0(particle_cloud_ibs, num_particle_cloud_ibs)
736+ !> @brief Writes restart_data/ ib_state_0.dat (or, under file_per_process, one restart_data/ lustre_0/ ib_state_0_<rank>.dat chunk
737+ !! per rank): the initial IB layout - namelist patch_ib entries, then any generated particle- cloud beds - with each rank writing
738+ !! only the entries f_local_rank_owns_location says are its own. Read back by simulation at startup via
739+ !! s_read_ib_restart_data(0 , ...) (src/ simulation/ m_start_up.fpp), which dispatches on the same file_per_process flag, so the
740+ !! two writers must stay format - compatible: this mirrors s_write_parallel_ib_state/ s_write_serial_ib_state
741+ !! (src/ simulation/ m_data_output.fpp) exactly, just sourcing entries from this rank' s local subset instead of patch_ib/
742+ !! local_ib_patch_ids post-reduce. Only position (fields 17:19) and radius (field 20) are populated here; everything else (time,
743+ !! force, torque, vel, angular_vel, angles) is zero for a freshly generated IB.
744+ impure subroutine s_write_ib_state_0_file(glb_bounds, particle_cloud_ibs, num_particle_cloud_ibs)
745+
746+ type(bounds_info), dimension(3), intent(in) :: glb_bounds
747+ type(ib_patch_parameters), dimension(:), intent(in) :: particle_cloud_ibs
748+ integer, intent(in) :: num_particle_cloud_ibs
749+ integer, allocatable :: local_namelist_ids(:)
750+ integer :: num_local_namelist
751+ integer :: i
752+ real(wp), dimension(3) :: centroid
753+
754+ allocate (local_namelist_ids(max(1, num_ibs)))
755+ num_local_namelist = 0
756+ do i = 1, num_ibs
757+ centroid = [patch_ib(i)%x_centroid, patch_ib(i)%y_centroid, 0._wp]
758+ if (num_dims == 3) centroid(3) = patch_ib(i)%z_centroid
759+ if (f_local_rank_owns_location(centroid, glb_bounds)) then
760+ num_local_namelist = num_local_namelist + 1
761+ local_namelist_ids(num_local_namelist) = i
762+ end if
763+ end do
764+
765+ if (.not. parallel_io) then
766+ ! Mirrors s_write_serial_ib_state (src/simulation/m_data_output.fpp): "must be called only on rank 0" - parallel_io
767+ ! = F is not MPI-aware for ib_state, so this combined with num_procs > 1 is a pre-existing limitation, not one
768+ ! introduced here.
769+ if (proc_rank == 0) call s_write_ib_state_0_serial(local_namelist_ids, num_local_namelist, particle_cloud_ibs, &
770+ & num_particle_cloud_ibs)
771+ else if (file_per_process) then
772+ call s_write_ib_state_0_file_per_process(local_namelist_ids, num_local_namelist, particle_cloud_ibs, &
773+ & num_particle_cloud_ibs)
774+ else
775+ call s_write_ib_state_0_shared(local_namelist_ids, num_local_namelist, particle_cloud_ibs, num_particle_cloud_ibs)
776+ end if
743777
778+ deallocate (local_namelist_ids)
779+
780+ end subroutine s_write_ib_state_0_file
781+
782+ !> Writes this rank' s local entries into its own restart_data/ lustre_0/ ib_state_0_<rank>.dat chunk file - mirrors
783+ !! s_write_parallel_ib_state' s file_per_process branch (src/simulation/m_data_output.fpp).
784+ subroutine s_write_ib_state_0_file_per_process(local_namelist_ids, num_local_namelist, particle_cloud_ibs, &
785+ & num_particle_cloud_ibs)
786+
787+ integer, dimension(:), intent(in) :: local_namelist_ids
788+ integer, intent(in) :: num_local_namelist
744789 type(ib_patch_parameters), dimension(:), intent(in) :: particle_cloud_ibs
745790 integer, intent(in) :: num_particle_cloud_ibs
746791 character(LEN=len_trim(case_dir) + 2*name_len) :: file_loc
747792 integer :: i, ios, file_unit
748793 integer, parameter :: NFIELDS_PER_IB = 20
749794 real(wp) :: ib_buf(NFIELDS_PER_IB)
750795
751- call s_create_directory(trim(case_dir) // ' / restart_data' )
796+ if (proc_rank == 0) call s_create_directory(trim(case_dir) // ' / restart_data/ lustre_0' )
797+ call s_mpi_barrier()
798+ call s_delay_file_access(proc_rank)
799+
800+ write (file_loc, ' (A,i7.7 ,A)' ) ' ib_state_0_' , proc_rank, ' .dat'
801+ file_loc = trim(case_dir) // ' / restart_data/ lustre_0/ ' // trim(file_loc)
802+
803+ open (newunit=file_unit, file=trim(file_loc), form=' unformatted' , access=' stream' , status=' replace' , iostat=ios)
804+ if (ios /= 0) call s_mpi_abort(' Cannot open IB state output file: ' // trim(file_loc))
805+
806+ ib_buf = 0._wp
807+
808+ write (file_unit) num_local_namelist + num_particle_cloud_ibs
809+
810+ do i = 1, num_local_namelist
811+ ib_buf(17) = patch_ib(local_namelist_ids(i))%x_centroid
812+ ib_buf(18) = patch_ib(local_namelist_ids(i))%y_centroid
813+ ib_buf(19) = patch_ib(local_namelist_ids(i))%z_centroid
814+ ib_buf(20) = patch_ib(local_namelist_ids(i))%radius
815+ write (file_unit) local_namelist_ids(i)
816+ write (file_unit) ib_buf
817+ end do
818+
819+ do i = 1, num_particle_cloud_ibs
820+ ib_buf(17) = particle_cloud_ibs(i)%x_centroid
821+ ib_buf(18) = particle_cloud_ibs(i)%y_centroid
822+ ib_buf(19) = particle_cloud_ibs(i)%z_centroid
823+ ib_buf(20) = particle_cloud_ibs(i)%radius
824+ write (file_unit) particle_cloud_ibs(i)%gbl_patch_id
825+ write (file_unit) ib_buf
826+ end do
827+
828+ close (file_unit)
829+
830+ end subroutine s_write_ib_state_0_file_per_process
752831
832+ !> Writes this rank' s local entries into the single shared restart_data/ ib_state_0.dat, each rank placing its own records at
833+ !! their gbl_patch_id- based offset via MPI- IO - mirrors s_write_parallel_ib_state' s non-file_per_process branch
834+ !! (src/simulation/m_data_output.fpp). Only reached when parallel_io = T (see s_write_ib_state_0_file), matching that
835+ !! routine' s own precondition of running under MFC_MPI.
836+ subroutine s_write_ib_state_0_shared (local_namelist_ids , num_local_namelist , particle_cloud_ibs , num_particle_cloud_ibs )
837+
838+ integer , dimension (:), intent (in ) :: local_namelist_ids
839+ integer , intent (in ) :: num_local_namelist
840+ type(ib_patch_parameters), dimension (:), intent (in ) :: particle_cloud_ibs
841+ integer , intent (in ) :: num_particle_cloud_ibs
842+ integer , parameter :: NFIELDS_PER_IB = 20
843+ real (wp) :: ib_buf(NFIELDS_PER_IB)
844+ integer :: i
845+ #ifdef MFC_MPI
846+ character (LEN= len_trim (case_dir) + 2 * name_len) :: file_loc
847+ integer (kind= MPI_OFFSET_KIND) :: disp, WP_MOK
848+ integer :: ifile, ierr
849+ integer , dimension (MPI_STATUS_SIZE) :: status
850+ logical :: file_exist
851+
852+ if (proc_rank == 0 ) call s_create_directory(trim (case_dir) // ' /restart_data' )
853+ call s_mpi_barrier()
854+
855+ WP_MOK = int (storage_size(0._wp )/ 8 , MPI_OFFSET_KIND)
856+ file_loc = trim (case_dir) // ' /restart_data/ib_state_0.dat'
857+
858+ inquire (FILE= trim (file_loc), EXIST= file_exist)
859+ if (file_exist .and. proc_rank == 0 ) call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
860+ call s_mpi_barrier()
861+
862+ call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, ior (MPI_MODE_WRONLY, MPI_MODE_CREATE), mpi_info_int, ifile, ierr)
863+
864+ ib_buf = 0._wp
865+
866+ do i = 1 , num_local_namelist
867+ ib_buf(17 ) = patch_ib(local_namelist_ids(i))%x_centroid
868+ ib_buf(18 ) = patch_ib(local_namelist_ids(i))%y_centroid
869+ ib_buf(19 ) = patch_ib(local_namelist_ids(i))%z_centroid
870+ ib_buf(20 ) = patch_ib(local_namelist_ids(i))%radius
871+ disp = int (local_namelist_ids(i) - 1 , MPI_OFFSET_KIND)* int (NFIELDS_PER_IB, MPI_OFFSET_KIND)* WP_MOK
872+ call MPI_FILE_WRITE_AT(ifile, disp, ib_buf, NFIELDS_PER_IB, mpi_p, status, ierr)
873+ end do
874+
875+ do i = 1 , num_particle_cloud_ibs
876+ ib_buf(17 ) = particle_cloud_ibs(i)%x_centroid
877+ ib_buf(18 ) = particle_cloud_ibs(i)%y_centroid
878+ ib_buf(19 ) = particle_cloud_ibs(i)%z_centroid
879+ ib_buf(20 ) = particle_cloud_ibs(i)%radius
880+ disp = int (particle_cloud_ibs(i)%gbl_patch_id - 1 , MPI_OFFSET_KIND)* int (NFIELDS_PER_IB, MPI_OFFSET_KIND)* WP_MOK
881+ call MPI_FILE_WRITE_AT(ifile, disp, ib_buf, NFIELDS_PER_IB, mpi_p, status, ierr)
882+ end do
883+
884+ call MPI_FILE_CLOSE(ifile, ierr)
885+ #endif
886+
887+ end subroutine s_write_ib_state_0_shared
888+
889+ !> Writes ALL of this rank' s local entries directly into restart_data/ib_state_0.dat with plain Fortran I/O - mirrors
890+ !! s_write_serial_ib_state (src/simulation/m_data_output.fpp). Used only when parallel_io = F; the caller (rank 0 only) mirrors
891+ !! that routine' s " must be called only on rank 0" precondition, so this is a plain sequential write , no MPI needed.
892+ subroutine s_write_ib_state_0_serial (local_namelist_ids , num_local_namelist , particle_cloud_ibs , num_particle_cloud_ibs )
893+
894+ integer , dimension (:), intent (in ) :: local_namelist_ids
895+ integer , intent (in ) :: num_local_namelist
896+ type(ib_patch_parameters), dimension (:), intent (in ) :: particle_cloud_ibs
897+ integer , intent (in ) :: num_particle_cloud_ibs
898+ character (LEN= len_trim (case_dir) + 2 * name_len) :: file_loc
899+ integer :: i, ios, file_unit
900+ integer , parameter :: NFIELDS_PER_IB = 20
901+ real (wp) :: ib_buf(NFIELDS_PER_IB)
902+
903+ call s_create_directory(trim (case_dir) // ' /restart_data' )
753904 file_loc = trim (case_dir) // ' /restart_data/ib_state_0.dat'
754905
755906 open (newunit= file_unit, file= trim (file_loc), form= ' unformatted' , access= ' stream' , status= ' replace' , iostat= ios)
756907 if (ios /= 0 ) call s_mpi_abort(' Cannot open IB state output file: ' // trim (file_loc))
757908
758909 ib_buf = 0._wp
759910
760- do i = 1, num_ibs
761- ib_buf(17) = patch_ib(i )%x_centroid
762- ib_buf(18) = patch_ib(i )%y_centroid
763- ib_buf(19) = patch_ib(i )%z_centroid
764- ib_buf(20) = patch_ib(i )%radius
911+ do i = 1 , num_local_namelist
912+ ib_buf(17 ) = patch_ib(local_namelist_ids(i) )%x_centroid
913+ ib_buf(18 ) = patch_ib(local_namelist_ids(i) )%y_centroid
914+ ib_buf(19 ) = patch_ib(local_namelist_ids(i) )%z_centroid
915+ ib_buf(20 ) = patch_ib(local_namelist_ids(i) )%radius
765916 write (file_unit) ib_buf
766917 end do
767918
@@ -775,7 +926,7 @@ contains
775926
776927 close (file_unit)
777928
778- end subroutine s_write_ib_state_0
929+ end subroutine s_write_ib_state_0_serial
779930
780931 !> Resets s_write_data_files pointer
781932 impure subroutine s_finalize_data_output_module
0 commit comments