From 3b6cfde86c8cdac7e6995b5457606c1215c404de Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 15 Jul 2022 17:32:09 +0100 Subject: [PATCH 01/52] local para --- src/ansys/fluent/parametric/lispy.py | 316 +++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 src/ansys/fluent/parametric/lispy.py diff --git a/src/ansys/fluent/parametric/lispy.py b/src/ansys/fluent/parametric/lispy.py new file mode 100644 index 00000000..357e3017 --- /dev/null +++ b/src/ansys/fluent/parametric/lispy.py @@ -0,0 +1,316 @@ +################ Scheme Interpreter in Python + +## (c) Peter Norvig, 2010; See http://norvig.com/lispy2.html + +################ Symbol, Procedure, classes + +import re, sys, io + +class Symbol(str): pass + +def Sym(s, symbol_table={}): + "Find or create unique Symbol entry for str s in symbol table." + if s not in symbol_table: symbol_table[s] = Symbol(s) + return symbol_table[s] + +_quote, _if, _set, _define, _lambda, _begin, _definemacro, = map(Sym, +"quote if set! define lambda begin define-macro".split()) + +_quasiquote, _unquote, _unquotesplicing = map(Sym, +"quasiquote unquote unquote-splicing".split()) + +class Procedure: + "A user-defined Scheme procedure." + def __init__(self, parms, exp, env): + self.parms, self.exp, self.env = parms, exp, env + def __call__(self, *args): + return eval(self.exp, Env(self.parms, args, self.env)) + +################ parse, read, and user interaction + +def parse(inport): + "Parse a program: read and expand/error-check it." + # Backwards compatibility: given a str, convert it to an InPort + if isinstance(inport, str): inport = InPort(io.StringIO(inport)) + return expand(read(inport), toplevel=True) + +eof_object = Symbol('#') # Note: uninterned; can't be read + +class InPort: + "An input port. Retains a line of chars." + tokenizer = r"""\s*(,@|[('`,)]|"(?:[\\].|[^\\"])*"|;.*|[^\s('"`,;)]*)(.*)""" + def __init__(self, file): + self.file = file; self.line = '' + def next_token(self): + "Return the next token, reading new text into line buffer if needed." + while True: + if self.line == '': self.line = self.file.readline() + if self.line == '': return eof_object + token, self.line = re.match(InPort.tokenizer, self.line).groups() + if token != '' and not token.startswith(';'): + return token + +def readchar(inport): + "Read the next character from an input port." + if inport.line != '': + ch, inport.line = inport.line[0], inport.line[1:] + return ch + else: + return inport.file.read(1) or eof_object + +def read(inport): + "Read a Scheme expression from an input port." + def read_ahead(token): + if '(' == token: + L = [] + while True: + token = inport.next_token() + if token == ')': return L + else: L.append(read_ahead(token)) + elif ')' == token: raise SyntaxError('unexpected )') + elif token in quotes: return [quotes[token], read(inport)] + elif token is eof_object: raise SyntaxError('unexpected EOF in list') + else: return atom(token) + # body of read: + token1 = inport.next_token() + return eof_object if token1 is eof_object else read_ahead(token1) + +quotes = {"'":_quote, "`":_quasiquote, ",":_unquote, ",@":_unquotesplicing} + +def atom(token): + 'Numbers become numbers; #t and #f are booleans; "..." string; otherwise Symbol.' + if token == '#t': return True + elif token == '#f': return False + elif token[0] == '"': return token[1:-1] + try: return int(token) + except ValueError: + try: return float(token) + except ValueError: + try: return complex(token.replace('i', 'j', 1)) + except ValueError: + return Sym(token) + +def to_string(x): + "Convert a Python object back into a Lisp-readable string." + if x is True: return "#t" + elif x is False: return "#f" + elif isa(x, Symbol): return x + elif isa(x, str): return repr(x) + elif isa(x, list): return '('+' '.join(map(to_string, x))+')' + elif isa(x, complex): return str(x).replace('j', 'i') + else: return str(x) + +def load(filename): + "Eval every expression from a file." + repl(None, InPort(open(filename)), None) + +def repl(prompt='lispy> ', inport=InPort(sys.stdin), out=sys.stdout): + "A prompt-read-eval-print loop." + sys.stderr.write("Lispy version 2.0\n") + while True: + try: + if prompt: sys.stderr.write(prompt) + x = parse(inport) + if x is eof_object: return + val = eval(x) + if val is not None and out: print(to_string(val), file=out) + except Exception as e: + print('%s: %s' % (type(e).__name__, e)) + +################ Environment class + +class Env(dict): + "An environment: a dict of {'var':val} pairs, with an outer Env." + def __init__(self, parms=(), args=(), outer=None): + # Bind parm list to corresponding args, or single parm to list of args + self.outer = outer + if isa(parms, Symbol): + self.update({parms:list(args)}) + else: + if len(args) != len(parms): + raise TypeError('expected %s, given %s, ' + % (to_string(parms), to_string(args))) + self.update(zip(parms,args)) + def find(self, var): + "Find the innermost Env where var appears." + if var in self: return self + elif self.outer is None: raise LookupError(var) + else: return self.outer.find(var) + +def is_pair(x): return x != [] and isa(x, list) +def cons(x, y): return [x]+y + +def callcc(proc): + "Call proc with current continuation; escape only" + ball = RuntimeWarning("Sorry, can't continue this continuation any longer.") + def throw(retval): ball.retval = retval; raise ball + try: + return proc(throw) + except RuntimeWarning as w: + if w is ball: return ball.retval + else: raise w + +def add_globals(self): + "Add some Scheme standard procedures." + import math, cmath, operator as op + self.update(vars(math)) + self.update(vars(cmath)) + self.update({ + '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, 'not':op.not_, + '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, + 'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':cons, + 'car':lambda x:x[0], 'cdr':lambda x:x[1:], 'append':op.add, + 'list':lambda *x:list(x), 'list?': lambda x:isa(x,list), + 'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol), + 'boolean?':lambda x: isa(x, bool), 'pair?':is_pair, + 'port?': lambda x:isa(x,file), 'apply':lambda proc,l: proc(*l), + 'eval':lambda x: eval(expand(x)), 'load':lambda fn: load(fn), 'call/cc':callcc, + 'open-input-file':open,'close-input-port':lambda p: p.file.close(), + 'open-output-file':lambda f:open(f,'w'), 'close-output-port':lambda p: p.close(), + 'eof-object?':lambda x:x is eof_object, 'read-char':readchar, + 'read':read, 'write':lambda x,port=sys.stdout:port.write(to_string(x)), + 'display':lambda x,port=sys.stdout:port.write(x if isa(x,str) else to_string(x))}) + return self + +isa = isinstance + +global_env = add_globals(Env()) + +################ eval (tail recursive) + +def eval(x, env=global_env): + "Evaluate an expression in an environment." + while True: + if isa(x, Symbol): # variable reference + return env.find(x)[x] + elif not isa(x, list): # constant literal + return x + elif x[0] is _quote: # (quote exp) + (_, exp) = x + return exp + elif x[0] is _if: # (if test conseq alt) + (_, test, conseq, alt) = x + x = (conseq if eval(test, env) else alt) + elif x[0] is _set: # (set! var exp) + (_, var, exp) = x + env.find(var)[var] = eval(exp, env) + return None + elif x[0] is _define: # (define var exp) + (_, var, exp) = x + env[var] = eval(exp, env) + return None + elif x[0] is _lambda: # (lambda (var*) exp) + (_, vars, exp) = x + return Procedure(vars, exp, env) + elif x[0] is _begin: # (begin exp+) + for exp in x[1:-1]: + eval(exp, env) + x = x[-1] + else: # (proc exp*) + exps = [eval(exp, env) for exp in x] + proc = exps.pop(0) + if isa(proc, Procedure): + x = proc.exp + env = Env(proc.parms, exps, proc.env) + else: + return proc(*exps) + +################ expand + +def expand(x, toplevel=False): + "Walk tree of x, making optimizations/fixes, and signaling SyntaxError." + require(x, x!=[]) # () => Error + if not isa(x, list): # constant => unchanged + return x + elif x[0] is _quote: # (quote exp) + require(x, len(x)==2) + return x + elif x[0] is _if: + if len(x)==3: x = x + [None] # (if t c) => (if t c None) + require(x, len(x)==4) + return list(map(expand, x)) + elif x[0] is _set: + require(x, len(x)==3); + var = x[1] # (set! non-var exp) => Error + require(x, isa(var, Symbol), "can set! only a symbol") + return [_set, var, expand(x[2])] + elif x[0] is _define or x[0] is _definemacro: + require(x, len(x)>=3) + _def, v, body = x[0], x[1], x[2:] + if isa(v, list) and v: # (define (f args) body) + f, args = v[0], v[1:] # => (define f (lambda (args) body)) + return expand([_def, f, [_lambda, args]+body]) + else: + require(x, len(x)==3) # (define non-var/list exp) => Error + require(x, isa(v, Symbol), "can define only a symbol") + exp = expand(x[2]) + if _def is _definemacro: + require(x, toplevel, "define-macro only allowed at top level") + proc = eval(exp) + require(x, callable(proc), "macro must be a procedure") + macro_table[v] = proc # (define-macro v proc) + return None # => None; add v:proc to macro_table + return [_define, v, exp] + elif x[0] is _begin: + if len(x)==1: return None # (begin) => None + else: return [expand(xi, toplevel) for xi in x] + elif x[0] is _lambda: # (lambda (x) e1 e2) + require(x, len(x)>=3) # => (lambda (x) (begin e1 e2)) + vars, body = x[1], x[2:] + require(x, (isa(vars, list) and all(isa(v, Symbol) for v in vars)) + or isa(vars, Symbol), "illegal lambda argument list") + exp = body[0] if len(body) == 1 else [_begin] + body + return [_lambda, vars, expand(exp)] + elif x[0] is _quasiquote: # `x => expand_quasiquote(x) + require(x, len(x)==2) + return expand_quasiquote(x[1]) + elif isa(x[0], Symbol) and x[0] in macro_table: + return expand(macro_table[x[0]](*x[1:]), toplevel) # (m arg...) + else: # => macroexpand if m isa macro + return list(map(expand, x)) # (f arg...) => expand each + +def require(x, predicate, msg="wrong length"): + "Signal a syntax error if predicate is false." + if not predicate: raise SyntaxError(to_string(x)+': '+msg) + +_append, _cons, _let = map(Sym, "append cons let".split()) + +def expand_quasiquote(x): + """Expand `x => 'x; `,x => x; `(,@x y) => (append x y) """ + if not is_pair(x): + return [_quote, x] + require(x, x[0] is not _unquotesplicing, "can't splice here") + if x[0] is _unquote: + require(x, len(x)==2) + return x[1] + elif is_pair(x[0]) and x[0][0] is _unquotesplicing: + require(x[0], len(x[0])==2) + return [_append, x[0][1], expand_quasiquote(x[1:])] + else: + return [_cons, expand_quasiquote(x[0]), expand_quasiquote(x[1:])] + +def let(*args): + args = list(args) + x = cons(_let, args) + require(x, len(args)>1) + bindings, body = args[0], args[1:] + require(x, all(isa(b, list) and len(b)==2 and isa(b[0], Symbol) + for b in bindings), "illegal binding list") + vars, vals = zip(*bindings) + return [[_lambda, list(vars)]+list(map(expand, body))] + list(map(expand, vals)) + +macro_table = {_let:let} ## More macros can go here + +eval(parse("""(begin + +(define-macro and (lambda args + (if (null? args) #t + (if (= (length args) 1) (car args) + `(if ,(car args) (and ,@(cdr args)) #f))))) + +;; More macros can also go here + +)""")) + +if __name__ == '__main__': + repl() \ No newline at end of file From d6244a81dd7f3c3de7e1e7fb60f943b112895669 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 15 Jul 2022 19:57:57 +0100 Subject: [PATCH 02/52] PoC --- src/ansys/fluent/parametric/lispy.py | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/parametric/lispy.py b/src/ansys/fluent/parametric/lispy.py index 357e3017..d912873d 100644 --- a/src/ansys/fluent/parametric/lispy.py +++ b/src/ansys/fluent/parametric/lispy.py @@ -4,6 +4,32 @@ ################ Symbol, Procedure, classes + +''' Example usage + +import h5py +f = h5py.File('E:/elbow1_param.cas.h5') +settings = f['settings'] +rpvars = settings['Rampant Variables'] +rpvars0 = rpvars[0] +from ansys.fluent.parametric import lispy +lines = lispy.parse(rpvars0.decode())[1] +exprs = None +for line in lines: + if type(line) == list and len(line) and line[0] == "named-expressions": + exprs = line + +input_params = [] +for expr in expr_data: + for attr in expr: + if attr[0] == 'input-parameter' and attr[2] == True: + input_params.append(expr) + +import pprint +pprint.pprint(input_params) + +''' + import re, sys, io class Symbol(str): pass @@ -219,7 +245,9 @@ def eval(x, env=global_env): def expand(x, toplevel=False): "Walk tree of x, making optimizations/fixes, and signaling SyntaxError." - require(x, x!=[]) # () => Error + #require(x, x!=[]) # () => Error + if x == []: + return x if not isa(x, list): # constant => unchanged return x elif x[0] is _quote: # (quote exp) From 124d88ae244adf42e26426c39d7c3497b54c242e Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 18 Jul 2022 16:06:36 +0100 Subject: [PATCH 03/52] local para --- .../parametric/local/filereader/__init__.py | 0 .../parametric/local/filereader/casereader.py | 31 ++ .../{ => local/filereader}/lispy.py | 26 +- src/ansys/fluent/parametric/local/local.py | 380 ++++++++++++++++++ 4 files changed, 413 insertions(+), 24 deletions(-) create mode 100644 src/ansys/fluent/parametric/local/filereader/__init__.py create mode 100644 src/ansys/fluent/parametric/local/filereader/casereader.py rename src/ansys/fluent/parametric/{ => local/filereader}/lispy.py (95%) create mode 100644 src/ansys/fluent/parametric/local/local.py diff --git a/src/ansys/fluent/parametric/local/filereader/__init__.py b/src/ansys/fluent/parametric/local/filereader/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py new file mode 100644 index 00000000..8b41f8c9 --- /dev/null +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -0,0 +1,31 @@ + +import h5py +from .import lispy + +class CaseReader: + + def __init__(self, file_path): + file = h5py.File(file_path) + settings = file['settings'] + rpvars = settings['Rampant Variables'][0] + rp_vars_str = rpvars.decode() + self._rp_vars = lispy.parse(rp_vars_str)[1] + + def input_parameters(self): + exprs = self.named_expressions() + + input_params = [] + for expr in exprs: + for attr in expr: + if attr[0] == 'input-parameter' and attr[2] == True: + input_params.append(expr) + return input_params + + def named_expressions(self): + return self._find_rp_var("named-expressions") + + def _find_rp_var(self, name: str): + for var in self._rp_vars: + if type(var) == list and len(var) and var[0] == name: + return var[1] + diff --git a/src/ansys/fluent/parametric/lispy.py b/src/ansys/fluent/parametric/local/filereader/lispy.py similarity index 95% rename from src/ansys/fluent/parametric/lispy.py rename to src/ansys/fluent/parametric/local/filereader/lispy.py index d912873d..4b87ef89 100644 --- a/src/ansys/fluent/parametric/lispy.py +++ b/src/ansys/fluent/parametric/local/filereader/lispy.py @@ -4,31 +4,9 @@ ################ Symbol, Procedure, classes +## This code is copied from https://github.com/norvig/pytudes/blob/main/py/lispy.py and modified +## as necessary -''' Example usage - -import h5py -f = h5py.File('E:/elbow1_param.cas.h5') -settings = f['settings'] -rpvars = settings['Rampant Variables'] -rpvars0 = rpvars[0] -from ansys.fluent.parametric import lispy -lines = lispy.parse(rpvars0.decode())[1] -exprs = None -for line in lines: - if type(line) == list and len(line) and line[0] == "named-expressions": - exprs = line - -input_params = [] -for expr in expr_data: - for attr in expr: - if attr[0] == 'input-parameter' and attr[2] == True: - input_params.append(expr) - -import pprint -pprint.pprint(input_params) - -''' import re, sys, io diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py new file mode 100644 index 00000000..6f6964f8 --- /dev/null +++ b/src/ansys/fluent/parametric/local/local.py @@ -0,0 +1,380 @@ +""" +Classes for running a parametric study in Fluent. + +Example +------- +from ansys.fluent.addons.parametric import ParametricStudy, DesignPointStatus # noqa: E501 + +Instantiate the study, specifying the case + +study = ParametricStudy(case_file_name=my_case_file_name) + +Add one new design point and set an input parameter + +dp1 = study.add_design_point("DP1") +dp1.set_input("parameter_1", 0.235) +dp1.set_input("velocity_inlet_5_y_velocity", 0.772) + +The solver has not been run yet so no outputs are computed +The design point is out of date + +assert(dp1.status == DesignPointStatus.OUT_OF_DATE) + +Get the base design point + +base = study.design_point("Base DP") + +Check that block updates works + +dp1.block_updates() +base.block_updates() +assert(dp1.status == DesignPointStatus.BLOCKED) +study.update_all() +assert(dp1.outputs == base.outputs) + +Update the design points + +dp1.allow_updates() +base.allow_updates() +assert(dp1.status == DesignPointStatus.OUT_OF_DATE) +study.update_all() + +Check that dp1 is up to date and that the outputs differ + +assert(dp1.status == DesignPointStatus.UPDATED) +assert(dp1.outputs != base.outputs) + +It's important to clean up any studies to help ensure that +all Fluent sessions are cleaned up + +del study +""" + +from enum import Enum + +import ansys.fluent as pyfluent + + +class DesignPointStatus(Enum): + """ + Status of a design point in a parametric study. + + Attributes + ---------- + OUT_OF_DATE : int + UPDATING : int + UPDATED : int + FAILED : int + BLOCKED : int + """ + + OUT_OF_DATE = 1 + UPDATING = 2 + UPDATED = 3 + FAILED = 4 + BLOCKED = 5 + + +class DesignPoint: + """ + Design point in a parametric study. + + Attributes + ---------- + name : str + Name of the design point as a str. + outputs : dict + Dict of output parameters + (name of parameter to value). + inputs : dict + Dict of input parameters + (name of parameter to value). + status : DesignPointStatus + Current status of the design point. + + Methods + ------- + set_input(parameter_name: str, value) + Set one parameter in the design point to the value provided. + on_end_updating(outputs: dict) + Inform the design point that it is in an UPDATED state and + provides the associated output parameters. + block_updates() + Move the design point into a do not update state. + block_updates() + Move the design point into a needs update state. + """ + + def __init__(self, design_point_name: str, base_design_point=None): + self.name = design_point_name + if base_design_point: + self.__inputs = base_design_point.inputs.copy() + self.__outputs = base_design_point.outputs.copy() + else: + self.__inputs = {} + self.__outputs = {} + # TODO add listener for __status: + self.__status = DesignPointStatus.OUT_OF_DATE + + @property + def inputs(self) -> dict: + return self.__inputs + + @inputs.setter + def inputs(self, inputs: dict): + self.__status = DesignPointStatus.OUT_OF_DATE + self.__inputs = inputs + + @property + def outputs(self) -> dict: + return self.__outputs + + @outputs.setter + def outputs(self, outputs: dict): + self.__status = DesignPointStatus.OUT_OF_DATE + self.__outputs = outputs + + @property + def status(self) -> DesignPointStatus: + return self.__status + + def set_input(self, parameter_name: str, value): + self.__status = DesignPointStatus.OUT_OF_DATE + self.__inputs[parameter_name] = value + + def on_start_updating(self): + self.__status = DesignPointStatus.UPDATING + + def on_end_updating(self, outputs: dict): + self.__outputs = outputs + self.__status = DesignPointStatus.UPDATED + + def block_updates(self): + self.__status = DesignPointStatus.BLOCKED + + def allow_updates(self): + self.__status = DesignPointStatus.OUT_OF_DATE + + +class DesignPointTable(list): + """ + Design point study in a parametric study + + Methods + ------- + add_design_point(design_point_name: str) -> DesignPoint + Add a new design point to the table with the provided name. + find_design_point(idx_or_name) + Get a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + remove_design_point(idx_or_name) + Remove a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + """ + + def __init__(self, base_design_point: DesignPoint): + super().__init__() + self.append(base_design_point) + + def add_design_point(self, design_point_name: str) -> DesignPoint: + self.append(DesignPoint(design_point_name, self[0])) + return self[-1] + + def find_design_point(self, idx_or_name) -> DesignPoint: + if isinstance(idx_or_name, int): + return self[idx_or_name] + for design_point in self: + if idx_or_name == design_point.name: + return design_point + raise RuntimeError(f"Design point not found: {idx_or_name}") + + def remove_design_point(self, idx_or_name): + design_point = self.find_design_point(idx_or_name) + if design_point is self[0]: + raise RuntimeError("Cannot remove base design point") + self.remove(self.find_design_point(idx_or_name)) + + +class FluentParameterAccessor: + """ + Extracts parameter name to value dicts from table strs + currently returned by the API + + Attributes + ---------- + input_parameters : dict + The current input parameter dict. + output_parameters : dict + The current input parameter dict. + """ + + def __init__(self, fluent_session): + self.__list_parameters = ( + fluent_session.tui.solver.define.parameters.list_parameters + ) + + @property + def input_parameters(self) -> dict: + return FluentParameterAccessor.__parameter_table_to_dict( + self.__list_parameters.input_parameters() + ) + + @property + def output_parameters(self) -> dict: + return FluentParameterAccessor.__parameter_table_to_dict( + self.__list_parameters.output_parameters() + ) + + @staticmethod + def __parameter_table_to_dict(table: str) -> dict: + # this code has become more complex now. Originally table was + # str here - now ExecuteCommandResult is returned by the calls + # to (in|out)put_parameters() + table_str = table + if not isinstance(table, str): + try: + table_str = table.result + except AttributeError as attr_err: + raise RuntimeError( + "Unexpected design point table " + f"type in parse: {type(table)}" + ) from attr_err + data_lines = table_str.splitlines()[3:] + table_as_dict = {} + for line in data_lines: + line_as_list = line.split() + table_as_dict[line_as_list[0]] = line_as_list[1] + return table_as_dict + + +class ParametricSession: + """ + Full set of interactions with Fluent in the context of a parametric study + + Attributes + ---------- + input_parameters : dict + The current input parameter dict. + output_parameters : dict + The current input parameter dict. + + Methods + ------- + set_input_parameter(parameter_name: str) + Set a single input parameter value in the Fluent session. + initialize_with_case(case_file_name: str) + Read the specified case into Fluent. + update() + Run the solver until convergence. + """ + + def __init__(self, fluent_session): + self.__fluent_session = fluent_session + self.__parameter_accessor = FluentParameterAccessor(fluent_session) + + @property + def input_parameters(self) -> dict: + return self.__parameter_accessor.input_parameters + + @property + def output_parameters(self) -> dict: + return self.__parameter_accessor.output_parameters + + def set_input_parameter(self, parameter_name: str, value): + self.__fluent_session.tui.solver.define.parameters.input_parameters.edit( # noqa: E501 + parameter_name, parameter_name, value + ) + + def initialize_with_case(self, case_file_name: str): + self.__fluent_session.tui.solver.file.read_case( + case_file_name=case_file_name + ) + + def update(self): + self.__fluent_session.tui.solver.solve.initialize.initialize_flow() + self.__fluent_session.tui.solver.solve.iterate() + + def __del__(self): + self.__fluent_session.exit() + + +class FluentLauncher: + """ + Launches fluent sessions. + + Methods + ------- + __call__() + Launch a session + """ + + def __call__(self): + return ParametricSession(fluent_session=pyfluent.launch_fluent()) + + +class ParametricStudy: + """ + Parametric study that manages design points to parametrize a + Fluent solver set-up. Provides ability to run Fluent for a series + of design points, and access the inputs and outputs. + + Methods + ------- + update_all() + Bring all design point outputs up to date by running the + solver on each design point. Ignores BLOCKED design points. + update_design_point() + Bring the outputs of the specified design point up to date + by running the solver. + add_design_point(design_point_name: str) -> DesignPoint + Add a design point + design_point(idx_or_name) + Get a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + """ + + def __init__( + self, + case_file_name: str = "", + base_design_point_name: str = "Base DP", + launcher=FluentLauncher(), + ): + self.__session = launcher() + if case_file_name: + self.__session.initialize_with_case(case_file_name) + base_design_point = DesignPoint(base_design_point_name) + base_design_point.inputs = self.__session.input_parameters.copy() + base_design_point.outputs = self.__session.output_parameters.copy() + self.__design_point_table = DesignPointTable(base_design_point) + + def update_all(self): + for design_point in self.__design_point_table: + if design_point.status != DesignPointStatus.BLOCKED: + self.update_design_point(design_point) + + def update_design_point(self, design_point: DesignPoint): + design_point.on_start_updating() + for parameter_name, value in design_point.inputs.items(): + self.__session.set_input_parameter(parameter_name, value) + self.__session.update() + design_point.on_end_updating( + outputs=self.__session.output_parameters.copy() + ) + + def add_design_point(self, design_point_name: str) -> DesignPoint: + return self.__design_point_table.add_design_point(design_point_name) + + def design_point(self, idx_or_name) -> DesignPoint: + return self.__design_point_table.find_design_point(idx_or_name) From 450bf0b64ef872f8b8383b7203eb055118c1f2c6 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 18 Jul 2022 16:57:57 +0100 Subject: [PATCH 04/52] cons fix --- .../fluent/parametric/local/filereader/casereader.py | 2 +- .../fluent/parametric/local/filereader/lispy.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 8b41f8c9..6c19d786 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -17,7 +17,7 @@ def input_parameters(self): input_params = [] for expr in exprs: for attr in expr: - if attr[0] == 'input-parameter' and attr[2] == True: + if attr[0] == 'input-parameter' and attr[1] == True: input_params.append(expr) return input_params diff --git a/src/ansys/fluent/parametric/local/filereader/lispy.py b/src/ansys/fluent/parametric/local/filereader/lispy.py index 4b87ef89..fe09c3c9 100644 --- a/src/ansys/fluent/parametric/local/filereader/lispy.py +++ b/src/ansys/fluent/parametric/local/filereader/lispy.py @@ -67,10 +67,20 @@ def read(inport): def read_ahead(token): if '(' == token: L = [] + cons = None while True: token = inport.next_token() if token == ')': return L - else: L.append(read_ahead(token)) + if token == '.': + if len(L) > 1: + cons = [L.pop()] + else: + ahead = read_ahead(token) + if cons: + cons.append(ahead) + ahead = cons + cons = None + L.append(ahead) elif ')' == token: raise SyntaxError('unexpected )') elif token in quotes: return [quotes[token], read(inport)] elif token is eof_object: raise SyntaxError('unexpected EOF in list') From 37796a7b4762ca119471083152c3dec439018a47 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 18 Jul 2022 17:08:13 +0100 Subject: [PATCH 05/52] refactor --- .../parametric/local/filereader/casereader.py | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 6c19d786..ae1ea241 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -4,26 +4,35 @@ class CaseReader: - def __init__(self, file_path): - file = h5py.File(file_path) + def __init__(self, case_file_path): + file = h5py.File(case_file_path) settings = file['settings'] rpvars = settings['Rampant Variables'][0] rp_vars_str = rpvars.decode() self._rp_vars = lispy.parse(rp_vars_str)[1] def input_parameters(self): - exprs = self.named_expressions() + return self._parameters(input_parameter=True) + def output_parameters(self): + return self._parameters(input_parameter=False) + + def named_expressions(self): + return self._named_expressions() + + def _named_expressions(self): + return self._find_rp_var("named-expressions") + + def _parameters(self, input_parameter: bool): + exprs = self._named_expressions() input_params = [] + parameter_type = ('in' if input_parameter else 'out') + 'put-parameter' for expr in exprs: for attr in expr: - if attr[0] == 'input-parameter' and attr[1] == True: + if attr[0] == parameter_type and attr[1] == True: input_params.append(expr) return input_params - def named_expressions(self): - return self._find_rp_var("named-expressions") - def _find_rp_var(self, name: str): for var in self._rp_vars: if type(var) == list and len(var) and var[0] == name: From 8947b52c6d3aa97f8396487400c7eac1cf42ff6f Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 18 Jul 2022 18:12:29 +0100 Subject: [PATCH 06/52] test --- tests/test_lispy.py | 55 ++++++++++++++++ tests/test_local.py | 155 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 tests/test_lispy.py create mode 100644 tests/test_local.py diff --git a/tests/test_lispy.py b/tests/test_lispy.py new file mode 100644 index 00000000..fbc4e58e --- /dev/null +++ b/tests/test_lispy.py @@ -0,0 +1,55 @@ + +from ansys.fluent.parametric.local.filereader import lispy + +def test_read(): + in_outs = [ + [ + "1", + 1 + ], + + [ + "(1)", + [1] + ], + + [ + "(1 2)", + [1, 2] + ], + + [ + "(1 . 2)", + [1, 2] + ], + + [ + "(1 2 3)", + [1, 2, 3] + + ], + + [ + "(1 2 . 3)", + [1, [2, 3]] + ], + + [ + "((1 . 2) . 3)", + [[1, 2], 3] + ], + + [ + "(1 . (2 . 3))", + [1, [2, 3]] + ], + + [ + "(x 1)", + ["x", 1] + ] + ] + + for in_out in in_outs: + assert lispy.parse(in_out[0]) == in_out[1] + diff --git a/tests/test_local.py b/tests/test_local.py new file mode 100644 index 00000000..a96442c5 --- /dev/null +++ b/tests/test_local.py @@ -0,0 +1,155 @@ +""" +Unit tests for parameteric study code: local version +""" + +from ansys.fluent.parametric.local import ( + DesignPoint, + DesignPointStatus, + DesignPointTable, + ParametricStudy + ) + + +def make_simple_base_design_point(): + dp = DesignPoint("base") + dp.inputs = {"x": 2} + dp.outputs = {"y": 0} + return dp + + +class XTimes: + """ + test class + """ + + def __init__(self, multiplier): + self.multiplier = multiplier + self.input_parameters = {"x": 0} + self.output_parameters = {"y": 0} + + def __call__(self): + return self + + def set_input_parameter(self, parameter_name: str, value): + self.input_parameters[parameter_name] = value + + def update(self): + self.output_parameters["y"] = ( + self.multiplier * self.input_parameters["x"] + ) + + +def test_create_base_design_point(): + dp = make_simple_base_design_point() + assert dp.name == "base" + assert dp.inputs == {"x": 2} + assert dp.outputs == {"y": 0} + assert dp.status == DesignPointStatus.OUT_OF_DATE + + +def test_create_user_defined_design_point(): + dp = DesignPoint("DP1", base_design_point=make_simple_base_design_point()) + assert dp.name == "DP1" + assert dp.inputs == {"x": 2} + assert dp.outputs == {"y": 0} + assert dp.status == DesignPointStatus.OUT_OF_DATE + + +def test_start_and_end_design_point_update(): + base_dp = make_simple_base_design_point() + dp1 = DesignPoint("DP1", base_design_point=base_dp) + base_dp.on_start_updating() + assert base_dp.status == DesignPointStatus.UPDATING + assert dp1.status == DesignPointStatus.OUT_OF_DATE + base_dp.on_end_updating({"y": 1}) + assert base_dp.status == DesignPointStatus.UPDATED + assert dp1.status == DesignPointStatus.OUT_OF_DATE + dp1.on_start_updating() + assert base_dp.status == DesignPointStatus.UPDATED + assert dp1.status == DesignPointStatus.UPDATING + dp1.on_end_updating({"y": 42}) + assert base_dp.status == DesignPointStatus.UPDATED + assert dp1.status == DesignPointStatus.UPDATED + + +def test_add_remove_find_points_in_table(): + table = DesignPointTable(DesignPoint("base")) + table.append(DesignPoint("a")) + table.append(DesignPoint("b")) + table.append(DesignPoint("c")) + assert table.find_design_point("b").name == "b" + assert table.find_design_point("base").name == "base" + assert table.find_design_point(0).name == "base" + assert table.find_design_point(3).name == "c" + table.remove_design_point("a") + table.remove_design_point(2) + assert len(table) == 2 + assert table.find_design_point("b").name == "b" + assert table.find_design_point("base").name == "base" + throws = False + try: + table.remove_design_point(0) + except RuntimeError: + throws = True + assert throws + throws = False + try: + table.remove_design_point("base") + except RuntimeError: + throws = True + assert throws + assert len(table) == 2 + assert table.find_design_point("b").name == "b" + assert table.find_design_point("base").name == "base" + + +def test_run_parametric_study(): + multiplier = 3 + study = ParametricStudy( + base_design_point_name="xxx", launcher=XTimes(multiplier) + ) + inputs = [0, 3, 8, -5] + for i in range(1, len(inputs)): + study.add_design_point("d" + repr(i)).set_input("x", inputs[i]) + for i in range(len(inputs)): + assert study.design_point(i).status == DesignPointStatus.OUT_OF_DATE + study.update_all() + for i in range(len(inputs)): + assert study.design_point(i).status == DesignPointStatus.UPDATED + assert study.design_point(i).outputs["y"] == multiplier * inputs[i] + + +def test_run_parametric_study_and_block(): + multiplier = 3 + study = ParametricStudy( + base_design_point_name="xxx", launcher=XTimes(multiplier) + ) + inputs = [0, 3, 8, -5] + for i in range(1, len(inputs)): + study.add_design_point("d" + repr(i)).set_input("x", inputs[i]) + for i in range(len(inputs)): + if i % 2: + study.design_point(i).block_updates() + for i in range(len(inputs)): + status = ( + DesignPointStatus.BLOCKED + if i % 2 + else DesignPointStatus.OUT_OF_DATE + ) + assert study.design_point(i).status == status + study.update_all() + for i in range(len(inputs)): + status = ( + DesignPointStatus.BLOCKED if i % 2 else DesignPointStatus.UPDATED + ) + assert study.design_point(i).status == status + assert ( + study.design_point(i).outputs["y"] + == (0 if i % 2 else multiplier) * inputs[i] + ) + for i in range(len(inputs)): + if i % 2: + study.update_design_point(study.design_point(i)) + for i in range(len(inputs)): + assert study.design_point(i).status == DesignPointStatus.UPDATED + assert study.design_point(i).outputs["y"] == multiplier * inputs[i] From 9f989586f1f860b30dbf8af520886baaf6751569 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Mon, 18 Jul 2022 18:19:17 +0100 Subject: [PATCH 07/52] refactor --- tests/test_lispy.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_lispy.py b/tests/test_lispy.py index fbc4e58e..094dafd3 100644 --- a/tests/test_lispy.py +++ b/tests/test_lispy.py @@ -47,6 +47,11 @@ def test_read(): [ "(x 1)", ["x", 1] + ], + + [ + "(x . \"1.0 [m/s]\")", + ["x", "1.0 [m/s]"] # should be "'1.0 [m/s]'" ? ] ] From 36fcdc93bfbca18c47a277651b0379209dfdccba Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 11:17:51 +0100 Subject: [PATCH 08/52] spread values into runtime study --- src/ansys/fluent/parametric/local/__init__.py | 0 src/ansys/fluent/parametric/local/local.py | 80 ++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/ansys/fluent/parametric/local/__init__.py diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 6f6964f8..b9ec7ea5 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -51,8 +51,10 @@ """ from enum import Enum +from math import ceil import ansys.fluent as pyfluent +from .filereader.casereader import CaseReader class DesignPointStatus(Enum): @@ -349,9 +351,9 @@ def __init__( self, case_file_name: str = "", base_design_point_name: str = "Base DP", - launcher=FluentLauncher(), + launcher=None, ): - self.__session = launcher() + self.__session = launcher() if launcher else FluentLauncher() if case_file_name: self.__session.initialize_with_case(case_file_name) base_design_point = DesignPoint(base_design_point_name) @@ -378,3 +380,77 @@ def add_design_point(self, design_point_name: str) -> DesignPoint: def design_point(self, idx_or_name) -> DesignPoint: return self.__design_point_table.find_design_point(idx_or_name) + + +class CaseParametricStudy: + """ + Parametric study that manages design points to parametrize a + Fluent solver set-up. + + Methods + ------- + add_design_point(design_point_name: str) -> DesignPoint + Add a design point + design_point(idx_or_name) + Get a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + """ + + def __init__( + self, + case_file_path: str, + base_design_point_name: str = "Base DP" + ): + base_design_point = DesignPoint(base_design_point_name) + case_reader = CaseReader(case_file_path=case_file_path) + inputs = case_reader.input_parameters() + for parameter in inputs: + name, value = None, None + for k, v in parameter: + if k == "name": + name = v + elif k == "definition": + value = v + base_design_point.inputs[name] = value + outputs = case_reader.output_parameters() + for parameter in outputs: + name, value = None, None + for k, v in parameter: + if k == "name": + name = v + elif k == "definition": + value = v + base_design_point.outputs[name] = value + self.__design_point_table = DesignPointTable(base_design_point) + + def add_design_point(self, design_point_name: str) -> DesignPoint: + return self.__design_point_table.add_design_point(design_point_name) + + def design_point(self, idx_or_name) -> DesignPoint: + return self.__design_point_table.find_design_point(idx_or_name) + + def apply_to_studies(self, studies) -> None: + num_studies = len(studies) + total_num_points = num_points = len(self.__design_point_table) + for study in studies: + count = ceil(num_points/num_studies) + range_base = total_num_points - num_points + num_points -= count + num_studies -= 1 + self.apply_to_study( + study, + range(range_base, range_base + count), + ) + + def apply_to_study(self, study, design_point_range=None) -> None: + if design_point_range is None: + design_point_range = range(0, len(self.__design_point_table)) + for idx in design_point_range: + design_point = self.design_point(idx_or_name = idx) + for k, v in design_point.inputs.items(): + # want to chose the name via design_point.name + study.add_design_point().input_parameters = {k : v} From 5b4081ce68ae82fff022c296dc77949d449f72ac Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 12:43:22 +0100 Subject: [PATCH 09/52] spread values into runtime study --- src/ansys/fluent/parametric/local/local.py | 98 ++++++++++++++++------ 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index b9ec7ea5..24ab72c6 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -56,6 +56,8 @@ import ansys.fluent as pyfluent from .filereader.casereader import CaseReader +from ansys.fluent.parametric import ParametricSession as FluentParametricSession + class DesignPointStatus(Enum): """ @@ -359,10 +361,10 @@ def __init__( base_design_point = DesignPoint(base_design_point_name) base_design_point.inputs = self.__session.input_parameters.copy() base_design_point.outputs = self.__session.output_parameters.copy() - self.__design_point_table = DesignPointTable(base_design_point) + self.design_point_table = DesignPointTable(base_design_point) def update_all(self): - for design_point in self.__design_point_table: + for design_point in self.design_point_table: if design_point.status != DesignPointStatus.BLOCKED: self.update_design_point(design_point) @@ -376,10 +378,10 @@ def update_design_point(self, design_point: DesignPoint): ) def add_design_point(self, design_point_name: str) -> DesignPoint: - return self.__design_point_table.add_design_point(design_point_name) + return self.design_point_table.add_design_point(design_point_name) def design_point(self, idx_or_name) -> DesignPoint: - return self.__design_point_table.find_design_point(idx_or_name) + return self.design_point_table.find_design_point(idx_or_name) class CaseParametricStudy: @@ -402,11 +404,12 @@ class CaseParametricStudy: def __init__( self, - case_file_path: str, + case_filepath: str, base_design_point_name: str = "Base DP" ): + self.case_filepath = case_filepath base_design_point = DesignPoint(base_design_point_name) - case_reader = CaseReader(case_file_path=case_file_path) + case_reader = CaseReader(case_file_path=case_filepath) inputs = case_reader.input_parameters() for parameter in inputs: name, value = None, None @@ -425,32 +428,75 @@ def __init__( elif k == "definition": value = v base_design_point.outputs[name] = value - self.__design_point_table = DesignPointTable(base_design_point) + self.design_point_table = DesignPointTable(base_design_point) def add_design_point(self, design_point_name: str) -> DesignPoint: - return self.__design_point_table.add_design_point(design_point_name) + return self.design_point_table.add_design_point(design_point_name) def design_point(self, idx_or_name) -> DesignPoint: - return self.__design_point_table.find_design_point(idx_or_name) + return self.design_point_table.find_design_point(idx_or_name) - def apply_to_studies(self, studies) -> None: - num_studies = len(studies) - total_num_points = num_points = len(self.__design_point_table) - for study in studies: - count = ceil(num_points/num_studies) - range_base = total_num_points - num_points - num_points -= count - num_studies -= 1 - self.apply_to_study( - study, - range(range_base, range_base + count), - ) - def apply_to_study(self, study, design_point_range=None) -> None: +def run_local_study_in_fluent( + local_study, + num_servers): + + source_table_size = len(local_study.design_point_table) + + def make_input_for_study(design_point_range) -> None: if design_point_range is None: - design_point_range = range(0, len(self.__design_point_table)) + design_point_range = range(0, source_table_size) + study_input = [] for idx in design_point_range: - design_point = self.design_point(idx_or_name = idx) - for k, v in design_point.inputs.items(): - # want to chose the name via design_point.name + design_point = local_study.design_point(idx_or_name = idx) + study_input.append(design_point.inputs.copy()) + return study_input + + def make_input_for_studies(num_servers) -> None: + study_inputs = [] + total_num_points = num_points = source_table_size + for i in range(num_servers): + count = ceil(num_points/num_servers) + range_base = total_num_points - num_points + num_points -= count + num_servers -= 1 + study_inputs.append(make_input_for_study( + range(range_base, range_base + count) + )) + return study_inputs + + def apply_to_study(study, inputs) -> None: + for inpt in inputs: + for k, v in inpt.items(): + # want to choose the name via design_point.name study.add_design_point().input_parameters = {k : v} + + def apply_to_studies(studies, inputs) -> None: + for item in list(zip(studies, inputs)): + study, inpt = item + apply_to_study(study, inpt) + + study_inputs = make_input_for_studies(num_servers) + + sessions = [] + studies = [] + for i in range(num_servers): + session = FluentParametricSession(case_filepath=local_study.case_filepath) + sessions.append(session) + studies.append(next(iter(session.studies.values()))) + + apply_to_studies(studies, study_inputs) + + for study in studies: + study.update_all_design_points() + + for study in studies: + for name, design_point in study.design_points.items(): + for k, v in design_point.input_parameters.items(): + print("input parameter", k, v) + for k, v in design_point.output_parameters.items(): + print("output parameter", k, v) + print(72 * "-") + + + From 7894299372181767b95fd2ca92b8c86c9e98a5e9 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 12:56:28 +0100 Subject: [PATCH 10/52] spread values into runtime study --- src/ansys/fluent/parametric/local/local.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 24ab72c6..54a12a12 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -467,9 +467,7 @@ def make_input_for_studies(num_servers) -> None: def apply_to_study(study, inputs) -> None: for inpt in inputs: - for k, v in inpt.items(): - # want to choose the name via design_point.name - study.add_design_point().input_parameters = {k : v} + study.add_design_point().input_parameters = inpt.copy() def apply_to_studies(studies, inputs) -> None: for item in list(zip(studies, inputs)): From e170ab2752d7ce7e1c4cf0d324bfb47a75999ffe Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 16:09:09 +0100 Subject: [PATCH 11/52] in parallel = tricky --- src/ansys/fluent/parametric/local/local.py | 36 +++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 54a12a12..377503ed 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -53,12 +53,13 @@ from enum import Enum from math import ceil -import ansys.fluent as pyfluent + +from ansys.fluent.core.utils.async_execution import asynchronous + from .filereader.casereader import CaseReader from ansys.fluent.parametric import ParametricSession as FluentParametricSession - class DesignPointStatus(Enum): """ Status of a design point in a parametric study. @@ -465,28 +466,47 @@ def make_input_for_studies(num_servers) -> None: )) return study_inputs - def apply_to_study(study, inputs) -> None: + @asynchronous + def make_parametric_study(case_filepath): + return FluentParametricSession(case_filepath=case_filepath) + + @asynchronous + def apply_to_study(study, inputs): for inpt in inputs: study.add_design_point().input_parameters = inpt.copy() + @asynchronous + def update_design_point(study): + study.update_all_design_points() + def apply_to_studies(studies, inputs) -> None: + results = [] for item in list(zip(studies, inputs)): study, inpt = item - apply_to_study(study, inpt) + results.append(apply_to_study(study, inpt)) + for result in results: + result.result() study_inputs = make_input_for_studies(num_servers) sessions = [] studies = [] for i in range(num_servers): - session = FluentParametricSession(case_filepath=local_study.case_filepath) - sessions.append(session) - studies.append(next(iter(session.studies.values()))) + sessions.append(make_parametric_study( + case_filepath=local_study.case_filepath + )) + + for session in sessions: + studies.append(next(iter(session.result().studies.values()))) apply_to_studies(studies, study_inputs) + updates = [] for study in studies: - study.update_all_design_points() + update_design_point(study) + + for update in updates: + update.result() for study in studies: for name, design_point in study.design_points.items(): From 3182b21ebbf3c2ee29cc883abcd63fcf631958d1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 16:38:19 +0100 Subject: [PATCH 12/52] fix for class attributes --- src/ansys/fluent/parametric/__init__.py | 47 ++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 5500ada1..989a9224 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -185,25 +185,23 @@ class ParametricStudy: Update a list of design points. """ - _all_studies: Dict[int, "ParametricStudy"] = {} - current_study_name = None - def __init__( self, parametric_studies, + session, name: Optional[str] = None, design_points: Dict[str, DesignPoint] = None, ): self._parametric_studies = parametric_studies + self.session = session self.name = name self.design_points = {} if design_points is not None: self.design_points = design_points self.project_filepath = None - ParametricStudy._all_studies[id(self)] = self + session.register_study(self) - @classmethod - def get_all_studies(cls) -> Dict[str, "ParametricStudy"]: + def get_all_studies(self) -> Dict[str, "ParametricStudy"]: """Get all currently active studies. Returns @@ -211,7 +209,7 @@ def get_all_studies(cls) -> Dict[str, "ParametricStudy"]: Dict[str, "ParametricStudy"] currently active studies """ - return {v.name: v for _, v in cls._all_studies.items()} + return {v.name: v for _, v in self.session._all_studies.items()} def initialize(self) -> "ParametricStudy": """Initialize parametric study.""" @@ -235,7 +233,7 @@ def initialize(self) -> "ParametricStudy": self._parametric_studies[self.name].design_points[BASE_DP_NAME], ) self.design_points = {BASE_DP_NAME: base_design_point} - ParametricStudy.current_study_name = self.name + self.session.current_study_name = self.name return self else: LOG.error("initialize is not available") @@ -258,13 +256,13 @@ def rename(self, new_name: str) -> None: @property def is_current(self) -> bool: """Whether the parametric study is the current parametric study.""" - return ParametricStudy.current_study_name == self.name + return self.session.current_study_name == self.name def set_as_current(self) -> None: """Set the parametric study as the current parametric study.""" if not self.is_current: self._parametric_studies.set_as_current(self.name) - ParametricStudy.current_study_name = self.name + self.session.current_study_name = self.name def duplicate(self, copy_design_points: bool = True) -> "ParametricStudy": """Duplicate the current study. @@ -283,8 +281,8 @@ def duplicate(self, copy_design_points: bool = True) -> "ParametricStudy": self._parametric_studies.duplicate(copy_design_points=copy_design_points) new_study_names = self._parametric_studies.get_object_names() clone_name = set(new_study_names).difference(set(old_study_names)).pop() - current_study = ParametricStudy.get_all_studies()[ - ParametricStudy.current_study_name + current_study = self.get_all_studies()[ + self.session.current_study_name ] if copy_design_points: clone_design_points = { @@ -298,9 +296,9 @@ def duplicate(self, copy_design_points: bool = True) -> "ParametricStudy": ) clone_design_points = {BASE_DP_NAME: base_design_point} clone = ParametricStudy( - self._parametric_studies, clone_name, clone_design_points + self._parametric_studies, self.session, clone_name, clone_design_points ) - ParametricStudy.current_study_name = clone.name + self.session.current_study_name = clone.name return clone def delete(self) -> None: @@ -508,11 +506,13 @@ def __init__( parametric_project, parametric_studies, project_filepath: str, - open_project: bool = True, + session, + open_project: bool = True ): self._parametric_project = parametric_project self._parametric_studies = parametric_studies self.project_filepath = project_filepath + self.session = session if open_project: self.open(project_filepath=project_filepath) @@ -534,7 +534,7 @@ def open( ) self.project_filepath = project_filepath for study_name in self._parametric_studies.get_object_names(): - study = ParametricStudy(self._parametric_studies, study_name) + study = ParametricStudy(self._parametric_studies, self.session, study_name) dps_settings = self._parametric_studies[study_name].design_points for dp_name in dps_settings.get_object_names(): study.design_points[dp_name] = DesignPoint( @@ -646,6 +646,8 @@ def __init__( False. """ self.studies = {} + self._all_studies: Dict[int, "ParametricStudy"] = {} + self.current_study_name = None self.project = None self._session = launcher() self.scheme_eval = self._session.scheme_eval.scheme_eval @@ -657,30 +659,35 @@ def __init__( self._root = self._session.solver.root if case_filepath is not None: self._root.file.read(file_name=case_filepath, file_type="case") - study = ParametricStudy(self._root.parametric_studies).initialize() + study = ParametricStudy(self._root.parametric_studies, self).initialize() self.studies[study.name] = study self.project = ParametricProject( parametric_project=self._root.file.parametric_project, parametric_studies=self._root.parametric_studies, project_filepath=str(study.project_filepath), open_project=False, + session=self._session ) elif project_filepath is not None: self.project = ParametricProject( parametric_project=self._root.file.parametric_project, parametric_studies=self._root.parametric_studies, project_filepath=project_filepath, + session=self._session ) studies_settings = self._root.parametric_studies for study_name in studies_settings.get_object_names(): - study = ParametricStudy(studies_settings, study_name) + study = ParametricStudy(studies_settings, self, study_name) dps_settings = studies_settings[study_name].design_points for dp_name in dps_settings.get_object_names(): study.design_points[dp_name] = DesignPoint( dp_name, dps_settings[dp_name] ) self.studies[study_name] = study - ParametricStudy.current_study_name = self._root.current_parametric_study() + self.current_study_name = self._root.current_parametric_study() + + def register_study(self, study): + self._all_studies[id(study)] = study def new_study(self) -> ParametricStudy: """Create new study. @@ -690,7 +697,7 @@ def new_study(self) -> ParametricStudy: ParametricStudy New study. """ - study = self.studies[ParametricStudy.current_study_name].duplicate() + study = self.studies[self.current_study_name].duplicate() self.studies[study.name] = study return study From 477c853b025c04550bfbc3ae5151753c85e3fb40 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 17:13:59 +0100 Subject: [PATCH 13/52] sync fix --- src/ansys/fluent/parametric/local/local.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 377503ed..7375423c 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -467,7 +467,7 @@ def make_input_for_studies(num_servers) -> None: return study_inputs @asynchronous - def make_parametric_study(case_filepath): + def make_parametric_session(case_filepath): return FluentParametricSession(case_filepath=case_filepath) @asynchronous @@ -492,7 +492,7 @@ def apply_to_studies(studies, inputs) -> None: sessions = [] studies = [] for i in range(num_servers): - sessions.append(make_parametric_study( + sessions.append(make_parametric_session( case_filepath=local_study.case_filepath )) @@ -503,7 +503,7 @@ def apply_to_studies(studies, inputs) -> None: updates = [] for study in studies: - update_design_point(study) + updates.append(update_design_point(study)) for update in updates: update.result() From 01cdf7a59ab55ac5fae3228df007ec58bd4079e0 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 17:39:57 +0100 Subject: [PATCH 14/52] fix by using base dp expicitly --- src/ansys/fluent/parametric/local/local.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 7375423c..1efe3c67 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -59,6 +59,8 @@ from .filereader.casereader import CaseReader from ansys.fluent.parametric import ParametricSession as FluentParametricSession +from ansys.fluent.parametric import BASE_DP_NAME + class DesignPointStatus(Enum): """ @@ -440,7 +442,8 @@ def design_point(self, idx_or_name) -> DesignPoint: def run_local_study_in_fluent( local_study, - num_servers): + num_servers, + capture_report_data=False): source_table_size = len(local_study.design_point_table) @@ -472,8 +475,19 @@ def make_parametric_session(case_filepath): @asynchronous def apply_to_study(study, inputs): + first = True for inpt in inputs: - study.add_design_point().input_parameters = inpt.copy() + if first: + design_point = study.design_points[BASE_DP_NAME] + design_point.capture_simulation_report_data_enabled = ( + capture_report_data + ) + first = False + else: + design_point = study.add_design_point( + capture_simulation_report_data=capture_report_data + ) + design_point.input_parameters = inpt.copy() @asynchronous def update_design_point(study): From 9a24ce64abac7adf800ee0a86f6dd5e028ac07fe Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 18:08:58 +0100 Subject: [PATCH 15/52] nice refactor --- src/ansys/fluent/parametric/local/local.py | 41 ++++++++++++---------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 1efe3c67..5d433e90 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -413,24 +413,28 @@ def __init__( self.case_filepath = case_filepath base_design_point = DesignPoint(base_design_point_name) case_reader = CaseReader(case_file_path=case_filepath) - inputs = case_reader.input_parameters() - for parameter in inputs: - name, value = None, None - for k, v in parameter: - if k == "name": - name = v - elif k == "definition": - value = v - base_design_point.inputs[name] = value - outputs = case_reader.output_parameters() - for parameter in outputs: + + def parameter_info(parameter): name, value = None, None for k, v in parameter: if k == "name": name = v elif k == "definition": value = v - base_design_point.outputs[name] = value + return name, value + + def set_parameter_info(source, target): + for parameter in source: + target.update((parameter_info(parameter),)) + + set_parameter_info( + source=case_reader.input_parameters(), + target=base_design_point.inputs) + + set_parameter_info( + source=case_reader.output_parameters(), + target=base_design_point.outputs) + self.design_point_table = DesignPointTable(base_design_point) def add_design_point(self, design_point_name: str) -> DesignPoint: @@ -522,13 +526,14 @@ def apply_to_studies(studies, inputs) -> None: for update in updates: update.result() + it = iter(local_study.design_point_table) + for study in studies: - for name, design_point in study.design_points.items(): - for k, v in design_point.input_parameters.items(): - print("input parameter", k, v) - for k, v in design_point.output_parameters.items(): - print("output parameter", k, v) - print(72 * "-") + for _, design_point in study.design_points.items(): + next(it).outputs = design_point.output_parameters.copy() + + + From e9a9fdaf05b1c34f9ee8023c9ea8a8568d9299d1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 19:40:35 +0100 Subject: [PATCH 16/52] nice refactor --- src/ansys/fluent/parametric/local/local.py | 342 ++------------------- 1 file changed, 31 insertions(+), 311 deletions(-) diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 5d433e90..89dcd5ba 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -1,53 +1,7 @@ """ Classes for running a parametric study in Fluent. -Example -------- -from ansys.fluent.addons.parametric import ParametricStudy, DesignPointStatus # noqa: E501 -Instantiate the study, specifying the case - -study = ParametricStudy(case_file_name=my_case_file_name) - -Add one new design point and set an input parameter - -dp1 = study.add_design_point("DP1") -dp1.set_input("parameter_1", 0.235) -dp1.set_input("velocity_inlet_5_y_velocity", 0.772) - -The solver has not been run yet so no outputs are computed -The design point is out of date - -assert(dp1.status == DesignPointStatus.OUT_OF_DATE) - -Get the base design point - -base = study.design_point("Base DP") - -Check that block updates works - -dp1.block_updates() -base.block_updates() -assert(dp1.status == DesignPointStatus.BLOCKED) -study.update_all() -assert(dp1.outputs == base.outputs) - -Update the design points - -dp1.allow_updates() -base.allow_updates() -assert(dp1.status == DesignPointStatus.OUT_OF_DATE) -study.update_all() - -Check that dp1 is up to date and that the outputs differ - -assert(dp1.status == DesignPointStatus.UPDATED) -assert(dp1.outputs != base.outputs) - -It's important to clean up any studies to help ensure that -all Fluent sessions are cleaned up - -del study """ from enum import Enum @@ -58,114 +12,57 @@ from .filereader.casereader import CaseReader -from ansys.fluent.parametric import ParametricSession as FluentParametricSession +from ansys.fluent.parametric import ParametricSession from ansys.fluent.parametric import BASE_DP_NAME -class DesignPointStatus(Enum): +class LocalDesignPoint: """ - Status of a design point in a parametric study. - - Attributes - ---------- - OUT_OF_DATE : int - UPDATING : int - UPDATED : int - FAILED : int - BLOCKED : int - """ - - OUT_OF_DATE = 1 - UPDATING = 2 - UPDATED = 3 - FAILED = 4 - BLOCKED = 5 - - -class DesignPoint: - """ - Design point in a parametric study. + Purely local version of design point in a parametric study. Attributes ---------- name : str Name of the design point as a str. - outputs : dict + output_parameters : dict Dict of output parameters (name of parameter to value). - inputs : dict + input_parameters : dict Dict of input parameters (name of parameter to value). status : DesignPointStatus Current status of the design point. - - Methods - ------- - set_input(parameter_name: str, value) - Set one parameter in the design point to the value provided. - on_end_updating(outputs: dict) - Inform the design point that it is in an UPDATED state and - provides the associated output parameters. - block_updates() - Move the design point into a do not update state. - block_updates() - Move the design point into a needs update state. """ def __init__(self, design_point_name: str, base_design_point=None): self.name = design_point_name if base_design_point: - self.__inputs = base_design_point.inputs.copy() - self.__outputs = base_design_point.outputs.copy() + self.__inputs = base_design_point.input_parameters.copy() + self.__outputs = base_design_point.output_parameters.copy() else: self.__inputs = {} self.__outputs = {} - # TODO add listener for __status: - self.__status = DesignPointStatus.OUT_OF_DATE @property - def inputs(self) -> dict: + def input_parameters(self) -> dict: return self.__inputs - @inputs.setter - def inputs(self, inputs: dict): - self.__status = DesignPointStatus.OUT_OF_DATE + @input_parameters.setter + def input_parameters(self, inputs: dict): self.__inputs = inputs @property - def outputs(self) -> dict: + def output_parameters(self) -> dict: return self.__outputs - @outputs.setter - def outputs(self, outputs: dict): - self.__status = DesignPointStatus.OUT_OF_DATE - self.__outputs = outputs - - @property - def status(self) -> DesignPointStatus: - return self.__status - - def set_input(self, parameter_name: str, value): - self.__status = DesignPointStatus.OUT_OF_DATE - self.__inputs[parameter_name] = value - - def on_start_updating(self): - self.__status = DesignPointStatus.UPDATING - - def on_end_updating(self, outputs: dict): + @output_parameters.setter + def output_parameters(self, outputs: dict): self.__outputs = outputs - self.__status = DesignPointStatus.UPDATED - - def block_updates(self): - self.__status = DesignPointStatus.BLOCKED - - def allow_updates(self): - self.__status = DesignPointStatus.OUT_OF_DATE -class DesignPointTable(list): +class LocalDesignPointTable(list): """ - Design point study in a parametric study + Local version of Design point table in a parametric study Methods ------- @@ -187,15 +84,15 @@ class DesignPointTable(list): If the design point is not found. """ - def __init__(self, base_design_point: DesignPoint): + def __init__(self, base_design_point: LocalDesignPoint): super().__init__() self.append(base_design_point) - def add_design_point(self, design_point_name: str) -> DesignPoint: - self.append(DesignPoint(design_point_name, self[0])) + def add_design_point(self, design_point_name: str) -> LocalDesignPoint: + self.append(LocalDesignPoint(design_point_name, self[0])) return self[-1] - def find_design_point(self, idx_or_name) -> DesignPoint: + def find_design_point(self, idx_or_name) -> LocalDesignPoint: if isinstance(idx_or_name, int): return self[idx_or_name] for design_point in self: @@ -210,191 +107,14 @@ def remove_design_point(self, idx_or_name): self.remove(self.find_design_point(idx_or_name)) -class FluentParameterAccessor: +class LocalParametricStudy: """ - Extracts parameter name to value dicts from table strs - currently returned by the API - - Attributes - ---------- - input_parameters : dict - The current input parameter dict. - output_parameters : dict - The current input parameter dict. - """ - - def __init__(self, fluent_session): - self.__list_parameters = ( - fluent_session.tui.solver.define.parameters.list_parameters - ) - - @property - def input_parameters(self) -> dict: - return FluentParameterAccessor.__parameter_table_to_dict( - self.__list_parameters.input_parameters() - ) - - @property - def output_parameters(self) -> dict: - return FluentParameterAccessor.__parameter_table_to_dict( - self.__list_parameters.output_parameters() - ) - - @staticmethod - def __parameter_table_to_dict(table: str) -> dict: - # this code has become more complex now. Originally table was - # str here - now ExecuteCommandResult is returned by the calls - # to (in|out)put_parameters() - table_str = table - if not isinstance(table, str): - try: - table_str = table.result - except AttributeError as attr_err: - raise RuntimeError( - "Unexpected design point table " - f"type in parse: {type(table)}" - ) from attr_err - data_lines = table_str.splitlines()[3:] - table_as_dict = {} - for line in data_lines: - line_as_list = line.split() - table_as_dict[line_as_list[0]] = line_as_list[1] - return table_as_dict - - -class ParametricSession: - """ - Full set of interactions with Fluent in the context of a parametric study - - Attributes - ---------- - input_parameters : dict - The current input parameter dict. - output_parameters : dict - The current input parameter dict. - - Methods - ------- - set_input_parameter(parameter_name: str) - Set a single input parameter value in the Fluent session. - initialize_with_case(case_file_name: str) - Read the specified case into Fluent. - update() - Run the solver until convergence. - """ - - def __init__(self, fluent_session): - self.__fluent_session = fluent_session - self.__parameter_accessor = FluentParameterAccessor(fluent_session) - - @property - def input_parameters(self) -> dict: - return self.__parameter_accessor.input_parameters - - @property - def output_parameters(self) -> dict: - return self.__parameter_accessor.output_parameters - - def set_input_parameter(self, parameter_name: str, value): - self.__fluent_session.tui.solver.define.parameters.input_parameters.edit( # noqa: E501 - parameter_name, parameter_name, value - ) - - def initialize_with_case(self, case_file_name: str): - self.__fluent_session.tui.solver.file.read_case( - case_file_name=case_file_name - ) - - def update(self): - self.__fluent_session.tui.solver.solve.initialize.initialize_flow() - self.__fluent_session.tui.solver.solve.iterate() - - def __del__(self): - self.__fluent_session.exit() - - -class FluentLauncher: - """ - Launches fluent sessions. - - Methods - ------- - __call__() - Launch a session - """ - - def __call__(self): - return ParametricSession(fluent_session=pyfluent.launch_fluent()) - - -class ParametricStudy: - """ - Parametric study that manages design points to parametrize a - Fluent solver set-up. Provides ability to run Fluent for a series - of design points, and access the inputs and outputs. - - Methods - ------- - update_all() - Bring all design point outputs up to date by running the - solver on each design point. Ignores BLOCKED design points. - update_design_point() - Bring the outputs of the specified design point up to date - by running the solver. - add_design_point(design_point_name: str) -> DesignPoint - Add a design point - design_point(idx_or_name) - Get a design point, either by name (str) or an index - indicating the position in the table (by order of insertion). - Raises - ------ - RuntimeError - If the design point is not found. - """ - - def __init__( - self, - case_file_name: str = "", - base_design_point_name: str = "Base DP", - launcher=None, - ): - self.__session = launcher() if launcher else FluentLauncher() - if case_file_name: - self.__session.initialize_with_case(case_file_name) - base_design_point = DesignPoint(base_design_point_name) - base_design_point.inputs = self.__session.input_parameters.copy() - base_design_point.outputs = self.__session.output_parameters.copy() - self.design_point_table = DesignPointTable(base_design_point) - - def update_all(self): - for design_point in self.design_point_table: - if design_point.status != DesignPointStatus.BLOCKED: - self.update_design_point(design_point) - - def update_design_point(self, design_point: DesignPoint): - design_point.on_start_updating() - for parameter_name, value in design_point.inputs.items(): - self.__session.set_input_parameter(parameter_name, value) - self.__session.update() - design_point.on_end_updating( - outputs=self.__session.output_parameters.copy() - ) - - def add_design_point(self, design_point_name: str) -> DesignPoint: - return self.design_point_table.add_design_point(design_point_name) - - def design_point(self, idx_or_name) -> DesignPoint: - return self.design_point_table.find_design_point(idx_or_name) - - -class CaseParametricStudy: - """ - Parametric study that manages design points to parametrize a + Local version of parametric study that manages design points to parametrize a Fluent solver set-up. Methods ------- - add_design_point(design_point_name: str) -> DesignPoint + add_design_point(design_point_name: str) -> LocalDesignPoint Add a design point design_point(idx_or_name) Get a design point, either by name (str) or an index @@ -411,7 +131,7 @@ def __init__( base_design_point_name: str = "Base DP" ): self.case_filepath = case_filepath - base_design_point = DesignPoint(base_design_point_name) + base_design_point = LocalDesignPoint(base_design_point_name) case_reader = CaseReader(case_file_path=case_filepath) def parameter_info(parameter): @@ -429,18 +149,18 @@ def set_parameter_info(source, target): set_parameter_info( source=case_reader.input_parameters(), - target=base_design_point.inputs) + target=base_design_point.input_parameters) set_parameter_info( source=case_reader.output_parameters(), - target=base_design_point.outputs) + target=base_design_point.output_parameters) - self.design_point_table = DesignPointTable(base_design_point) + self.design_point_table = LocalDesignPointTable(base_design_point) - def add_design_point(self, design_point_name: str) -> DesignPoint: + def add_design_point(self, design_point_name: str) -> LocalDesignPoint: return self.design_point_table.add_design_point(design_point_name) - def design_point(self, idx_or_name) -> DesignPoint: + def design_point(self, idx_or_name) -> LocalDesignPoint: return self.design_point_table.find_design_point(idx_or_name) @@ -457,7 +177,7 @@ def make_input_for_study(design_point_range) -> None: study_input = [] for idx in design_point_range: design_point = local_study.design_point(idx_or_name = idx) - study_input.append(design_point.inputs.copy()) + study_input.append(design_point.input_parameters.copy()) return study_input def make_input_for_studies(num_servers) -> None: @@ -475,7 +195,7 @@ def make_input_for_studies(num_servers) -> None: @asynchronous def make_parametric_session(case_filepath): - return FluentParametricSession(case_filepath=case_filepath) + return ParametricSession(case_filepath=case_filepath) @asynchronous def apply_to_study(study, inputs): @@ -530,7 +250,7 @@ def apply_to_studies(studies, inputs) -> None: for study in studies: for _, design_point in study.design_points.items(): - next(it).outputs = design_point.output_parameters.copy() + next(it).output_parameters = design_point.output_parameters.copy() From 8aea7743d0ebdff54425ce640a7426bf63dbfbb8 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Tue, 19 Jul 2022 22:54:46 +0100 Subject: [PATCH 17/52] nice refactor --- src/ansys/fluent/parametric/__init__.py | 22 +++++++++++++++++++--- src/ansys/fluent/parametric/local/local.py | 21 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 989a9224..2b85fe1f 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -55,7 +55,7 @@ from pathlib import Path import tempfile -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Union import ansys.fluent.core as pyfluent from ansys.fluent.core import LOG @@ -69,6 +69,22 @@ BASE_DP_NAME = "Base DP" +def convert_units_for_design_point(value: Dict[str, Union[float, str]]) -> Dict[str, float]: + def conv(val): + if type(val) is float: + return val + if type(val) is not str: + raise RuntimeError("Invalid value type for input parameter") + pos = val.find(" [") + if pos == -1: + return float(val) + return float(val[:pos]) + + return dict(map( + lambda x: (x[0], conv(x[1])), + value.items() + )) + class DesignPoint: """Design point in a parametric study. @@ -97,8 +113,8 @@ def input_parameters(self) -> Dict[str, float]: return self._dp_settings.input_parameters() @input_parameters.setter - def input_parameters(self, value: Dict[str, float]) -> None: - self._dp_settings.input_parameters = value + def input_parameters(self, value: Dict[str, Union[float, str]]) -> None: + self._dp_settings.input_parameters = convert_units_for_design_point(value) @property def output_parameters(self) -> Dict[str, float]: diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index 89dcd5ba..f06d7dfe 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -1,6 +1,27 @@ """ Classes for running a parametric study in Fluent. +Example +------- +>>> from ansys.fluent.parametric.local.local import LocalParametricStudy, run_local_study_in_fluent + +>>> local_study = LocalParametricStudy(case_filepath="E:\elbow1_param.cas.h5") + +>>> design_point = local_study.design_point("Base DP") +>>> design_point.input_parameters['v1'] = 0.0 + +>>> for idx in range(1, 20): +>>> design_point = local_study.add_design_point("dp_"+str(idx)) +>>> design_point.input_parameters['v1'] = float(idx)/10.0 + +>>> run_local_study_in_fluent(local_study, 5) + +>>> for design_point in local_study.design_point_table: +>>> for k, v in design_point.input_parameters.items(): +>>> print("input parameter", k, v) +>>> for k, v in design_point.output_parameters.items(): +>>> print("output parameter", k, v) +>>> print(72 * "-") """ From 8422186eaa00867b1e31464b3a1bdd58a1a91832 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 18:21:54 +0100 Subject: [PATCH 18/52] nice refactor --- .../parametric_static_mixer_1.py | 2 + .../parametric/local/filereader/casereader.py | 23 +++-- src/ansys/fluent/parametric/local/local.py | 22 +++-- tests/test_parametric_local.py | 85 +++++++++++++++++++ 4 files changed, 114 insertions(+), 18 deletions(-) create mode 100644 tests/test_parametric_local.py diff --git a/examples/00-parametric/parametric_static_mixer_1.py b/examples/00-parametric/parametric_static_mixer_1.py index 86f48936..a6ae2ddc 100644 --- a/examples/00-parametric/parametric_static_mixer_1.py +++ b/examples/00-parametric/parametric_static_mixer_1.py @@ -54,6 +54,7 @@ session.solver.tui.define.boundary_conditions.set.velocity_inlet( "inlet1", (), "vmag", "yes", "inlet1_vel", 1, "quit" ) + session.solver.tui.define.boundary_conditions.set.velocity_inlet( "inlet1", (), "temperature", "yes", "inlet1_temp", 300, "quit" ) @@ -61,6 +62,7 @@ session.solver.tui.define.boundary_conditions.set.velocity_inlet( "inlet2", (), "vmag", "yes", "no", "inlet2_vel", 1, "quit" ) + session.solver.tui.define.boundary_conditions.set.velocity_inlet( "inlet2", (), "temperature", "yes", "no", "inlet2_temp", 350, "quit" ) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index ae1ea241..0989b999 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -12,27 +12,24 @@ def __init__(self, case_file_path): self._rp_vars = lispy.parse(rp_vars_str)[1] def input_parameters(self): - return self._parameters(input_parameter=True) + exprs = self._named_expressions() + input_params = [] + for expr in exprs: + for attr in expr: + if attr[0] == 'input-parameter' and attr[1] is True: + input_params.append(expr) + return input_params def output_parameters(self): - return self._parameters(input_parameter=False) - + parameters = self._find_rp_var("parameters/output-parameters") + return parameters + def named_expressions(self): return self._named_expressions() def _named_expressions(self): return self._find_rp_var("named-expressions") - def _parameters(self, input_parameter: bool): - exprs = self._named_expressions() - input_params = [] - parameter_type = ('in' if input_parameter else 'out') + 'put-parameter' - for expr in exprs: - for attr in expr: - if attr[0] == parameter_type and attr[1] == True: - input_params.append(expr) - return input_params - def _find_rp_var(self, name: str): for var in self._rp_vars: if type(var) == list and len(var) and var[0] == name: diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py index f06d7dfe..c4dfc321 100644 --- a/src/ansys/fluent/parametric/local/local.py +++ b/src/ansys/fluent/parametric/local/local.py @@ -155,7 +155,7 @@ def __init__( base_design_point = LocalDesignPoint(base_design_point_name) case_reader = CaseReader(case_file_path=case_filepath) - def parameter_info(parameter): + def input_parameter_info(parameter): name, value = None, None for k, v in parameter: if k == "name": @@ -164,18 +164,30 @@ def parameter_info(parameter): value = v return name, value - def set_parameter_info(source, target): + def set_input_parameter_info(source, target): for parameter in source: - target.update((parameter_info(parameter),)) + target.update((input_parameter_info(parameter),)) - set_parameter_info( + def output_parameter_info(parameter): + parameter = parameter[1] + for elem in parameter: + if len(elem) and elem[0] == "name": + return elem[1][1], None + + def set_output_parameter_info(source, target): + for parameter in source: + target.update((output_parameter_info(parameter),)) + + set_input_parameter_info( source=case_reader.input_parameters(), target=base_design_point.input_parameters) - set_parameter_info( + set_output_parameter_info( source=case_reader.output_parameters(), target=base_design_point.output_parameters) + print(case_reader.output_parameters()) + self.design_point_table = LocalDesignPointTable(base_design_point) def add_design_point(self, design_point_name: str) -> LocalDesignPoint: diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py new file mode 100644 index 00000000..0cdd7106 --- /dev/null +++ b/tests/test_parametric_local.py @@ -0,0 +1,85 @@ +""" +This local parametric study workflow test performs these steps + +- TODO +""" + +############################################################################ +from pathlib import Path +from ansys.fluent.core import examples, session +import ansys.fluent.core as pyfluent +from ansys.fluent.parametric.local.local import LocalParametricStudy + + +def test_parametric_local(): + + session = pyfluent.launch_fluent() + + import_filename = examples.download_file( + "Static_Mixer_main.cas.h5", "pyfluent/static_mixer" + ) + + session.solver.tui.file.read_case(case_file_name=import_filename) + + session.solver.tui.define.parameters.enable_in_TUI("yes") + + session.solver.tui.define.boundary_conditions.set.velocity_inlet( + "inlet1", (), "vmag", "yes", "inlet1_vel", 1, "quit" + ) + session.solver.tui.define.boundary_conditions.set.velocity_inlet( + "inlet1", (), "temperature", "yes", "inlet1_temp", 300, "quit" + ) + session.solver.tui.define.boundary_conditions.set.velocity_inlet( + "inlet2", (), "vmag", "yes", "no", "inlet2_vel", 1, "quit" + ) + session.solver.tui.define.boundary_conditions.set.velocity_inlet( + "inlet2", (), "temperature", "yes", "no", "inlet2_temp", 350, "quit" + ) + + session.solver.root.solution.report_definitions.surface["outlet-temp-avg"] = {} + session.solver.root.solution.report_definitions.surface[ + "outlet-temp-avg" + ].report_type = "surface-areaavg" + session.solver.root.solution.report_definitions.surface[ + "outlet-temp-avg" + ].field = "temperature" + session.solver.root.solution.report_definitions.surface[ + "outlet-temp-avg" + ].surface_names = ["outlet"] + + session.solver.root.solution.report_definitions.surface["outlet-vel-avg"] = {} + session.solver.root.solution.report_definitions.surface[ + "outlet-vel-avg" + ].report_type = "surface-areaavg" + session.solver.root.solution.report_definitions.surface[ + "outlet-vel-avg" + ].field = "velocity-magnitude" + session.solver.root.solution.report_definitions.surface[ + "outlet-vel-avg" + ].surface_names = ["outlet"] + + session.solver.tui.define.parameters.enable_in_TUI("yes") + session.solver.tui.define.parameters.output_parameters.create( + "report-definition", "outlet-temp-avg" + ) + session.solver.tui.define.parameters.output_parameters.create( + "report-definition", "outlet-vel-avg" + ) + + param_case_path = str(Path(pyfluent.EXAMPLES_PATH) / "Static_Mixer_Parameters.cas.h5") + session.solver.tui.file.write_case(param_case_path) + + local_study = LocalParametricStudy(case_filepath=param_case_path) + + base_design_point = local_study.design_point("Base DP") + + input_parameters = base_design_point.input_parameters + + assert len(input_parameters) + + output_parameters = base_design_point.output_parameters + + assert len(output_parameters) + + print (input_parameters) + print (output_parameters) \ No newline at end of file From 87b2b5902bfb470415ff0217b11c0961c0bdf5a5 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 19:30:54 +0100 Subject: [PATCH 19/52] nice refactor --- src/ansys/fluent/parametric/__init__.py | 31 +- src/ansys/fluent/parametric/local/__init__.py | 286 +++++++++++++++++ src/ansys/fluent/parametric/local/local.py | 292 ------------------ tests/test_local.py | 155 ---------- tests/test_parametric_local.py | 2 +- tests/test_parametric_workflow.py | 9 +- 6 files changed, 311 insertions(+), 464 deletions(-) delete mode 100644 src/ansys/fluent/parametric/local/local.py delete mode 100644 tests/test_local.py diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 2b85fe1f..42c80dab 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -71,10 +71,10 @@ def convert_units_for_design_point(value: Dict[str, Union[float, str]]) -> Dict[str, float]: def conv(val): - if type(val) is float: + if type(val) in (float, int): return val if type(val) is not str: - raise RuntimeError("Invalid value type for input parameter") + raise RuntimeError("Invalid value type for input parameter", val, type(val)) pos = val.find(" [") if pos == -1: return float(val) @@ -204,18 +204,18 @@ class ParametricStudy: def __init__( self, parametric_studies, - session, + session=None, name: Optional[str] = None, design_points: Dict[str, DesignPoint] = None, ): self._parametric_studies = parametric_studies - self.session = session + self.session = session if session is not None else BaseParametricSession() self.name = name self.design_points = {} if design_points is not None: self.design_points = design_points self.project_filepath = None - session.register_study(self) + self.session.register_study(self) def get_all_studies(self) -> Dict[str, "ParametricStudy"]: """Get all currently active studies. @@ -323,7 +323,7 @@ def delete(self) -> None: LOG.error("Cannot delete the current study %s", self.name) else: del self._parametric_studies[self.name] - ParametricStudy._all_studies.pop(id(self)) + self.session._all_studies.pop(id(self)) del self def use_base_data(self) -> None: @@ -522,13 +522,13 @@ def __init__( parametric_project, parametric_studies, project_filepath: str, - session, + session=None, open_project: bool = True ): self._parametric_project = parametric_project self._parametric_studies = parametric_studies self.project_filepath = project_filepath - self.session = session + self.session = session if session is not None else BaseParametricSession() if open_project: self.open(project_filepath=project_filepath) @@ -615,8 +615,18 @@ def __init__(self, *args, **kwargs): def __call__(self): return pyfluent.launch_fluent(*self._args, **self._kwargs) +class BaseParametricSession: + + def __init__( + self + ): + self._all_studies: Dict[int, "ParametricStudy"] = {} + self.current_study_name = None + + def register_study(self, study): + self._all_studies[id(study)] = study -class ParametricSession: +class ParametricSession(BaseParametricSession): """ParametricSession class which encapsulates studies and project. Attributes @@ -702,9 +712,6 @@ def __init__( self.studies[study_name] = study self.current_study_name = self._root.current_parametric_study() - def register_study(self, study): - self._all_studies[id(study)] = study - def new_study(self) -> ParametricStudy: """Create new study. diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index e69de29b..66602ab2 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -0,0 +1,286 @@ +""" +Classes for running a parametric study in Fluent. + +Example +------- +from ansys.fluent.parametric.local.local import LocalParametricStudy, run_local_study_in_fluent + +local_study = LocalParametricStudy(case_filepath="E:\elbow1_param.cas.h5") + +design_point = local_study.design_point("Base DP") +design_point.input_parameters['v1'] = 0.0 + +for idx in range(1, 20): + design_point = local_study.add_design_point("dp_"+str(idx)) + design_point.input_parameters['v1'] = float(idx)/10.0 + +run_local_study_in_fluent(local_study, 5) + +for design_point in local_study.design_point_table: + for k, v in design_point.input_parameters.items(): + print("input parameter", k, v) + for k, v in design_point.output_parameters.items(): + print("output parameter", k, v) + print(72 * "-") + +""" + +from enum import Enum +from math import ceil + + +from ansys.fluent.core.utils.async_execution import asynchronous + +from .filereader.casereader import CaseReader + +from ansys.fluent.parametric import ParametricSession +from ansys.fluent.parametric import BASE_DP_NAME + + +class LocalDesignPoint: + """ + Purely local version of design point in a parametric study. + + Attributes + ---------- + name : str + Name of the design point as a str. + output_parameters : dict + Dict of output parameters + (name of parameter to value). + input_parameters : dict + Dict of input parameters + (name of parameter to value). + status : DesignPointStatus + Current status of the design point. + """ + + def __init__(self, design_point_name: str, base_design_point=None): + self.name = design_point_name + if base_design_point: + self.__inputs = base_design_point.input_parameters.copy() + self.__outputs = base_design_point.output_parameters.copy() + else: + self.__inputs = {} + self.__outputs = {} + + @property + def input_parameters(self) -> dict: + return self.__inputs + + @input_parameters.setter + def input_parameters(self, inputs: dict): + self.__inputs = inputs + + @property + def output_parameters(self) -> dict: + return self.__outputs + + @output_parameters.setter + def output_parameters(self, outputs: dict): + self.__outputs = outputs + + +class LocalDesignPointTable(list): + """ + Local version of Design point table in a parametric study + + Methods + ------- + add_design_point(design_point_name: str) -> DesignPoint + Add a new design point to the table with the provided name. + find_design_point(idx_or_name) + Get a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + remove_design_point(idx_or_name) + Remove a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + """ + + def __init__(self, base_design_point: LocalDesignPoint): + super().__init__() + self.append(base_design_point) + + def add_design_point(self, design_point_name: str) -> LocalDesignPoint: + self.append(LocalDesignPoint(design_point_name, self[0])) + return self[-1] + + def find_design_point(self, idx_or_name) -> LocalDesignPoint: + if isinstance(idx_or_name, int): + return self[idx_or_name] + for design_point in self: + if idx_or_name == design_point.name: + return design_point + raise RuntimeError(f"Design point not found: {idx_or_name}") + + def remove_design_point(self, idx_or_name): + design_point = self.find_design_point(idx_or_name) + if design_point is self[0]: + raise RuntimeError("Cannot remove base design point") + self.remove(self.find_design_point(idx_or_name)) + + +class LocalParametricStudy: + """ + Local version of parametric study that manages design points to parametrize a + Fluent solver set-up. + + Methods + ------- + add_design_point(design_point_name: str) -> LocalDesignPoint + Add a design point + design_point(idx_or_name) + Get a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + """ + + def __init__( + self, + case_filepath: str, + base_design_point_name: str = "Base DP" + ): + self.case_filepath = case_filepath + base_design_point = LocalDesignPoint(base_design_point_name) + case_reader = CaseReader(case_file_path=case_filepath) + + def input_parameter_info(parameter): + name, value = None, None + for k, v in parameter: + if k == "name": + name = v + elif k == "definition": + value = v + return name, value + + def set_input_parameter_info(source, target): + for parameter in source: + target.update((input_parameter_info(parameter),)) + + def output_parameter_info(parameter): + parameter = parameter[1] + for elem in parameter: + if len(elem) and elem[0] == "name": + return elem[1][1], None + + def set_output_parameter_info(source, target): + for parameter in source: + target.update((output_parameter_info(parameter),)) + + set_input_parameter_info( + source=case_reader.input_parameters(), + target=base_design_point.input_parameters) + + set_output_parameter_info( + source=case_reader.output_parameters(), + target=base_design_point.output_parameters) + + print(case_reader.output_parameters()) + + self.design_point_table = LocalDesignPointTable(base_design_point) + + def add_design_point(self, design_point_name: str) -> LocalDesignPoint: + return self.design_point_table.add_design_point(design_point_name) + + def design_point(self, idx_or_name) -> LocalDesignPoint: + return self.design_point_table.find_design_point(idx_or_name) + + +def run_local_study_in_fluent( + local_study, + num_servers, + capture_report_data=False): + + source_table_size = len(local_study.design_point_table) + + def make_input_for_study(design_point_range) -> None: + if design_point_range is None: + design_point_range = range(0, source_table_size) + study_input = [] + for idx in design_point_range: + design_point = local_study.design_point(idx_or_name = idx) + study_input.append(design_point.input_parameters.copy()) + return study_input + + def make_input_for_studies(num_servers) -> None: + study_inputs = [] + total_num_points = num_points = source_table_size + for i in range(num_servers): + count = ceil(num_points/num_servers) + range_base = total_num_points - num_points + num_points -= count + num_servers -= 1 + study_inputs.append(make_input_for_study( + range(range_base, range_base + count) + )) + return study_inputs + + @asynchronous + def make_parametric_session(case_filepath): + return ParametricSession(case_filepath=case_filepath) + + @asynchronous + def apply_to_study(study, inputs): + first = True + for inpt in inputs: + if first: + design_point = study.design_points[BASE_DP_NAME] + design_point.capture_simulation_report_data_enabled = ( + capture_report_data + ) + first = False + else: + design_point = study.add_design_point( + capture_simulation_report_data=capture_report_data + ) + design_point.input_parameters = inpt.copy() + + @asynchronous + def update_design_point(study): + study.update_all_design_points() + + def apply_to_studies(studies, inputs) -> None: + results = [] + for item in list(zip(studies, inputs)): + study, inpt = item + results.append(apply_to_study(study, inpt)) + for result in results: + result.result() + + study_inputs = make_input_for_studies(num_servers) + + sessions = [] + studies = [] + for i in range(num_servers): + sessions.append(make_parametric_session( + case_filepath=local_study.case_filepath + )) + + for session in sessions: + studies.append(next(iter(session.result().studies.values()))) + + apply_to_studies(studies, study_inputs) + + updates = [] + for study in studies: + updates.append(update_design_point(study)) + + for update in updates: + update.result() + + it = iter(local_study.design_point_table) + + for study in studies: + for _, design_point in study.design_points.items(): + next(it).output_parameters = design_point.output_parameters.copy() diff --git a/src/ansys/fluent/parametric/local/local.py b/src/ansys/fluent/parametric/local/local.py deleted file mode 100644 index c4dfc321..00000000 --- a/src/ansys/fluent/parametric/local/local.py +++ /dev/null @@ -1,292 +0,0 @@ -""" -Classes for running a parametric study in Fluent. - -Example -------- ->>> from ansys.fluent.parametric.local.local import LocalParametricStudy, run_local_study_in_fluent - ->>> local_study = LocalParametricStudy(case_filepath="E:\elbow1_param.cas.h5") - ->>> design_point = local_study.design_point("Base DP") ->>> design_point.input_parameters['v1'] = 0.0 - ->>> for idx in range(1, 20): ->>> design_point = local_study.add_design_point("dp_"+str(idx)) ->>> design_point.input_parameters['v1'] = float(idx)/10.0 - ->>> run_local_study_in_fluent(local_study, 5) - ->>> for design_point in local_study.design_point_table: ->>> for k, v in design_point.input_parameters.items(): ->>> print("input parameter", k, v) ->>> for k, v in design_point.output_parameters.items(): ->>> print("output parameter", k, v) ->>> print(72 * "-") - -""" - -from enum import Enum -from math import ceil - - -from ansys.fluent.core.utils.async_execution import asynchronous - -from .filereader.casereader import CaseReader - -from ansys.fluent.parametric import ParametricSession -from ansys.fluent.parametric import BASE_DP_NAME - - -class LocalDesignPoint: - """ - Purely local version of design point in a parametric study. - - Attributes - ---------- - name : str - Name of the design point as a str. - output_parameters : dict - Dict of output parameters - (name of parameter to value). - input_parameters : dict - Dict of input parameters - (name of parameter to value). - status : DesignPointStatus - Current status of the design point. - """ - - def __init__(self, design_point_name: str, base_design_point=None): - self.name = design_point_name - if base_design_point: - self.__inputs = base_design_point.input_parameters.copy() - self.__outputs = base_design_point.output_parameters.copy() - else: - self.__inputs = {} - self.__outputs = {} - - @property - def input_parameters(self) -> dict: - return self.__inputs - - @input_parameters.setter - def input_parameters(self, inputs: dict): - self.__inputs = inputs - - @property - def output_parameters(self) -> dict: - return self.__outputs - - @output_parameters.setter - def output_parameters(self, outputs: dict): - self.__outputs = outputs - - -class LocalDesignPointTable(list): - """ - Local version of Design point table in a parametric study - - Methods - ------- - add_design_point(design_point_name: str) -> DesignPoint - Add a new design point to the table with the provided name. - find_design_point(idx_or_name) - Get a design point, either by name (str) or an index - indicating the position in the table (by order of insertion). - Raises - ------ - RuntimeError - If the design point is not found. - remove_design_point(idx_or_name) - Remove a design point, either by name (str) or an index - indicating the position in the table (by order of insertion). - Raises - ------ - RuntimeError - If the design point is not found. - """ - - def __init__(self, base_design_point: LocalDesignPoint): - super().__init__() - self.append(base_design_point) - - def add_design_point(self, design_point_name: str) -> LocalDesignPoint: - self.append(LocalDesignPoint(design_point_name, self[0])) - return self[-1] - - def find_design_point(self, idx_or_name) -> LocalDesignPoint: - if isinstance(idx_or_name, int): - return self[idx_or_name] - for design_point in self: - if idx_or_name == design_point.name: - return design_point - raise RuntimeError(f"Design point not found: {idx_or_name}") - - def remove_design_point(self, idx_or_name): - design_point = self.find_design_point(idx_or_name) - if design_point is self[0]: - raise RuntimeError("Cannot remove base design point") - self.remove(self.find_design_point(idx_or_name)) - - -class LocalParametricStudy: - """ - Local version of parametric study that manages design points to parametrize a - Fluent solver set-up. - - Methods - ------- - add_design_point(design_point_name: str) -> LocalDesignPoint - Add a design point - design_point(idx_or_name) - Get a design point, either by name (str) or an index - indicating the position in the table (by order of insertion). - Raises - ------ - RuntimeError - If the design point is not found. - """ - - def __init__( - self, - case_filepath: str, - base_design_point_name: str = "Base DP" - ): - self.case_filepath = case_filepath - base_design_point = LocalDesignPoint(base_design_point_name) - case_reader = CaseReader(case_file_path=case_filepath) - - def input_parameter_info(parameter): - name, value = None, None - for k, v in parameter: - if k == "name": - name = v - elif k == "definition": - value = v - return name, value - - def set_input_parameter_info(source, target): - for parameter in source: - target.update((input_parameter_info(parameter),)) - - def output_parameter_info(parameter): - parameter = parameter[1] - for elem in parameter: - if len(elem) and elem[0] == "name": - return elem[1][1], None - - def set_output_parameter_info(source, target): - for parameter in source: - target.update((output_parameter_info(parameter),)) - - set_input_parameter_info( - source=case_reader.input_parameters(), - target=base_design_point.input_parameters) - - set_output_parameter_info( - source=case_reader.output_parameters(), - target=base_design_point.output_parameters) - - print(case_reader.output_parameters()) - - self.design_point_table = LocalDesignPointTable(base_design_point) - - def add_design_point(self, design_point_name: str) -> LocalDesignPoint: - return self.design_point_table.add_design_point(design_point_name) - - def design_point(self, idx_or_name) -> LocalDesignPoint: - return self.design_point_table.find_design_point(idx_or_name) - - -def run_local_study_in_fluent( - local_study, - num_servers, - capture_report_data=False): - - source_table_size = len(local_study.design_point_table) - - def make_input_for_study(design_point_range) -> None: - if design_point_range is None: - design_point_range = range(0, source_table_size) - study_input = [] - for idx in design_point_range: - design_point = local_study.design_point(idx_or_name = idx) - study_input.append(design_point.input_parameters.copy()) - return study_input - - def make_input_for_studies(num_servers) -> None: - study_inputs = [] - total_num_points = num_points = source_table_size - for i in range(num_servers): - count = ceil(num_points/num_servers) - range_base = total_num_points - num_points - num_points -= count - num_servers -= 1 - study_inputs.append(make_input_for_study( - range(range_base, range_base + count) - )) - return study_inputs - - @asynchronous - def make_parametric_session(case_filepath): - return ParametricSession(case_filepath=case_filepath) - - @asynchronous - def apply_to_study(study, inputs): - first = True - for inpt in inputs: - if first: - design_point = study.design_points[BASE_DP_NAME] - design_point.capture_simulation_report_data_enabled = ( - capture_report_data - ) - first = False - else: - design_point = study.add_design_point( - capture_simulation_report_data=capture_report_data - ) - design_point.input_parameters = inpt.copy() - - @asynchronous - def update_design_point(study): - study.update_all_design_points() - - def apply_to_studies(studies, inputs) -> None: - results = [] - for item in list(zip(studies, inputs)): - study, inpt = item - results.append(apply_to_study(study, inpt)) - for result in results: - result.result() - - study_inputs = make_input_for_studies(num_servers) - - sessions = [] - studies = [] - for i in range(num_servers): - sessions.append(make_parametric_session( - case_filepath=local_study.case_filepath - )) - - for session in sessions: - studies.append(next(iter(session.result().studies.values()))) - - apply_to_studies(studies, study_inputs) - - updates = [] - for study in studies: - updates.append(update_design_point(study)) - - for update in updates: - update.result() - - it = iter(local_study.design_point_table) - - for study in studies: - for _, design_point in study.design_points.items(): - next(it).output_parameters = design_point.output_parameters.copy() - - - - - - diff --git a/tests/test_local.py b/tests/test_local.py deleted file mode 100644 index a96442c5..00000000 --- a/tests/test_local.py +++ /dev/null @@ -1,155 +0,0 @@ -""" -Unit tests for parameteric study code: local version -""" - -from ansys.fluent.parametric.local import ( - DesignPoint, - DesignPointStatus, - DesignPointTable, - ParametricStudy - ) - - -def make_simple_base_design_point(): - dp = DesignPoint("base") - dp.inputs = {"x": 2} - dp.outputs = {"y": 0} - return dp - - -class XTimes: - """ - test class - """ - - def __init__(self, multiplier): - self.multiplier = multiplier - self.input_parameters = {"x": 0} - self.output_parameters = {"y": 0} - - def __call__(self): - return self - - def set_input_parameter(self, parameter_name: str, value): - self.input_parameters[parameter_name] = value - - def update(self): - self.output_parameters["y"] = ( - self.multiplier * self.input_parameters["x"] - ) - - -def test_create_base_design_point(): - dp = make_simple_base_design_point() - assert dp.name == "base" - assert dp.inputs == {"x": 2} - assert dp.outputs == {"y": 0} - assert dp.status == DesignPointStatus.OUT_OF_DATE - - -def test_create_user_defined_design_point(): - dp = DesignPoint("DP1", base_design_point=make_simple_base_design_point()) - assert dp.name == "DP1" - assert dp.inputs == {"x": 2} - assert dp.outputs == {"y": 0} - assert dp.status == DesignPointStatus.OUT_OF_DATE - - -def test_start_and_end_design_point_update(): - base_dp = make_simple_base_design_point() - dp1 = DesignPoint("DP1", base_design_point=base_dp) - base_dp.on_start_updating() - assert base_dp.status == DesignPointStatus.UPDATING - assert dp1.status == DesignPointStatus.OUT_OF_DATE - base_dp.on_end_updating({"y": 1}) - assert base_dp.status == DesignPointStatus.UPDATED - assert dp1.status == DesignPointStatus.OUT_OF_DATE - dp1.on_start_updating() - assert base_dp.status == DesignPointStatus.UPDATED - assert dp1.status == DesignPointStatus.UPDATING - dp1.on_end_updating({"y": 42}) - assert base_dp.status == DesignPointStatus.UPDATED - assert dp1.status == DesignPointStatus.UPDATED - - -def test_add_remove_find_points_in_table(): - table = DesignPointTable(DesignPoint("base")) - table.append(DesignPoint("a")) - table.append(DesignPoint("b")) - table.append(DesignPoint("c")) - assert table.find_design_point("b").name == "b" - assert table.find_design_point("base").name == "base" - assert table.find_design_point(0).name == "base" - assert table.find_design_point(3).name == "c" - table.remove_design_point("a") - table.remove_design_point(2) - assert len(table) == 2 - assert table.find_design_point("b").name == "b" - assert table.find_design_point("base").name == "base" - throws = False - try: - table.remove_design_point(0) - except RuntimeError: - throws = True - assert throws - throws = False - try: - table.remove_design_point("base") - except RuntimeError: - throws = True - assert throws - assert len(table) == 2 - assert table.find_design_point("b").name == "b" - assert table.find_design_point("base").name == "base" - - -def test_run_parametric_study(): - multiplier = 3 - study = ParametricStudy( - base_design_point_name="xxx", launcher=XTimes(multiplier) - ) - inputs = [0, 3, 8, -5] - for i in range(1, len(inputs)): - study.add_design_point("d" + repr(i)).set_input("x", inputs[i]) - for i in range(len(inputs)): - assert study.design_point(i).status == DesignPointStatus.OUT_OF_DATE - study.update_all() - for i in range(len(inputs)): - assert study.design_point(i).status == DesignPointStatus.UPDATED - assert study.design_point(i).outputs["y"] == multiplier * inputs[i] - - -def test_run_parametric_study_and_block(): - multiplier = 3 - study = ParametricStudy( - base_design_point_name="xxx", launcher=XTimes(multiplier) - ) - inputs = [0, 3, 8, -5] - for i in range(1, len(inputs)): - study.add_design_point("d" + repr(i)).set_input("x", inputs[i]) - for i in range(len(inputs)): - if i % 2: - study.design_point(i).block_updates() - for i in range(len(inputs)): - status = ( - DesignPointStatus.BLOCKED - if i % 2 - else DesignPointStatus.OUT_OF_DATE - ) - assert study.design_point(i).status == status - study.update_all() - for i in range(len(inputs)): - status = ( - DesignPointStatus.BLOCKED if i % 2 else DesignPointStatus.UPDATED - ) - assert study.design_point(i).status == status - assert ( - study.design_point(i).outputs["y"] - == (0 if i % 2 else multiplier) * inputs[i] - ) - for i in range(len(inputs)): - if i % 2: - study.update_design_point(study.design_point(i)) - for i in range(len(inputs)): - assert study.design_point(i).status == DesignPointStatus.UPDATED - assert study.design_point(i).outputs["y"] == multiplier * inputs[i] diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index 0cdd7106..08054915 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -8,7 +8,7 @@ from pathlib import Path from ansys.fluent.core import examples, session import ansys.fluent.core as pyfluent -from ansys.fluent.parametric.local.local import LocalParametricStudy +from ansys.fluent.parametric.local import LocalParametricStudy def test_parametric_local(): diff --git a/tests/test_parametric_workflow.py b/tests/test_parametric_workflow.py index 17599dc0..efa32e68 100644 --- a/tests/test_parametric_workflow.py +++ b/tests/test_parametric_workflow.py @@ -116,10 +116,11 @@ ########################################################################### # Instantiate a parametric study from a Fluent session -study_1 = ParametricStudy(session.solver.root.parametric_studies).initialize() +study_1 = ParametricStudy( + session.solver.root.parametric_studies).initialize() parametricStudies_exp = 1 -parametricStudies_test = len(ParametricStudy._all_studies.keys()) +parametricStudies_test = len(study_1.get_all_studies().keys()) assert parametricStudies_test == parametricStudies_exp ########################################################################### @@ -237,7 +238,7 @@ assert len(study_2.design_points) == 2 parametricStudies_exp = 2 -parametricStudies_test = len(ParametricStudy._all_studies.keys()) +parametricStudies_test = len(study_1.get_all_studies().keys()) assert parametricStudies_test == parametricStudies_exp ######################################################################### @@ -251,7 +252,7 @@ study_1.delete() parametricStudies_exp = 1 -parametricStudies_test = len(ParametricStudy._all_studies.keys()) +parametricStudies_test = len(study_1.get_all_studies().keys()) assert parametricStudies_test == parametricStudies_exp ######################################################################### From 6c64fd3dd6088f8afb41bb271a140cbc2785766c Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 19:47:52 +0100 Subject: [PATCH 20/52] nice refactor --- tests/test_lispy.py | 63 ++++++++------------------------------------- 1 file changed, 11 insertions(+), 52 deletions(-) diff --git a/tests/test_lispy.py b/tests/test_lispy.py index 094dafd3..0346155b 100644 --- a/tests/test_lispy.py +++ b/tests/test_lispy.py @@ -1,60 +1,19 @@ - from ansys.fluent.parametric.local.filereader import lispy + def test_read(): in_outs = [ - [ - "1", - 1 - ], - - [ - "(1)", - [1] - ], - - [ - "(1 2)", - [1, 2] - ], - - [ - "(1 . 2)", - [1, 2] - ], - - [ - "(1 2 3)", - [1, 2, 3] - - ], - - [ - "(1 2 . 3)", - [1, [2, 3]] - ], - - [ - "((1 . 2) . 3)", - [[1, 2], 3] - ], - - [ - "(1 . (2 . 3))", - [1, [2, 3]] - ], - - [ - "(x 1)", - ["x", 1] - ], - - [ - "(x . \"1.0 [m/s]\")", - ["x", "1.0 [m/s]"] # should be "'1.0 [m/s]'" ? - ] + ["1", 1], + ["(1)", [1]], + ["(1 2)", [1, 2]], + ["(1 . 2)", [1, 2]], + ["(1 2 3)", [1, 2, 3]], + ["(1 2 . 3)", [1, [2, 3]]], + ["((1 . 2) . 3)", [[1, 2], 3]], + ["(1 . (2 . 3))", [1, [2, 3]]], + ["(x 1)", ["x", 1]], + ['(x . "1.0 [m/s]")', ["x", "1.0 [m/s]"]], # should be "'1.0 [m/s]'" ? ] for in_out in in_outs: assert lispy.parse(in_out[0]) == in_out[1] - From 2207ebd7fd3d304a5e5d22d7acf90b05ab1b7788 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 19:50:04 +0100 Subject: [PATCH 21/52] nice refactor --- src/ansys/fluent/parametric/local/__init__.py | 43 ++++++++----------- .../parametric/local/filereader/casereader.py | 15 +++---- tests/test_parametric_local.py | 14 +++--- 3 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 66602ab2..e20b5191 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -28,13 +28,11 @@ from enum import Enum from math import ceil - from ansys.fluent.core.utils.async_execution import asynchronous -from .filereader.casereader import CaseReader +from ansys.fluent.parametric import BASE_DP_NAME, ParametricSession -from ansys.fluent.parametric import ParametricSession -from ansys.fluent.parametric import BASE_DP_NAME +from .filereader.casereader import CaseReader class LocalDesignPoint: @@ -146,11 +144,7 @@ class LocalParametricStudy: If the design point is not found. """ - def __init__( - self, - case_filepath: str, - base_design_point_name: str = "Base DP" - ): + def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): self.case_filepath = case_filepath base_design_point = LocalDesignPoint(base_design_point_name) case_reader = CaseReader(case_file_path=case_filepath) @@ -180,12 +174,14 @@ def set_output_parameter_info(source, target): set_input_parameter_info( source=case_reader.input_parameters(), - target=base_design_point.input_parameters) + target=base_design_point.input_parameters, + ) set_output_parameter_info( source=case_reader.output_parameters(), - target=base_design_point.output_parameters) - + target=base_design_point.output_parameters, + ) + print(case_reader.output_parameters()) self.design_point_table = LocalDesignPointTable(base_design_point) @@ -197,10 +193,7 @@ def design_point(self, idx_or_name) -> LocalDesignPoint: return self.design_point_table.find_design_point(idx_or_name) -def run_local_study_in_fluent( - local_study, - num_servers, - capture_report_data=False): +def run_local_study_in_fluent(local_study, num_servers, capture_report_data=False): source_table_size = len(local_study.design_point_table) @@ -209,7 +202,7 @@ def make_input_for_study(design_point_range) -> None: design_point_range = range(0, source_table_size) study_input = [] for idx in design_point_range: - design_point = local_study.design_point(idx_or_name = idx) + design_point = local_study.design_point(idx_or_name=idx) study_input.append(design_point.input_parameters.copy()) return study_input @@ -217,13 +210,13 @@ def make_input_for_studies(num_servers) -> None: study_inputs = [] total_num_points = num_points = source_table_size for i in range(num_servers): - count = ceil(num_points/num_servers) + count = ceil(num_points / num_servers) range_base = total_num_points - num_points num_points -= count num_servers -= 1 - study_inputs.append(make_input_for_study( - range(range_base, range_base + count) - )) + study_inputs.append( + make_input_for_study(range(range_base, range_base + count)) + ) return study_inputs @asynchronous @@ -243,7 +236,7 @@ def apply_to_study(study, inputs): else: design_point = study.add_design_point( capture_simulation_report_data=capture_report_data - ) + ) design_point.input_parameters = inpt.copy() @asynchronous @@ -263,9 +256,9 @@ def apply_to_studies(studies, inputs) -> None: sessions = [] studies = [] for i in range(num_servers): - sessions.append(make_parametric_session( - case_filepath=local_study.case_filepath - )) + sessions.append( + make_parametric_session(case_filepath=local_study.case_filepath) + ) for session in sessions: studies.append(next(iter(session.result().studies.values()))) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 0989b999..bcf053cd 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -1,13 +1,13 @@ - import h5py -from .import lispy -class CaseReader: +from . import lispy + +class CaseReader: def __init__(self, case_file_path): file = h5py.File(case_file_path) - settings = file['settings'] - rpvars = settings['Rampant Variables'][0] + settings = file["settings"] + rpvars = settings["Rampant Variables"][0] rp_vars_str = rpvars.decode() self._rp_vars = lispy.parse(rp_vars_str)[1] @@ -16,10 +16,10 @@ def input_parameters(self): input_params = [] for expr in exprs: for attr in expr: - if attr[0] == 'input-parameter' and attr[1] is True: + if attr[0] == "input-parameter" and attr[1] is True: input_params.append(expr) return input_params - + def output_parameters(self): parameters = self._find_rp_var("parameters/output-parameters") return parameters @@ -34,4 +34,3 @@ def _find_rp_var(self, name: str): for var in self._rp_vars: if type(var) == list and len(var) and var[0] == name: return var[1] - diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index 08054915..a0031064 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -6,8 +6,10 @@ ############################################################################ from pathlib import Path -from ansys.fluent.core import examples, session + import ansys.fluent.core as pyfluent +from ansys.fluent.core import examples + from ansys.fluent.parametric.local import LocalParametricStudy @@ -22,7 +24,7 @@ def test_parametric_local(): session.solver.tui.file.read_case(case_file_name=import_filename) session.solver.tui.define.parameters.enable_in_TUI("yes") - + session.solver.tui.define.boundary_conditions.set.velocity_inlet( "inlet1", (), "vmag", "yes", "inlet1_vel", 1, "quit" ) @@ -66,7 +68,9 @@ def test_parametric_local(): "report-definition", "outlet-vel-avg" ) - param_case_path = str(Path(pyfluent.EXAMPLES_PATH) / "Static_Mixer_Parameters.cas.h5") + param_case_path = str( + Path(pyfluent.EXAMPLES_PATH) / "Static_Mixer_Parameters.cas.h5" + ) session.solver.tui.file.write_case(param_case_path) local_study = LocalParametricStudy(case_filepath=param_case_path) @@ -81,5 +85,5 @@ def test_parametric_local(): assert len(output_parameters) - print (input_parameters) - print (output_parameters) \ No newline at end of file + print(input_parameters) + print(output_parameters) From 9438b83950126ebfa865f5ddb72a168b3771c481 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 19:55:49 +0100 Subject: [PATCH 22/52] nice refactor --- src/ansys/fluent/parametric/__init__.py | 29 +- .../parametric/local/filereader/lispy.py | 415 ++++++++++++------ 2 files changed, 288 insertions(+), 156 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 42c80dab..7dd2f99d 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -69,7 +69,10 @@ BASE_DP_NAME = "Base DP" -def convert_units_for_design_point(value: Dict[str, Union[float, str]]) -> Dict[str, float]: + +def convert_units_for_design_point( + value: Dict[str, Union[float, str]] +) -> Dict[str, float]: def conv(val): if type(val) in (float, int): return val @@ -80,10 +83,7 @@ def conv(val): return float(val) return float(val[:pos]) - return dict(map( - lambda x: (x[0], conv(x[1])), - value.items() - )) + return dict(map(lambda x: (x[0], conv(x[1])), value.items())) class DesignPoint: @@ -297,9 +297,7 @@ def duplicate(self, copy_design_points: bool = True) -> "ParametricStudy": self._parametric_studies.duplicate(copy_design_points=copy_design_points) new_study_names = self._parametric_studies.get_object_names() clone_name = set(new_study_names).difference(set(old_study_names)).pop() - current_study = self.get_all_studies()[ - self.session.current_study_name - ] + current_study = self.get_all_studies()[self.session.current_study_name] if copy_design_points: clone_design_points = { k: DesignPoint(k, self._parametric_studies[clone_name].design_points[k]) @@ -523,7 +521,7 @@ def __init__( parametric_studies, project_filepath: str, session=None, - open_project: bool = True + open_project: bool = True, ): self._parametric_project = parametric_project self._parametric_studies = parametric_studies @@ -615,17 +613,16 @@ def __init__(self, *args, **kwargs): def __call__(self): return pyfluent.launch_fluent(*self._args, **self._kwargs) + class BaseParametricSession: - - def __init__( - self - ): + def __init__(self): self._all_studies: Dict[int, "ParametricStudy"] = {} self.current_study_name = None - + def register_study(self, study): self._all_studies[id(study)] = study + class ParametricSession(BaseParametricSession): """ParametricSession class which encapsulates studies and project. @@ -692,14 +689,14 @@ def __init__( parametric_studies=self._root.parametric_studies, project_filepath=str(study.project_filepath), open_project=False, - session=self._session + session=self._session, ) elif project_filepath is not None: self.project = ParametricProject( parametric_project=self._root.file.parametric_project, parametric_studies=self._root.parametric_studies, project_filepath=project_filepath, - session=self._session + session=self._session, ) studies_settings = self._root.parametric_studies for study_name in studies_settings.get_object_names(): diff --git a/src/ansys/fluent/parametric/local/filereader/lispy.py b/src/ansys/fluent/parametric/local/filereader/lispy.py index fe09c3c9..d9660dbf 100644 --- a/src/ansys/fluent/parametric/local/filereader/lispy.py +++ b/src/ansys/fluent/parametric/local/filereader/lispy.py @@ -4,74 +4,107 @@ ################ Symbol, Procedure, classes -## This code is copied from https://github.com/norvig/pytudes/blob/main/py/lispy.py and modified -## as necessary +## This code is copied from +## https://github.com/norvig/pytudes/blob/main/py/lispy.py +## and modified as necessary -import re, sys, io +import io +import re +import sys + + +class Symbol(str): + pass -class Symbol(str): pass def Sym(s, symbol_table={}): "Find or create unique Symbol entry for str s in symbol table." - if s not in symbol_table: symbol_table[s] = Symbol(s) + if s not in symbol_table: + symbol_table[s] = Symbol(s) return symbol_table[s] -_quote, _if, _set, _define, _lambda, _begin, _definemacro, = map(Sym, -"quote if set! define lambda begin define-macro".split()) -_quasiquote, _unquote, _unquotesplicing = map(Sym, -"quasiquote unquote unquote-splicing".split()) +( + _quote, + _if, + _set, + _define, + _lambda, + _begin, + _definemacro, +) = map(Sym, "quote if set! define lambda begin define-macro".split()) + +_quasiquote, _unquote, _unquotesplicing = map( + Sym, "quasiquote unquote unquote-splicing".split() +) + class Procedure: "A user-defined Scheme procedure." - def __init__(self, parms, exp, env): - self.parms, self.exp, self.env = parms, exp, env + + def __init__(self, params, exp, env): + self.params, self.exp, self.env = params, exp, env + def __call__(self, *args): - return eval(self.exp, Env(self.parms, args, self.env)) + return eval(self.exp, Env(self.params, args, self.env)) + ################ parse, read, and user interaction -def parse(inport): + +def parse(in_port): "Parse a program: read and expand/error-check it." - # Backwards compatibility: given a str, convert it to an InPort - if isinstance(inport, str): inport = InPort(io.StringIO(inport)) - return expand(read(inport), toplevel=True) + # Backwards compatibility: given a str, convert it to an InputPort + if isinstance(in_port, str): + in_port = InputPort(io.StringIO(in_port)) + return expand(read(in_port), toplevel=True) + + +eof_object = Symbol("#") # Note: uninterned; can't be read -eof_object = Symbol('#') # Note: uninterned; can't be read -class InPort: +class InputPort: "An input port. Retains a line of chars." tokenizer = r"""\s*(,@|[('`,)]|"(?:[\\].|[^\\"])*"|;.*|[^\s('"`,;)]*)(.*)""" + def __init__(self, file): - self.file = file; self.line = '' + self.file = file + self.line = "" + def next_token(self): "Return the next token, reading new text into line buffer if needed." while True: - if self.line == '': self.line = self.file.readline() - if self.line == '': return eof_object - token, self.line = re.match(InPort.tokenizer, self.line).groups() - if token != '' and not token.startswith(';'): + if self.line == "": + self.line = self.file.readline() + if self.line == "": + return eof_object + token, self.line = re.match(InputPort.tokenizer, self.line).groups() + if token != "" and not token.startswith(";"): return token -def readchar(inport): + +def readchar(in_port): "Read the next character from an input port." - if inport.line != '': - ch, inport.line = inport.line[0], inport.line[1:] + if in_port.line != "": + ch, in_port.line = in_port.line[0], in_port.line[1:] return ch else: - return inport.file.read(1) or eof_object + return in_port.file.read(1) or eof_object -def read(inport): + +def read(in_port): "Read a Scheme expression from an input port." + def read_ahead(token): - if '(' == token: + if "(" == token: L = [] cons = None while True: - token = inport.next_token() - if token == ')': return L - if token == '.': + token = in_port.next_token() + if token == ")": + return L + if token == ".": if len(L) > 1: cons = [L.pop()] else: @@ -81,243 +114,343 @@ def read_ahead(token): ahead = cons cons = None L.append(ahead) - elif ')' == token: raise SyntaxError('unexpected )') - elif token in quotes: return [quotes[token], read(inport)] - elif token is eof_object: raise SyntaxError('unexpected EOF in list') - else: return atom(token) + elif ")" == token: + raise SyntaxError("unexpected )") + elif token in quotes: + return [quotes[token], read(in_port)] + elif token is eof_object: + raise SyntaxError("unexpected EOF in list") + else: + return atom(token) + # body of read: - token1 = inport.next_token() + token1 = in_port.next_token() return eof_object if token1 is eof_object else read_ahead(token1) -quotes = {"'":_quote, "`":_quasiquote, ",":_unquote, ",@":_unquotesplicing} + +quotes = {"'": _quote, "`": _quasiquote, ",": _unquote, ",@": _unquotesplicing} + def atom(token): 'Numbers become numbers; #t and #f are booleans; "..." string; otherwise Symbol.' - if token == '#t': return True - elif token == '#f': return False - elif token[0] == '"': return token[1:-1] - try: return int(token) + if token == "#t": + return True + elif token == "#f": + return False + elif token[0] == '"': + return token[1:-1] + try: + return int(token) except ValueError: - try: return float(token) + try: + return float(token) except ValueError: - try: return complex(token.replace('i', 'j', 1)) + try: + return complex(token.replace("i", "j", 1)) except ValueError: return Sym(token) + def to_string(x): "Convert a Python object back into a Lisp-readable string." - if x is True: return "#t" - elif x is False: return "#f" - elif isa(x, Symbol): return x - elif isa(x, str): return repr(x) - elif isa(x, list): return '('+' '.join(map(to_string, x))+')' - elif isa(x, complex): return str(x).replace('j', 'i') - else: return str(x) + if x is True: + return "#t" + elif x is False: + return "#f" + elif isa(x, Symbol): + return x + elif isa(x, str): + return repr(x) + elif isa(x, list): + return "(" + " ".join(map(to_string, x)) + ")" + elif isa(x, complex): + return str(x).replace("j", "i") + else: + return str(x) + def load(filename): "Eval every expression from a file." - repl(None, InPort(open(filename)), None) + repl(None, InputPort(open(filename)), None) -def repl(prompt='lispy> ', inport=InPort(sys.stdin), out=sys.stdout): + +def repl(prompt="lispy> ", in_port=InputPort(sys.stdin), out=sys.stdout): "A prompt-read-eval-print loop." sys.stderr.write("Lispy version 2.0\n") while True: try: - if prompt: sys.stderr.write(prompt) - x = parse(inport) - if x is eof_object: return + if prompt: + sys.stderr.write(prompt) + x = parse(in_port) + if x is eof_object: + return val = eval(x) - if val is not None and out: print(to_string(val), file=out) + if val is not None and out: + print(to_string(val), file=out) except Exception as e: - print('%s: %s' % (type(e).__name__, e)) + print("%s: %s" % (type(e).__name__, e)) + ################ Environment class + class Env(dict): "An environment: a dict of {'var':val} pairs, with an outer Env." - def __init__(self, parms=(), args=(), outer=None): - # Bind parm list to corresponding args, or single parm to list of args + + def __init__(self, params=(), args=(), outer=None): + # Bind paarm list to corresponding args, or single param to list of args self.outer = outer - if isa(parms, Symbol): - self.update({parms:list(args)}) + if isa(params, Symbol): + self.update({params: list(args)}) else: - if len(args) != len(parms): - raise TypeError('expected %s, given %s, ' - % (to_string(parms), to_string(args))) - self.update(zip(parms,args)) + if len(args) != len(params): + raise TypeError( + "expected %s, given %s, " % (to_string(params), to_string(args)) + ) + self.update(zip(params, args)) + def find(self, var): "Find the innermost Env where var appears." - if var in self: return self - elif self.outer is None: raise LookupError(var) - else: return self.outer.find(var) + if var in self: + return self + elif self.outer is None: + raise LookupError(var) + else: + return self.outer.find(var) + + +def is_pair(x): + return x != [] and isa(x, list) + + +def cons(x, y): + return [x] + y -def is_pair(x): return x != [] and isa(x, list) -def cons(x, y): return [x]+y def callcc(proc): "Call proc with current continuation; escape only" ball = RuntimeWarning("Sorry, can't continue this continuation any longer.") - def throw(retval): ball.retval = retval; raise ball + + def throw(retval): + ball.retval = retval + raise ball + try: return proc(throw) except RuntimeWarning as w: - if w is ball: return ball.retval - else: raise w + if w is ball: + return ball.retval + else: + raise w + def add_globals(self): "Add some Scheme standard procedures." - import math, cmath, operator as op + import cmath + import math + import operator as op + self.update(vars(math)) self.update(vars(cmath)) - self.update({ - '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, 'not':op.not_, - '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, - 'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':cons, - 'car':lambda x:x[0], 'cdr':lambda x:x[1:], 'append':op.add, - 'list':lambda *x:list(x), 'list?': lambda x:isa(x,list), - 'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol), - 'boolean?':lambda x: isa(x, bool), 'pair?':is_pair, - 'port?': lambda x:isa(x,file), 'apply':lambda proc,l: proc(*l), - 'eval':lambda x: eval(expand(x)), 'load':lambda fn: load(fn), 'call/cc':callcc, - 'open-input-file':open,'close-input-port':lambda p: p.file.close(), - 'open-output-file':lambda f:open(f,'w'), 'close-output-port':lambda p: p.close(), - 'eof-object?':lambda x:x is eof_object, 'read-char':readchar, - 'read':read, 'write':lambda x,port=sys.stdout:port.write(to_string(x)), - 'display':lambda x,port=sys.stdout:port.write(x if isa(x,str) else to_string(x))}) + self.update( + { + "+": op.add, + "-": op.sub, + "*": op.mul, + "/": op.truediv, + "not": op.not_, + ">": op.gt, + "<": op.lt, + ">=": op.ge, + "<=": op.le, + "=": op.eq, + "equal?": op.eq, + "eq?": op.is_, + "length": len, + "cons": cons, + "car": lambda x: x[0], + "cdr": lambda x: x[1:], + "append": op.add, + "list": lambda *x: list(x), + "list?": lambda x: isa(x, list), + "null?": lambda x: x == [], + "symbol?": lambda x: isa(x, Symbol), + "boolean?": lambda x: isa(x, bool), + "pair?": is_pair, + "port?": lambda x: isa(x, file), + "apply": lambda proc, l: proc(*l), + "eval": lambda x: eval(expand(x)), + "load": lambda fn: load(fn), + "call/cc": callcc, + "open-input-file": open, + "close-input-port": lambda p: p.file.close(), + "open-output-file": lambda f: open(f, "w"), + "close-output-port": lambda p: p.close(), + "eof-object?": lambda x: x is eof_object, + "read-char": readchar, + "read": read, + "write": lambda x, port=sys.stdout: port.write(to_string(x)), + "display": lambda x, port=sys.stdout: port.write( + x if isa(x, str) else to_string(x) + ), + } + ) return self + isa = isinstance global_env = add_globals(Env()) ################ eval (tail recursive) + def eval(x, env=global_env): "Evaluate an expression in an environment." while True: - if isa(x, Symbol): # variable reference + if isa(x, Symbol): # variable reference return env.find(x)[x] - elif not isa(x, list): # constant literal + elif not isa(x, list): # constant literal return x - elif x[0] is _quote: # (quote exp) + elif x[0] is _quote: # (quote exp) (_, exp) = x return exp - elif x[0] is _if: # (if test conseq alt) + elif x[0] is _if: # (if test conseq alt) (_, test, conseq, alt) = x - x = (conseq if eval(test, env) else alt) - elif x[0] is _set: # (set! var exp) + x = conseq if eval(test, env) else alt + elif x[0] is _set: # (set! var exp) (_, var, exp) = x env.find(var)[var] = eval(exp, env) return None - elif x[0] is _define: # (define var exp) + elif x[0] is _define: # (define var exp) (_, var, exp) = x env[var] = eval(exp, env) return None - elif x[0] is _lambda: # (lambda (var*) exp) + elif x[0] is _lambda: # (lambda (var*) exp) (_, vars, exp) = x return Procedure(vars, exp, env) - elif x[0] is _begin: # (begin exp+) + elif x[0] is _begin: # (begin exp+) for exp in x[1:-1]: eval(exp, env) x = x[-1] - else: # (proc exp*) + else: # (proc exp*) exps = [eval(exp, env) for exp in x] proc = exps.pop(0) if isa(proc, Procedure): x = proc.exp - env = Env(proc.parms, exps, proc.env) + env = Env(proc.params, exps, proc.env) else: return proc(*exps) + ################ expand + def expand(x, toplevel=False): "Walk tree of x, making optimizations/fixes, and signaling SyntaxError." - #require(x, x!=[]) # () => Error + # require(x, x!=[]) # () => Error if x == []: return x - if not isa(x, list): # constant => unchanged + if not isa(x, list): # constant => unchanged return x - elif x[0] is _quote: # (quote exp) - require(x, len(x)==2) + elif x[0] is _quote: # (quote exp) + require(x, len(x) == 2) return x elif x[0] is _if: - if len(x)==3: x = x + [None] # (if t c) => (if t c None) - require(x, len(x)==4) + if len(x) == 3: + x = x + [None] # (if t c) => (if t c None) + require(x, len(x) == 4) return list(map(expand, x)) elif x[0] is _set: - require(x, len(x)==3); - var = x[1] # (set! non-var exp) => Error + require(x, len(x) == 3) + var = x[1] # (set! non-var exp) => Error require(x, isa(var, Symbol), "can set! only a symbol") return [_set, var, expand(x[2])] elif x[0] is _define or x[0] is _definemacro: - require(x, len(x)>=3) + require(x, len(x) >= 3) _def, v, body = x[0], x[1], x[2:] - if isa(v, list) and v: # (define (f args) body) - f, args = v[0], v[1:] # => (define f (lambda (args) body)) - return expand([_def, f, [_lambda, args]+body]) + if isa(v, list) and v: # (define (f args) body) + f, args = v[0], v[1:] # => (define f (lambda (args) body)) + return expand([_def, f, [_lambda, args] + body]) else: - require(x, len(x)==3) # (define non-var/list exp) => Error + require(x, len(x) == 3) # (define non-var/list exp) => Error require(x, isa(v, Symbol), "can define only a symbol") exp = expand(x[2]) if _def is _definemacro: require(x, toplevel, "define-macro only allowed at top level") proc = eval(exp) require(x, callable(proc), "macro must be a procedure") - macro_table[v] = proc # (define-macro v proc) - return None # => None; add v:proc to macro_table + macro_table[v] = proc # (define-macro v proc) + return None # => None; add v:proc to macro_table return [_define, v, exp] elif x[0] is _begin: - if len(x)==1: return None # (begin) => None - else: return [expand(xi, toplevel) for xi in x] - elif x[0] is _lambda: # (lambda (x) e1 e2) - require(x, len(x)>=3) # => (lambda (x) (begin e1 e2)) + if len(x) == 1: + return None # (begin) => None + else: + return [expand(xi, toplevel) for xi in x] + elif x[0] is _lambda: # (lambda (x) e1 e2) + require(x, len(x) >= 3) # => (lambda (x) (begin e1 e2)) vars, body = x[1], x[2:] - require(x, (isa(vars, list) and all(isa(v, Symbol) for v in vars)) - or isa(vars, Symbol), "illegal lambda argument list") + require( + x, + (isa(vars, list) and all(isa(v, Symbol) for v in vars)) + or isa(vars, Symbol), + "illegal lambda argument list", + ) exp = body[0] if len(body) == 1 else [_begin] + body return [_lambda, vars, expand(exp)] - elif x[0] is _quasiquote: # `x => expand_quasiquote(x) - require(x, len(x)==2) + elif x[0] is _quasiquote: # `x => expand_quasiquote(x) + require(x, len(x) == 2) return expand_quasiquote(x[1]) elif isa(x[0], Symbol) and x[0] in macro_table: - return expand(macro_table[x[0]](*x[1:]), toplevel) # (m arg...) - else: # => macroexpand if m isa macro - return list(map(expand, x)) # (f arg...) => expand each + return expand(macro_table[x[0]](*x[1:]), toplevel) # (m arg...) + else: # => macroexpand if m isa macro + return list(map(expand, x)) # (f arg...) => expand each + def require(x, predicate, msg="wrong length"): "Signal a syntax error if predicate is false." - if not predicate: raise SyntaxError(to_string(x)+': '+msg) + if not predicate: + raise SyntaxError(to_string(x) + ": " + msg) + _append, _cons, _let = map(Sym, "append cons let".split()) + def expand_quasiquote(x): - """Expand `x => 'x; `,x => x; `(,@x y) => (append x y) """ + """Expand `x => 'x; `,x => x; `(,@x y) => (append x y)""" if not is_pair(x): return [_quote, x] require(x, x[0] is not _unquotesplicing, "can't splice here") if x[0] is _unquote: - require(x, len(x)==2) + require(x, len(x) == 2) return x[1] elif is_pair(x[0]) and x[0][0] is _unquotesplicing: - require(x[0], len(x[0])==2) + require(x[0], len(x[0]) == 2) return [_append, x[0][1], expand_quasiquote(x[1:])] else: return [_cons, expand_quasiquote(x[0]), expand_quasiquote(x[1:])] + def let(*args): args = list(args) x = cons(_let, args) - require(x, len(args)>1) + require(x, len(args) > 1) bindings, body = args[0], args[1:] - require(x, all(isa(b, list) and len(b)==2 and isa(b[0], Symbol) - for b in bindings), "illegal binding list") + require( + x, + all(isa(b, list) and len(b) == 2 and isa(b[0], Symbol) for b in bindings), + "illegal binding list", + ) vars, vals = zip(*bindings) - return [[_lambda, list(vars)]+list(map(expand, body))] + list(map(expand, vals)) + return [[_lambda, list(vars)] + list(map(expand, body))] + list(map(expand, vals)) + -macro_table = {_let:let} ## More macros can go here +macro_table = {_let: let} ## More macros can go here -eval(parse("""(begin +eval( + parse( + """(begin (define-macro and (lambda args (if (null? args) #t @@ -326,7 +459,9 @@ def let(*args): ;; More macros can also go here -)""")) +)""" + ) +) -if __name__ == '__main__': - repl() \ No newline at end of file +if __name__ == "__main__": + repl() From 511f28fc7aff2306bf078a55ab8099315392f214 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 20:03:57 +0100 Subject: [PATCH 23/52] nice refactor --- tests/test_parametric_workflow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_parametric_workflow.py b/tests/test_parametric_workflow.py index efa32e68..5371b64d 100644 --- a/tests/test_parametric_workflow.py +++ b/tests/test_parametric_workflow.py @@ -116,8 +116,7 @@ ########################################################################### # Instantiate a parametric study from a Fluent session -study_1 = ParametricStudy( - session.solver.root.parametric_studies).initialize() +study_1 = ParametricStudy(session.solver.root.parametric_studies).initialize() parametricStudies_exp = 1 parametricStudies_test = len(study_1.get_all_studies().keys()) From 586ac90b4223d604ae500ae4eac1fdf36015c510 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 20:27:02 +0100 Subject: [PATCH 24/52] h5py --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index b2f17cd0..7ff6516b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ packages = [ python = ">=3.7,<4.0" importlib-metadata = {version = "^4.0", python = "<3.8"} ansys-fluent-core = "~=0.10" +h5py = ">=3.7.0" [tool.black] line-length = 88 From a61b4b1379c8c0642c237d1b9a586382c8860212 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 21:57:41 +0100 Subject: [PATCH 25/52] h5py --- tests/test_parametric_local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index a0031064..47f9b138 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -38,7 +38,7 @@ def test_parametric_local(): "inlet2", (), "temperature", "yes", "no", "inlet2_temp", 350, "quit" ) - session.solver.root.solution.report_definitions.surface["outlet-temp-avg"] = {} + session.solver.root.solution.report_definitions.surface.create("outlet-temp-avg") session.solver.root.solution.report_definitions.surface[ "outlet-temp-avg" ].report_type = "surface-areaavg" @@ -49,7 +49,7 @@ def test_parametric_local(): "outlet-temp-avg" ].surface_names = ["outlet"] - session.solver.root.solution.report_definitions.surface["outlet-vel-avg"] = {} + session.solver.root.solution.report_definitions.surface.create("outlet-vel-avg") session.solver.root.solution.report_definitions.surface[ "outlet-vel-avg" ].report_type = "surface-areaavg" From 1eaf4ebe07707f2d5a5721b7fa3387f87b3fd444 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 22:37:52 +0100 Subject: [PATCH 26/52] h5py --- tests/test_parametric_local.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index 47f9b138..20a070a8 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -15,7 +15,9 @@ def test_parametric_local(): - session = pyfluent.launch_fluent() + session = pyfluent.launch_fluent( + precision="double", processor_count=2, start_transcript=False + ) import_filename = examples.download_file( "Static_Mixer_main.cas.h5", "pyfluent/static_mixer" From c42b5b41fe3480b8902bd23cf1bd06467a8c4f6b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Wed, 20 Jul 2022 22:57:38 +0100 Subject: [PATCH 27/52] h5py --- tests/test_parametric_local.py | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index 20a070a8..e4f96353 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -19,12 +19,25 @@ def test_parametric_local(): precision="double", processor_count=2, start_transcript=False ) + ############################################################################ + # Read the hopper/mixer case + import_filename = examples.download_file( "Static_Mixer_main.cas.h5", "pyfluent/static_mixer" ) session.solver.tui.file.read_case(case_file_name=import_filename) + ############################################################################ + # Set number of iterations to 100 + session.solver.tui.solve.set.number_of_iterations("100") + + ############################################################################ + # Create input parameters after enabling parameter creation in the TUI: + # Parameter values: + # Inlet1: velocity (inlet1_vel) 0.5 m/s and temperature (inlet1_temp) at 300 K + # Inlet2: velocity (inlet2_vel) 0.5 m/s and temperature (inlet2_temp) at 350 K + session.solver.tui.define.parameters.enable_in_TUI("yes") session.solver.tui.define.boundary_conditions.set.velocity_inlet( @@ -40,7 +53,10 @@ def test_parametric_local(): "inlet2", (), "temperature", "yes", "no", "inlet2_temp", 350, "quit" ) - session.solver.root.solution.report_definitions.surface.create("outlet-temp-avg") + ########################################################################### + # Create output parameters using report definitions + + session.solver.root.solution.report_definitions.surface["outlet-temp-avg"] = {} session.solver.root.solution.report_definitions.surface[ "outlet-temp-avg" ].report_type = "surface-areaavg" @@ -51,7 +67,7 @@ def test_parametric_local(): "outlet-temp-avg" ].surface_names = ["outlet"] - session.solver.root.solution.report_definitions.surface.create("outlet-vel-avg") + session.solver.root.solution.report_definitions.surface["outlet-vel-avg"] = {} session.solver.root.solution.report_definitions.surface[ "outlet-vel-avg" ].report_type = "surface-areaavg" @@ -70,12 +86,17 @@ def test_parametric_local(): "report-definition", "outlet-vel-avg" ) - param_case_path = str( - Path(pyfluent.EXAMPLES_PATH) / "Static_Mixer_Parameters.cas.h5" - ) - session.solver.tui.file.write_case(param_case_path) + ########################################################################### + # Enable convergence condition check + + session.solver.tui.solve.monitors.residual.criterion_type("0") + + ########################################################################### + # Write case with all the settings in place + case_path = str(Path(pyfluent.EXAMPLES_PATH) / "Static_Mixer_Parameters.cas.h5") + session.solver.tui.file.write_case(case_path) - local_study = LocalParametricStudy(case_filepath=param_case_path) + local_study = LocalParametricStudy(case_filepath=case_path) base_design_point = local_study.design_point("Base DP") From e8b14166c52bc605c8b9dcab7287d710eae5a2ee Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 09:30:32 +0100 Subject: [PATCH 28/52] test simplified --- tests/test_parametric_local.py | 87 ++-------------------------------- 1 file changed, 4 insertions(+), 83 deletions(-) diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index e4f96353..89043230 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -1,13 +1,11 @@ """ This local parametric study workflow test performs these steps -- TODO +TODO """ ############################################################################ -from pathlib import Path -import ansys.fluent.core as pyfluent from ansys.fluent.core import examples from ansys.fluent.parametric.local import LocalParametricStudy @@ -15,88 +13,14 @@ def test_parametric_local(): - session = pyfluent.launch_fluent( - precision="double", processor_count=2, start_transcript=False - ) - ############################################################################ # Read the hopper/mixer case - import_filename = examples.download_file( - "Static_Mixer_main.cas.h5", "pyfluent/static_mixer" + case_filename = examples.download_file( + "Static_Mixer_Parameters.cas.h5", "pyfluent/static_mixer" ) - session.solver.tui.file.read_case(case_file_name=import_filename) - - ############################################################################ - # Set number of iterations to 100 - session.solver.tui.solve.set.number_of_iterations("100") - - ############################################################################ - # Create input parameters after enabling parameter creation in the TUI: - # Parameter values: - # Inlet1: velocity (inlet1_vel) 0.5 m/s and temperature (inlet1_temp) at 300 K - # Inlet2: velocity (inlet2_vel) 0.5 m/s and temperature (inlet2_temp) at 350 K - - session.solver.tui.define.parameters.enable_in_TUI("yes") - - session.solver.tui.define.boundary_conditions.set.velocity_inlet( - "inlet1", (), "vmag", "yes", "inlet1_vel", 1, "quit" - ) - session.solver.tui.define.boundary_conditions.set.velocity_inlet( - "inlet1", (), "temperature", "yes", "inlet1_temp", 300, "quit" - ) - session.solver.tui.define.boundary_conditions.set.velocity_inlet( - "inlet2", (), "vmag", "yes", "no", "inlet2_vel", 1, "quit" - ) - session.solver.tui.define.boundary_conditions.set.velocity_inlet( - "inlet2", (), "temperature", "yes", "no", "inlet2_temp", 350, "quit" - ) - - ########################################################################### - # Create output parameters using report definitions - - session.solver.root.solution.report_definitions.surface["outlet-temp-avg"] = {} - session.solver.root.solution.report_definitions.surface[ - "outlet-temp-avg" - ].report_type = "surface-areaavg" - session.solver.root.solution.report_definitions.surface[ - "outlet-temp-avg" - ].field = "temperature" - session.solver.root.solution.report_definitions.surface[ - "outlet-temp-avg" - ].surface_names = ["outlet"] - - session.solver.root.solution.report_definitions.surface["outlet-vel-avg"] = {} - session.solver.root.solution.report_definitions.surface[ - "outlet-vel-avg" - ].report_type = "surface-areaavg" - session.solver.root.solution.report_definitions.surface[ - "outlet-vel-avg" - ].field = "velocity-magnitude" - session.solver.root.solution.report_definitions.surface[ - "outlet-vel-avg" - ].surface_names = ["outlet"] - - session.solver.tui.define.parameters.enable_in_TUI("yes") - session.solver.tui.define.parameters.output_parameters.create( - "report-definition", "outlet-temp-avg" - ) - session.solver.tui.define.parameters.output_parameters.create( - "report-definition", "outlet-vel-avg" - ) - - ########################################################################### - # Enable convergence condition check - - session.solver.tui.solve.monitors.residual.criterion_type("0") - - ########################################################################### - # Write case with all the settings in place - case_path = str(Path(pyfluent.EXAMPLES_PATH) / "Static_Mixer_Parameters.cas.h5") - session.solver.tui.file.write_case(case_path) - - local_study = LocalParametricStudy(case_filepath=case_path) + local_study = LocalParametricStudy(case_filepath=case_filename) base_design_point = local_study.design_point("Base DP") @@ -107,6 +31,3 @@ def test_parametric_local(): output_parameters = base_design_point.output_parameters assert len(output_parameters) - - print(input_parameters) - print(output_parameters) From 182117f02af2f15a4cf44d4aefd11a29187cd37a Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 10:08:23 +0100 Subject: [PATCH 29/52] refac --- src/ansys/fluent/parametric/local/__init__.py | 13 ++------- .../parametric/local/filereader/casereader.py | 29 +++++++++++++++++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index e20b5191..5ac6e27b 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -150,23 +150,14 @@ def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): case_reader = CaseReader(case_file_path=case_filepath) def input_parameter_info(parameter): - name, value = None, None - for k, v in parameter: - if k == "name": - name = v - elif k == "definition": - value = v - return name, value + return parameter.name, parameter.value def set_input_parameter_info(source, target): for parameter in source: target.update((input_parameter_info(parameter),)) def output_parameter_info(parameter): - parameter = parameter[1] - for elem in parameter: - if len(elem) and elem[0] == "name": - return elem[1][1], None + return parameter.name, parameter.value def set_output_parameter_info(source, target): for parameter in source: diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index bcf053cd..6eada032 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -3,6 +3,31 @@ from . import lispy +class InputParameter: + def __init__(self, raw_data): + def input_parameter_info(parameter): + name, value = None, None + for k, v in parameter: + if k == "name": + name = v + elif k == "definition": + value = v + return name, value + + self.name, self.value = input_parameter_info(raw_data) + + +class OutputParameter: + def __init__(self, raw_data): + def output_parameter_info(parameter): + parameter = parameter[1] + for elem in parameter: + if len(elem) and elem[0] == "name": + return elem[1][1], None + + self.name, self.value = output_parameter_info(raw_data) + + class CaseReader: def __init__(self, case_file_path): file = h5py.File(case_file_path) @@ -17,12 +42,12 @@ def input_parameters(self): for expr in exprs: for attr in expr: if attr[0] == "input-parameter" and attr[1] is True: - input_params.append(expr) + input_params.append(InputParameter(expr)) return input_params def output_parameters(self): parameters = self._find_rp_var("parameters/output-parameters") - return parameters + return [OutputParameter(param) for param in parameters] def named_expressions(self): return self._named_expressions() From 318e7dffab7b0fcc0710ac8dda2b0e302bbea72b Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 10:25:39 +0100 Subject: [PATCH 30/52] refac --- src/ansys/fluent/parametric/local/__init__.py | 2 +- src/ansys/fluent/parametric/local/filereader/casereader.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 5ac6e27b..c1fcd31d 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -157,7 +157,7 @@ def set_input_parameter_info(source, target): target.update((input_parameter_info(parameter),)) def output_parameter_info(parameter): - return parameter.name, parameter.value + return parameter.name, None def set_output_parameter_info(source, target): for parameter in source: diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 6eada032..fb08c7a7 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -23,9 +23,9 @@ def output_parameter_info(parameter): parameter = parameter[1] for elem in parameter: if len(elem) and elem[0] == "name": - return elem[1][1], None + return elem[1][1] - self.name, self.value = output_parameter_info(raw_data) + self.name = output_parameter_info(raw_data) class CaseReader: From de815d87aa113375dbed6798e23d8e7287c7b544 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 10:26:15 +0100 Subject: [PATCH 31/52] refac --- src/ansys/fluent/parametric/local/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index c1fcd31d..45018274 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -154,7 +154,7 @@ def input_parameter_info(parameter): def set_input_parameter_info(source, target): for parameter in source: - target.update((input_parameter_info(parameter),)) + target.update(((input_parameter_info(parameter)),)) def output_parameter_info(parameter): return parameter.name, None From 5bf4b1283bdf33d6d73400bb06f091cb2022d980 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 10:27:12 +0100 Subject: [PATCH 32/52] refac --- src/ansys/fluent/parametric/local/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 45018274..38717ea2 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -154,7 +154,7 @@ def input_parameter_info(parameter): def set_input_parameter_info(source, target): for parameter in source: - target.update(((input_parameter_info(parameter)),)) + target.update(((parameter.name, parameter.value),)) def output_parameter_info(parameter): return parameter.name, None From bead2a92585cf9c82de3c1fcf911a95764dd292d Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 10:30:09 +0100 Subject: [PATCH 33/52] refac --- src/ansys/fluent/parametric/local/__init__.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 38717ea2..1ee5ce0d 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -149,19 +149,13 @@ def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): base_design_point = LocalDesignPoint(base_design_point_name) case_reader = CaseReader(case_file_path=case_filepath) - def input_parameter_info(parameter): - return parameter.name, parameter.value - def set_input_parameter_info(source, target): for parameter in source: target.update(((parameter.name, parameter.value),)) - def output_parameter_info(parameter): - return parameter.name, None - def set_output_parameter_info(source, target): for parameter in source: - target.update((output_parameter_info(parameter),)) + target.update(((parameter.name, None),)) set_input_parameter_info( source=case_reader.input_parameters(), From 19da42bcdf10cd72002f3ca12829b703d7e419a1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 10:42:06 +0100 Subject: [PATCH 34/52] test simplified --- src/ansys/fluent/parametric/local/__init__.py | 20 ++++++------------- tests/test_parametric_local.py | 16 +++++++++++++-- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 1ee5ce0d..ebd2b07b 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -149,25 +149,17 @@ def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): base_design_point = LocalDesignPoint(base_design_point_name) case_reader = CaseReader(case_file_path=case_filepath) - def set_input_parameter_info(source, target): - for parameter in source: - target.update(((parameter.name, parameter.value),)) - def set_output_parameter_info(source, target): for parameter in source: target.update(((parameter.name, None),)) - set_input_parameter_info( - source=case_reader.input_parameters(), - target=base_design_point.input_parameters, - ) - - set_output_parameter_info( - source=case_reader.output_parameters(), - target=base_design_point.output_parameters, - ) + for parameter in case_reader.input_parameters(): + base_design_point.input_parameters.update( + ((parameter.name, parameter.value),) + ) - print(case_reader.output_parameters()) + for parameter in case_reader.output_parameters(): + base_design_point.output_parameters.update(((parameter.name, None),)) self.design_point_table = LocalDesignPointTable(base_design_point) diff --git a/tests/test_parametric_local.py b/tests/test_parametric_local.py index 89043230..5ed4886d 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_parametric_local.py @@ -26,8 +26,20 @@ def test_parametric_local(): input_parameters = base_design_point.input_parameters - assert len(input_parameters) + assert len(input_parameters) == 4 + + assert input_parameters["inlet1_temp"] == "300 [K]" + + assert input_parameters["inlet1_vel"] == "1 [m/s]" + + assert input_parameters["inlet2_temp"] == "350 [K]" + + assert input_parameters["inlet2_vel"] == "1 [m/s]" output_parameters = base_design_point.output_parameters - assert len(output_parameters) + assert len(output_parameters) == 2 + + assert output_parameters["outlet-temp-avg-op"] == None + + assert output_parameters["outlet-vel-avg-op"] == None From 52f649ea48ef302d9db4a93487eb951939e96899 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 12:25:50 +0100 Subject: [PATCH 35/52] testing --- src/ansys/fluent/parametric/__init__.py | 6 +- src/ansys/fluent/parametric/local/__init__.py | 93 ++++++++++--------- .../parametric/local/filereader/casereader.py | 4 +- tests/test_casereader.py | 34 +++++++ tests/test_local_parametric_run.py | 49 ++++++++++ ...ocal.py => test_local_parametric_setup.py} | 2 +- 6 files changed, 138 insertions(+), 50 deletions(-) create mode 100644 tests/test_casereader.py create mode 100644 tests/test_local_parametric_run.py rename tests/{test_parametric_local.py => test_local_parametric_setup.py} (97%) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 7dd2f99d..1909136b 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -70,7 +70,7 @@ BASE_DP_NAME = "Base DP" -def convert_units_for_design_point( +def convert_units_for_design_point_parameters( value: Dict[str, Union[float, str]] ) -> Dict[str, float]: def conv(val): @@ -114,7 +114,9 @@ def input_parameters(self) -> Dict[str, float]: @input_parameters.setter def input_parameters(self, value: Dict[str, Union[float, str]]) -> None: - self._dp_settings.input_parameters = convert_units_for_design_point(value) + self._dp_settings.input_parameters = convert_units_for_design_point_parameters( + value + ) @property def output_parameters(self) -> Dict[str, float]: diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index ebd2b07b..fa9c4fe3 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -126,51 +126,7 @@ def remove_design_point(self, idx_or_name): self.remove(self.find_design_point(idx_or_name)) -class LocalParametricStudy: - """ - Local version of parametric study that manages design points to parametrize a - Fluent solver set-up. - - Methods - ------- - add_design_point(design_point_name: str) -> LocalDesignPoint - Add a design point - design_point(idx_or_name) - Get a design point, either by name (str) or an index - indicating the position in the table (by order of insertion). - Raises - ------ - RuntimeError - If the design point is not found. - """ - - def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): - self.case_filepath = case_filepath - base_design_point = LocalDesignPoint(base_design_point_name) - case_reader = CaseReader(case_file_path=case_filepath) - - def set_output_parameter_info(source, target): - for parameter in source: - target.update(((parameter.name, None),)) - - for parameter in case_reader.input_parameters(): - base_design_point.input_parameters.update( - ((parameter.name, parameter.value),) - ) - - for parameter in case_reader.output_parameters(): - base_design_point.output_parameters.update(((parameter.name, None),)) - - self.design_point_table = LocalDesignPointTable(base_design_point) - - def add_design_point(self, design_point_name: str) -> LocalDesignPoint: - return self.design_point_table.add_design_point(design_point_name) - - def design_point(self, idx_or_name) -> LocalDesignPoint: - return self.design_point_table.find_design_point(idx_or_name) - - -def run_local_study_in_fluent(local_study, num_servers, capture_report_data=False): +def _run_local_study_in_fluent(local_study, num_servers, capture_report_data): source_table_size = len(local_study.design_point_table) @@ -254,3 +210,50 @@ def apply_to_studies(studies, inputs) -> None: for study in studies: for _, design_point in study.design_points.items(): next(it).output_parameters = design_point.output_parameters.copy() + + +class LocalParametricStudy: + """ + Local version of parametric study that manages design points to parametrize a + Fluent solver set-up. + + Methods + ------- + add_design_point(design_point_name: str) -> LocalDesignPoint + Add a design point + design_point(idx_or_name) + Get a design point, either by name (str) or an index + indicating the position in the table (by order of insertion). + Raises + ------ + RuntimeError + If the design point is not found. + """ + + def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): + self.case_filepath = case_filepath + base_design_point = LocalDesignPoint(base_design_point_name) + case_reader = CaseReader(case_file_path=case_filepath) + + base_design_point.input_parameters = { + p.name: p.value for p in case_reader.input_parameters() + } + + base_design_point.output_parameters = { + p.name: None for p in case_reader.output_parameters() + } + + self.design_point_table = LocalDesignPointTable(base_design_point) + + def add_design_point(self, design_point_name: str) -> LocalDesignPoint: + return self.design_point_table.add_design_point(design_point_name) + + def design_point(self, idx_or_name) -> LocalDesignPoint: + return self.design_point_table.find_design_point(idx_or_name) + + def run_in_fluent(self, num_servers, capture_report_data=False): + _run_local_study_in_fluent( + local_study=self, + num_servers=num_servers, + capture_report_data=capture_report_data, + ) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index fb08c7a7..360d7001 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -29,8 +29,8 @@ def output_parameter_info(parameter): class CaseReader: - def __init__(self, case_file_path): - file = h5py.File(case_file_path) + def __init__(self, case_filepath): + file = h5py.File(case_filepath) settings = file["settings"] rpvars = settings["Rampant Variables"][0] rp_vars_str = rpvars.decode() diff --git a/tests/test_casereader.py b/tests/test_casereader.py new file mode 100644 index 00000000..5218d8a6 --- /dev/null +++ b/tests/test_casereader.py @@ -0,0 +1,34 @@ +from ansys.fluent.core import examples + +from ansys.fluent.parametric.local.filereader.casereader import CaseReader + + +def test_casereader(): + + case_filepath = examples.download_file( + "Static_Mixer_Parameters.cas.h5", "pyfluent/static_mixer" + ) + + reader = CaseReader(case_filepath=case_filepath) + + input_parameters = reader.input_parameters() + + assert len(input_parameters) == 4 + + input_parameter_dict = {p.name: p.value for p in input_parameters} + + assert input_parameter_dict["inlet1_temp"] == "300 [K]" + + assert input_parameter_dict["inlet1_vel"] == "1 [m/s]" + + assert input_parameter_dict["inlet2_temp"] == "350 [K]" + + assert input_parameter_dict["inlet2_vel"] == "1 [m/s]" + + output_parameters = reader.output_parameters() + + assert len(output_parameters) == 2 + + assert {"outlet-temp-avg-op", "outlet-vel-avg-op"} == { + p.name for p in output_parameters + } diff --git a/tests/test_local_parametric_run.py b/tests/test_local_parametric_run.py new file mode 100644 index 00000000..833e52b3 --- /dev/null +++ b/tests/test_local_parametric_run.py @@ -0,0 +1,49 @@ +""" +This local parametric study workflow test performs these steps + +TODO +""" + +############################################################################ + +from math import inf + +from ansys.fluent.core import examples + +from ansys.fluent.parametric import convert_units_for_design_point_parameters +from ansys.fluent.parametric.local import LocalParametricStudy + + +def test_local_parametric_setup(): + + ############################################################################ + # Read the hopper/mixer case + + case_filename = examples.download_file( + "Static_Mixer_Parameters.cas.h5", "pyfluent/static_mixer" + ) + + local_study = LocalParametricStudy(case_filepath=case_filename) + + for idx in range(20): + design_point = local_study.add_design_point("dp_" + str(idx)) + design_point.input_parameters["inlet1_vel"] = float(2 + idx) + + local_study.run_in_fluent(num_servers=4) + + table = local_study.design_point_table + + assert len(table) == 21 + + outlet_velocity = -inf + inlet_velocity = 0.0 + + for point in table: + ins = convert_units_for_design_point_parameters(point.input_parameters) + outs = point.output_parameters + new_inlet_velocity = ins["inlet1_vel"] + new_outlet_velocity = outs["outlet-vel-avg-op"] + assert new_inlet_velocity - inlet_velocity == 1.0 + assert new_outlet_velocity > outlet_velocity + inlet_velocity = new_inlet_velocity + outlet_velocity = new_outlet_velocity diff --git a/tests/test_parametric_local.py b/tests/test_local_parametric_setup.py similarity index 97% rename from tests/test_parametric_local.py rename to tests/test_local_parametric_setup.py index 5ed4886d..598f51a6 100644 --- a/tests/test_parametric_local.py +++ b/tests/test_local_parametric_setup.py @@ -11,7 +11,7 @@ from ansys.fluent.parametric.local import LocalParametricStudy -def test_parametric_local(): +def test_local_parametric_setup(): ############################################################################ # Read the hopper/mixer case From abc5c2ab5a0b0b49eb1c219f328bc14c7588bd00 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 13:50:29 +0100 Subject: [PATCH 36/52] name fix --- src/ansys/fluent/parametric/local/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index fa9c4fe3..ca76f925 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -233,7 +233,7 @@ class LocalParametricStudy: def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): self.case_filepath = case_filepath base_design_point = LocalDesignPoint(base_design_point_name) - case_reader = CaseReader(case_file_path=case_filepath) + case_reader = CaseReader(case_filepath=case_filepath) base_design_point.input_parameters = { p.name: p.value for p in case_reader.input_parameters() From ed4641d0f52ef6d5fd0baa69fb1e4fbe335a70d1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 15:46:13 +0100 Subject: [PATCH 37/52] tidy ups --- src/ansys/fluent/parametric/local/__init__.py | 41 +++++---- .../parametric/local/filereader/casereader.py | 85 ++++++++++++++----- 2 files changed, 86 insertions(+), 40 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index ca76f925..2efdf995 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -1,31 +1,36 @@ """ -Classes for running a parametric study in Fluent. +Classes for locally defining a parametric study for Fluent without +running Fluent. The study can then be submitted to be executed in +parallel. Example ------- -from ansys.fluent.parametric.local.local import LocalParametricStudy, run_local_study_in_fluent -local_study = LocalParametricStudy(case_filepath="E:\elbow1_param.cas.h5") +Set up a local study -design_point = local_study.design_point("Base DP") -design_point.input_parameters['v1'] = 0.0 +>>> from ansys.fluent.parametric.local.local import LocalParametricStudy +>>> local_study = LocalParametricStudy(case_filepath="E:\elbow1_param.cas.h5") +>>> design_point = local_study.design_point("Base DP") +>>> design_point.input_parameters['v1'] = 0.0 +>>> for idx in range(1, 20): +>>> design_point = local_study.add_design_point("dp_"+str(idx)) +>>> design_point.input_parameters['v1'] = float(idx)/10.0 -for idx in range(1, 20): - design_point = local_study.add_design_point("dp_"+str(idx)) - design_point.input_parameters['v1'] = float(idx)/10.0 - -run_local_study_in_fluent(local_study, 5) +Run in Fluent -for design_point in local_study.design_point_table: - for k, v in design_point.input_parameters.items(): - print("input parameter", k, v) - for k, v in design_point.output_parameters.items(): - print("output parameter", k, v) - print(72 * "-") +>>> local_study.run_in_fluent(5) + +Display results + +>>> for design_point in local_study.design_point_table: +>>> for k, v in design_point.input_parameters.items(): +>>> print("input parameter", k, v) +>>> for k, v in design_point.output_parameters.items(): +>>> print("output parameter", k, v) +>>> print(72 * "-") """ -from enum import Enum from math import ceil from ansys.fluent.core.utils.async_execution import asynchronous @@ -228,6 +233,8 @@ class LocalParametricStudy: ------ RuntimeError If the design point is not found. + run_in_fluent + Run the study in Fluent """ def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 360d7001..db92bb5e 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -1,42 +1,84 @@ +""" +Reader for Fluent case files. + +Example +------- + +>>> from ansys.fluent.parametric.local.filereader.casereader import CaseReader + +Instantiate a case reader + +>>> reader = CaseReader(case_filepath=case_filepath) + +Get lists of input and output parameters + +>>> input_parameters = reader.input_parameters() +>>> output_parameters = reader.output_parameters() + + +""" + +from typing import List + import h5py from . import lispy class InputParameter: - def __init__(self, raw_data): - def input_parameter_info(parameter): - name, value = None, None - for k, v in parameter: - if k == "name": - name = v - elif k == "definition": - value = v - return name, value + """Class to represent an input parameter + + Attributes + ---------- + name : str + value + The value of this input parameter, usually + a string, qualified by units + """ - self.name, self.value = input_parameter_info(raw_data) + def __init__(self, raw_data): + self.name, self.name = None, None + for k, v in raw_data: + if k == "name": + self.name = v + elif k == "definition": + self.value = v class OutputParameter: - def __init__(self, raw_data): - def output_parameter_info(parameter): - parameter = parameter[1] - for elem in parameter: - if len(elem) and elem[0] == "name": - return elem[1][1] + """Class to represent an output parameter - self.name = output_parameter_info(raw_data) + Attributes + ---------- + name : str + """ + + def __init__(self, raw_data): + parameter = raw_data[1] + for elem in parameter: + if len(elem) and elem[0] == "name": + self.name = elem[1][1] class CaseReader: - def __init__(self, case_filepath): + """Class to read a Fluent case file. + + Methods + ------- + input_parameters + Get a list of input parameter objects + output_parameters + Get a list of output parameter objects + """ + + def __init__(self, case_filepath: str): file = h5py.File(case_filepath) settings = file["settings"] rpvars = settings["Rampant Variables"][0] rp_vars_str = rpvars.decode() self._rp_vars = lispy.parse(rp_vars_str)[1] - def input_parameters(self): + def input_parameters(self) -> List[InputParameter]: exprs = self._named_expressions() input_params = [] for expr in exprs: @@ -45,13 +87,10 @@ def input_parameters(self): input_params.append(InputParameter(expr)) return input_params - def output_parameters(self): + def output_parameters(self) -> List[OutputParameter]: parameters = self._find_rp_var("parameters/output-parameters") return [OutputParameter(param) for param in parameters] - def named_expressions(self): - return self._named_expressions() - def _named_expressions(self): return self._find_rp_var("named-expressions") From 306059316bc842b7269f5185c30b2397383e3242 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 16:02:30 +0100 Subject: [PATCH 38/52] tidy ups --- src/ansys/fluent/parametric/__init__.py | 16 -------------- src/ansys/fluent/parametric/local/__init__.py | 21 ++++++++++++++++++- tests/test_local_parametric_run.py | 4 ++-- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 1909136b..03b14f1c 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -70,22 +70,6 @@ BASE_DP_NAME = "Base DP" -def convert_units_for_design_point_parameters( - value: Dict[str, Union[float, str]] -) -> Dict[str, float]: - def conv(val): - if type(val) in (float, int): - return val - if type(val) is not str: - raise RuntimeError("Invalid value type for input parameter", val, type(val)) - pos = val.find(" [") - if pos == -1: - return float(val) - return float(val[:pos]) - - return dict(map(lambda x: (x[0], conv(x[1])), value.items())) - - class DesignPoint: """Design point in a parametric study. diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 2efdf995..0e847a22 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -32,6 +32,7 @@ """ from math import ceil +from typing import Dict, Union from ansys.fluent.core.utils.async_execution import asynchronous @@ -40,6 +41,22 @@ from .filereader.casereader import CaseReader +def convert_design_point_parameter_units( + value: Dict[str, Union[float, str]] +) -> Dict[str, float]: + def conv(val): + if type(val) in (float, int): + return val + if type(val) is not str: + raise RuntimeError("Invalid value type for input parameter", val, type(val)) + pos = val.find(" [") + if pos == -1: + return float(val) + return float(val[:pos]) + + return dict(map(lambda x: (x[0], conv(x[1])), value.items())) + + class LocalDesignPoint: """ Purely local version of design point in a parametric study. @@ -175,7 +192,9 @@ def apply_to_study(study, inputs): design_point = study.add_design_point( capture_simulation_report_data=capture_report_data ) - design_point.input_parameters = inpt.copy() + design_point.input_parameters = convert_design_point_parameter_units( + inpt.copy() + ) @asynchronous def update_design_point(study): diff --git a/tests/test_local_parametric_run.py b/tests/test_local_parametric_run.py index 833e52b3..5119b411 100644 --- a/tests/test_local_parametric_run.py +++ b/tests/test_local_parametric_run.py @@ -10,7 +10,7 @@ from ansys.fluent.core import examples -from ansys.fluent.parametric import convert_units_for_design_point_parameters +from ansys.fluent.parametric import convert_design_point_parameter_units from ansys.fluent.parametric.local import LocalParametricStudy @@ -39,7 +39,7 @@ def test_local_parametric_setup(): inlet_velocity = 0.0 for point in table: - ins = convert_units_for_design_point_parameters(point.input_parameters) + ins = convert_design_point_parameter_units(point.input_parameters) outs = point.output_parameters new_inlet_velocity = ins["inlet1_vel"] new_outlet_velocity = outs["outlet-vel-avg-op"] From 36109caeef44ce326926d7aa270fef74488ee40f Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 16:36:42 +0100 Subject: [PATCH 39/52] tidy up --- src/ansys/fluent/parametric/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 03b14f1c..8e8ac107 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -97,10 +97,8 @@ def input_parameters(self) -> Dict[str, float]: return self._dp_settings.input_parameters() @input_parameters.setter - def input_parameters(self, value: Dict[str, Union[float, str]]) -> None: - self._dp_settings.input_parameters = convert_units_for_design_point_parameters( - value - ) + def input_parameters(self, value: Dict[str, float]) -> None: + self._dp_settings.input_parameters = value @property def output_parameters(self) -> Dict[str, float]: From fb269c1bf64cfaa6064f9e3372b27ba7d16df7d5 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 16:48:19 +0100 Subject: [PATCH 40/52] tidy ups --- src/ansys/fluent/parametric/__init__.py | 25 ++++++++++++++++++------- tests/test_local_parametric_run.py | 6 ++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 8e8ac107..26e7acde 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -55,7 +55,7 @@ from pathlib import Path import tempfile -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional import ansys.fluent.core as pyfluent from ansys.fluent.core import LOG @@ -193,7 +193,9 @@ def __init__( design_points: Dict[str, DesignPoint] = None, ): self._parametric_studies = parametric_studies - self.session = session if session is not None else BaseParametricSession() + self.session = ( + session if session is not None else (_shared_parametric_study_registry()) + ) self.name = name self.design_points = {} if design_points is not None: @@ -510,7 +512,9 @@ def __init__( self._parametric_project = parametric_project self._parametric_studies = parametric_studies self.project_filepath = project_filepath - self.session = session if session is not None else BaseParametricSession() + self.session = ( + session if session is not None else (_shared_parametric_study_registry()) + ) if open_project: self.open(project_filepath=project_filepath) @@ -598,7 +602,7 @@ def __call__(self): return pyfluent.launch_fluent(*self._args, **self._kwargs) -class BaseParametricSession: +class ParametricStudyRegistry: def __init__(self): self._all_studies: Dict[int, "ParametricStudy"] = {} self.current_study_name = None @@ -607,7 +611,7 @@ def register_study(self, study): self._all_studies[id(study)] = study -class ParametricSession(BaseParametricSession): +class ParametricSession(ParametricStudyRegistry): """ParametricSession class which encapsulates studies and project. Attributes @@ -653,8 +657,6 @@ def __init__( False. """ self.studies = {} - self._all_studies: Dict[int, "ParametricStudy"] = {} - self.current_study_name = None self.project = None self._session = launcher() self.scheme_eval = self._session.scheme_eval.scheme_eval @@ -752,4 +754,13 @@ def stop_transcript(self) -> None: self._session.stop_transcript() +def _shared_parametric_study_registry(): + if _shared_parametric_study_registry.instance is None: + _shared_parametric_study_registry.instance = ParametricStudyRegistry() + return _shared_parametric_study_registry.instance + + +_shared_parametric_study_registry.instance = None + + from ansys.fluent.parametric.parameters import InputParameters, OutputParameters diff --git a/tests/test_local_parametric_run.py b/tests/test_local_parametric_run.py index 5119b411..c15fd050 100644 --- a/tests/test_local_parametric_run.py +++ b/tests/test_local_parametric_run.py @@ -10,8 +10,10 @@ from ansys.fluent.core import examples -from ansys.fluent.parametric import convert_design_point_parameter_units -from ansys.fluent.parametric.local import LocalParametricStudy +from ansys.fluent.parametric.local import ( + LocalParametricStudy, + convert_design_point_parameter_units, +) def test_local_parametric_setup(): From e28c1d24081fc688c6ab90a8dc7ac82de53b07a8 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 17:07:44 +0100 Subject: [PATCH 41/52] tidy ups --- src/ansys/fluent/parametric/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 26e7acde..8ea87a1c 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -656,6 +656,7 @@ def __init__( Whether to start streaming of Fluent transcript, by default False. """ + super().__init__() self.studies = {} self.project = None self._session = launcher() From ceeb494f172e3bbf8ebf0d23df8fe482b3e966e9 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 17:09:55 +0100 Subject: [PATCH 42/52] tidy ups --- src/ansys/fluent/parametric/local/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 0e847a22..71db5269 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -9,7 +9,7 @@ Set up a local study >>> from ansys.fluent.parametric.local.local import LocalParametricStudy ->>> local_study = LocalParametricStudy(case_filepath="E:\elbow1_param.cas.h5") +>>> local_study = LocalParametricStudy(case_filepath="E:/elbow1_param.cas.h5") >>> design_point = local_study.design_point("Base DP") >>> design_point.input_parameters['v1'] = 0.0 >>> for idx in range(1, 20): From d3535ea8bac9997d426e7ee7df70699db7a620b1 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 18:06:17 +0100 Subject: [PATCH 43/52] tidy ups --- src/ansys/fluent/parametric/__init__.py | 4 +-- src/ansys/fluent/parametric/local/__init__.py | 32 ++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/ansys/fluent/parametric/__init__.py b/src/ansys/fluent/parametric/__init__.py index 8ea87a1c..f03b98b9 100644 --- a/src/ansys/fluent/parametric/__init__.py +++ b/src/ansys/fluent/parametric/__init__.py @@ -664,8 +664,8 @@ def __init__( self.scheme_eval( "(set parametric-study-dependents-manager " "save-project-at-exit? #f)" ) - if start_transcript: - self.start_transcript() + if not start_transcript: + self.stop_transcript() self._root = self._session.solver.root if case_filepath is not None: self._root.file.read(file_name=case_filepath, file_type="case") diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 71db5269..4dd4c83b 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -32,11 +32,15 @@ """ from math import ceil -from typing import Dict, Union +from typing import Any, Dict, Union from ansys.fluent.core.utils.async_execution import asynchronous -from ansys.fluent.parametric import BASE_DP_NAME, ParametricSession +from ansys.fluent.parametric import ( + BASE_DP_NAME, + ParametricSession, + ParametricSessionLauncher, +) from .filereader.casereader import CaseReader @@ -148,7 +152,13 @@ def remove_design_point(self, idx_or_name): self.remove(self.find_design_point(idx_or_name)) -def _run_local_study_in_fluent(local_study, num_servers, capture_report_data): +def _run_local_study_in_fluent( + local_study, + num_servers: int, + launcher: Any, + start_transcript: bool, + capture_report_data: bool, +): source_table_size = len(local_study.design_point_table) @@ -176,7 +186,11 @@ def make_input_for_studies(num_servers) -> None: @asynchronous def make_parametric_session(case_filepath): - return ParametricSession(case_filepath=case_filepath) + return ParametricSession( + case_filepath=case_filepath, + launcher=launcher, + start_transcript=start_transcript, + ) @asynchronous def apply_to_study(study, inputs): @@ -277,9 +291,17 @@ def add_design_point(self, design_point_name: str) -> LocalDesignPoint: def design_point(self, idx_or_name) -> LocalDesignPoint: return self.design_point_table.find_design_point(idx_or_name) - def run_in_fluent(self, num_servers, capture_report_data=False): + def run_in_fluent( + self, + num_servers: int, + launcher: Any = ParametricSessionLauncher(), + start_transcript: bool = False, + capture_report_data: bool = False, + ): _run_local_study_in_fluent( local_study=self, num_servers=num_servers, + launcher=launcher, + start_transcript=start_transcript, capture_report_data=capture_report_data, ) From a6e811abe0547c9ff844675a4e5169c6abef1d10 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 18:38:57 +0100 Subject: [PATCH 44/52] extend case reader --- .../parametric/local/filereader/casereader.py | 24 ++++++++++++++++--- tests/test_casereader.py | 4 ++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index db92bb5e..8a4c49be 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -77,6 +77,7 @@ def __init__(self, case_filepath: str): rpvars = settings["Rampant Variables"][0] rp_vars_str = rpvars.decode() self._rp_vars = lispy.parse(rp_vars_str)[1] + self._rp_var_cache = {} def input_parameters(self) -> List[InputParameter]: exprs = self._named_expressions() @@ -91,10 +92,27 @@ def output_parameters(self) -> List[OutputParameter]: parameters = self._find_rp_var("parameters/output-parameters") return [OutputParameter(param) for param in parameters] + def num_dimensions(self) -> int: + for attr in self._case_config(): + if attr[0] == "rp-3d?": + return 3 if attr[1] is True else 2 + + def precision(self) -> int: + for attr in self._case_config(): + if attr[0] == "rp-double?": + return 2 if attr[1] is True else 1 + def _named_expressions(self): return self._find_rp_var("named-expressions") + def _case_config(self): + return self._find_rp_var("case-config") + def _find_rp_var(self, name: str): - for var in self._rp_vars: - if type(var) == list and len(var) and var[0] == name: - return var[1] + try: + return self._rp_var_cache[name] + except KeyError: + for var in self._rp_vars: + if type(var) == list and len(var) and var[0] == name: + self._rp_var_cache[name] = var[1] + return var[1] diff --git a/tests/test_casereader.py b/tests/test_casereader.py index 5218d8a6..05ec1bc8 100644 --- a/tests/test_casereader.py +++ b/tests/test_casereader.py @@ -13,6 +13,10 @@ def test_casereader(): input_parameters = reader.input_parameters() + assert reader.precision() == 2 + + assert reader.num_dimensions() == 3 + assert len(input_parameters) == 4 input_parameter_dict = {p.name: p.value for p in input_parameters} From 8b1038616837ccf69c84d507b79bbe5ae83a2997 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Thu, 21 Jul 2022 19:25:34 +0100 Subject: [PATCH 45/52] conditional import --- src/ansys/fluent/parametric/local/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 4dd4c83b..08783243 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -42,7 +42,10 @@ ParametricSessionLauncher, ) -from .filereader.casereader import CaseReader +try: + from ansys.fluent.core.filereader.casereader import CaseReader +except ImportError: + from ansys.fluent.parametric.local.filereader.casereader import CaseReader def convert_design_point_parameter_units( From dee0406991898f81a1b686835431a55921628440 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 22 Jul 2022 08:07:21 +0100 Subject: [PATCH 46/52] review comments --- src/ansys/fluent/parametric/local/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index 08783243..eaea9335 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -49,8 +49,8 @@ def convert_design_point_parameter_units( - value: Dict[str, Union[float, str]] -) -> Dict[str, float]: + value: Dict[str, Union[float, int, str]] +) -> Dict[str, Union[float, int]]: def conv(val): if type(val) in (float, int): return val @@ -61,7 +61,7 @@ def conv(val): return float(val) return float(val[:pos]) - return dict(map(lambda x: (x[0], conv(x[1])), value.items())) + return {k: conv(v) for k, v in value.items()} class LocalDesignPoint: From de063f1f4239af58a7dd03a25a36f33813c4aeac Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 22 Jul 2022 09:46:57 +0100 Subject: [PATCH 47/52] undo test changes --- tests/test_parametric_workflow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_parametric_workflow.py b/tests/test_parametric_workflow.py index 5371b64d..17599dc0 100644 --- a/tests/test_parametric_workflow.py +++ b/tests/test_parametric_workflow.py @@ -119,7 +119,7 @@ study_1 = ParametricStudy(session.solver.root.parametric_studies).initialize() parametricStudies_exp = 1 -parametricStudies_test = len(study_1.get_all_studies().keys()) +parametricStudies_test = len(ParametricStudy._all_studies.keys()) assert parametricStudies_test == parametricStudies_exp ########################################################################### @@ -237,7 +237,7 @@ assert len(study_2.design_points) == 2 parametricStudies_exp = 2 -parametricStudies_test = len(study_1.get_all_studies().keys()) +parametricStudies_test = len(ParametricStudy._all_studies.keys()) assert parametricStudies_test == parametricStudies_exp ######################################################################### @@ -251,7 +251,7 @@ study_1.delete() parametricStudies_exp = 1 -parametricStudies_test = len(study_1.get_all_studies().keys()) +parametricStudies_test = len(ParametricStudy._all_studies.keys()) assert parametricStudies_test == parametricStudies_exp ######################################################################### From bd9bc744caebd1234ed569171a8317797b5f5414 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 22 Jul 2022 12:27:58 +0100 Subject: [PATCH 48/52] .h5 checks --- src/ansys/fluent/parametric/local/__init__.py | 2 +- .../parametric/local/filereader/casereader.py | 21 ++++++++++++++++--- tests/test_casereader.py | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/ansys/fluent/parametric/local/__init__.py b/src/ansys/fluent/parametric/local/__init__.py index eaea9335..53e290be 100644 --- a/src/ansys/fluent/parametric/local/__init__.py +++ b/src/ansys/fluent/parametric/local/__init__.py @@ -276,7 +276,7 @@ class LocalParametricStudy: def __init__(self, case_filepath: str, base_design_point_name: str = "Base DP"): self.case_filepath = case_filepath base_design_point = LocalDesignPoint(base_design_point_name) - case_reader = CaseReader(case_filepath=case_filepath) + case_reader = CaseReader(hdf5_case_filepath=case_filepath) base_design_point.input_parameters = { p.name: p.value for p in case_reader.input_parameters() diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 8a4c49be..25808342 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -8,7 +8,7 @@ Instantiate a case reader ->>> reader = CaseReader(case_filepath=case_filepath) +>>> reader = CaseReader(hdf5_case_filepath=case_filepath) Get lists of input and output parameters @@ -18,6 +18,7 @@ """ +from pathlib import Path from typing import List import h5py @@ -71,8 +72,22 @@ class CaseReader: Get a list of output parameter objects """ - def __init__(self, case_filepath: str): - file = h5py.File(case_filepath) + def __init__(self, hdf5_case_filepath: str): + try: + file = h5py.File(hdf5_case_filepath) + except FileNotFoundError: + raise RuntimeError(f"The case file {hdf5_case_filepath} cannot be found.") + except OSError: + error_message = ( + "Could not read case file. " "Only valid HDF5 files can be read. " + ) + if Path(hdf5_case_filepath).suffix != ".h5": + error_message += ( + f"The file {hdf5_case_filepath} does not have a .h5 extension." + ) + raise RuntimeError(error_message) + except BaseException: + raise RuntimeError(f"Could not read case file {hdf5_case_filepath}") settings = file["settings"] rpvars = settings["Rampant Variables"][0] rp_vars_str = rpvars.decode() diff --git a/tests/test_casereader.py b/tests/test_casereader.py index 05ec1bc8..c40cd40f 100644 --- a/tests/test_casereader.py +++ b/tests/test_casereader.py @@ -9,7 +9,7 @@ def test_casereader(): "Static_Mixer_Parameters.cas.h5", "pyfluent/static_mixer" ) - reader = CaseReader(case_filepath=case_filepath) + reader = CaseReader(hdf5_case_filepath=case_filepath) input_parameters = reader.input_parameters() From b98102b2b025a5c9f47b7db117d695ab1a571cb9 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 22 Jul 2022 13:03:23 +0100 Subject: [PATCH 49/52] .h5 checks --- tests/test_casereader.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_casereader.py b/tests/test_casereader.py index c40cd40f..172adeaf 100644 --- a/tests/test_casereader.py +++ b/tests/test_casereader.py @@ -36,3 +36,12 @@ def test_casereader(): assert {"outlet-temp-avg-op", "outlet-vel-avg-op"} == { p.name for p in output_parameters } + + +def test_casereader_no_file(): + throws = False + try: + reader = CaseReader(hdf5_case_filepath="no_file.cas.h5") + except BaseException: + throws = True + assert throws From 2195fa01302fcda26607780a6fa49acb29da7215 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 22 Jul 2022 13:48:42 +0100 Subject: [PATCH 50/52] redo test changes so that tests don't fail --- tests/test_parametric_workflow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_parametric_workflow.py b/tests/test_parametric_workflow.py index 17599dc0..5371b64d 100644 --- a/tests/test_parametric_workflow.py +++ b/tests/test_parametric_workflow.py @@ -119,7 +119,7 @@ study_1 = ParametricStudy(session.solver.root.parametric_studies).initialize() parametricStudies_exp = 1 -parametricStudies_test = len(ParametricStudy._all_studies.keys()) +parametricStudies_test = len(study_1.get_all_studies().keys()) assert parametricStudies_test == parametricStudies_exp ########################################################################### @@ -237,7 +237,7 @@ assert len(study_2.design_points) == 2 parametricStudies_exp = 2 -parametricStudies_test = len(ParametricStudy._all_studies.keys()) +parametricStudies_test = len(study_1.get_all_studies().keys()) assert parametricStudies_test == parametricStudies_exp ######################################################################### @@ -251,7 +251,7 @@ study_1.delete() parametricStudies_exp = 1 -parametricStudies_test = len(ParametricStudy._all_studies.keys()) +parametricStudies_test = len(study_1.get_all_studies().keys()) assert parametricStudies_test == parametricStudies_exp ######################################################################### From 6a2c0825b5500b2976b14514db4dea3c1c6c2954 Mon Sep 17 00:00:00 2001 From: "ANSYS\\spearson" Date: Fri, 22 Jul 2022 13:57:21 +0100 Subject: [PATCH 51/52] case reader --- src/ansys/fluent/parametric/local/filereader/casereader.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansys/fluent/parametric/local/filereader/casereader.py b/src/ansys/fluent/parametric/local/filereader/casereader.py index 25808342..33053b29 100644 --- a/src/ansys/fluent/parametric/local/filereader/casereader.py +++ b/src/ansys/fluent/parametric/local/filereader/casereader.py @@ -70,6 +70,10 @@ class CaseReader: Get a list of input parameter objects output_parameters Get a list of output parameter objects + num_dimensions + Get the dimensionality of the case (2 or 3) + precision + Get the precision (1 or 2 for 1D of 2D) """ def __init__(self, hdf5_case_filepath: str): From 3c66f9f3c761909b1b6a8da3d578a492718c6aa2 Mon Sep 17 00:00:00 2001 From: Sean Pearson <93727996+seanpearsonuk@users.noreply.github.com> Date: Sat, 23 Jul 2022 08:10:22 +0100 Subject: [PATCH 52/52] Update conf.py --- doc/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index a43be1bd..f0b73be0 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -59,7 +59,7 @@ # Intersphinx mapping intersphinx_mapping = { "python": ("https://docs.python.org/dev", None), - "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "scipy": ("https://docs.scipy.org/doc/scipy", None), "numpy": ("https://numpy.org/devdocs", None), "matplotlib": ("https://matplotlib.org/stable", None), "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None),