Перейти к основному содержимому

Примеры

Все примеры на этой странице прогнаны на реальном проекте — дипольной антенне из комплекта примеров GAMMA — и приведены с фактическим результатом.

Открыть, посчитать, выгрузить, сохранить

Сценарий CalculateAndExport.gcp:

REM Без этих переменных сценарий работал бы с пустыми путями
Break IfVariableIsNotDefined GAMMA_PROJECT
Break IfVariableIsNotDefined GAMMA_EXPORT_DIR
REM
Directory Create "%GAMMA_EXPORT_DIR%"
Project Open "%GAMMA_PROJECT%"
Mode Set FEM
Solver Start
Solver RecalcSMatrix
CalculationResult Export SNP "%GAMMA_EXPORT_DIR%"
Project Save
Project Close
REM Журнал покажет, на какой строке сценарий остановился
CommandProcessorLog Export "%GAMMA_EXPORT_DIR%\scenario.log"
Exit

Запуск:

set GAMMA_PROJECT=D:\Work\Dipole.gma
set GAMMA_EXPORT_DIR=D:\Work\Export
Gamma.exe CalculateAndExport.gcp
if %errorlevel% neq 0 (
echo [ERROR] сценарий завершился с кодом %errorlevel%
exit /b 1
)

Результат: код возврата 0, в каталоге экспорта Dipole_1.s1p, Dipole_2.s1p и scenario.log.

То же самое из Python

import os
import sys
import gammapy as gamma


def main(project, export_dir):
os.makedirs(export_dir, exist_ok=True)
with gamma.service.start() as app:
gamma.service.set_verbose_mode(app, False)
app.project_open(project)
app.mode_set('FEM')
app.solver_start()
app.solver_recalc_s_matrix()
app.calculation_result_export('SNP', export_dir)
app.project_save()
app.project_close()
print('готово, файлов: %d' % len(os.listdir(export_dir)))


main(sys.argv[1], sys.argv[2])

Проверять код возврата не нужно: неуспешная команда возбудит исключение, и скрипт завершится с ненулевым кодом.

Пакетный обход каталога

Запуск GAMMA стоит дороже, чем открытие проекта, поэтому весь пакет обрабатывается в одном экземпляре приложения.

import glob
import os
import sys
import gammapy as gamma


def run_one(app, project, export_root):
name = os.path.splitext(os.path.basename(project))[0]
export_dir = os.path.join(export_root, name)
os.makedirs(export_dir, exist_ok=True)

app.project_open(project)
try:
app.mode_set('FEM')
app.solver_start()
app.calculation_result_export('SNP', export_dir)
app.project_save()
finally:
# Незакрытый проект сломал бы следующую итерацию
app.project_close()


def main(source_dir, export_root):
# "~tmp<Имя>.gma" — файл восстановления рядом с проектом, он тоже
# попадает под маску *.gma. Считать его не нужно.
projects = sorted(p for p in glob.glob(os.path.join(source_dir, '*.gma'))
if not os.path.basename(p).startswith('~tmp'))
failed = []
with gamma.service.start() as app:
gamma.service.set_verbose_mode(app, False)
for i, project in enumerate(projects, 1):
print('[%d/%d] %s' % (i, len(projects),
os.path.basename(project)), flush=True)
try:
run_one(app, project, export_root)
except Exception as error:
print(' ОШИБКА:', error)
failed.append(os.path.basename(project))
print('%d из %d успешно' % (len(projects) - len(failed), len(projects)))
return 1 if failed else 0


sys.exit(main(sys.argv[1], sys.argv[2]))

Фактический прогон на двух проектах:

[1/2] Dipole.gma
ok, 236.6 s
[2/2] WaveguideTee.gma
ok, 32.5 s

2 of 2 succeeded
подсказка

Разброс времени между двумя небольшими проектами — семикратный, и почти всё время сценария занимает сам расчёт: в замере это 271 секунда из 277. Планируя пакетный прогон, ориентируйтесь на самый тяжёлый проект, а не на среднее.

