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.error from .grafana import Silencer from .stl import copy_stl from .blockmesh import blockmesh from .snappyhexmesh import snappyhexmesh _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') grafana = Silencer( url=config.get('grafana', 'url'), apikey=config.get('grafana', 'apikey'), ) grafana.silence_alert() 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) log.info(f'Copying stl directory ({stl_in})') copy_stl(stl_in, case_dir) if config.getboolean('blockMesh', 'enable', fallback=False): log.info('Running blockMesh') code = blockmesh(case_dir) 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') code = snappyhexmesh(case_dir) 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') grafana.unsilence_alert() _t1 = time() log.info(f'Program ended successfully after {timedelta(seconds=_t1-_t0)}')