Index: GenericIO.cxx
===================================================================
--- GenericIO.cxx	(revision a4fee139105de3bf748818b08fe85b87b6d2bf56)
+++ GenericIO.cxx	(revision 8f0a211de68fdaf18f8af21d8574c73197b28c5e)
@@ -739,9 +739,11 @@
 
 template <bool IsBigEndian>
-void GenericIO::readHeaderLeader(void *GHPtr, bool MustMatch, int SplitNRanks,
-                                 string &LocalFileName, uint64_t &HeaderSize, vector<char> &Header) {
+void GenericIO::readHeaderLeader(void *GHPtr, MismatchBehavior MB, int NRanks,
+                                 int Rank, int SplitNRanks,
+                                 string &LocalFileName, uint64_t &HeaderSize,
+                                 vector<char> &Header) {
   GlobalHeader<IsBigEndian> &GH = *(GlobalHeader<IsBigEndian> *) GHPtr;
 
-  if (MustMatch) {
+  if (MB == MismatchDisallowed) {
     if (SplitNRanks != (int) GH.NRanks) {
       stringstream ss;
@@ -777,4 +779,34 @@
     }
 #endif
+  } else if (MB == MismatchRedistribute && !Redistributing) {
+    Redistributing = true;
+
+    int NFileRanks = RankMap.empty() ? (int) GH.NRanks : (int) RankMap.size();
+    int NFileRanksPerRank = NFileRanks/NRanks;
+    int NRemFileRank = NFileRanks % NRanks;
+
+    if (!NFileRanksPerRank) {
+      // We have only the remainder, so the last NRemFileRank ranks get one
+      // file rank, and the others don't.
+      if (NRemFileRank && NRanks - Rank <= NRemFileRank)
+        SourceRanks.push_back(NRanks - (Rank + 1));
+    } else {
+      // Since NRemFileRank < NRanks, and we don't want to put any extra memory
+      // load on rank 0 (because rank 0's memory load is normally higher than
+      // the other ranks anyway), the last NRemFileRank will each take
+      // (NFileRanksPerRank+1) file ranks.
+
+      int FirstFileRank = 0, LastFileRank = NFileRanksPerRank - 1;
+      for (int i = 1; i <= Rank; ++i) {
+        FirstFileRank = LastFileRank + 1;
+        LastFileRank  = FirstFileRank + NFileRanksPerRank - 1;
+
+        if (NRemFileRank && NRanks - i <= NRemFileRank)
+          ++LastFileRank;
+      }
+
+      for (int i = FirstFileRank; i <= LastFileRank; ++i)
+        SourceRanks.push_back(i);
+    }
   }
 
@@ -791,5 +823,5 @@
 // Note: Errors from this function should be recoverable. This means that if
 // one rank throws an exception, then all ranks should.
-void GenericIO::openAndReadHeader(bool MustMatch, int EffRank, bool CheckPartMap) {
+void GenericIO::openAndReadHeader(MismatchBehavior MB, int EffRank, bool CheckPartMap) {
   int NRanks, Rank;
 #ifndef GENERICIO_NO_MPI
@@ -802,5 +834,5 @@
 
   if (EffRank == -1)
-    EffRank = Rank;
+    EffRank = MB == MismatchRedistribute ? 0 : Rank;
 
   if (RankMap.empty() && CheckPartMap) {
@@ -814,5 +846,5 @@
         GenericIO GIO(FileName, FileIOType);
 #endif
-        GIO.openAndReadHeader(true, 0, false);
+        GIO.openAndReadHeader(MismatchDisallowed, 0, false);
         RanksInMap = GIO.readNumElems();
 
@@ -846,5 +878,5 @@
     LocalFileName = FileName;
 #ifndef GENERICIO_NO_MPI
-    MPI_Comm_dup(Comm, &SplitComm);
+    MPI_Comm_dup(MB == MismatchRedistribute ? MPI_COMM_SELF : Comm, &SplitComm);
 #endif
   } else {
@@ -853,8 +885,12 @@
     LocalFileName = ss.str();
 #ifndef GENERICIO_NO_MPI
+    if (MB == MismatchRedistribute) {
+      MPI_Comm_dup(MPI_COMM_SELF, &SplitComm);
+    } else {
 #ifdef __bgq__
-    MPI_Barrier(Comm);
-#endif
-    MPI_Comm_split(Comm, RankMap[EffRank], Rank, &SplitComm);
+      MPI_Barrier(Comm);
+#endif
+      MPI_Comm_split(Comm, RankMap[EffRank], Rank, &SplitComm);
+    }
 #endif
   }
@@ -897,8 +933,8 @@
 
       if (string(GH.Magic, GH.Magic + MagicSize - 1) == MagicLE) {
-        readHeaderLeader<false>(&GH, MustMatch, SplitNRanks, LocalFileName,
+        readHeaderLeader<false>(&GH, MB, NRanks, Rank, SplitNRanks, LocalFileName,
                                 HeaderSize, Header);
       } else if (string(GH.Magic, GH.Magic + MagicSize - 1) == MagicBE) {
-        readHeaderLeader<true>(&GH, MustMatch, SplitNRanks, LocalFileName,
+        readHeaderLeader<true>(&GH, MB, NRanks, Rank, SplitNRanks, LocalFileName,
                                HeaderSize, Header);
       } else {
@@ -936,5 +972,4 @@
 #endif
 
-
   FH.getHeaderCache().clear();
 
@@ -946,5 +981,6 @@
 
 #ifndef GENERICIO_NO_MPI
-  MPI_Barrier(Comm);
+  if (!DisableCollErrChecking)
+    MPI_Barrier(Comm);
 
   if (FileIOType == FileIOMPI)
@@ -958,8 +994,10 @@
   try {
     FH.get()->open(LocalFileName, true);
-    MPI_Allreduce(&OpenErr, &TotOpenErr, 1, MPI_INT, MPI_SUM, Comm);
+    MPI_Allreduce(&OpenErr, &TotOpenErr, 1, MPI_INT, MPI_SUM,
+                  DisableCollErrChecking ? MPI_COMM_SELF : Comm);
   } catch (...) {
     OpenErr = 1;
-    MPI_Allreduce(&OpenErr, &TotOpenErr, 1, MPI_INT, MPI_SUM, Comm);
+    MPI_Allreduce(&OpenErr, &TotOpenErr, 1, MPI_INT, MPI_SUM,
+                  DisableCollErrChecking ? MPI_COMM_SELF : Comm);
     throw;
   }
@@ -1097,5 +1135,5 @@
   }
 
-  openAndReadHeader(false, EffRank, false);
+  openAndReadHeader(MismatchAllowed, EffRank, false);
 
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
@@ -1116,4 +1154,15 @@
 
 size_t GenericIO::readNumElems(int EffRank) {
+  if (EffRank == -1 && Redistributing) {
+    DisableCollErrChecking = true;
+
+    size_t TotalSize = 0;
+    for (int i = 0, ie = SourceRanks.size(); i != ie; ++i)
+      TotalSize += readNumElems(SourceRanks[i]);
+
+    DisableCollErrChecking = false;
+    return TotalSize;
+  }
+
   if (FH.isBigEndian())
     return readNumElems<true>(EffRank);
@@ -1131,5 +1180,6 @@
   }
 
-  openAndReadHeader(false, EffRank, false);
+  openAndReadHeader(Redistributing ? MismatchRedistribute : MismatchAllowed,
+                    EffRank, false);
 
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
@@ -1146,4 +1196,9 @@
 
 void GenericIO::readCoords(int Coords[3], int EffRank) {
+  if (EffRank == -1 && Redistributing) {
+    std::fill(Coords, Coords + 3, 0);
+    return;
+  }
+
   if (FH.isBigEndian())
     readCoords<true>(Coords, EffRank);
@@ -1162,5 +1217,5 @@
   }
 
-  openAndReadHeader(false, EffRank, false);
+  openAndReadHeader(MismatchAllowed, EffRank, false);
 
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
@@ -1178,8 +1233,90 @@
 
 void GenericIO::readData(int EffRank, bool PrintStats, bool CollStats) {
+  int Rank;
+#ifndef GENERICIO_NO_MPI
+  MPI_Comm_rank(Comm, &Rank);
+#else
+  Rank = 0;
+#endif
+
+  uint64_t TotalReadSize = 0;
+#ifndef GENERICIO_NO_MPI
+  double StartTime = MPI_Wtime();
+#else
+  double StartTime = double(clock())/CLOCKS_PER_SEC;
+#endif
+
+  int NErrs[3] = { 0, 0, 0 };
+
+  if (EffRank == -1 && Redistributing) {
+    DisableCollErrChecking = true;
+
+    size_t RowOffset = 0;
+    for (int i = 0, ie = SourceRanks.size(); i != ie; ++i) {
+      readData(SourceRanks[i], RowOffset, Rank, TotalReadSize, NErrs);
+      RowOffset += readNumElems(SourceRanks[i]);
+    }
+
+    DisableCollErrChecking = false;
+  } else {
+    readData(EffRank, 0, Rank, TotalReadSize, NErrs);
+  }
+
+  int AllNErrs[3];
+#ifndef GENERICIO_NO_MPI
+  MPI_Allreduce(NErrs, AllNErrs, 3, MPI_INT, MPI_SUM, Comm);
+#else
+  AllNErrs[0] = NErrs[0]; AllNErrs[1] = NErrs[1]; AllNErrs[2] = NErrs[2];
+#endif
+
+  if (AllNErrs[0] > 0 || AllNErrs[1] > 0 || AllNErrs[2] > 0) {
+    stringstream ss;
+    ss << "Experienced " << AllNErrs[0] << " I/O error(s), " <<
+          AllNErrs[1] << " CRC error(s) and " << AllNErrs[2] <<
+          " decompression CRC error(s) reading: " << OpenFileName;
+    throw runtime_error(ss.str());
+  }
+
+#ifndef GENERICIO_NO_MPI
+  MPI_Barrier(Comm);
+#endif
+
+#ifndef GENERICIO_NO_MPI
+  double EndTime = MPI_Wtime();
+#else
+  double EndTime = double(clock())/CLOCKS_PER_SEC;
+#endif
+
+  double TotalTime = EndTime - StartTime;
+  double MaxTotalTime;
+#ifndef GENERICIO_NO_MPI
+  if (CollStats)
+    MPI_Reduce(&TotalTime, &MaxTotalTime, 1, MPI_DOUBLE, MPI_MAX, 0, Comm);
+  else
+#endif
+  MaxTotalTime = TotalTime;
+
+  uint64_t AllTotalReadSize;
+#ifndef GENERICIO_NO_MPI
+  if (CollStats)
+    MPI_Reduce(&TotalReadSize, &AllTotalReadSize, 1, MPI_UINT64_T, MPI_SUM, 0, Comm);
+  else
+#endif
+  AllTotalReadSize = TotalReadSize;
+
+  if (Rank == 0 && PrintStats) {
+    double Rate = ((double) AllTotalReadSize) / MaxTotalTime / (1024.*1024.);
+    cout << "Read " << Vars.size() << " variables from " << FileName <<
+            " (" << AllTotalReadSize << " bytes) in " << MaxTotalTime << "s: " <<
+            Rate << " MB/s [excluding header read]" << endl;
+  }
+}
+
+void GenericIO::readData(int EffRank, size_t RowOffset, int Rank,
+                         uint64_t &TotalReadSize, int NErrs[3]) {
   if (FH.isBigEndian())
-    readData<true>(EffRank, PrintStats, CollStats);
+    readData<true>(EffRank, RowOffset, Rank, TotalReadSize, NErrs);
   else
-    readData<false>(EffRank, PrintStats, CollStats);
+    readData<false>(EffRank, RowOffset, Rank, TotalReadSize, NErrs);
 }
 
@@ -1187,13 +1324,8 @@
 // one rank throws an exception, then all ranks should.
 template <bool IsBigEndian>
-void GenericIO::readData(int EffRank, bool PrintStats, bool CollStats) {
-  int Rank;
-#ifndef GENERICIO_NO_MPI
-  MPI_Comm_rank(Comm, &Rank);
-#else
-  Rank = 0;
-#endif
-
-  openAndReadHeader(false, EffRank, false);
+void GenericIO::readData(int EffRank, size_t RowOffset, int Rank,
+                         uint64_t &TotalReadSize, int NErrs[3]) {
+  openAndReadHeader(Redistributing ? MismatchRedistribute : MismatchAllowed,
+                    EffRank, false);
 
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
@@ -1210,12 +1342,4 @@
                                                RankIndex*GH->RanksSize];
 
-  uint64_t TotalReadSize = 0;
-#ifndef GENERICIO_NO_MPI
-  double StartTime = MPI_Wtime();
-#else
-  double StartTime = double(clock())/CLOCKS_PER_SEC;
-#endif
-
-  int NErrs[3] = { 0, 0, 0 };
   for (size_t i = 0; i < Vars.size(); ++i) {
     uint64_t Offset = RH->Start;
@@ -1263,6 +1387,9 @@
       }
 
+      size_t VarOffset = RowOffset*Vars[i].Size;
+      void *VarData = ((char *) Vars[i].Data) + VarOffset;
+
       vector<unsigned char> LData;
-      void *Data = Vars[i].Data;
+      void *Data = VarData;
       bool HasExtraSpace = Vars[i].HasExtraSpace;
       if (offsetof_safe(GH, BlocksStart) < GH->GlobalHeaderSize &&
@@ -1403,7 +1530,7 @@
 
         blosc_decompress(&LData[0] + sizeof(CompressHeader<IsBigEndian>),
-                         Vars[i].Data, Vars[i].Size*RH->NElems);
-
-        if (CH->OrigCRC != crc64_omp(Vars[i].Data, Vars[i].Size*RH->NElems)) {
+                         VarData, Vars[i].Size*RH->NElems);
+
+        if (CH->OrigCRC != crc64_omp(VarData, Vars[i].Size*RH->NElems)) {
           ++NErrs[2];
           break;
@@ -1414,5 +1541,5 @@
       if (IsBigEndian != isBigEndian())
         for (size_t j = 0; j < RH->NElems; ++j) {
-          char *Offset = ((char *) Vars[i].Data) + j*Vars[i].Size;
+          char *Offset = ((char *) VarData) + j*Vars[i].Size;
           bswap(Offset, Vars[i].Size);
         }
@@ -1451,54 +1578,4 @@
       break;
   }
-
-  int AllNErrs[3];
-#ifndef GENERICIO_NO_MPI
-  MPI_Allreduce(NErrs, AllNErrs, 3, MPI_INT, MPI_SUM, Comm);
-#else
-  AllNErrs[0] = NErrs[0]; AllNErrs[1] = NErrs[1]; AllNErrs[2] = NErrs[2];
-#endif
-
-  if (AllNErrs[0] > 0 || AllNErrs[1] > 0 || AllNErrs[2] > 0) {
-    stringstream ss;
-    ss << "Experienced " << AllNErrs[0] << " I/O error(s), " <<
-          AllNErrs[1] << " CRC error(s) and " << AllNErrs[2] <<
-          " decompression CRC error(s) reading: " << OpenFileName;
-    throw runtime_error(ss.str());
-  }
-
-#ifndef GENERICIO_NO_MPI
-  MPI_Barrier(Comm);
-#endif
-
-#ifndef GENERICIO_NO_MPI
-  double EndTime = MPI_Wtime();
-#else
-  double EndTime = double(clock())/CLOCKS_PER_SEC;
-#endif
-
-  double TotalTime = EndTime - StartTime;
-  double MaxTotalTime;
-#ifndef GENERICIO_NO_MPI
-  if (CollStats)
-    MPI_Reduce(&TotalTime, &MaxTotalTime, 1, MPI_DOUBLE, MPI_MAX, 0, Comm);
-  else
-#endif
-  MaxTotalTime = TotalTime;
-
-  uint64_t AllTotalReadSize;
-#ifndef GENERICIO_NO_MPI
-  if (CollStats)
-    MPI_Reduce(&TotalReadSize, &AllTotalReadSize, 1, MPI_UINT64_T, MPI_SUM, 0, Comm);
-  else
-#endif
-  AllTotalReadSize = TotalReadSize;
-
-  if (Rank == 0 && PrintStats) {
-    double Rate = ((double) AllTotalReadSize) / MaxTotalTime / (1024.*1024.);
-    cout << "Read " << Vars.size() << " variables from " << FileName <<
-            " (" << AllTotalReadSize << " bytes) in " << MaxTotalTime << "s: " <<
-            Rate << " MB/s [excluding header read]" << endl;
-  }
-
 }
 
Index: GenericIO.h
===================================================================
--- GenericIO.h	(revision a4fee139105de3bf748818b08fe85b87b6d2bf56)
+++ GenericIO.h	(revision 8f0a211de68fdaf18f8af21d8574c73197b28c5e)
@@ -188,5 +188,6 @@
   GenericIO(const MPI_Comm &C, const std::string &FN, unsigned FIOT = -1)
     : NElems(0), FileIOType(FIOT == (unsigned) -1 ? DefaultFileIOType : FIOT),
-      Partition(DefaultPartition), Comm(C), FileName(FN), SplitComm(MPI_COMM_NULL) {
+      Partition(DefaultPartition), Comm(C), FileName(FN), Redistributing(false),
+      DisableCollErrChecking(false), SplitComm(MPI_COMM_NULL) {
     std::fill(PhysOrigin, PhysOrigin + 3, 0.0);
     std::fill(PhysScale,  PhysScale + 3, 0.0);
@@ -195,5 +196,6 @@
   GenericIO(const std::string &FN, unsigned FIOT = -1)
     : NElems(0), FileIOType(FIOT == (unsigned) -1 ? DefaultFileIOType : FIOT),
-      Partition(DefaultPartition), FileName(FN) {
+      Partition(DefaultPartition), FileName(FN), Redistributing(false),
+      DisableCollErrChecking(false) {
     std::fill(PhysOrigin, PhysOrigin + 3, 0.0);
     std::fill(PhysScale,  PhysScale + 3, 0.0);
@@ -264,7 +266,13 @@
 #endif
 
+  enum MismatchBehavior {
+    MismatchAllowed,
+    MismatchDisallowed,
+    MismatchRedistribute
+  };
+
   // Reading
-  void openAndReadHeader(bool MustMatch = true, int EffRank = -1,
-                         bool CheckPartMap = true);
+  void openAndReadHeader(MismatchBehavior MB = MismatchDisallowed,
+                         int EffRank = -1, bool CheckPartMap = true);
 
   int readNRanks();
@@ -280,5 +288,4 @@
 
   int getNumberOfVariables() { return this->Vars.size(); };
-
 
   void getVariableInfo(std::vector<VariableInfo> &VI);
@@ -330,7 +337,7 @@
 
   template <bool IsBigEndian>
-  void readHeaderLeader(void *GHPtr, bool MustMatch, int SplitNRanks,
-                        std::string &LocalFileName, uint64_t &HeaderSize,
-                        std::vector<char> &Header);
+  void readHeaderLeader(void *GHPtr, MismatchBehavior MB, int Rank, int NRanks,
+                        int SplitNRanks, std::string &LocalFileName,
+                        uint64_t &HeaderSize, std::vector<char> &Header);
 
   template <bool IsBigEndian>
@@ -358,6 +365,10 @@
   void readCoords(int Coords[3], int EffRank);
 
-  template <bool IsBigEndian>
-  void readData(int EffRank, bool PrintStats, bool CollStats);
+  void readData(int EffRank, size_t RowOffset, int Rank,
+                uint64_t &TotalReadSize, int NErrs[3]);
+
+  template <bool IsBigEndian>
+  void readData(int EffRank, size_t RowOffset,
+                int Rank, uint64_t &TotalReadSize, int NErrs[3]);
 
   template <bool IsBigEndian>
@@ -384,4 +395,8 @@
   static std::size_t CollectiveMPIIOThreshold;
 #endif
+
+  // When redistributing, the rank blocks which this process should read.
+  bool Redistributing, DisableCollErrChecking;
+  std::vector<int> SourceRanks;
 
   std::vector<int> RankMap;
Index: GenericIO2Cosmo.cxx
===================================================================
--- GenericIO2Cosmo.cxx	(revision da65757e00f1d262bf6da9c45b4a33e8b80b8e88)
+++ GenericIO2Cosmo.cxx	(revision 8f0a211de68fdaf18f8af21d8574c73197b28c5e)
@@ -102,5 +102,5 @@
 #endif
     mpiioName, Method);
-  GIO.openAndReadHeader(false);
+  GIO.openAndReadHeader(GenericIO::MismatchAllowed);
 
   int NR = GIO.readNRanks();
Index: GenericIOBenchmarkRead.cxx
===================================================================
--- GenericIOBenchmarkRead.cxx	(revision ba0fbd18085d2978bd2d6cc1f3dfe7d93da737d7)
+++ GenericIOBenchmarkRead.cxx	(revision 8f0a211de68fdaf18f8af21d8574c73197b28c5e)
@@ -87,5 +87,5 @@
     MPI_COMM_WORLD,
     mpiioName, Method);
-  GIO.openAndReadHeader();
+  GIO.openAndReadHeader(GenericIO::MismatchRedistribute);
 
   MPI_Barrier(MPI_COMM_WORLD);
Index: GenericIOPrint.cxx
===================================================================
--- GenericIOPrint.cxx	(revision da65757e00f1d262bf6da9c45b4a33e8b80b8e88)
+++ GenericIOPrint.cxx	(revision 8f0a211de68fdaf18f8af21d8574c73197b28c5e)
@@ -144,5 +144,5 @@
     GenericIO GIO(FileName, Method);
 #endif
-    GIO.openAndReadHeader(false, -1, !ShowMap);
+    GIO.openAndReadHeader(GenericIO::MismatchAllowed, -1, !ShowMap);
 
     int NR = GIO.readNRanks();
Index: GenericIOVerify.cxx
===================================================================
--- GenericIOVerify.cxx	(revision da65757e00f1d262bf6da9c45b4a33e8b80b8e88)
+++ GenericIOVerify.cxx	(revision 8f0a211de68fdaf18f8af21d8574c73197b28c5e)
@@ -106,5 +106,6 @@
       bool MustMatch = false;
 #endif
-      GIO.openAndReadHeader(MustMatch);
+      GIO.openAndReadHeader(MustMatch ? GenericIO::MismatchRedistribute :
+                                        GenericIO::MismatchDisallowed);
       if (Verbose) cout << "\theader: okay" << endl;
 
