From 70862995e71346ebf6e9d587ceab44725b32a97b Mon Sep 17 00:00:00 2001
From: Uwe Schulzweida <uwe.schulzweida@mpimet.mpg.de>
Date: Sat, 28 Dec 2024 14:31:48 +0100
Subject: [PATCH] NetCDF4: improved calculation of output chunk size

---
 ChangeLog       |  4 ++++
 src/cdf_write.c | 35 +++++++++++++++++++++++++++++------
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2ee6a6ba4..e36c0a0f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2024-12-28  Uwe Schulzweida
+
+	* NetCDF4: improved calculation of output chunk size
+
 2024-12-23  Uwe Schulzweida
 
 	* NetCDF4: improved calculation of input chunk cache size for numStep>1 and zSize>1
diff --git a/src/cdf_write.c b/src/cdf_write.c
index eb556afca..1e73c949e 100644
--- a/src/cdf_write.c
+++ b/src/cdf_write.c
@@ -702,19 +702,41 @@ calc_chunksize(size_t chunkSizeLim, size_t size)
 static const size_t chunkSizeMin = 262144;    // 256k
 static const size_t chunkSizeLim = 16777216;  // 16m
 
+size_t
+auto_chunksize_y(size_t gridsize, size_t xsize, size_t ysize)
+{
+  size_t gridChunkSize = calc_chunksize(chunkSizeLim, gridsize);
+  size_t yChunkSize = gridChunkSize / xsize;
+  size_t numChunks = (ysize % yChunkSize == 0) ? (ysize / yChunkSize) : (ysize / yChunkSize) + 1;
+  size_t modChunk = ysize % numChunks;
+  size_t maxChunks = numChunks * 2;
+  for (size_t i = numChunks; i < maxChunks; ++i)
+    {
+      size_t imod = ysize % i;
+      if (imod == 0 || imod > modChunk)
+        {
+          numChunks = i;
+          modChunk = imod;
+          if (modChunk == 0) break;
+        }
+    }
+  yChunkSize = ysize / numChunks;
+  return yChunkSize;
+}
+
 size_t
 calc_chunksize_y(int chunkType, size_t gridsize, size_t xsize, size_t ysize)
 {
   if (chunkType == CDI_CHUNK_AUTO)
-    return (gridsize <= chunkSizeMin) ? ysize : chunkSizeMin / xsize;
+    return auto_chunksize_y(gridsize, xsize, ysize);
   else
     return (chunkType == CDI_CHUNK_LINES) ? 1 : ysize;
 }
 
 size_t
-calc_chunksize_x(int chunkType, long chunkSize, size_t xsize, bool yIsUndefined)
+calc_chunksize_x(int chunkType, long chunkSize, size_t xsize, bool isReg2dGrid)
 {
-  if (chunkType == CDI_CHUNK_AUTO && yIsUndefined)
+  if (chunkType == CDI_CHUNK_AUTO && !isReg2dGrid)
     return (chunkSize > 0 && (size_t) chunkSize < xsize) ? (size_t) chunkSize : ((xsize <= chunkSizeMin) ? xsize : chunkSizeMin);
   else
     return calc_chunksize(chunkSizeLim, xsize);
@@ -753,9 +775,10 @@ cdfDefineDimsAndChunks(const stream_t *streamptr, int varID, int xid, int yid, i
   cdiInqKeyInt(vlistID, varID, CDI_KEY_CHUNKSIZE, &chunkSize);
   if (chunkSize > 0 && yid == CDI_UNDEFID) chunkType = CDI_CHUNK_AUTO;
 
-  if (chunkType == CDI_CHUNK_GRID && gridsize > ChunkSizeLim)
+  bool isReg2dGrid = (yid != CDI_UNDEFID && xid != CDI_UNDEFID);
+  if (chunkType == CDI_CHUNK_GRID && gridsize > ChunkSizeLim && isReg2dGrid)
     {
-      if (CDI_Debug) fprintf(stderr, "gridsize > %u, changed chunkType to CDI_CHUNK_LINES!\n", ChunkSizeLim);
+      if (CDI_Debug) fprintf(stderr, "gridsize > %u, changed chunkType to CDI_CHUNK_AUTO!\n", ChunkSizeLim);
       chunkType = CDI_CHUNK_AUTO;
     }
 
@@ -776,7 +799,7 @@ cdfDefineDimsAndChunks(const stream_t *streamptr, int varID, int xid, int yid, i
         }
       else if (dimorder[id] == 1 && xid != CDI_UNDEFID)
         {
-          chunks[ndims] = calc_chunksize_x(chunkType, chunkSize, xsize, (yid == CDI_UNDEFID));
+          chunks[ndims] = calc_chunksize_x(chunkType, chunkSize, xsize, isReg2dGrid);
           dims[ndims] = xid;
           ndims++;
         }
-- 
GitLab