2022-01-23 12:27:04 +01:00
|
|
|
import sys
|
2022-01-23 14:13:36 +01:00
|
|
|
import shutil
|
2022-01-23 12:27:04 +01:00
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import configparser
|
|
|
|
from pprint import pp
|
|
|
|
|
|
|
|
from time import time
|
|
|
|
from datetime import timedelta
|
2022-01-23 16:56:50 +01:00
|
|
|
from datetime import datetime
|
2022-01-23 12:27:04 +01:00
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
import subprocess as sp
|
2022-01-23 16:56:50 +01:00
|
|
|
import urllib.request
|
|
|
|
import urllib.parse
|
|
|
|
import urllib.error
|
|
|
|
import json
|
|
|
|
|
2022-01-23 12:27:04 +01:00
|
|
|
|
|
|
|
_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(
|
2022-01-23 13:16:00 +01:00
|
|
|
filename=config.get('main', 'log_file', fallback=None),
|
2022-01-23 12:27:04 +01:00
|
|
|
level=args.log_level
|
|
|
|
)
|
|
|
|
log = logging.getLogger('openfoam')
|
|
|
|
|
|
|
|
log.info('Starting program')
|
|
|
|
|
2022-01-23 16:56:50 +01:00
|
|
|
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)
|
|
|
|
|
2022-01-23 13:42:53 +01:00
|
|
|
input_dir = Path(config.get('main', 'input_dir'), config.get('main', 'case'))\
|
|
|
|
.expanduser()
|
|
|
|
work_dir = Path(config.get('main', 'work_dir')).expanduser()
|
2022-01-23 12:27:04 +01:00
|
|
|
|
|
|
|
if not work_dir.exists():
|
|
|
|
log.error(f'Work directory ({work_dir}) not found')
|
|
|
|
sys.exit(1)
|
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
case_dir = work_dir.joinpath(config.get('main', 'case'))
|
2022-01-23 12:27:04 +01:00
|
|
|
if case_dir.exists():
|
|
|
|
log.info(f'Deleting case ({case_dir})')
|
2022-01-23 14:13:36 +01:00
|
|
|
shutil.rmtree(case_dir)
|
2022-01-23 12:27:04 +01:00
|
|
|
|
|
|
|
log.info(f'Copying case ({input_dir} -> {case_dir})')
|
2022-01-23 14:13:36 +01:00
|
|
|
shutil.copytree(input_dir, case_dir)
|
2022-01-23 12:27:04 +01:00
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
if config.getboolean('stl', 'copy', fallback=False):
|
2022-01-23 14:13:36 +01:00
|
|
|
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)
|
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
stl_dir = case_dir.joinpath('constant', 'triSurface')
|
|
|
|
if stl_dir.exists():
|
|
|
|
log.info(f'Deleting stl directory ({stl_dir})')
|
2022-01-23 14:13:36 +01:00
|
|
|
shutil.rmtree(stl_dir)
|
2022-01-23 13:16:00 +01:00
|
|
|
|
|
|
|
log.info(f'Copying stl directory ({stl_in} -> {stl_dir})')
|
2022-01-23 14:13:36 +01:00
|
|
|
shutil.copytree(stl_in, stl_dir)
|
2022-01-23 13:16:00 +01:00
|
|
|
|
|
|
|
if config.getboolean('blockMesh', 'enable', fallback=False):
|
2022-01-23 12:27:04 +01:00
|
|
|
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')
|
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
if config.getboolean('snappyHexMesh', 'enable', fallback=False):
|
2022-01-23 12:27:04 +01:00
|
|
|
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')
|
2022-01-23 14:13:36 +01:00
|
|
|
shutil.copytree(
|
|
|
|
case_dir.joinpath('0.org'),
|
|
|
|
case_dir.joinpath('0'),
|
2022-01-23 12:27:04 +01:00
|
|
|
)
|
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
if config.getboolean('setFields', 'enable', fallback=False):
|
2022-01-23 12:27:04 +01:00
|
|
|
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')
|
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
if config.getboolean('olaFlow', 'enable', fallback=False):
|
2022-01-23 12:27:04 +01:00
|
|
|
cmd = ('olaFlow')
|
2022-01-23 13:16:00 +01:00
|
|
|
if config.getboolean('parallel', 'enable', fallback=False):
|
2022-01-23 12:27:04 +01:00
|
|
|
cmd = (
|
|
|
|
'mpirun',
|
2022-01-23 13:16:00 +01:00
|
|
|
'-np', config.get('parallel', 'threads'),
|
2022-01-23 12:27:04 +01:00
|
|
|
'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')
|
|
|
|
|
2022-01-23 13:16:00 +01:00
|
|
|
if config.getboolean('parallel', 'enable', fallback=False) \
|
|
|
|
and config.getboolean('reconstructPar', 'enable', fallback=False):
|
2022-01-23 12:27:04 +01:00
|
|
|
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}')
|
2022-01-23 14:13:36 +01:00
|
|
|
shutil.rmtree(proc_dir)
|
2022-01-23 12:27:04 +01:00
|
|
|
|
2022-01-23 16:56:50 +01:00
|
|
|
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)
|
|
|
|
|
2022-01-23 12:27:04 +01:00
|
|
|
_t1 = time()
|
|
|
|
log.info(f'Program ended successfully after {timedelta(seconds=_t1-_t0)}')
|