This repository has been archived on 2022-02-01. You can view files and clone it, but cannot push or open issues or pull requests.
openfoam_project/openfoam/run/__main__.py

267 lines
7.9 KiB
Python

import sys
import shutil
import argparse
import logging
import configparser
from pprint import pp
from time import time
from datetime import timedelta
from datetime import datetime
from pathlib import Path
import subprocess as sp
import urllib.request
import urllib.parse
import urllib.error
import json
_t0 = time()
parser = argparse.ArgumentParser(
description='Run the OpenFoam simulation'
)
parser.add_argument('-c', '--config', default='config.ini', type=Path,
help='Configuration file (default config.ini)')
parser.add_argument('-l', '--log-level', default='INFO', type=str,
help='Log level')
args = parser.parse_args()
config = configparser.ConfigParser()
config.read(args.config)
logging.basicConfig(
filename=config.get('main', 'log_file', fallback=None),
level=args.log_level
)
log = logging.getLogger('openfoam')
log.info('Starting program')
if config.getboolean('grafana', 'pause', fallback=False):
log.info('Silencing Grafana alert')
try:
with urllib.request.urlopen(
urllib.request.Request(
urllib.parse.urljoin(
config.get('grafana', 'url'),
'api/alertmanager/grafana/api/v2/silences',
),
headers={
'Authorization':
f'Bearer {config.get("grafana", "apikey")}',
},
),
data=bytes(json.dumps({
"comment": "Openfoam run",
"createdBy": "Python OpenFoam run",
"endsAt": (datetime.utcnow() + timedelta(days=1)).isoformat(),
"matchers": [
{
"isEqual": True,
"isRegex": False,
"name": "alertname",
"value": "CPU Usage"
}
],
"startsAt": datetime.utcnow().isoformat()
}), 'utf-8'),
) as api_req:
api_res = api_req.read()
grafana_alert_id = json.loads(api_res)['id']
except urllib.error.HTTPError as e:
log.error(f'Grafana silence returned code {e.code}')
sys.exit(1)
input_dir = Path(config.get('main', 'input_dir'), config.get('main', 'case'))\
.expanduser()
work_dir = Path(config.get('main', 'work_dir')).expanduser()
if not work_dir.exists():
log.error(f'Work directory ({work_dir}) not found')
sys.exit(1)
case_dir = work_dir.joinpath(config.get('main', 'case'))
if case_dir.exists():
log.info(f'Deleting case ({case_dir})')
shutil.rmtree(case_dir)
log.info(f'Copying case ({input_dir} -> {case_dir})')
shutil.copytree(input_dir, case_dir)
if config.getboolean('stl', 'copy', fallback=False):
stl_in = Path(config.get('stl', 'from')).expanduser()
if not stl_in.exists():
log.error(f'STL from directory does not exist ({stl_in})')
sys.exit(1)
stl_dir = case_dir.joinpath('constant', 'triSurface')
if stl_dir.exists():
log.info(f'Deleting stl directory ({stl_dir})')
shutil.rmtree(stl_dir)
log.info(f'Copying stl directory ({stl_in} -> {stl_dir})')
shutil.copytree(stl_in, stl_dir)
if config.getboolean('blockMesh', 'enable', fallback=False):
log.info('Running blockMesh')
blockmesh_log = logging.getLogger('blockMesh')
proc = sp.Popen(
('blockMesh'),
cwd=case_dir,
stdout=sp.PIPE,
stderr=sp.PIPE,
text=True,
)
for line in proc.stdout:
blockmesh_log.info(line[:-1])
for line in proc.stderr:
blockmesh_log.error(line[:-1])
code = proc.wait()
if code != 0:
log.error('blockMesh failed')
sys.exit(code)
log.info(f'blockMesh finished successfully')
if config.getboolean('snappyHexMesh', 'enable', fallback=False):
log.info('Running snappyHexMesh')
snappy_log = logging.getLogger('snappyHexMesh')
proc = sp.Popen(
('snappyHexMesh', '-overwrite'),
cwd=case_dir,
stdout=sp.PIPE,
stderr=sp.PIPE,
text=True,
)
for line in proc.stdout:
snappy_log.info(line[:-1])
for line in proc.stderr:
snappy_log.error(line[:-1])
code = proc.wait()
if code != 0:
log.error('snappyHexMesh failed')
sys.exit(code)
log.info(f'snappyHexMesh finished successfully')
log.info('Copying 0.org -> 0')
shutil.copytree(
case_dir.joinpath('0.org'),
case_dir.joinpath('0'),
)
if config.getboolean('setFields', 'enable', fallback=False):
log.info('Running setFields')
setfields_log = logging.getLogger('setFields')
proc = sp.Popen(
('setFields'),
cwd=case_dir,
stdout=sp.PIPE,
stderr=sp.PIPE,
text=True,
)
for line in proc.stdout:
setfields_log.info(line[:-1])
for line in proc.stderr:
setfields_log.info(line[:-1])
code = proc.wait()
if code != 0:
log.error('setFields failed')
sys.exit(code)
log.info(f'setFields finished successfully')
if config.getboolean('olaFlow', 'enable', fallback=False):
cmd = ('olaFlow')
if config.getboolean('parallel', 'enable', fallback=False):
cmd = (
'mpirun',
'-np', config.get('parallel', 'threads'),
'olaFlow', '-parallel'
)
decpar_log = logging.getLogger('decomposePar')
proc = sp.Popen(
('decomposePar'),
cwd=case_dir,
stdout=sp.PIPE,
stderr=sp.PIPE,
text=True,
)
for line in proc.stdout:
decpar_log.info(line[:-1])
for line in proc.stderr:
decpar_log.error(line[:-1])
code = proc.wait()
if code != 0:
log.error('decomposePar failed')
sys.exit(code)
log.info(f'decomposePar finished successfully')
log.info('Running olaFlow')
olaflow_log = logging.getLogger('olaFlow')
proc = sp.Popen(
cmd,
cwd=case_dir,
stdout=sp.PIPE,
stderr=sp.PIPE,
text=True,
)
for line in proc.stdout:
olaflow_log.info(line[:-1])
for line in proc.stderr:
olaflow_log.error(line[:-1])
code = proc.wait()
if code != 0:
log.error('olaFlow failed')
sys.exit(code)
log.info(f'olaFlow finished successfully')
if config.getboolean('parallel', 'enable', fallback=False) \
and config.getboolean('reconstructPar', 'enable', fallback=False):
recpar_log = logging.getLogger('reconstructPar')
proc = sp.Popen(
('reconstructPar'),
cwd=case_dir,
stdout=sp.PIPE,
stderr=sp.PIPE,
text=True,
)
for line in proc.stdout:
recpar_log.info(line[:-1])
for line in proc.stderr:
recpar_log.error(line[:-1])
code = proc.wait()
if code != 0:
log.error('reconstructPar failed')
sys.exit(code)
log.info(f'reconstructPar finished successfully')
log.info(f'Deleting processor directories')
for proc_dir in case_dir.glob(r'processor*'):
log.info(f'Deleting {proc_dir}')
shutil.rmtree(proc_dir)
if config.getboolean('grafana', 'pause', fallback=False):
log.info('Unsilencing Grafana alert')
try:
with urllib.request.urlopen(
urllib.request.Request(
urllib.parse.urljoin(
config.get('grafana', 'url'),
'api/alertmanager/grafana/api/v2/silence/'
f'{grafana_alert_id}',
),
headers={
'Authorization':
f'Bearer {config.get("grafana", "apikey")}',
},
method='DELETE',
),
) as api_req:
api_res = api_req.read()
except urllib.error.HTTPError as e:
log.error(f'Grafana unsilence returned code {e.code}')
sys.exit(1)
_t1 = time()
log.info(f'Program ended successfully after {timedelta(seconds=_t1-_t0)}')