Каков рабочий процесс создания зоны для работы zone_budget на лету? - PullRequest
1 голос
/ 29 октября 2019

У меня есть рабочая модель с выходом. Я пытаюсь воспользоваться преимуществом флопи при опросе результатов. В частности, я хотел бы иметь возможность генерировать (на лету) информацию о бюджете зоны для конкретных ячеек. Конечно, я могу пойти на создание файлов зон, которые меня интересуют, но я надеялся, что смогу извлекать результаты по мере необходимости, не проходя этот промежуточный этап.

IЯ ищу рабочий процесс, который я могу использовать в Python для извлечения информации о сетевом потоке из CBB (уже сгенерированного) для определенных ячеек только в консоли Python (скорее избегать устаревшего стиля генерации файлов зон, импорта, затем извлечения).

РЕДАКТИРОВАТЬ

Возникли проблемы с попыткой заставить утилиту работать вообще. Вот последняя попытка. Не могу сказать, что Flopy задыхается от самого CBB или из-за того, что предоставленная мною зона создает проблемы.

Модель состоит из 7 слоев, 196 рядов, 241 столбца. Я пытаюсь извлечь Layer = 3, Row = 58, Col = 30. Объект списка, который я создал для зоны, находится здесь:

zon_lst = []
for lay in range(7):
    for row in range(196):
        for col in range(241):
            if lay == 2 and row == 57 and col == 29:
                zon_lst.append(1)
            else:
                zon_lst.append(0)

Затем я записал это в файл, используя следующее:

def chunk_list(alist, n):
    for i in range(0, len(alist), n):
        yield alist[i:i + n]

def zon_gen(mylst, rows, cols, file_cols):
    # Assumes integers for zonation file
    frmt = '{:>3}'
    list_by_lay = chunk_list(mylst, rows * cols)
    astr = '\n'.join(['\n'.join([''.join([frmt.format(i) for i in seq]) for seq in chunk_list(layer, file_cols)]) for layer in list_by_lay])
    return astr

zon_str = zon_gen(zon_lst, 196, 241, 10)
with open('t_26.zon', 'w+') as file:
    file.write('# For Scoping Work\n')
    file.write('1\n')
    file.write('t_26\n')
    file.write('INTERNAL 1 (10I3)  1\n')
    file.write(zon_str)

Затем я строю свою модель modflow для бюджета зоныкласс / методы:

import flopy
mf = flopy.modflow.Modflow(modelname='t_26_scope', version='mf2k')
zon = flopy.modflow.ModflowZon.load(r"t_26.zon",mf,nrow=196, ncol=241)
zb = flopy.utils.zonbud.ZoneBudget(r"P2Rv8.2_1000yr.cbb", zon)

Все это работает до самой последней команды, где я получаю следующую ошибку:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\ProgramData\Miniconda3\envs\ca_cie\lib\site-packages\flopy\utils\zonbud.py", line 53, in __init__
    self.cbc = CellBudgetFile(cbc_file)
  File "C:\ProgramData\Miniconda3\envs\ca_cie\lib\site-packages\flopy\utils\binaryfile.py", line 618, in __init__
    self._build_index()
  File "C:\ProgramData\Miniconda3\envs\ca_cie\lib\site-packages\flopy\utils\binaryfile.py", line 708, in _build_index
    self._skip_record(header)
  File "C:\ProgramData\Miniconda3\envs\ca_cie\lib\site-packages\flopy\utils\binaryfile.py", line 768, in _skip_record
    self.file.seek(nbytes, 1)
OSError: [Errno 22] Invalid argument

Пожалуйста, помните, что я все еще заинтересованв пропуске части записи файла. Я включил его, чтобы показать свою работу до этого момента

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

Матрица, требуемая классом ZoneBudget, должна иметь следующие измерения (в общих выражениях):

ndarray_dim = lays * rows * cols

В приведенном здесь примере задачи соответствующие измерения: 7 * 196 * 241, в результатев:

len(my_array)
>>> 7
len(my_array[0])
>>> 196
len(my_array[0][0])
>>> 241

Как было указано, мне нужно будет отследить причину, по которой двоичный считыватель для двоичного файла бюджета по ячейкам не может прочитать файл, поэтому я подготовлю этокак еще одно обсуждение в будущем. Спасибо за забаву в вопросе @Jason Bellino!

Кстати, генератор файлов зон не генерирует файл блочного стиля, как то, что ожидает flopy. Я добавил мой обновленный код здесь:

def chunk_list(alist, n):
for i in range(0, len(alist), n):
    yield alist[i:i + n]


def block_gen(mylst, rows, cols, file_cols, field_len):
    # mylst is a 1D array whose length matches that of the number of cells in the model
    # rows, cols: These are the total rows, columns; respectively
    # Assumes integers for zonation file
    frmt = '{:>%d}' % field_len
    zon_str = ''
    for lay in chunk_list(mylst, (rows * cols)):
        zon_str += 'INTERNAL          ({:}I{})\n'.format(file_cols, field_len)
        for block in chunk_list(lay, cols):
            for line in chunk_list(block, file_cols):
                zon_str += ''.join([frmt.format(cell) for cell in line]) + '\n'
    return zon_str


def write_zb_zonefile(filepath, lays, rows, cols, zon_str):
    with open(filepath, 'w+') as file:
        file.write('{:<6}{:<6}{:<6}\n'.format(lays, rows, cols))
        file.write(zon_str)
    return

Который, если вы используете результирующий файл с flopy.utils.zonbud.read_zbarray(<filepath>), вы получите пригодный для использования zone_dict в классе flopy.utils.zonbud.ZoneBudget.

Поскольку я хотел избежать необходимости записывать файл каждый раз, когда мне нужен новый бюджет зоны, я изменил функцию block_gen() и создал функцию, которая будет генерировать что-то, что можно непосредственно использовать в классе ZoneBudget:

from numpy import array
def arr_block_gen(mylst, rows, cols):
    # mylst: 1D array containing zone definition for every cell in the model
    # rows: total number of rows in the model
    # cols: total number of columns in the model
    zon_arr = []
    lay_idx = 0
    for lay in chunk_list(mylst, (rows * cols)):
        row_idx = 0
        zon_arr.append([])
        for block in chunk_list(lay, cols):
            zon_arr[lay_idx].append(block)
            row_idx += 1
        lay_idx += 1
    zon_arr = array(zon_arr)
    return zon_arr

ОБНОВЛЕНИЕ Оказывается, причина, по которой метод был взорван, была вызвана тем, что поведение этого метода по умолчанию состоит в передаче пути файла CBB к классу чтения двоичных файлов, по умолчанию эточитать файлы CBB с одинарной точностью. Итак, я решил эту проблему, создав объект CBB с использованием средства чтения двоичных файлов (передавая значение double в качестве точности), а затем явно передал объект CBB, а не файл, как показано в моем вопросе.

0 голосов
/ 29 октября 2019

Вы можете получить информацию о бюджете, используя ZoneBudget класс flopy. Он принимает массив NumPy в качестве входных данных;вспомогательные утилиты read_zbarray и write_zbarray были включены для обратной совместимости. Если вы столкнетесь с проблемой, опубликуйте минимальный рабочий пример здесь, и я посмотрю, смогу ли я вам помочь.

...