pythonflopy

Truncate CBB File using Flopy


I am interested in truncating a binary MODFLOW CBB file after a certain number of stress periods. Using the Flopy binary file utilities, I have been able to understand how to unpack a binary file and extract values into an array. However, it is unclear if I can use the Flopy utilities directly to create a new binary file. Does Flopy have a utility that would help facilitate writing out a portion of the CBB file to a new binary file? The new CBB file will serve as input to MODPATH, so the formatting of the CBB file would need to remain intact.

With Flopy alone, I feel like I am close to getting the results I need. I'm sure there are Python specific libraries that could be used to get the desired results, but I figured I would see if I can get there with Flopy first.

Here is what I have looked into so far:

import flopy.utils.binaryfile as bf
CBBFile = 'PRE_WT_WP3_PREISS_MidK.cbb'
CBB = bf.CellBudgetFile(CBBFile)
CBB.list_records()

Output from CBB.list_records() for first and last stress periods:

(1, 1, '         STORAGE', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, '   CONSTANT HEAD', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, 'FLOW RIGHT FACE ', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, 'FLOW FRONT FACE ', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, 'FLOW LOWER FACE ', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, '          DRAINS', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, '   RIVER LEAKAGE', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, ' HEAD DEP BOUNDS', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 1, '        RECHARGE', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')

....

(1, 6, '         STORAGE', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, '   CONSTANT HEAD', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, 'FLOW RIGHT FACE ', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, 'FLOW FRONT FACE ', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, 'FLOW LOWER FACE ', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, '          DRAINS', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, '   RIVER LEAKAGE', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, ' HEAD DEP BOUNDS', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')
(1, 6, '        RECHARGE', 537, 341, 12, 0, 0.0, 0.0, -1.0, '', '', '', '')

I am looking to keep all of these budget terms in the new binary file, but would like to drop all terms from the last stress period (Stress Period 6 in this example).

I tried to query stress period data into an array and then write this data to a new binary file with the code below. I am running into memory issues with this code. The example CBB file being processed here is considerably smaller (~460 mb) than the CBB I would ultimately like to process (~55 gb). It seems that reading the file to an array may be unnecessary for what I am trying to do.

allRec = CBB.get_data(kstpkper = (0,1))
i = 1
while i < 45:
   rec = CBB.get_data(kstpkper = (0,i))
   allRec = np.append(allRec, rec)
   i += 1
np.save('StrippedCBBFile', allRec)

My other idea was to read the CBB file line-by-line and write out only the data I need. This would require decoding the header line to determine the current stress period to know when to stop writing data. I have not been able to decode the header information to do so.

Thanks!


Solution

  • There are not any specific flopy utilities for rewriting binary budget files. The flopy develop branch has a method (.get_position()) for determining the position of the start of the data (and the header information) for a record in a binary budget file. The .get_position() method will be available in future flopy versions (version > 3.2.10).

    >>> import flopy 
    >>> cobj = flopy.utils.CellBudgetFile('freyberg.gitcbc')
    >>> cobj.get_indices(text='CONSTANT HEAD')
    array([   0,    8,   16, ..., 8752, 8760, 8767])
    >>> cobj.get_position(8767)
    50235424
    >>> cobj.get_position(8767, header=True)
    50235372
    

    The position data could be used to create a binary file with a slice of the binary budget file using standard python.

    fin = open('freyberg.gitcbc', 'rb')
    fin.seek(50235372)
    length = os.path.getsize(fpth) - 50235372
    
    buffsize = 32
    with open('end.cbc', 'wb') as fout:
        while length:
            chunk = min(buffsize, length)
            data = fin.read(chunk)
            fout.write(data)
            length -= chunk