Перенос настроек решателя

Project Open "%GAMMA_PROJECT%"
REM Посмотреть параметры
FEMSolverSettings Get Solution.SweepType
FEMSolverSettings Get Refinement.MaxPasses
REM Изменить и вернуть к значению по умолчанию
FEMSolverSettings Set Refinement.MaxPasses 12
FEMSolverSettings Reset Refinement.MaxPasses
REM Выгрузить весь набор и загрузить обратно
FEMSolverSettings Export "%GAMMA_SETTINGS%"
FEMSolverSettings Import "%GAMMA_SETTINGS%"
Project Close
Exit

Формат файла определяется расширением: .ini, .json или .txt. Первые два покрывают всё состояние настроек, включая параметры без имени в командном процессоре; .txt — только те параметры, что адресуются командой.

Перенос горячих клавиш

REM Действия одного режима. Без открытого проекта режим называется явно
Shortcuts Get File.New Mode=FEM
Shortcuts Get All Mode=FEM
REM Назначить, проверить и сбросить к значению по умолчанию
Shortcuts Set File.Save Ctrl+Shift+S Mode=FEM
Shortcuts Reset File.Save Mode=FEM
REM Выгрузить весь набор режима и загрузить обратно
Shortcuts Export "%GAMMA_SHORTCUTS%" Mode=FEM
Shortcuts Import "%GAMMA_SHORTCUTS%" Mode=FEM
Exit

Действие адресуется своим objectNameFile.New, Common.Edit.Rename — а не подписью в меню: подпись меняется вместе с языком интерфейса, имя нет. Полный список действий режима выдаёт Shortcuts Get All.

Команда работает с действиями одного режима — того же набора, что показывает диалог «Настройка горячих клавиш». Режим берётся из открытого проекта; когда проекта нет, его нужно назвать через Mode=, иначе команда откажется работать, а не вернёт пустой список. Режим, не покрытый лицензией, тоже отклоняется.

Формат файла определяется расширением: .xml, .txt или .json. Файл .xml совместим с диалогом — выгруженное командой можно загрузить кнопкой «Импорт» и наоборот.

примечание

Изменение записывается в реестр сразу, а не при выходе из приложения — чтобы скрипт не терял настройку, если процесс после него завершат принудительно.

Выгрузить журнал приложения

REM Журнал приложения - не журнал команд: это то, что пишут решатель,
REM построитель сетки и остальные подсистемы
Project Open "%GAMMA_PROJECT%"
REM Все записи, независимо от категории и уровня
Log Export All "%GAMMA_EXPORT_DIR%\application.log"
REM Только открытая вкладка журнала - то же, что делает кнопка окна
Log Export "%GAMMA_EXPORT_DIR%\application_page.log"
REM UTF-8, если журнал потом разбирается find/findstr
Log Export Encoding=UTF-8 All "%GAMMA_EXPORT_DIR%\application_utf8.log"
Log Clear
Project Close
Exit

Фактический прогон на дипольной антенне: код возврата 0, три файла —

ФайлРазмерЗаписей
application.log3 668 байт19: 13 в категории common, 6 в mesher
application_page.log2 474 байта13, только common
application_utf8.log1 871 байтте же 19

Записи в журнале появляются уже от одного Project Open — расчёт для этого не нужен: при открытии проекта журнал восстанавливается с диска. Разница между первым и вторым файлом — это разница между двумя пунктами меню кнопки: с флагом All выгружаются все категории, без него — только та вкладка, что открыта.

Каждая строка файла — одна запись в формате JSONL, тот же формат, в котором приложение пишет свои *.log рядом с проектом:

{"cat":"common","lvl":"stat","txt":"Hello World"}

По умолчанию файл пишется в UTF-16 — как и все остальные журналы приложения. Encoding=UTF-8 нужен, если журнал потом разбирается однобайтовыми средствами.

примечание

Log Clear очищает журнал целиком, как кнопка «Очистить» в окне. Экспорт сразу после очистки даёт файл из одной метки порядка байт — 2 байта, ноль записей.