!*********************************************************************** !* GNU Lesser General Public License !* !* This file is part of the GFDL Flexible Modeling System (FMS). !* !* FMS is free software: you can redistribute it and/or modify it under !* the terms of the GNU Lesser General Public License as published by !* the Free Software Foundation, either version 3 of the License, or (at !* your option) any later version. !* !* FMS is distributed in the hope that it will be useful, but WITHOUT !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License !* for more details. !* !* You should have received a copy of the GNU Lesser General Public !* License along with FMS. If not, see . !*********************************************************************** !---------- !ug support !------------------------------------------------------------------------------ !>Write data for a 1D field associated with an unstructured mpp domain to a !!restart file. subroutine mpp_io_unstructured_write_r_1D(funit, & field, & domain, & fdata, & nelems_io, & tstamp, & default_data) !Inputs/outputs integer(INT_KIND),intent(in) :: funit ! null() io_domain => mpp_get_UG_io_domain(domain) !Get the pelist associated with the I/O domain. io_domain_npes = mpp_get_UG_domain_npes(io_domain) allocate(pelist(io_domain_npes)) call mpp_get_UG_domain_pelist(io_domain, & pelist) !Make sure that only the root rank of the pelist will write to the file. !This check is needed because data is only gathered on the lowest rank !of the pelist. if (mpp_pe() .eq. pelist(1) .and. .not. & mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_r_1D:" & //" the root rank of the pelist must be allowed" & //" to perform the write.") endif if (mpp_pe() .ne. pelist(1) .and. mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_r_1D:" & //" the non-root ranks of the pelist are not" & //" allowed to perform the write.") endif !Allocate an array which will be used to gather the data to be written !onto the root rank of the pelist. if (mpp_pe() .eq. pelist(1)) then nelems = sum(nelems_io) allocate(rbuff(nelems)) else allocate(rbuff(1)) endif !Perform the gather of data onto the root rank (pelist(1)). call mpp_gather(fdata, & size(fdata), & rbuff, & nelems_io, & pelist) !Write out the data to the file. This is only done by the root rank !of the pelist. if (mpp_pe() .eq. pelist(1)) then allocate(cdata(nelems)) cdata = fill do i = 1,nelems cdata(i) = rbuff(i) enddo field%size(1) = nelems call write_record_default(funit, & field, & nelems, & cdata, & tstamp) deallocate(cdata) endif !Deallocate local allocatables. deallocate(rbuff) deallocate(pelist) !Stop the mpp timer. call mpp_clock_end(mpp_write_clock) return end subroutine mpp_io_unstructured_write_r_1D !------------------------------------------------------------------------------ !>Write data for a 2D field associated with an unstructured mpp domain to a !!restart file. subroutine mpp_io_unstructured_write_r_2D(funit, & field, & domain, & fdata, & nelems_io, & tstamp, & default_data) !Inputs/outputs integer(INT_KIND),intent(in) :: funit ! null() io_domain => mpp_get_UG_io_domain(domain) !Get the pelist associated with the I/O domain. io_domain_npes = mpp_get_UG_domain_npes(io_domain) allocate(pelist(io_domain_npes)) call mpp_get_UG_domain_pelist(io_domain, & pelist) !Make sure that only the root rank of the pelist will write to the file. !This check is needed because data is only gathered on the lowest rank !of the pelist. if (mpp_pe() .eq. pelist(1) .and. .not. & mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_r_2D:" & //" the root rank of the pelist must be allowed" & //" to perform the write.") endif if (mpp_pe() .ne. pelist(1) .and. mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_r_2D:" & //" the non-root ranks of the pelist are not" & //" allowed to perform the write.") endif !Load the data elements for each rank into a one dimensional array, which !will be used to gather the data onto the root rank of the pelist. allocate(sbuff(size(fdata))) dim_size_1 = size(fdata,1) dim_size_2 = size(fdata,2) do j = 1,dim_size_2 do i = 1,dim_size_1 sbuff((j-1)*dim_size_1+i) = fdata(i,j) enddo enddo !Allocate an array which will be used to gather the data to be written !onto the root rank of the pelist. if (mpp_pe() .eq. pelist(1)) then nelems = sum(nelems_io) allocate(rbuff(nelems*dim_size_2)) else allocate(rbuff(1)) endif !Perform the gather of data onto the root rank (pelist(1)). call mpp_gather(sbuff, & size(sbuff), & rbuff, & nelems_io*dim_size_2, & pelist) !Reorder the gather data so that is of the form (nelems,dim_size_2). Write !out the data to the file. This is only done by the root rank of the !pelist. if (mpp_pe() .eq. pelist(1)) then allocate(cdata(nelems,dim_size_2)) cdata = fill do j = 1,dim_size_2 offset_c = 0 do k = 1,io_domain_npes if (k .gt. 1) then offset_r = (j-1)*nelems_io(k) + dim_size_2*(sum(nelems_io(1:k-1))) else offset_r = (j-1)*nelems_io(k) endif do i = 1,nelems_io(k) cdata(i+offset_c,j) = rbuff(i+offset_r) enddo offset_c = offset_c + nelems_io(k) enddo enddo field%size(1) = nelems call write_record_default(funit, & field, & nelems*dim_size_2, & cdata, & tstamp) deallocate(cdata) endif !Deallocate local allocatables. deallocate(sbuff) deallocate(rbuff) deallocate(pelist) !Stop the mpp timer. call mpp_clock_end(mpp_write_clock) return end subroutine mpp_io_unstructured_write_r_2D !------------------------------------------------------------------------------ !>Write data for a 3D field associated with an unstructured mpp domain to a !!restart file. subroutine mpp_io_unstructured_write_r_3D(funit, & field, & domain, & fdata, & nelems_io, & tstamp, & default_data) !Inputs/outputs integer(INT_KIND),intent(in) :: funit ! null() io_domain => mpp_get_UG_io_domain(domain) !Get the pelist associated with the I/O domain. io_domain_npes = mpp_get_UG_domain_npes(io_domain) allocate(pelist(io_domain_npes)) call mpp_get_UG_domain_pelist(io_domain, & pelist) !Make sure that only the root rank of the pelist will write to the file. !This check is needed because data is only gathered on the lowest rank !of the pelist. if (mpp_pe() .eq. pelist(1) .and. .not. & mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_r_3D:" & //" the root rank of the pelist must be allowed" & //" to perform the write.") endif if (mpp_pe() .ne. pelist(1) .and. mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_r_3D:" & //" the non-root ranks of the pelist are not" & //" allowed to perform the write.") endif !Load the data elements for each rank into a one dimensional array, which !will be used to gather the data onto the root rank of the pelist. allocate(sbuff(size(fdata))) dim_size_1 = size(fdata,1) dim_size_2 = size(fdata,2) dim_size_3 = size(fdata,3) do k = 1,dim_size_3 do j = 1,dim_size_2 do i = 1,dim_size_1 sbuff((k-1)*dim_size_2*dim_size_1+(j-1)*dim_size_1+i) = fdata(i,j,k) enddo enddo enddo !Allocate an array which will be used to gather the data to be written !onto the root rank of the pelist. if (mpp_pe() .eq. pelist(1)) then nelems = sum(nelems_io) allocate(rbuff(nelems*dim_size_2*dim_size_3)) else allocate(rbuff(1)) endif !Perform the gather of data onto the root rank (pelist(1)). call mpp_gather(sbuff, & size(sbuff), & rbuff, & nelems_io*dim_size_2*dim_size_3, & pelist) !Reorder the gather data so that is of the form (nelems,dim_size_2). Write !out the data to the file. This is only done by the root rank of the !pelist. if (mpp_pe() .eq. pelist(1)) then allocate(cdata(nelems,dim_size_2,dim_size_3)) cdata = fill do m = 1,dim_size_3 do j = 1,dim_size_2 offset_c = 0 do k = 1,io_domain_npes if (k .gt. 1) then offset_r = (m-1)*dim_size_2*nelems_io(k) + & (j-1)*nelems_io(k) + & dim_size_2*dim_size_3*(sum(nelems_io(1:k-1))) else offset_r = (m-1)*dim_size_2*nelems_io(k) + & (j-1)*nelems_io(k) endif do i = 1,nelems_io(k) cdata(i+offset_c,j,m) = rbuff(i+offset_r) enddo offset_c = offset_c + nelems_io(k) enddo enddo enddo field%size(1) = nelems call write_record_default(funit, & field, & nelems*dim_size_2*dim_size_3, & cdata, & tstamp) deallocate(cdata) endif !Deallocate local allocatables. deallocate(sbuff) deallocate(rbuff) deallocate(pelist) !Stop the mpp timer. call mpp_clock_end(mpp_write_clock) return end subroutine mpp_io_unstructured_write_r_3D !------------------------------------------------------------------------------ !>Write data for a 4D field associated with an unstructured mpp domain to a !!restart file. subroutine mpp_io_unstructured_write_r_4D(funit, & field, & domain, & fdata, & nelems_io_in, & tstamp, & default_data) !Inputs/outputs integer(INT_KIND),intent(in) :: funit ! null() io_domain => mpp_get_UG_io_domain(domain) !Get the pelist associated with the I/O domain. io_domain_npes = mpp_get_UG_domain_npes(io_domain) allocate(pelist(io_domain_npes)) call mpp_get_UG_domain_pelist(io_domain, & pelist) !Make sure that only the root rank of the pelist will write to the file. !This check is needed because data is only gathered on the lowest rank !of the pelist. if (mpp_pe() .eq. pelist(1) .and. .not. & mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_compressed_r_4D:" & //" the root rank of the pelist must be allowed" & //" to perform the write.") endif if (mpp_pe() .ne. pelist(1) .and. mpp_file(funit)%write_on_this_pe) then call mpp_error(FATAL, & "mpp_io_unstructured_write_compressed_r_4D:" & //" the non-root ranks of the pelist are not" & //" allowed to perform the write.") endif !For the 3D unstructured case, data is assumed to be of the form !fdata = fdata(unstructured,z,cc). The number of data elements in the !unstructured dimension (size(fdata,1)) may differ between ranks. !If not passed in, the number of data elements in the unstructured !dimension must be gathered on the root rank of the pelist. The number !data elements in the unstructured dimension should be equal to the size !of the unstructured computed domain. if (present(nelems_io_in)) then allocate(nelems_io(size(nelems_io_in))) nelems_io = nelems_io_in else allocate(nelems_io(io_domain_npes)) nelems_io = 0 call mpp_get_UG_compute_domains(io_domain, & size=nelems_io) endif !The number of data elements in the non-unstructured dimensions are !required to be the same for all ranks. Perform gathers to check this. size_fdata_dim_2 = size(fdata,2) size_fdata_dim_3 = size(fdata,3) size_fdata_dim_4 = size(fdata,4) !Allocate arrays which will be used to gather the data to be written !onto the root rank of the pelist. mynelems = size(fdata,1) allocate(sbuff(mynelems*size_fdata_dim_2*size_fdata_dim_3*size_fdata_dim_4)) if (mpp_pe() .eq. pelist(1)) then nelems = sum(nelems_io) allocate(rbuff(nelems*size_fdata_dim_2*size_fdata_dim_3*size_fdata_dim_4)) else allocate(rbuff(1)) endif !Load the data into the sbuff array. The data is transposed so that the !gather may be performed more easily. do k = 1,mynelems do j = 1,size_fdata_dim_2 do i = 1,size_fdata_dim_3 do n = 1,size_fdata_dim_4 sbuff((k-1)*size_fdata_dim_2*size_fdata_dim_3*size_fdata_dim_4 & + (j-1)*size_fdata_dim_3*size_fdata_dim_4 & + (i-1)*size_fdata_dim_4 + n) = fdata(k,j,i,n) enddo enddo enddo enddo !Perform the gather of data onto the root rank (pelist(1)). call mpp_gather(sbuff, & size(sbuff), & rbuff, & nelems_io*size_fdata_dim_2*size_fdata_dim_3*size_fdata_dim_4, & pelist) !Write out the data to the file. This is only done by the root rank !of the pelist. if (mpp_pe() .eq. pelist(1)) then allocate(cdata(nelems,size_fdata_dim_2,size_fdata_dim_3,size_fdata_dim_4)) cdata = fill do n = 1,size_fdata_dim_4 do k = 1,size_fdata_dim_3 do j = 1,size_fdata_dim_2 do i = 1,nelems cdata(i,j,k,n) = rbuff((i-1)*size_fdata_dim_2*size_fdata_dim_3*size_fdata_dim_4 & + (j-1)*size_fdata_dim_3*size_fdata_dim_4 & + (k-1)*size_fdata_dim_4 + n) enddo enddo enddo enddo field%size(1) = nelems call write_record_default(funit, & field, & nelems*size_fdata_dim_2*size_fdata_dim_3*size_fdata_dim_4, & cdata, & tstamp) deallocate(cdata) endif !Deallocate local allocatables. deallocate(sbuff) deallocate(rbuff) deallocate(pelist) deallocate(nelems_io) !Stop the mpp timer. call mpp_clock_end(mpp_write_clock) return end subroutine mpp_io_unstructured_write_r_4D !------------------------------------------------------------------------------ !----------