From 587e56947db291fd16d007864f07f5aa15c63772 Mon Sep 17 00:00:00 2001 From: flabowski Date: Fri, 18 Feb 2022 16:50:55 +0100 Subject: [PATCH 01/10] imports explicit, rather than using '*' and autopep8 formatting --- oasis/common/__init__.py | 67 +++++- oasis/common/io.py | 248 +++++++++++++-------- oasis/common/utilities.py | 253 +++++++++++++--------- oasis/problems/NSfracStep/Cylinder.py | 112 +++++++--- oasis/problems/NSfracStep/DrivenCavity.py | 155 ++++++++++--- oasis/problems/NSfracStep/__init__.py | 144 +++++++----- oasis/problems/__init__.py | 104 +++++---- 7 files changed, 702 insertions(+), 381 deletions(-) diff --git a/oasis/common/__init__.py b/oasis/common/__init__.py index 50053381..b727b022 100644 --- a/oasis/common/__init__.py +++ b/oasis/common/__init__.py @@ -1,34 +1,80 @@ -from .io import * -from .utilities import * +# lots of unused imports, that are all imported and used by the main script +# from .io import * +from oasis.common.io import ( + create_initial_folders, + save_solution, + save_tstep_solution_h5, + save_checkpoint_solution_h5, + check_if_kill, + check_if_reset_statistics, + init_from_restart, + merge_visualization_files, + merge_xml_files, +) +from os import makedirs, getcwd, listdir, remove, system, path +from xml.etree import ElementTree as ET +import pickle +import time +import glob +from oasis.problems import info_red + +# from .utilities import * +from oasis.common.utilities import ( + A_cache, + Solver_cache, + Mat_cache_dict, + Solver_cache_dict, + assemble_matrix, + OasisFunction, + GradFunction, + DivFunction, + CG1Function, + AssignedVectorFunction, + LESsource, + NNsource, + homogenize, +) +from ufl.tensors import ListTensor +from ufl import Coefficient import sys import json + def convert(input): if isinstance(input, dict): return {convert(key): convert(value) for key, value in input.iter()} elif isinstance(input, list): return [convert(element) for element in input] elif isinstance(input, str): - return input.encode('utf-8') + return input.encode("utf-8") else: return input + # Parse command-line keyword arguments def parse_command_line(): commandline_kwargs = {} for s in sys.argv[1:]: - if s.count('=') == 1: - key, value = s.split('=', 1) + if s.count("=") == 1: + key, value = s.split("=", 1) else: - raise TypeError((s + " Only kwargs separated with '=' sign " + - "allowed. See NSdefault_hooks for a range of " + - "parameters. Your problem file should contain " + - "problem specific parameters.")) + raise TypeError( + ( + s + + " Only kwargs separated with '=' sign " + + "allowed. See NSdefault_hooks for a range of " + + "parameters. Your problem file should contain " + + "problem specific parameters." + ) + ) try: value = json.loads(value) except ValueError: - if value in ("True", "False"): # json understands true/false, but not True/False + if value in ( + "True", + "False", + ): # json understands true/false, but not True/False value = eval(value) elif "True" in value or "False" in value: value = eval(value) @@ -38,5 +84,6 @@ def parse_command_line(): commandline_kwargs[key] = value return commandline_kwargs + # Note to self. To change a dictionary variable through commandline do, e.g., # run NSfracStep velocity_update_solver='{"method":"gradient_matrix"}' diff --git a/oasis/common/io.py b/oasis/common/io.py index 5899b24b..62febcf3 100644 --- a/oasis/common/io.py +++ b/oasis/common/io.py @@ -8,46 +8,60 @@ import pickle import time import glob -from dolfin import (MPI, Function, XDMFFile, HDF5File, - VectorFunctionSpace, FunctionAssigner) +import dolfin as df from oasis.problems import info_red -__all__ = ["create_initial_folders", "save_solution", "save_tstep_solution_h5", - "save_checkpoint_solution_h5", "check_if_kill", "check_if_reset_statistics", - "init_from_restart", "merge_visualization_files", "merge_xml_files"] - - -def create_initial_folders(folder, restart_folder, sys_comp, tstep, info_red, - scalar_components, output_timeseries_as_vector, - **NS_namespace): +__all__ = [ + "create_initial_folders", + "save_solution", + "save_tstep_solution_h5", + "save_checkpoint_solution_h5", + "check_if_kill", + "check_if_reset_statistics", + "init_from_restart", + "merge_visualization_files", + "merge_xml_files", +] + + +def create_initial_folders( + folder, + restart_folder, + sys_comp, + tstep, + info_red, + scalar_components, + output_timeseries_as_vector, + **NS_namespace +): """Create necessary folders.""" info_red("Creating initial folders") # To avoid writing over old data create a new folder for each run - if MPI.rank(MPI.comm_world) == 0: + if df.MPI.rank(df.MPI.comm_world) == 0: try: makedirs(folder) except OSError: pass - MPI.barrier(MPI.comm_world) - newfolder = path.join(folder, 'data') + df.MPI.barrier(df.MPI.comm_world) + newfolder = path.join(folder, "data") if restart_folder: - newfolder = path.join(newfolder, restart_folder.split('/')[-2]) + newfolder = path.join(newfolder, restart_folder.split("/")[-2]) else: if not path.exists(newfolder): - newfolder = path.join(newfolder, '1') + newfolder = path.join(newfolder, "1") else: - #previous = listdir(newfolder) - previous = [f for f in listdir(newfolder) if not f.startswith('.')] + # previous = listdir(newfolder) + previous = [f for f in listdir(newfolder) if not f.startswith(".")] previous = max(map(eval, previous)) if previous else 0 newfolder = path.join(newfolder, str(previous + 1)) - MPI.barrier(MPI.comm_world) - if MPI.rank(MPI.comm_world) == 0: + df.MPI.barrier(df.MPI.comm_world) + if df.MPI.rank(df.MPI.comm_world) == 0: if not restart_folder: - #makedirs(path.join(newfolder, "Voluviz")) - #makedirs(path.join(newfolder, "Stats")) - #makedirs(path.join(newfolder, "VTK")) + # makedirs(path.join(newfolder, "Voluviz")) + # makedirs(path.join(newfolder, "Stats")) + # makedirs(path.join(newfolder, "VTK")) makedirs(path.join(newfolder, "Timeseries")) makedirs(path.join(newfolder, "Checkpoint")) @@ -55,27 +69,56 @@ def create_initial_folders(folder, restart_folder, sys_comp, tstep, info_red, tstepfiles = {} comps = sys_comp if output_timeseries_as_vector: - comps = ['p', 'u'] + scalar_components + comps = ["p", "u"] + scalar_components for ui in comps: - tstepfiles[ui] = XDMFFile(MPI.comm_world, path.join( - tstepfolder, ui + '_from_tstep_{}.xdmf'.format(tstep))) + tstepfiles[ui] = df.XDMFFile( + df.MPI.comm_world, + path.join(tstepfolder, ui + "_from_tstep_{}.xdmf".format(tstep)), + ) tstepfiles[ui].parameters["rewrite_function_mesh"] = False tstepfiles[ui].parameters["flush_output"] = True return newfolder, tstepfiles -def save_solution(tstep, t, q_, q_1, folder, newfolder, save_step, checkpoint, - NS_parameters, tstepfiles, u_, u_components, scalar_components, - output_timeseries_as_vector, constrained_domain, - AssignedVectorFunction, killtime, total_timer, **NS_namespace): +def save_solution( + tstep, + t, + q_, + q_1, + folder, + newfolder, + save_step, + checkpoint, + NS_parameters, + tstepfiles, + u_, + u_components, + scalar_components, + output_timeseries_as_vector, + constrained_domain, + AssignedVectorFunction, + killtime, + total_timer, + **NS_namespace +): """Called at end of timestep. Check for kill and save solution if required.""" NS_parameters.update(t=t, tstep=tstep) if tstep % save_step == 0: - save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_domain, - output_timeseries_as_vector, u_components, AssignedVectorFunction, - scalar_components, NS_parameters) + save_tstep_solution_h5( + tstep, + q_, + u_, + newfolder, + tstepfiles, + constrained_domain, + output_timeseries_as_vector, + u_components, + AssignedVectorFunction, + scalar_components, + NS_parameters, + ) pauseoasis = check_if_pause(folder) while pauseoasis: @@ -84,17 +127,28 @@ def save_solution(tstep, t, q_, q_1, folder, newfolder, save_step, checkpoint, killoasis = check_if_kill(folder, killtime, total_timer) if tstep % checkpoint == 0 or killoasis: - save_checkpoint_solution_h5(tstep, q_, q_1, newfolder, u_components, - NS_parameters) + save_checkpoint_solution_h5( + tstep, q_, q_1, newfolder, u_components, NS_parameters + ) return killoasis -def save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_domain, - output_timeseries_as_vector, u_components, AssignedVectorFunction, - scalar_components, NS_parameters): +def save_tstep_solution_h5( + tstep, + q_, + u_, + newfolder, + tstepfiles, + constrained_domain, + output_timeseries_as_vector, + u_components, + AssignedVectorFunction, + scalar_components, + NS_parameters, +): """Store solution on current timestep to XDMF file.""" - timefolder = path.join(newfolder, 'Timeseries') + timefolder = path.join(newfolder, "Timeseries") if output_timeseries_as_vector: # project or store velocity to vector function space for comp, tstepfile in tstepfiles.items(): @@ -118,14 +172,13 @@ def save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_dom for comp, tstepfile in tstepfiles.items(): tstepfile << (q_[comp], float(tstep)) - if MPI.rank(MPI.comm_world) == 0: + if df.MPI.rank(df.MPI.comm_world) == 0: if not path.exists(path.join(timefolder, "params.dat")): - f = open(path.join(timefolder, 'params.dat'), 'wb') - pickle.dump(NS_parameters, f) + f = open(path.join(timefolder, "params.dat"), "wb") + pickle.dump(NS_parameters, f) -def save_checkpoint_solution_h5(tstep, q_, q_1, newfolder, u_components, - NS_parameters): +def save_checkpoint_solution_h5(tstep, q_, q_1, newfolder, u_components, NS_parameters): """Overwrite solution in Checkpoint folder. For safety reasons, in case the solver is interrupted, take backup of @@ -136,53 +189,59 @@ def save_checkpoint_solution_h5(tstep, q_, q_1, newfolder, u_components, """ checkpointfolder = path.join(newfolder, "Checkpoint") - NS_parameters["num_processes"] = MPI.size(MPI.comm_world) - if MPI.rank(MPI.comm_world) == 0: + NS_parameters["num_processes"] = df.MPI.size(df.MPI.comm_world) + if df.MPI.rank(df.MPI.comm_world) == 0: if path.exists(path.join(checkpointfolder, "params.dat")): - system('cp {0} {1}'.format(path.join(checkpointfolder, "params.dat"), - path.join(checkpointfolder, "params_old.dat"))) - f = open(path.join(checkpointfolder, "params.dat"), 'wb') - pickle.dump(NS_parameters, f) - - MPI.barrier(MPI.comm_world) + system( + "cp {0} {1}".format( + path.join(checkpointfolder, "params.dat"), + path.join(checkpointfolder, "params_old.dat"), + ) + ) + f = open(path.join(checkpointfolder, "params.dat"), "wb") + pickle.dump(NS_parameters, f) + + df.MPI.barrier(df.MPI.comm_world) for ui in q_: - h5file = path.join(checkpointfolder, ui + '.h5') - oldfile = path.join(checkpointfolder, ui + '_old.h5') + h5file = path.join(checkpointfolder, ui + ".h5") + oldfile = path.join(checkpointfolder, ui + "_old.h5") # For safety reasons... if path.exists(h5file): - if MPI.rank(MPI.comm_world) == 0: - system('cp {0} {1}'.format(h5file, oldfile)) - MPI.barrier(MPI.comm_world) + if df.MPI.rank(df.MPI.comm_world) == 0: + system("cp {0} {1}".format(h5file, oldfile)) + df.MPI.barrier(df.MPI.comm_world) ### - newfile = HDF5File(MPI.comm_world, h5file, 'w') + newfile = df.HDF5File(df.MPI.comm_world, h5file, "w") newfile.flush() - newfile.write(q_[ui].vector(), '/current') + newfile.write(q_[ui].vector(), "/current") if ui in u_components: - newfile.write(q_1[ui].vector(), '/previous') + newfile.write(q_1[ui].vector(), "/previous") if path.exists(oldfile): - if MPI.rank(MPI.comm_world) == 0: - system('rm {0}'.format(oldfile)) - MPI.barrier(MPI.comm_world) - if MPI.rank(MPI.comm_world) == 0 and path.exists(path.join(checkpointfolder, "params_old.dat")): - system('rm {0}'.format(path.join(checkpointfolder, "params_old.dat"))) + if df.MPI.rank(df.MPI.comm_world) == 0: + system("rm {0}".format(oldfile)) + df.MPI.barrier(df.MPI.comm_world) + if df.MPI.rank(df.MPI.comm_world) == 0 and path.exists( + path.join(checkpointfolder, "params_old.dat") + ): + system("rm {0}".format(path.join(checkpointfolder, "params_old.dat"))) def check_if_kill(folder, killtime, total_timer): """Check if user has put a file named killoasis in folder or if given killtime has been reached.""" found = 0 - if 'killoasis' in listdir(folder): + if "killoasis" in listdir(folder): found = 1 - collective = MPI.sum(MPI.comm_world, found) + collective = df.MPI.sum(df.MPI.comm_world, found) if collective > 0: - if MPI.rank(MPI.comm_world) == 0: - remove(path.join(folder, 'killoasis')) - info_red('killoasis Found! Stopping simulations cleanly...') + if df.MPI.rank(df.MPI.comm_world) == 0: + remove(path.join(folder, "killoasis")) + info_red("killoasis Found! Stopping simulations cleanly...") return True else: elapsed_time = float(total_timer.elapsed()[0]) if killtime is not None and killtime <= elapsed_time: - if MPI.rank(MPI.comm_world) == 0: - info_red('Given killtime reached! Stopping simulations cleanly...') + if df.MPI.rank(df.MPI.comm_world) == 0: + info_red("Given killtime reached! Stopping simulations cleanly...") return True else: return False @@ -191,12 +250,16 @@ def check_if_kill(folder, killtime, total_timer): def check_if_pause(folder): """Check if user has put a file named pauseoasis in folder.""" found = 0 - if 'pauseoasis' in listdir(folder): + if "pauseoasis" in listdir(folder): found = 1 - collective = MPI.sum(MPI.comm_world, found) + collective = df.MPI.sum(df.MPI.comm_world, found) if collective > 0: - if MPI.rank(MPI.comm_world) == 0: - info_red('pauseoasis Found! Simulations paused. Remove ' + path.join(folder, 'pauseoasis') + ' to resume simulations...') + if df.MPI.rank(df.MPI.comm_world) == 0: + info_red( + "pauseoasis Found! Simulations paused. Remove " + + path.join(folder, "pauseoasis") + + " to resume simulations..." + ) return True else: return False @@ -205,42 +268,43 @@ def check_if_pause(folder): def check_if_reset_statistics(folder): """Check if user has put a file named resetoasis in folder.""" found = 0 - if 'resetoasis' in listdir(folder): + if "resetoasis" in listdir(folder): found = 1 - collective = MPI.sum(MPI.comm_world, found) + collective = df.MPI.sum(df.MPI.comm_world, found) if collective > 0: - if MPI.rank(MPI.comm_world) == 0: - remove(path.join(folder, 'resetoasis')) - info_red('resetoasis Found!') + if df.MPI.rank(df.MPI.comm_world) == 0: + remove(path.join(folder, "resetoasis")) + info_red("resetoasis Found!") return True else: return False -def init_from_restart(restart_folder, sys_comp, uc_comp, u_components, - q_, q_1, q_2, tstep, **NS_namespace): - """Initialize solution from checkpoint files """ +def init_from_restart( + restart_folder, sys_comp, uc_comp, u_components, q_, q_1, q_2, tstep, **NS_namespace +): + """Initialize solution from checkpoint files""" if restart_folder: - if MPI.rank(MPI.comm_world) == 0: - info_red('Restarting from checkpoint at time step {}'.format(tstep)) + if df.MPI.rank(df.MPI.comm_world) == 0: + info_red("Restarting from checkpoint at time step {}".format(tstep)) for ui in sys_comp: - filename = path.join(restart_folder, ui + '.h5') - hdf5_file = HDF5File(MPI.comm_world, filename, "r") + filename = path.join(restart_folder, ui + ".h5") + hdf5_file = df.HDF5File(df.MPI.comm_world, filename, "r") hdf5_file.read(q_[ui].vector(), "/current", False) - q_[ui].vector().apply('insert') + q_[ui].vector().apply("insert") # Check for the solution at a previous timestep as well if ui in uc_comp: q_1[ui].vector().zero() - q_1[ui].vector().axpy(1., q_[ui].vector()) - q_1[ui].vector().apply('insert') + q_1[ui].vector().axpy(1.0, q_[ui].vector()) + q_1[ui].vector().apply("insert") if ui in u_components: hdf5_file.read(q_2[ui].vector(), "/previous", False) - q_2[ui].vector().apply('insert') + q_2[ui].vector().apply("insert") def merge_visualization_files(newfolder, **namesapce): - timefolder = path.join(newfolder, 'Timeseries') + timefolder = path.join(newfolder, "Timeseries") # Gather files xdmf_files = list(glob.glob(path.join(timefolder, "*.xdmf"))) xdmf_velocity = [f for f in xdmf_files if "u_from_tstep" in f.__str__()] diff --git a/oasis/common/utilities.py b/oasis/common/utilities.py index ee7d122c..48901f97 100644 --- a/oasis/common/utilities.py +++ b/oasis/common/utilities.py @@ -3,22 +3,18 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from dolfin import (assemble, KrylovSolver, LUSolver, Function, - TrialFunction,TestFunction, dx, Vector, Matrix, - FunctionSpace, Timer, div, Form, inner, grad, - as_backend_type, VectorFunctionSpace, FunctionAssigner, PETScKrylovSolver, - PETScPreconditioner, DirichletBC) - +import dolfin as df from ufl.tensors import ListTensor from ufl import Coefficient + # Create some dictionaries to hold work matrices class Mat_cache_dict(dict): """Items in dictionary are matrices stored for efficient reuse.""" def __missing__(self, key): form, bcs = key - A = assemble(form) + A = df.assemble(form) for bc in bcs: bc.apply(A) @@ -28,18 +24,19 @@ def __missing__(self, key): # Create some dictionaries to hold solvers used for projection class Solver_cache_dict(dict): - """Items in dictionary are Linear algebra solvers stored for efficient reuse. + """ + Items in dictionary are Linear algebra solvers stored for efficient reuse. """ def __missing__(self, key): assert len(key) == 4 form, bcs, solver_type, preconditioner_type = key - prec = PETScPreconditioner(preconditioner_type) - sol = PETScKrylovSolver(solver_type, prec) - #sol.prec = prec - #sol = KrylovSolver(solver_type, preconditioner_type) + prec = df.PETScPreconditioner(preconditioner_type) + sol = df.PETScKrylovSolver(solver_type, prec) + # sol.prec = prec + # sol = KrylovSolver(solver_type, preconditioner_type) - #sol.parameters["preconditioner"]["structure"] = "same" + # sol.parameters["preconditioner"]["structure"] = "same" sol.parameters["error_on_nonconvergence"] = False sol.parameters["monitor_convergence"] = False sol.parameters["report"] = False @@ -52,13 +49,12 @@ def __missing__(self, key): def assemble_matrix(form, bcs=[]): - """Assemble matrix using cache register. - """ - assert Form(form).rank() == 2 + """Assemble matrix using cache register.""" + assert df.Form(form).rank() == 2 return A_cache[(form, tuple(bcs))] -class OasisFunction(Function): +class OasisFunction(df.Function): """Function with more or less efficient projection methods of associated linear form. @@ -75,36 +71,42 @@ class OasisFunction(Function): """ - def __init__(self, form, Space, bcs=[], - name="x", - matvec=[None, None], - method="default", - solver_type="cg", - preconditioner_type="default"): - - Function.__init__(self, Space, name=name) + def __init__( + self, + form, + Space, + bcs=[], + name="x", + matvec=[None, None], + method="default", + solver_type="cg", + preconditioner_type="default", + ): + + df.Function.__init__(self, Space, name=name) self.form = form self.method = method self.bcs = bcs self.matvec = matvec - self.trial = trial = TrialFunction(Space) - self.test = test = TestFunction(Space) - Mass = inner(trial, test) * dx() - self.bf = inner(form, test) * dx() - self.rhs = Vector(self.vector()) + self.trial = trial = df.TrialFunction(Space) + self.test = test = df.TestFunction(Space) + Mass = df.inner(trial, test) * df.dx() + self.bf = df.inner(form, test) * df.dx() + self.rhs = df.Vector(self.vector()) if method.lower() == "default": self.A = A_cache[(Mass, tuple(bcs))] - self.sol = Solver_cache[(Mass, tuple( - bcs), solver_type, preconditioner_type)] + self.sol = Solver_cache[ + (Mass, tuple(bcs), solver_type, preconditioner_type) + ] elif method.lower() == "lumping": assert Space.ufl_element().degree() < 2 self.A = A_cache[(Mass, tuple(bcs))] - ones = Function(Space) - ones.vector()[:] = 1. + ones = df.Function(Space) + ones.vector()[:] = 1.0 self.ML = self.A * ones.vector() - self.ML.set_local(1. / self.ML.array()) + self.ML.set_local(1.0 / self.ML.array()) def assemble_rhs(self): """ @@ -116,13 +118,13 @@ def assemble_rhs(self): self.rhs.axpy(1.0, mat * func.vector()) else: - assemble(self.bf, tensor=self.rhs) + df.assemble(self.bf, tensor=self.rhs) def __call__(self, assemb_rhs=True): """ Compute the projection """ - timer = Timer("Projecting {}".format(self.name())) + timer = df.Timer("Projecting {}".format(self.name())) if assemb_rhs: self.assemble_rhs() @@ -151,30 +153,42 @@ def __init__(self, p_, Space, i=0, bcs=[], name="grad", method={}): assert len(p_.ufl_shape) == 0 assert i >= 0 and i < Space.mesh().geometry().dim() - solver_type = method.get('solver_type', 'cg') - preconditioner_type = method.get('preconditioner_type', 'default') - solver_method = method.get('method', 'default') - low_memory_version = method.get('low_memory_version', False) - - OasisFunction.__init__(self, p_.dx(i), Space, bcs=bcs, name=name, - method=solver_method, solver_type=solver_type, - preconditioner_type=preconditioner_type) + solver_type = method.get("solver_type", "cg") + preconditioner_type = method.get("preconditioner_type", "default") + solver_method = method.get("method", "default") + low_memory_version = method.get("low_memory_version", False) + + OasisFunction.__init__( + self, + p_.dx(i), + Space, + bcs=bcs, + name=name, + method=solver_method, + solver_type=solver_type, + preconditioner_type=preconditioner_type, + ) self.i = i Source = p_.function_space() if not low_memory_version: self.matvec = [ - A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], p_] + A_cache[(self.test * df.TrialFunction(Source).dx(i) * df.dx, ())], + p_, + ] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module - DG = FunctionSpace(Space.mesh(), 'DG', 0) - G = assemble(TrialFunction(DG) * self.test * dx()) - dg = Function(DG) - dP = assemble(TrialFunction(p_.function_space()).dx(i) - * TestFunction(DG) * dx()) + + DG = df.FunctionSpace(Space.mesh(), "DG", 0) + G = df.assemble(df.TrialFunction(DG) * self.test * df.dx()) + dg = df.Function(DG) + dP = df.assemble( + df.TrialFunction(p_.function_space()).dx(i) * TestFunction(DG) * df.dx() + ) self.WGM = compiled_gradient_module.compute_weighted_gradient_matrix( - G, dP, dg) + G, dP, dg + ) def assemble_rhs(self, u=None): """ @@ -187,19 +201,19 @@ def assemble_rhs(self, u=None): """ if isinstance(u, Coefficient): self.matvec[1] = u - self.bf = u.dx(self.i) * self.test * dx() + self.bf = u.dx(self.i) * self.test * df.dx() if not self.matvec[0] is None: mat, func = self.matvec self.rhs.zero() self.rhs.axpy(1.0, mat * func.vector()) else: - assemble(self.bf, tensor=self.rhs) + df.assemble(self.bf, tensor=self.rhs) def __call__(self, u=None, assemb_rhs=True): if isinstance(u, Coefficient): self.matvec[1] = u - self.bf = u.dx(self.i) * self.test * dx() + self.bf = u.dx(self.i) * self.test * df.dx() if self.method.lower() == "gradient_matrix": self.vector().zero() @@ -218,31 +232,46 @@ class DivFunction(OasisFunction): def __init__(self, u_, Space, bcs=[], name="div", method={}): - solver_type = method.get('solver_type', 'cg') - preconditioner_type = method.get('preconditioner_type', 'default') - solver_method = method.get('method', 'default') - low_memory_version = method.get('low_memory_version', False) - - OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name, - method=solver_method, solver_type=solver_type, - preconditioner_type=preconditioner_type) + solver_type = method.get("solver_type", "cg") + preconditioner_type = method.get("preconditioner_type", "default") + solver_method = method.get("method", "default") + low_memory_version = method.get("low_memory_version", False) + + OasisFunction.__init__( + self, + df.div(u_), + Space, + bcs=bcs, + name=name, + method=solver_method, + solver_type=solver_type, + preconditioner_type=preconditioner_type, + ) Source = u_[0].function_space() if not low_memory_version: - self.matvec = [[A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i]] - for i in range(Space.mesh().geometry().dim())] + self.matvec = [ + [ + A_cache[(self.test * df.TrialFunction(Source).dx(i) * df.dx, ())], + u_[i], + ] + for i in range(Space.mesh().geometry().dim()) + ] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module - DG = FunctionSpace(Space.mesh(), 'DG', 0) - G = assemble(TrialFunction(DG) * self.test * dx()) - dg = Function(DG) + + DG = df.FunctionSpace(Space.mesh(), "DG", 0) + G = df.assemble(df.TrialFunction(DG) * self.test * df.dx()) + dg = df.Function(DG) self.WGM = [] - st = TrialFunction(Source) + st = df.TrialFunction(Source) for i in range(Space.mesh().geometry().dim()): - dP = assemble(st.dx(i) * TestFunction(DG) * dx) - A = Matrix(G) - self.WGM.append(compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg)) + dP = df.assemble(st.dx(i) * df.TestFunction(DG) * df.dx) + A = df.Matrix(G) + self.WGM.append( + compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg) + ) def assemble_rhs(self): """ @@ -254,7 +283,7 @@ def assemble_rhs(self): self.rhs.axpy(1.0, mat * vec.vector()) else: - assemble(self.bf, tensor=self.rhs) + df.assemble(self.bf, tensor=self.rhs) def __call__(self, assemb_rhs=True): @@ -264,8 +293,7 @@ def __call__(self, assemb_rhs=True): self.assemble_rhs() self.vector().zero() for i in range(self.function_space().mesh().geometry().dim()): - self.vector().axpy( - 1., self.WGM[i] * self.matvec[i][1].vector()) + self.vector().axpy(1.0, self.WGM[i] * self.matvec[i][1].vector()) else: OasisFunction.__call__(self, assemb_rhs=assemb_rhs) @@ -281,31 +309,37 @@ class CG1Function(OasisFunction): def __init__(self, form, mesh, bcs=[], name="CG1", method={}, bounded=False): - solver_type = method.get('solver_type', 'cg') - preconditioner_type = method.get('preconditioner_type', 'default') - solver_method = method.get('method', 'default') + solver_type = method.get("solver_type", "cg") + preconditioner_type = method.get("preconditioner_type", "default") + solver_method = method.get("method", "default") self.bounded = bounded - Space = FunctionSpace(mesh, "CG", 1) - OasisFunction.__init__(self, form, Space, - bcs=bcs, name=name, - method=solver_method, solver_type=solver_type, - preconditioner_type=preconditioner_type) + Space = df.FunctionSpace(mesh, "CG", 1) + OasisFunction.__init__( + self, + form, + Space, + bcs=bcs, + name=name, + method=solver_method, + solver_type=solver_type, + preconditioner_type=preconditioner_type, + ) if solver_method.lower() == "weightedaverage": from fenicstools import compiled_gradient_module - DG = FunctionSpace(mesh, 'DG', 0) + + DG = df.FunctionSpace(mesh, "DG", 0) # Cannot use cache. Matrix will be modified - self.A = assemble(TrialFunction(DG) * self.test * dx()) - self.dg = dg = Function(DG) - compiled_gradient_module.compute_DG0_to_CG_weight_matrix( - self.A, dg) - self.bf_dg = inner(form, TestFunction(DG)) * dx() + self.A = df.assemble(df.TrialFunction(DG) * self.test * df.dx()) + self.dg = dg = df.Function(DG) + compiled_gradient_module.compute_DG0_to_CG_weight_matrix(self.A, dg) + self.bf_dg = df.inner(form, df.TestFunction(DG)) * df.dx() def __call__(self): if self.method.lower() == "weightedaverage": - assemble(self.bf_dg, tensor=self.dg.vector()) + df.assemble(self.bf_dg, tensor=self.dg.vector()) # Compute weighted average on CG1 self.vector().zero() @@ -324,7 +358,7 @@ def bound(self): self.vector().apply("insert") -class AssignedVectorFunction(Function): +class AssignedVectorFunction(df.Function): """Vector function used for postprocessing. Assign data from ListTensor components using FunctionAssigner. @@ -339,55 +373,58 @@ def __init__(self, u, name="Assigned Vector Function"): family = V.ufl_element().family() degree = V.ufl_element().degree() constrained_domain = V.dofmap().constrained_domain - Vv = VectorFunctionSpace(mesh, family, degree, - constrained_domain=constrained_domain) + Vv = df.VectorFunctionSpace( + mesh, family, degree, constrained_domain=constrained_domain + ) - Function.__init__(self, Vv, name=name) - self.fa = [FunctionAssigner(Vv.sub(i), V) for i, _u in enumerate(u)] + df.Function.__init__(self, Vv, name=name) + self.fa = [df.FunctionAssigner(Vv.sub(i), V) for i, _u in enumerate(u)] def __call__(self): for i, _u in enumerate(self.u): self.fa[i].assign(self.sub(i), _u) -class LESsource(Function): +class LESsource(df.Function): """Function used for computing the transposed source to the LES equation.""" def __init__(self, nut, u, Space, bcs=[], name=""): - Function.__init__(self, Space, name=name) + df.Function.__init__(self, Space, name=name) dim = Space.mesh().geometry().dim() - test = TestFunction(Space) - self.bf = [inner(inner(grad(nut), u.dx(i)), test) - * dx for i in range(dim)] + test = df.TestFunction(Space) + self.bf = [ + df.inner(df.inner(df.grad(nut), u.dx(i)), test) * df.dx for i in range(dim) + ] def assemble_rhs(self, i=0): """Assemble right hand side.""" - assemble(self.bf[i], tensor=self.vector()) + df.assemble(self.bf[i], tensor=self.vector()) -class NNsource(Function): +class NNsource(df.Function): """Function used for computing the transposed source to the non-Newtonian equation.""" def __init__(self, nunn, u, Space, bcs=[], name=""): - Function.__init__(self, Space, name=name) + df.Function.__init__(self, Space, name=name) dim = Space.mesh().geometry().dim() - test = TestFunction(Space) - self.bf = [inner(inner(grad(nunn), u.dx(i)), test) - * dx for i in range(dim)] + test = df.TestFunction(Space) + self.bf = [ + df.inner(df.inner(df.grad(nunn), u.dx(i)), test) * df.dx for i in range(dim) + ] def assemble_rhs(self, i=0): """Assemble right hand side.""" - assemble(self.bf[i], tensor=self.vector()) + df.assemble(self.bf[i], tensor=self.vector()) def homogenize(bcs): b = [] for bc in bcs: - b0 = DirichletBC(bc) + b0 = df.DirichletBC(bc) b0.homogenize() b.append(b0) return b diff --git a/oasis/problems/NSfracStep/Cylinder.py b/oasis/problems/NSfracStep/Cylinder.py index e7dd8e76..d0766ba3 100644 --- a/oasis/problems/NSfracStep/Cylinder.py +++ b/oasis/problems/NSfracStep/Cylinder.py @@ -1,24 +1,33 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2014-03-21" __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" +print(vars().keys()) from ..NSfracStep import * from ..Cylinder import * + +print(vars().keys()) + +# from oasis.NSfracStep import * +# from oasis.problems.Cylinder import * from os import getcwd import pickle import matplotlib.pyplot as plt -def problem_parameters(commandline_kwargs, NS_parameters, scalar_components, - Schmidt, **NS_namespace): + +def problem_parameters( + commandline_kwargs, NS_parameters, scalar_components, Schmidt, **NS_namespace +): # Example: python NSfracstep.py [...] restart_folder="results/data/8/Checkpoint" if "restart_folder" in commandline_kwargs.keys(): restart_folder = commandline_kwargs["restart_folder"] restart_folder = path.join(getcwd(), restart_folder) - f = open(path.join(restart_folder, 'params.dat'), 'rb') + f = open(path.join(restart_folder, "params.dat"), "rb") NS_parameters.update(pickle.load(f)) - NS_parameters['restart_folder'] = restart_folder + NS_parameters["restart_folder"] = restart_folder globals().update(NS_parameters) else: @@ -31,17 +40,19 @@ def problem_parameters(commandline_kwargs, NS_parameters, scalar_components, plot_interval=10, velocity_degree=2, print_intermediate_info=100, - use_krylov_solvers=True) - NS_parameters['krylov_solvers'].update(dict(monitor_convergence=True)) - NS_parameters['velocity_krylov_solver'].update(dict(preconditioner_type='jacobi', - solver_type='bicgstab')) + use_krylov_solvers=True, + ) + NS_parameters["krylov_solvers"].update(dict(monitor_convergence=True)) + NS_parameters["velocity_krylov_solver"].update( + dict(preconditioner_type="jacobi", solver_type="bicgstab") + ) scalar_components.append("alfa") Schmidt["alfa"] = 0.1 + def create_bcs(V, Q, Um, H, **NS_namespace): - inlet = Expression( - "4.*{0}*x[1]*({1}-x[1])/pow({1}, 2)".format(Um, H), degree=2) + inlet = Expression("4.*{0}*x[1]*({1}-x[1])/pow({1}, 2)".format(Um, H), degree=2) ux = Expression("0.00*x[1]", degree=1) uy = Expression("-0.00*(x[0]-{})".format(center), degree=1) bc00 = DirichletBC(V, inlet, Inlet) @@ -51,10 +62,7 @@ def create_bcs(V, Q, Um, H, **NS_namespace): bc2 = DirichletBC(V, 0, Wall) bcp = DirichletBC(Q, 0, Outlet) bca = DirichletBC(V, 1, Cyl) - return dict(u0=[bc00, bc10, bc2], - u1=[bc01, bc11, bc2], - p=[bcp], - alfa=[bca]) + return dict(u0=[bc00, bc10, bc2], u1=[bc01, bc11, bc2], p=[bcp], alfa=[bca]) def initialize(x_1, x_2, bcs, **NS_namespace): @@ -64,64 +72,99 @@ def initialize(x_1, x_2, bcs, **NS_namespace): [bc.apply(x_2[ui]) for bc in bcs[ui]] -def pre_solve_hook(mesh, V, newfolder, tstepfiles, tstep, ds, u_, - AssignedVectorFunction, **NS_namespace): - uv = AssignedVectorFunction(u_, name='Velocity') - omega = Function(V, name='omega') +def pre_solve_hook( + mesh, + V, + newfolder, + tstepfiles, + tstep, + ds, + u_, + AssignedVectorFunction, + **NS_namespace +): + uv = AssignedVectorFunction(u_, name="Velocity") + omega = Function(V, name="omega") # Store omega each save_step add_function_to_tstepfiles(omega, newfolder, tstepfiles, tstep) - ff = MeshFunction("size_t", mesh, mesh.ufl_cell().geometric_dimension()-1) + ff = MeshFunction("size_t", mesh, mesh.ufl_cell().geometric_dimension() - 1) Cyl.mark(ff, 1) n = FacetNormal(mesh) ds = ds[ff] return dict(uv=uv, omega=omega, ds=ds, ff=ff, n=n) -def temporal_hook(q_, u_, tstep, V, uv, p_, plot_interval, omega, ds, - save_step, mesh, nu, Umean, D, n, **NS_namespace): + +def temporal_hook( + q_, + u_, + tstep, + V, + uv, + p_, + plot_interval, + omega, + ds, + save_step, + mesh, + nu, + Umean, + D, + n, + **NS_namespace +): if tstep % plot_interval == 0: uv() plt.figure(1) - plot(uv, title='Velocity') + plot(uv, title="Velocity") plt.figure(2) - plot(p_, title='Pressure') + plot(p_, title="Pressure") plt.figure(3) - plot(q_['alfa'], title='alfa') + plot(q_["alfa"], title="alfa") plt.show() - R = VectorFunctionSpace(mesh, 'R', 0) + R = VectorFunctionSpace(mesh, "R", 0) c = TestFunction(R) tau = -p_ * Identity(2) + nu * (grad(u_) + grad(u_).T) - forces = assemble(dot(dot(tau, n), c) * ds(1)).get_local() * 2 / Umean**2 / D + forces = assemble(dot(dot(tau, n), c) * ds(1)).get_local() * 2 / Umean ** 2 / D print("Cd = {}, CL = {}".format(*forces)) if tstep % save_step == 0: try: from fenicstools import StreamFunction + omega.assign(StreamFunction(u_, [])) except: - omega.assign(project(curl(u_), V, solver_type='cg', - bcs=[DirichletBC(V, 0, DomainBoundary())])) + omega.assign( + project( + curl(u_), + V, + solver_type="cg", + bcs=[DirichletBC(V, 0, DomainBoundary())], + ) + ) + def theend_hook(q_, u_, p_, uv, mesh, ds, V, nu, Umean, D, **NS_namespace): uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') - plot(q_['alfa'], title='alfa') - R = VectorFunctionSpace(mesh, 'R', 0) + plot(uv, title="Velocity") + plot(p_, title="Pressure") + plot(q_["alfa"], title="alfa") + R = VectorFunctionSpace(mesh, "R", 0) c = TestFunction(R) tau = -p_ * Identity(2) + nu * (grad(u_) + grad(u_).T) - ff = MeshFunction("size_t", mesh, mesh.ufl_cell().geometric_dimension()-1) + ff = MeshFunction("size_t", mesh, mesh.ufl_cell().geometric_dimension() - 1) Cyl.mark(ff, 1) n = FacetNormal(mesh) ds = ds[ff] - forces = assemble(dot(dot(tau, n), c) * ds(1)).get_local() * 2 / Umean**2 / D + forces = assemble(dot(dot(tau, n), c) * ds(1)).get_local() * 2 / Umean ** 2 / D print("Cd = {}, CL = {}".format(*forces)) from fenicstools import Probes from numpy import linspace, repeat, where, resize + xx = linspace(0, L, 10000) x = resize(repeat(xx, 2), (10000, 2)) x[:, 1] = 0.2 @@ -130,3 +173,4 @@ def theend_hook(q_, u_, p_, uv, mesh, ds, V, nu, Umean, D, **NS_namespace): nmax = where(probes.array() < 0)[0][-1] print("L = ", x[nmax, 0] - 0.25) print("dP = ", p_(Point(0.15, 0.2)) - p_(Point(0.25, 0.2))) + print("dP = ", p_(Point(0.15, 0.2)) - p_(Point(0.25, 0.2))) diff --git a/oasis/problems/NSfracStep/DrivenCavity.py b/oasis/problems/NSfracStep/DrivenCavity.py index e1ee31fa..52baf854 100644 --- a/oasis/problems/NSfracStep/DrivenCavity.py +++ b/oasis/problems/NSfracStep/DrivenCavity.py @@ -3,10 +3,98 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * -from ..DrivenCavity import * - -#set_log_active(False) +# lots of unused imports, that are all imported here and used by the main script only +# from ..NSfracStep import * +from oasis.problems import ( + subprocess, + getpid, + path, + defaultdict, + array, + maximum, + zeros, + getMemoryUsage, + # NS_parameters, + NS_expressions, + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + Scalar, + RED, + BLUE, + GREEN, + info_blue, + info_green, + info_red, + OasisTimer, + OasisMemoryUsage, + initial_memory_use, + oasis_memory, + strain, + omega, + Omega, + Strain, + QC, + recursive_update, + OasisXDMFFile, + add_function_to_tstepfiles, + body_force, + initialize, + create_bcs, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + problem_parameters, + post_import_problem, +) +from dolfin import ( # oasis.problems also included whole dolfin namespace + as_vector, + assemble, + KrylovSolver, + LUSolver, + TrialFunction, + TestFunction, + dx, + Vector, + Matrix, + FunctionSpace, + Timer, + div, + Form, + inner, + grad, + as_backend_type, + VectorFunctionSpace, + FunctionAssigner, + PETScKrylovSolver, + PETScPreconditioner, + DirichletBC, + MPI, + Function, + XDMFFile, + HDF5File, + DOLFIN_EPS, + norm, + list_timings, + TimingClear, + TimingType, +) +from oasis.problems.NSfracStep import ( + NS_parameters, + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + + +# from ..DrivenCavity import * +from oasis.problems.DrivenCavity import noslip, top, bottom, mesh +import dolfin as df + +# set_log_active(False) # Override some problem specific parameters def problem_parameters(NS_parameters, scalar_components, Schmidt, **NS_namespace): @@ -19,13 +107,14 @@ def problem_parameters(NS_parameters, scalar_components, Schmidt, **NS_namespace save_step=10000, checkpoint=10000, print_intermediate_info=100, - use_krylov_solvers=True) + use_krylov_solvers=True, + ) scalar_components += ["alfa", "beta"] - Schmidt["alfa"] = 1. - Schmidt["beta"] = 10. + Schmidt["alfa"] = 1.0 + Schmidt["beta"] = 10.0 - #NS_parameters['krylov_solvers'] = {'monitor_convergence': False, + # NS_parameters['krylov_solvers'] = {'monitor_convergence': False, # 'report': False, # 'relative_tolerance': 1e-10, # 'absolute_tolerance': 1e-10} @@ -33,14 +122,16 @@ def problem_parameters(NS_parameters, scalar_components, Schmidt, **NS_namespace # Specify boundary conditions def create_bcs(V, **NS_namespace): - bc0 = DirichletBC(V, 0, noslip) - bc00 = DirichletBC(V, 1, top) - bc01 = DirichletBC(V, 0, top) - return dict(u0=[bc00, bc0], - u1=[bc01, bc0], - p=[], - alfa=[bc00], - beta=[DirichletBC(V, 1, bottom)]) + bc0 = df.DirichletBC(V, 0, noslip) + bc00 = df.DirichletBC(V, 1, top) + bc01 = df.DirichletBC(V, 0, top) + return dict( + u0=[bc00, bc0], + u1=[bc01, bc0], + p=[], + alfa=[bc00], + beta=[df.DirichletBC(V, 1, bottom)], + ) def initialize(x_1, x_2, bcs, **NS_namespace): @@ -51,37 +142,39 @@ def initialize(x_1, x_2, bcs, **NS_namespace): def pre_solve_hook(mesh, velocity_degree, **NS_namespace): - Vv = VectorFunctionSpace(mesh, 'CG', velocity_degree) - return dict(uv=Function(Vv)) + Vv = df.VectorFunctionSpace(mesh, "CG", velocity_degree) + return dict(uv=df.Function(Vv)) def temporal_hook(q_, tstep, u_, uv, p_, plot_interval, testing, **NS_namespace): if tstep % plot_interval == 0 and not testing: - assign(uv.sub(0), u_[0]) - assign(uv.sub(1), u_[1]) - plot(uv, title='Velocity') - plot(p_, title='Pressure') - plot(q_['alfa'], title='alfa') - plot(q_['beta'], title='beta') + df.assign(uv.sub(0), u_[0]) + df.assign(uv.sub(1), u_[1]) + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") + df.plot(q_["alfa"], title="alfa") + df.plot(q_["beta"], title="beta") def theend_hook(u_, p_, uv, mesh, testing, **NS_namespace): if not testing: - assign(uv.sub(0), u_[0]) - assign(uv.sub(1), u_[1]) - plot(uv, title='Velocity') - plot(p_, title='Pressure') + df.assign(uv.sub(0), u_[0]) + df.assign(uv.sub(1), u_[1]) + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") - u_norm = norm(u_[0].vector()) - if MPI.rank(MPI.comm_world) == 0 and testing: + u_norm = df.norm(u_[0].vector()) + if df.MPI.rank(df.MPI.comm_world) == 0 and testing: print("Velocity norm = {0:2.6e}".format(u_norm)) if not testing: try: from fenicstools import StreamFunction + psi = StreamFunction(uv, [], mesh, use_strong_bc=True) - plot(psi, title='Streamfunction') + df.plot(psi, title="Streamfunction") import matplotlib.pyplot as plt + plt.show() except: pass diff --git a/oasis/problems/NSfracStep/__init__.py b/oasis/problems/NSfracStep/__init__.py index 0720af95..c84c416f 100644 --- a/oasis/problems/NSfracStep/__init__.py +++ b/oasis/problems/NSfracStep/__init__.py @@ -3,66 +3,102 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from oasis.problems import * +# from oasis.problems import * +from oasis.problems import ( + subprocess, + getpid, + path, + defaultdict, + array, + maximum, + zeros, + getMemoryUsage, + NS_parameters, + NS_expressions, + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + Scalar, + RED, + BLUE, + GREEN, + info_blue, + info_green, + info_red, + OasisTimer, + OasisMemoryUsage, + initial_memory_use, + oasis_memory, + strain, + omega, + Omega, + Strain, + QC, + recursive_update, + OasisXDMFFile, + add_function_to_tstepfiles, + body_force, + initialize, + create_bcs, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + problem_parameters, + post_import_problem, +) # Default parameters NSfracStep solver NS_parameters.update( # Physical constants and solver parameters - t=0.0, # Time - tstep=0, # Timestep - T=1.0, # End time - dt=0.01, # Time interval on each timestep - + t=0.0, # Time + tstep=0, # Timestep + T=1.0, # End time + dt=0.01, # Time interval on each timestep # Some discretization options # Use Adams Bashforth projection as first estimate for pressure on new timestep AB_projection_pressure=False, solver="IPCS_ABCN", # "IPCS_ABCN", "IPCS_ABE", "IPCS", "Chorin", "BDFPC", "BDFPC_Fast" - # Parameters used to tweek solver - max_iter=1, # Number of inner pressure velocity iterations on timestep - max_error=1e-6, # Tolerance for inner iterations (pressure velocity iterations) + max_iter=1, # Number of inner pressure velocity iterations on timestep + max_error=1e-6, # Tolerance for inner iterations (pressure velocity iterations) iters_on_first_timestep=2, # Number of iterations on first timestep - use_krylov_solvers=True, # Otherwise use LU-solver + use_krylov_solvers=True, # Otherwise use LU-solver print_intermediate_info=10, print_velocity_pressure_convergence=False, - # Parameters used to tweek output plot_interval=10, - checkpoint=10, # Overwrite solution in Checkpoint folder each checkpoint - save_step=10, # Store solution each save_step - restart_folder=None, # If restarting solution, set the folder holding the solution to start from here + checkpoint=10, # Overwrite solution in Checkpoint folder each checkpoint + save_step=10, # Store solution each save_step + restart_folder=None, # If restarting solution, set the folder holding the solution to start from here output_timeseries_as_vector=True, # Store velocity as vector in Timeseries - # Stop simulations cleanly after the given number of seconds killtime=None, - # Choose LES model and set default parameters # NoModel, Smagorinsky, Wale, DynamicLagrangian, ScaleDepDynamicLagrangian - les_model='NoModel', - + les_model="NoModel", # LES model parameters - Smagorinsky=dict(Cs=0.1677), # Standard Cs, same as OpenFOAM + Smagorinsky=dict(Cs=0.1677), # Standard Cs, same as OpenFOAM Wale=dict(Cw=0.325), - DynamicSmagorinsky=dict(Cs_comp_step=1), # Time step interval for Cs to be recomputed + DynamicSmagorinsky=dict( + Cs_comp_step=1 + ), # Time step interval for Cs to be recomputed KineticEnergySGS=dict(Ck=0.08, Ce=1.05), - # Choose Non-Newtonian model and set default parameters # NoModel, ModifiedCross - nn_model='NoModel', - + nn_model="NoModel", # Non-Newtonian model parameters - ModifiedCross = dict( - lam=3.736, # s + ModifiedCross=dict( + lam=3.736, # s m_param=2.406, # for Non-Newtonian model - a_param=0.34, # for Non-Newtonian model - mu_inf=0.00372, # Pa-s for non-Newtonian model - mu_o=0.09, # Pa-s for non-Newtonian model - rho=1085 # kg/m^3 - ), - + a_param=0.34, # for Non-Newtonian model + mu_inf=0.00372, # Pa-s for non-Newtonian model + mu_o=0.09, # Pa-s for non-Newtonian model + rho=1085, # kg/m^3 + ), # Parameter set when enabling test mode testing=False, - # Solver parameters that will be transferred to dolfins parameters['krylov_solver'] krylov_solvers=dict( monitor_convergence=False, @@ -71,36 +107,28 @@ nonzero_initial_guess=True, maximum_iterations=200, relative_tolerance=1e-8, - absolute_tolerance=1e-8), - + absolute_tolerance=1e-8, + ), # Velocity update velocity_update_solver=dict( - method='default', # "lumping", "gradient_matrix" - solver_type='cg', - preconditioner_type='jacobi', - low_memory_version=False), - - velocity_krylov_solver=dict( - solver_type='bicgstab', - preconditioner_type='jacobi'), - - pressure_krylov_solver=dict( - solver_type='gmres', - preconditioner_type='hypre_amg'), - - scalar_krylov_solver=dict( - solver_type='bicgstab', - preconditioner_type='jacobi'), - + method="default", # "lumping", "gradient_matrix" + solver_type="cg", + preconditioner_type="jacobi", + low_memory_version=False, + ), + velocity_krylov_solver=dict(solver_type="bicgstab", preconditioner_type="jacobi"), + pressure_krylov_solver=dict(solver_type="gmres", preconditioner_type="hypre_amg"), + scalar_krylov_solver=dict(solver_type="bicgstab", preconditioner_type="jacobi"), nut_krylov_solver=dict( - method='WeightedAverage', # Or 'default' - solver_type='cg', - preconditioner_type='jacobi'), - + method="WeightedAverage", # Or 'default' + solver_type="cg", + preconditioner_type="jacobi", + ), nu_nn_krylov_solver=dict( - method='WeightedAverage', # Or 'default' - solver_type='cg', - preconditioner_type='jacobi'), + method="WeightedAverage", # Or 'default' + solver_type="cg", + preconditioner_type="jacobi", + ), ) diff --git a/oasis/problems/__init__.py b/oasis/problems/__init__.py index 42d06f21..0522f627 100644 --- a/oasis/problems/__init__.py +++ b/oasis/problems/__init__.py @@ -3,7 +3,8 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from dolfin import * +# from dolfin import * +import dolfin as df import subprocess from os import getpid, path from collections import defaultdict @@ -12,7 +13,7 @@ # UnitSquareMesh(20, 20) # Just due to MPI bug on Scinet # try: -#from fenicstools import getMemoryUsage +# from fenicstools import getMemoryUsage # except: @@ -20,30 +21,29 @@ def getMemoryUsage(rss=True): mypid = str(getpid()) rss = "rss" if rss else "vsz" - process = subprocess.Popen(['ps', '-o', rss, mypid], - stdout=subprocess.PIPE) + process = subprocess.Popen(["ps", "-o", rss, mypid], stdout=subprocess.PIPE) out, _ = process.communicate() mymemory = out.split()[1] return eval(mymemory) / 1024 -parameters["linear_algebra_backend"] = "PETSc" -parameters["form_compiler"]["optimize"] = True -parameters["form_compiler"]["cpp_optimize"] = True -parameters["form_compiler"]["representation"] = "uflacs" -#parameters["form_compiler"]["quadrature_degree"] = 4 -#parameters["form_compiler"]["cache_dir"] = "instant" -parameters["form_compiler"]["cpp_optimize_flags"] = "-O3" -#parameters["mesh_partitioner"] = "ParMETIS" -#parameters["form_compiler"].add("no_ferari", True) -#set_log_active(False) +df.parameters["linear_algebra_backend"] = "PETSc" +df.parameters["form_compiler"]["optimize"] = True +df.parameters["form_compiler"]["cpp_optimize"] = True +df.parameters["form_compiler"]["representation"] = "uflacs" +# df.parameters["form_compiler"]["quadrature_degree"] = 4 +# df.parameters["form_compiler"]["cache_dir"] = "instant" +df.parameters["form_compiler"]["cpp_optimize_flags"] = "-O3" +# df.parameters["mesh_partitioner"] = "ParMETIS" +# df.parameters["form_compiler"].add("no_ferari", True) +# df.set_log_active(False) # Default parameters for all solvers NS_parameters = dict( - nu=0.01, # Kinematic viscosity - folder='results', # Relative folder for storing results - velocity_degree=2, # default velocity degree - pressure_degree=1 # default pressure degree + nu=0.01, # Kinematic viscosity + folder="results", # Relative folder for storing results + velocity_degree=2, # default velocity degree + pressure_degree=1, # default pressure degree ) NS_expressions = {} @@ -55,12 +55,10 @@ def getMemoryUsage(rss=True): # With diffusivities given as a Schmidt number defined by: # Schmidt = nu / D (= momentum diffusivity / mass diffusivity) -Schmidt = defaultdict(lambda: 1.) +Schmidt = defaultdict(lambda: 1.0) Schmidt_T = defaultdict(lambda: 0.7) # Turbulent Schmidt number (LES) -Scalar = defaultdict(lambda: dict(Schmidt=1.0, - family="CG", - degree=1)) +Scalar = defaultdict(lambda: dict(Schmidt=1.0, family="CG", degree=1)) # The following helper functions are available in dolfin # They are redefined here for printing only on process 0. @@ -70,23 +68,23 @@ def getMemoryUsage(rss=True): def info_blue(s, check=True): - if MPI.rank(MPI.comm_world) == 0 and check: + if df.MPI.rank(df.MPI.comm_world) == 0 and check: print(BLUE % s) def info_green(s, check=True): - if MPI.rank(MPI.comm_world) == 0 and check: + if df.MPI.rank(df.MPI.comm_world) == 0 and check: print(GREEN % s) def info_red(s, check=True): - if MPI.rank(MPI.comm_world) == 0 and check: + if df.MPI.rank(df.MPI.comm_world) == 0 and check: print(RED % s) -class OasisTimer(Timer): +class OasisTimer(df.Timer): def __init__(self, task, verbose=False): - Timer.__init__(self, task) + df.Timer.__init__(self, task) info_blue(task, verbose) @@ -99,34 +97,40 @@ def __init__(self, s): def __call__(self, s, verbose=False): self.prev = self.memory self.prev_vm = self.memory_vm - self.memory = MPI.sum(MPI.comm_world, getMemoryUsage()) - self.memory_vm = MPI.sum(MPI.comm_world, getMemoryUsage(False)) - if MPI.rank(MPI.comm_world) == 0 and verbose: - info_blue('{0:26s} {1:10d} MB {2:10d} MB {3:10d} MB {4:10d} MB'.format(s, - int(self.memory - self.prev), int(self.memory), - int(self.memory_vm - self.prev_vm), int(self.memory_vm))) + self.memory = df.MPI.sum(df.MPI.comm_world, getMemoryUsage()) + self.memory_vm = df.MPI.sum(df.MPI.comm_world, getMemoryUsage(False)) + if df.MPI.rank(df.MPI.comm_world) == 0 and verbose: + info_blue( + "{0:26s} {1:10d} MB {2:10d} MB {3:10d} MB {4:10d} MB".format( + s, + int(self.memory - self.prev), + int(self.memory), + int(self.memory_vm - self.prev_vm), + int(self.memory_vm), + ) + ) # Print memory use up til now initial_memory_use = getMemoryUsage() -oasis_memory = OasisMemoryUsage('Start') +oasis_memory = OasisMemoryUsage("Start") # Convenience functions def strain(u): - return 0.5 * (grad(u) + grad(u).T) + return 0.5 * (df.grad(u) + df.grad(u).T) def omega(u): - return 0.5 * (grad(u) - grad(u).T) + return 0.5 * (df.grad(u) - df.grad(u).T) def Omega(u): - return inner(omega(u), omega(u)) + return df.inner(omega(u), omega(u)) def Strain(u): - return inner(strain(u), strain(u)) + return df.inner(strain(u), strain(u)) def QC(u): @@ -142,23 +146,26 @@ def recursive_update(dst, src): dst[key] = val return dst -class OasisXDMFFile(XDMFFile, object): + +class OasisXDMFFile(df.XDMFFile, object): def __init__(self, comm, filename): - XDMFFile.__init__(self, comm, filename) + df.XDMFFile.__init__(self, comm, filename) + def add_function_to_tstepfiles(function, newfolder, tstepfiles, tstep): name = function.name() tstepfolder = path.join(newfolder, "Timeseries") - tstepfiles[name] = OasisXDMFFile(MPI.comm_world, - path.join(tstepfolder, - '{}_from_tstep_{}.xdmf'.format(name, tstep))) + tstepfiles[name] = OasisXDMFFile( + df.MPI.comm_world, + path.join(tstepfolder, "{}_from_tstep_{}.xdmf".format(name, tstep)), + ) tstepfiles[name].function = function tstepfiles[name].parameters["rewrite_function_mesh"] = False def body_force(mesh, **NS_namespace): """Specify body force""" - return Constant((0,) * mesh.geometry().dim()) + return df.Constant((0,) * mesh.geometry().dim()) def initialize(**NS_namespace): @@ -178,7 +185,7 @@ def scalar_hook(**NS_namespace): def scalar_source(scalar_components, **NS_namespace): """Return a dictionary of scalar sources.""" - return dict((ci, Constant(0)) for ci in scalar_components) + return dict((ci, df.Constant(0)) for ci in scalar_components) def pre_solve_hook(**NS_namespace): @@ -196,8 +203,9 @@ def problem_parameters(**NS_namespace): pass -def post_import_problem(NS_parameters, mesh, commandline_kwargs, - NS_expressions, **NS_namespace): +def post_import_problem( + NS_parameters, mesh, commandline_kwargs, NS_expressions, **NS_namespace +): """Called after importing from problem.""" # Update NS_parameters with all parameters modified through command line @@ -211,7 +219,7 @@ def post_import_problem(NS_parameters, mesh, commandline_kwargs, if callable(mesh): mesh = mesh(**NS_parameters) - assert(isinstance(mesh, Mesh)) + assert isinstance(mesh, df.Mesh) # Returned dictionary to be updated in the NS namespace d = dict(mesh=mesh) From 729819deb6d4ba1a675bfdaa3b52b3e974c67834 Mon Sep 17 00:00:00 2001 From: flabowski Date: Fri, 18 Feb 2022 16:59:47 +0100 Subject: [PATCH 02/10] added .gitignore --- .gitignore | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..466ec15c --- /dev/null +++ b/.gitignore @@ -0,0 +1,141 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ +*.npy +*.pickle +*.png +*.pdf + +# Meshfiles +*.vtk +*.xdmf +*.xml +*.h5 + +core.* \ No newline at end of file From bd1bd4ab48230f7eec4673320a6cbd48b59fb6ec Mon Sep 17 00:00:00 2001 From: flabowski Date: Wed, 23 Feb 2022 11:59:31 +0100 Subject: [PATCH 03/10] Autoformat for conformance to the PEP 8 convention. --- oasis/NSfracStep.py | 115 ++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 48 deletions(-) diff --git a/oasis/NSfracStep.py b/oasis/NSfracStep.py index cd6c9edb..e9a04563 100755 --- a/oasis/NSfracStep.py +++ b/oasis/NSfracStep.py @@ -38,16 +38,18 @@ commandline_kwargs = parse_command_line() # Find the problem module -default_problem = 'DrivenCavity' -problemname = commandline_kwargs.get('problem', default_problem) -problemspec = importlib.util.find_spec('.'.join(('oasis.problems.NSfracStep', problemname))) +default_problem = "DrivenCavity" +problemname = commandline_kwargs.get("problem", default_problem) +problemspec = importlib.util.find_spec( + ".".join(("oasis.problems.NSfracStep", problemname)) +) if problemspec is None: problemspec = importlib.util.find_spec(problemname) if problemspec is None: - raise RuntimeError(problemname+' not found') + raise RuntimeError(problemname + " not found") # Import the problem module -print('Importing problem module '+problemname+':\n'+problemspec.origin) +print("Importing problem module " + problemname + ":\n" + problemspec.origin) problemmod = importlib.util.module_from_spec(problemspec) problemspec.loader.exec_module(problemmod) @@ -61,31 +63,33 @@ # Use t and tstep from stored paramteres if restarting if restart_folder is not None: - f = open(path.join(path.abspath(restart_folder), 'params.dat'), 'rb') + f = open(path.join(path.abspath(restart_folder), "params.dat"), "rb") params = pickle.load(f) f.close() t = params["t"] tstep = params["tstep"] # Import chosen functionality from solvers -solver = importlib.import_module('.'.join(('oasis.solvers.NSfracStep', solver))) -vars().update({name:solver.__dict__[name] for name in solver.__all__}) +solver = importlib.import_module(".".join(("oasis.solvers.NSfracStep", solver))) +vars().update({name: solver.__dict__[name] for name in solver.__all__}) # Create lists of components solved for dim = mesh.geometry().dim() -u_components = ['u' + str(x) for x in range(dim)] -sys_comp = u_components + ['p'] + scalar_components +u_components = ["u" + str(x) for x in range(dim)] +sys_comp = u_components + ["p"] + scalar_components uc_comp = u_components + scalar_components # Set up initial folders for storing results newfolder, tstepfiles = create_initial_folders(**vars()) # Declare FunctionSpaces and arguments -V = Q = FunctionSpace(mesh, 'CG', velocity_degree, - constrained_domain=constrained_domain) +V = Q = FunctionSpace( + mesh, "CG", velocity_degree, constrained_domain=constrained_domain +) if velocity_degree != pressure_degree: - Q = FunctionSpace(mesh, 'CG', pressure_degree, - constrained_domain=constrained_domain) + Q = FunctionSpace( + mesh, "CG", pressure_degree, constrained_domain=constrained_domain + ) u = TrialFunction(V) v = TestFunction(V) @@ -94,10 +98,10 @@ # Use dictionary to hold all FunctionSpaces VV = dict((ui, V) for ui in uc_comp) -VV['p'] = Q +VV["p"] = Q # Create dictionaries for the solutions at three timesteps -q_ = dict((ui, Function(VV[ui], name=ui)) for ui in sys_comp) +q_ = dict((ui, Function(VV[ui], name=ui)) for ui in sys_comp) q_1 = dict((ui, Function(VV[ui], name=ui + "_1")) for ui in sys_comp) q_2 = dict((ui, Function(V, name=ui + "_2")) for ui in u_components) @@ -105,46 +109,50 @@ init_from_restart(**vars()) # Create vectors of the segregated velocity components -u_ = as_vector([q_ [ui] for ui in u_components]) # Velocity vector at t -u_1 = as_vector([q_1[ui] for ui in u_components]) # Velocity vector at t - dt -u_2 = as_vector([q_2[ui] for ui in u_components]) # Velocity vector at t - 2*dt +u_ = as_vector([q_[ui] for ui in u_components]) # Velocity vector at t +u_1 = as_vector([q_1[ui] for ui in u_components]) # Velocity vector at t - dt +u_2 = as_vector([q_2[ui] for ui in u_components]) # Velocity vector at t - 2*dt # Adams Bashforth projection of velocity at t - dt/2 U_AB = 1.5 * u_1 - 0.5 * u_2 # Create short forms for accessing the solution vectors -x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors t -x_1 = dict((ui, q_1[ui].vector()) for ui in sys_comp) # Solution vectors t - dt +x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors t +x_1 = dict((ui, q_1[ui].vector()) for ui in sys_comp) # Solution vectors t - dt x_2 = dict((ui, q_2[ui].vector()) for ui in u_components) # Solution vectors t - 2*dt # Create vectors to hold rhs of equations -b = dict((ui, Vector(x_[ui])) for ui in sys_comp) # rhs vectors (final) +b = dict((ui, Vector(x_[ui])) for ui in sys_comp) # rhs vectors (final) b_tmp = dict((ui, Vector(x_[ui])) for ui in sys_comp) # rhs temp storage vectors # Short forms pressure and scalars -p_ = q_['p'] # pressure at t -p_1 = q_1['p'] # pressure at t - dt -dp_ = Function(Q) # pressure correction +p_ = q_["p"] # pressure at t +p_1 = q_1["p"] # pressure at t - dt +dp_ = Function(Q) # pressure correction for ci in scalar_components: exec("{}_ = q_ ['{}']".format(ci, ci)) exec("{}_1 = q_1['{}']".format(ci, ci)) -print_solve_info = use_krylov_solvers and krylov_solvers['monitor_convergence'] +print_solve_info = use_krylov_solvers and krylov_solvers["monitor_convergence"] # Boundary conditions bcs = create_bcs(**vars()) # LES setup -#exec("from oasis.solvers.NSfracStep.LES.{} import *".format(les_model)) -lesmodel = importlib.import_module('.'.join(('oasis.solvers.NSfracStep.LES', les_model))) -vars().update({name:lesmodel.__dict__[name] for name in lesmodel.__all__}) +# exec("from oasis.solvers.NSfracStep.LES.{} import *".format(les_model)) +lesmodel = importlib.import_module( + ".".join(("oasis.solvers.NSfracStep.LES", les_model)) +) +vars().update({name: lesmodel.__dict__[name] for name in lesmodel.__all__}) vars().update(les_setup(**vars())) # Non-Newtonian setup -#exec("from oasis.solvers.NSfracStep.NNModel.{} import *".format(nn_model)) -nnmodel = importlib.import_module('.'.join(('oasis.solvers.NSfracStep.NNModel', nn_model))) -vars().update({name:nnmodel.__dict__[name] for name in nnmodel.__all__}) +# exec("from oasis.solvers.NSfracStep.NNModel.{} import *".format(nn_model)) +nnmodel = importlib.import_module( + ".".join(("oasis.solvers.NSfracStep.NNModel", nn_model)) +) +vars().update({name: nnmodel.__dict__[name] for name in nnmodel.__all__}) vars().update(nn_setup(**vars())) @@ -156,13 +164,13 @@ # Get constant body forces f = body_force(**vars()) -assert(isinstance(f, Coefficient)) +assert isinstance(f, Coefficient) b0 = dict((ui, assemble(v * f[i] * dx)) for i, ui in enumerate(u_components)) # Get scalar sources fs = scalar_source(**vars()) for ci in scalar_components: - assert(isinstance(fs[ci], Coefficient)) + assert isinstance(fs[ci], Coefficient) b0[ci] = assemble(v * fs[ci] * dx) # Preassemble and allocate @@ -171,7 +179,7 @@ # Anything problem specific vars().update(pre_solve_hook(**vars())) -tx = OasisTimer('Timestep timer') +tx = OasisTimer("Timestep timer") tx.start() stop = False total_timer = OasisTimer("Start simulations", True) @@ -194,7 +202,7 @@ assemble_first_inner_iter(**vars()) udiff[0] = 0.0 for i, ui in enumerate(u_components): - t1 = OasisTimer('Solving tentative velocity ' + ui, print_solve_info) + t1 = OasisTimer("Solving tentative velocity " + ui, print_solve_info) velocity_tentative_assemble(**vars()) velocity_tentative_hook(**vars()) velocity_tentative_solve(**vars()) @@ -217,7 +225,7 @@ if len(scalar_components) > 0: scalar_assemble(**vars()) for ci in scalar_components: - t1 = OasisTimer('Solving scalar {}'.format(ci), print_solve_info) + t1 = OasisTimer("Solving scalar {}".format(ci), print_solve_info) scalar_hook(**vars()) scalar_solve(**vars()) t1.stop() @@ -236,30 +244,41 @@ for ci in scalar_components: x_1[ci].zero() - x_1[ci].axpy(1., x_[ci]) + x_1[ci].axpy(1.0, x_[ci]) # Print some information if tstep % print_intermediate_info == 0: toc = tx.stop() - info_green( 'Time = {0:2.4e}, timestep = {1:6d}, End time = {2:2.4e}'.format(t, tstep, T)) - info_red('Total computing time on previous {0:d} timesteps = {1:f}'.format( - print_intermediate_info, toc)) + info_green( + "Time = {0:2.4e}, timestep = {1:6d}, End time = {2:2.4e}".format( + t, tstep, T + ) + ) + info_red( + "Total computing time on previous {0:d} timesteps = {1:f}".format( + print_intermediate_info, toc + ) + ) list_timings(TimingClear.clear, [TimingType.wall]) tx.start() # AB projection for pressure on next timestep if AB_projection_pressure and t < (T - tstep * DOLFIN_EPS) and not stop: - x_['p'].axpy(0.5, dp_.vector()) + x_["p"].axpy(0.5, dp_.vector()) total_timer.stop() list_timings(TimingClear.keep, [TimingType.wall]) -info_red('Total computing time = {0:f}'.format(total_timer.elapsed()[0])) -oasis_memory('Final memory use ') +info_red("Total computing time = {0:f}".format(total_timer.elapsed()[0])) +oasis_memory("Final memory use ") total_initial_dolfin_memory = MPI.sum(MPI.comm_world, initial_memory_use) -info_red('Memory use for importing dolfin = {} MB (RSS)'.format( - total_initial_dolfin_memory)) -info_red('Total memory use of solver = ' + - str(oasis_memory.memory - total_initial_dolfin_memory) + " MB (RSS)") +info_red( + "Memory use for importing dolfin = {} MB (RSS)".format(total_initial_dolfin_memory) +) +info_red( + "Total memory use of solver = " + + str(oasis_memory.memory - total_initial_dolfin_memory) + + " MB (RSS)" +) if restart_folder is not None: merge_visualization_files(**vars()) From ac06f489bf80a4e3c6261f1c585079e12b6d1678 Mon Sep 17 00:00:00 2001 From: flabowski Date: Wed, 23 Feb 2022 14:32:43 +0100 Subject: [PATCH 04/10] explicit imports, pass arguments rather than **vars() --- oasis/NSfracStep.py | 312 +++++++++++++++++++++++++++++++------------- 1 file changed, 221 insertions(+), 91 deletions(-) diff --git a/oasis/NSfracStep.py b/oasis/NSfracStep.py index e9a04563..d48a3f23 100755 --- a/oasis/NSfracStep.py +++ b/oasis/NSfracStep.py @@ -33,16 +33,30 @@ """ import importlib -from oasis.common import * +import oasis.common.io as io +import pickle +from os import path +import dolfin as df +import numpy as np +from oasis.common import parse_command_line # ,convert +import oasis.common.utilities as ut +from ufl import Coefficient +from oasis.problems import ( + info_blue, + info_green, + info_red, + OasisTimer, + initial_memory_use, + oasis_memory, +) commandline_kwargs = parse_command_line() # Find the problem module -default_problem = "DrivenCavity" +default_problem = "DrivenCavity" # Cylinder, DrivenCavity problemname = commandline_kwargs.get("problem", default_problem) -problemspec = importlib.util.find_spec( - ".".join(("oasis.problems.NSfracStep", problemname)) -) +pth = ".".join(("oasis.problems.NSfracStep", problemname)) +problemspec = importlib.util.find_spec(pth) if problemspec is None: problemspec = importlib.util.find_spec(problemname) if problemspec is None: @@ -50,28 +64,39 @@ # Import the problem module print("Importing problem module " + problemname + ":\n" + problemspec.origin) -problemmod = importlib.util.module_from_spec(problemspec) -problemspec.loader.exec_module(problemmod) +pblm = importlib.util.module_from_spec(problemspec) +problemspec.loader.exec_module(pblm) -vars().update(**vars(problemmod)) +# what may be overwritten and what may not? +NS_parameters = pblm.NS_parameters +scalar_components = pblm.scalar_components # TODO: can that be in NS_parameters? +temporal_hook = pblm.temporal_hook +theend_hook = pblm.theend_hook -# Update problem spesific parameters -problem_parameters(**vars()) +# updates NS_parameters, scalar_components, Schmidt +pblm.problem_parameters(NS_parameters, scalar_components, pblm.Schmidt) # Update current namespace with NS_parameters and commandline_kwargs ++ -vars().update(post_import_problem(**vars())) +# updates NS_parameters! +mesh = pblm.post_import_problem( + NS_parameters, + pblm.mesh, + commandline_kwargs, + pblm.NS_expressions, +)["mesh"] # Use t and tstep from stored paramteres if restarting -if restart_folder is not None: - f = open(path.join(path.abspath(restart_folder), "params.dat"), "rb") +if NS_parameters["restart_folder"] is not None: + folder = path.abspath(NS_parameters["restart_folder"]) + f = open(path.join(folder, "params.dat"), "rb") params = pickle.load(f) f.close() t = params["t"] tstep = params["tstep"] # Import chosen functionality from solvers -solver = importlib.import_module(".".join(("oasis.solvers.NSfracStep", solver))) -vars().update({name: solver.__dict__[name] for name in solver.__all__}) +pth = ".".join(("oasis.solvers.NSfracStep", NS_parameters["solver"])) +solver = importlib.import_module(pth) # Create lists of components solved for dim = mesh.geometry().dim() @@ -80,38 +105,55 @@ uc_comp = u_components + scalar_components # Set up initial folders for storing results -newfolder, tstepfiles = create_initial_folders(**vars()) +newfolder, tstepfiles = io.create_initial_folders( + scalar_components=scalar_components, + sys_comp=sys_comp, + info_red=info_red, + **NS_parameters, +) +quantities = {} # Declare FunctionSpaces and arguments -V = Q = FunctionSpace( - mesh, "CG", velocity_degree, constrained_domain=constrained_domain +velocity_degree = NS_parameters["velocity_degree"] +pressure_degree = NS_parameters["pressure_degree"] +V = Q = df.FunctionSpace( + mesh, "CG", velocity_degree, constrained_domain=pblm.constrained_domain ) if velocity_degree != pressure_degree: - Q = FunctionSpace( - mesh, "CG", pressure_degree, constrained_domain=constrained_domain + Q = df.FunctionSpace( + mesh, "CG", pressure_degree, constrained_domain=pblm.constrained_domain ) - -u = TrialFunction(V) -v = TestFunction(V) -p = TrialFunction(Q) -q = TestFunction(Q) +quantities["V"] = V +quantities["Q"] = Q +quantities["u"] = u = df.TrialFunction(V) +quantities["v"] = v = df.TestFunction(V) +quantities["p"] = p = df.TrialFunction(Q) +quantities["q"] = q = df.TestFunction(Q) # Use dictionary to hold all FunctionSpaces VV = dict((ui, V) for ui in uc_comp) VV["p"] = Q # Create dictionaries for the solutions at three timesteps -q_ = dict((ui, Function(VV[ui], name=ui)) for ui in sys_comp) -q_1 = dict((ui, Function(VV[ui], name=ui + "_1")) for ui in sys_comp) -q_2 = dict((ui, Function(V, name=ui + "_2")) for ui in u_components) +q_ = dict((ui, df.Function(VV[ui], name=ui)) for ui in sys_comp) +q_1 = dict((ui, df.Function(VV[ui], name=ui + "_1")) for ui in sys_comp) +q_2 = dict((ui, df.Function(V, name=ui + "_2")) for ui in u_components) +quantities["q_"], quantities["q_1"], quantities["q_2"] = q_, q_1, q_2 # Read in previous solution if restarting -init_from_restart(**vars()) +io.init_from_restart( + sys_comp=sys_comp, + uc_comp=uc_comp, + u_components=u_components, + **quantities, + **NS_parameters, +) # Create vectors of the segregated velocity components -u_ = as_vector([q_[ui] for ui in u_components]) # Velocity vector at t -u_1 = as_vector([q_1[ui] for ui in u_components]) # Velocity vector at t - dt -u_2 = as_vector([q_2[ui] for ui in u_components]) # Velocity vector at t - 2*dt +u_ = df.as_vector([q_[ui] for ui in u_components]) # Velocity vector at t +u_1 = df.as_vector([q_1[ui] for ui in u_components]) # Velocity vector at t - dt +u_2 = df.as_vector([q_2[ui] for ui in u_components]) # Velocity vector at t - 2*dt +quantities["u_"], quantities["u_1"], quantities["u_2"] = u_, u_1, u_2 # Adams Bashforth projection of velocity at t - dt/2 U_AB = 1.5 * u_1 - 0.5 * u_2 @@ -120,121 +162,202 @@ x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors t x_1 = dict((ui, q_1[ui].vector()) for ui in sys_comp) # Solution vectors t - dt x_2 = dict((ui, q_2[ui].vector()) for ui in u_components) # Solution vectors t - 2*dt +quantities["x_"], quantities["x_1"], quantities["x_2"] = x_, x_1, x_2 # Create vectors to hold rhs of equations -b = dict((ui, Vector(x_[ui])) for ui in sys_comp) # rhs vectors (final) -b_tmp = dict((ui, Vector(x_[ui])) for ui in sys_comp) # rhs temp storage vectors +b = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) # rhs vectors (final) +b_tmp = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) # rhs temp storage vectors +quantities["b"], quantities["b_tmp"] = b, b_tmp # Short forms pressure and scalars -p_ = q_["p"] # pressure at t -p_1 = q_1["p"] # pressure at t - dt -dp_ = Function(Q) # pressure correction +quantities["p_"] = q_["p"] # pressure at t +quantities["p_1"] = q_1["p"] # pressure at t - dt +quantities["dp_"] = dp_ = df.Function(Q) # pressure correction for ci in scalar_components: exec("{}_ = q_ ['{}']".format(ci, ci)) exec("{}_1 = q_1['{}']".format(ci, ci)) +krylov_solvers = NS_parameters["krylov_solvers"] +use_krylov_solvers = NS_parameters["use_krylov_solvers"] print_solve_info = use_krylov_solvers and krylov_solvers["monitor_convergence"] # Boundary conditions -bcs = create_bcs(**vars()) +quantities["bcs"] = bcs = pblm.create_bcs(V=V) # LES setup -# exec("from oasis.solvers.NSfracStep.LES.{} import *".format(les_model)) -lesmodel = importlib.import_module( - ".".join(("oasis.solvers.NSfracStep.LES", les_model)) -) -vars().update({name: lesmodel.__dict__[name] for name in lesmodel.__all__}) - -vars().update(les_setup(**vars())) +pth = ".".join(("oasis.solvers.NSfracStep.LES", NS_parameters["les_model"])) +lesmodel = importlib.import_module(pth) +les_dict = lesmodel.les_setup() # FIXME: which dicts have to be passed? # Non-Newtonian setup # exec("from oasis.solvers.NSfracStep.NNModel.{} import *".format(nn_model)) -nnmodel = importlib.import_module( - ".".join(("oasis.solvers.NSfracStep.NNModel", nn_model)) -) -vars().update({name: nnmodel.__dict__[name] for name in nnmodel.__all__}) - -vars().update(nn_setup(**vars())) +pth = ".".join(("oasis.solvers.NSfracStep.NNModel", NS_parameters["nn_model"])) +nnmodel = importlib.import_module(pth) +nn_dict = nnmodel.nn_setup() # FIXME: which dicts have to be passed? # Initialize solution -initialize(**vars()) +pblm.initialize(**quantities, **NS_parameters) # Fetch linear algebra solvers -u_sol, p_sol, c_sol = get_solvers(**vars()) +u_sol, p_sol, c_sol = solver.get_solvers( + **quantities, + scalar_components=scalar_components, + **NS_parameters, +) # Get constant body forces -f = body_force(**vars()) +f = pblm.body_force(mesh=mesh, **NS_parameters) assert isinstance(f, Coefficient) -b0 = dict((ui, assemble(v * f[i] * dx)) for i, ui in enumerate(u_components)) +b0 = dict((ui, df.assemble(v * f[i] * df.dx)) for i, ui in enumerate(u_components)) +quantities["f"], quantities["b0"] = f, b0 # Get scalar sources -fs = scalar_source(**vars()) +fs = pblm.scalar_source(scalar_components=scalar_components, **NS_parameters) for ci in scalar_components: assert isinstance(fs[ci], Coefficient) - b0[ci] = assemble(v * fs[ci] * dx) + b0[ci] = df.assemble(v * fs[ci] * df.dx) +quantities["fs"] = fs # Preassemble and allocate -vars().update(setup(**vars())) +# TODO: ut.XXX should not be passed but raather imported in solver.py +F_dict = solver.setup( + scalar_components=scalar_components, + A_cache=ut.A_cache, + homogenize=ut.homogenize, + GradFunction=ut.GradFunction, + DivFunction=ut.DivFunction, + LESsource=ut.LESsource, + NNsource=ut.NNsource, + assemble_matrix=ut.assemble_matrix, + u_components=u_components, + **nn_dict, + **les_dict, + **quantities, + **NS_parameters, +) + +t = NS_parameters["t"] +tstep = NS_parameters["tstep"] +T = NS_parameters["T"] +max_iter = NS_parameters["max_iter"] +it0 = NS_parameters["iters_on_first_timestep"] +max_error = NS_parameters["max_error"] +print_intermediate_info = NS_parameters["print_intermediate_info"] +AB_projection_pressure = NS_parameters["AB_projection_pressure"] # Anything problem specific -vars().update(pre_solve_hook(**vars())) +psh_dict = pblm.pre_solve_hook(mesh=mesh, velocity_degree=velocity_degree) tx = OasisTimer("Timestep timer") tx.start() stop = False total_timer = OasisTimer("Start simulations", True) -while t < (T - tstep * DOLFIN_EPS) and not stop: - t += dt +while t < (T - tstep * df.DOLFIN_EPS) and not stop: + t += NS_parameters["dt"] tstep += 1 + NS_parameters["t"] = t + NS_parameters["tstep"] = tstep inner_iter = 0 - udiff = array([1e8]) # Norm of velocity change over last inner iter - num_iter = max(iters_on_first_timestep, max_iter) if tstep <= 10 else max_iter - - start_timestep_hook(**vars()) + udiff = np.array([1e8]) # Norm of velocity change over last inner iter + num_iter = max(it0, max_iter) if tstep <= 10 else max_iter + pblm.start_timestep_hook() # FIXME: what do we need to pass here? while udiff[0] > max_error and inner_iter < num_iter: inner_iter += 1 t0 = OasisTimer("Tentative velocity") if inner_iter == 1: - les_update(**vars()) - nn_update(**vars()) - assemble_first_inner_iter(**vars()) + lesmodel.les_update(**les_dict, **NS_parameters) + nnmodel.nn_update(**nn_dict, **NS_parameters) + solver.assemble_first_inner_iter( + scalar_components=scalar_components, + u_components=u_components, + **nn_dict, + **les_dict, + **F_dict, + **quantities, + **NS_parameters, + ) udiff[0] = 0.0 for i, ui in enumerate(u_components): t1 = OasisTimer("Solving tentative velocity " + ui, print_solve_info) - velocity_tentative_assemble(**vars()) - velocity_tentative_hook(**vars()) - velocity_tentative_solve(**vars()) + solver.velocity_tentative_assemble(ui=ui, **F_dict, **quantities) + pblm.velocity_tentative_hook(ui=ui, **quantities, **NS_parameters) + solver.velocity_tentative_solve( + udiff=udiff, + ui=ui, + u_sol=u_sol, + **F_dict, + **quantities, + **NS_parameters, + ) t1.stop() - t0 = OasisTimer("Pressure solve", print_solve_info) - pressure_assemble(**vars()) - pressure_hook(**vars()) - pressure_solve(**vars()) + solver.pressure_assemble(**quantities, **F_dict, **NS_parameters) + pblm.pressure_hook(**quantities) + solver.pressure_solve(p_sol=p_sol, **quantities, **F_dict) t0.stop() - print_velocity_pressure_info(**vars()) + solver.print_velocity_pressure_info( + num_iter=num_iter, + norm=df.norm, + info_blue=info_blue, + inner_iter=inner_iter, + udiff=udiff, + **quantities, + **NS_parameters, + ) # Update velocity t0 = OasisTimer("Velocity update") - velocity_update(**vars()) + solver.velocity_update( + u_components=u_components, + **quantities, + **F_dict, + **NS_parameters, + ) t0.stop() # Solve for scalars if len(scalar_components) > 0: - scalar_assemble(**vars()) + solver.scalar_assemble( + scalar_components=scalar_components, + Schmidt_T=pblm.Schmidt_T, + Schmidt=pblm.Schmidt, + **quantities, + **F_dict, + **nn_dict, + **les_dict, + **NS_parameters, + ) for ci in scalar_components: t1 = OasisTimer("Solving scalar {}".format(ci), print_solve_info) - scalar_hook(**vars()) - scalar_solve(**vars()) + pblm.scalar_hook() # FIXME: what do we need to pass here? + solver.scalar_solve( + scalar_components=scalar_components, + Schmidt=pblm.Schmidt, + c_sol=c_sol, + ci=ci, + **quantities, + **F_dict, + **NS_parameters, + ) t1.stop() - - temporal_hook(**vars()) + pblm.temporal_hook(**psh_dict, **quantities, **NS_parameters) # Save solution if required and check for killoasis file - stop = save_solution(**vars()) - + stop = io.save_solution( + newfolder=newfolder, + tstepfiles=tstepfiles, + u_components=u_components, + scalar_components=scalar_components, + NS_parameters=NS_parameters, + constrained_domain=pblm.constrained_domain, + AssignedVectorFunction=ut.AssignedVectorFunction, + total_timer=total_timer, + **NS_parameters, + **quantities, + ) # Update to a new timestep for ui in u_components: x_2[ui].zero() @@ -259,18 +382,18 @@ print_intermediate_info, toc ) ) - list_timings(TimingClear.clear, [TimingType.wall]) + solver.list_timings(df.TimingClear.clear, [df.TimingType.wall]) tx.start() # AB projection for pressure on next timestep - if AB_projection_pressure and t < (T - tstep * DOLFIN_EPS) and not stop: + if AB_projection_pressure and t < (T - tstep * df.DOLFIN_EPS) and not stop: x_["p"].axpy(0.5, dp_.vector()) total_timer.stop() -list_timings(TimingClear.keep, [TimingType.wall]) +solver.list_timings(df.TimingClear.keep, [df.TimingType.wall]) info_red("Total computing time = {0:f}".format(total_timer.elapsed()[0])) oasis_memory("Final memory use ") -total_initial_dolfin_memory = MPI.sum(MPI.comm_world, initial_memory_use) +total_initial_dolfin_memory = df.MPI.sum(df.MPI.comm_world, initial_memory_use) info_red( "Memory use for importing dolfin = {} MB (RSS)".format(total_initial_dolfin_memory) ) @@ -280,8 +403,15 @@ + " MB (RSS)" ) -if restart_folder is not None: - merge_visualization_files(**vars()) +if NS_parameters["restart_folder"] is not None: + io.merge_visualization_files(newfolder=newfolder) # Final hook -theend_hook(**vars()) +theend_hook(mesh=mesh, **psh_dict, **quantities, **NS_parameters) + +# F_dict.keys() = dict_keys(['A', 'M', 'K', 'Ap', 'divu', 'gradp', 'Ta', 'Tb', 'bb', 'bx', 'u_ab', 'a_conv', 'a_scalar', 'LT', 'KT', 'NT']) +# nn_dict.keys() = dict_keys(['nunn_']) +# les_dict.keys() = dict_keys(['nut_']) +# quantities.keys() = dict_keys(['u', 'u_', 'u_1', 'u_2', 'x_', 'x_1', 'x_2', 'b', 'b_tmp', 'p', 'p_', 'p_1', 'dp_', 'q', 'q_', 'q_1', 'q_2', 'v', 'V', 'Q', 'f', 'fs', 'bcs', 'b0']) +# NS_parameters.keys() = dict_keys(['nu', 'folder', 'velocity_degree', 'pressure_degree', 't', 'tstep', 'T', 'dt', 'AB_projection_pressure', 'solver', 'max_iter', 'max_error', 'iters_on_first_timestep', 'use_krylov_solvers', 'print_intermediate_info', 'print_velocity_pressure_convergence', 'plot_interval', 'checkpoint', 'save_step', 'restart_folder', 'output_timeseries_as_vector', 'killtime', 'les_model', 'Smagorinsky', 'Wale', 'DynamicSmagorinsky', 'KineticEnergySGS', 'nn_model', 'ModifiedCross', 'testing', 'krylov_solvers', 'velocity_update_solver', 'velocity_krylov_solver', 'pressure_krylov_solver', 'scalar_krylov_solver', 'nut_krylov_solver', 'nu_nn_krylov_solver']) +# psh_dict.keys() = dict_keys(['uv']) From a84c75a171329cc13b6fdef5ebd18f41b61948b3 Mon Sep 17 00:00:00 2001 From: flabowski Date: Thu, 24 Feb 2022 12:03:52 +0100 Subject: [PATCH 05/10] Autoformat for conformance to the PEP 8 convention. --- oasis/problems/NSfracStep/Channel.py | 189 ++++++++++++------ oasis/problems/NSfracStep/Cylinder.py | 3 - oasis/problems/NSfracStep/DrivenCavity3D.py | 29 +-- .../problems/NSfracStep/EccentricStenosis.py | 98 +++++---- oasis/problems/NSfracStep/FlowPastSphere3D.py | 46 +++-- oasis/problems/NSfracStep/LaminarChannel.py | 59 +++--- oasis/problems/NSfracStep/Lshape.py | 62 +++--- oasis/problems/NSfracStep/Skewed2D.py | 22 +- oasis/problems/NSfracStep/SkewedFlow.py | 44 ++-- oasis/problems/NSfracStep/TaylorGreen2D.py | 145 +++++++++----- oasis/problems/NSfracStep/TaylorGreen3D.py | 102 ++++++---- 11 files changed, 491 insertions(+), 308 deletions(-) diff --git a/oasis/problems/NSfracStep/Channel.py b/oasis/problems/NSfracStep/Channel.py index 9f1a691a..3196cccc 100644 --- a/oasis/problems/NSfracStep/Channel.py +++ b/oasis/problems/NSfracStep/Channel.py @@ -1,4 +1,5 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2013-06-25" __copyright__ = "Copyright (C) 2013 " + __author__ @@ -12,34 +13,41 @@ import random -def problem_parameters(commandline_kwargs, NS_parameters, NS_expressions, **NS_namespace): +def problem_parameters( + commandline_kwargs, NS_parameters, NS_expressions, **NS_namespace +): if "restart_folder" in commandline_kwargs.keys(): - restart_folder = commandline_kwargs["restart_folder"] - restart_folder = path.join(getcwd(), restart_folder) - f = open(path.join(path.dirname(path.abspath(__file__)), restart_folder, 'params.dat'), 'r') - NS_parameters.update(pickle.load(f)) - NS_parameters['restart_folder'] = restart_folder - globals().update(NS_parameters) + restart_folder = commandline_kwargs["restart_folder"] + restart_folder = path.join(getcwd(), restart_folder) + f = open( + path.join( + path.dirname(path.abspath(__file__)), restart_folder, "params.dat" + ), + "r", + ) + NS_parameters.update(pickle.load(f)) + NS_parameters["restart_folder"] = restart_folder + globals().update(NS_parameters) else: - Lx = 4. * pi - Ly = 2. - Lz = 4. * pi / 3. + Lx = 4.0 * pi + Ly = 2.0 + Lz = 4.0 * pi / 3.0 Nx = 16 Ny = 16 Nz = 16 NS_parameters.update(Lx=Lx, Ly=Ly, Lz=Lz, Nx=Nx, Ny=Ny, Nz=Nz) # Override some problem specific parameters - T = 1. + T = 1.0 dt = 0.2 - nu = 2.e-5 + nu = 2.0e-5 Re_tau = 178.12 NS_parameters.update( update_statistics=10, save_statistics=100, check_flux=10, checkpoint=100, - utau = nu * Re_tau, + utau=nu * Re_tau, save_step=100, nu=nu, Re_tau=Re_tau, @@ -47,7 +55,8 @@ def problem_parameters(commandline_kwargs, NS_parameters, NS_expressions, **NS_n dt=dt, velocity_degree=1, folder="channel_results", - use_krylov_solvers=True) + use_krylov_solvers=True, + ) NS_expressions.update(dict(constrained_domain=PeriodicDomain(Lx, Lz))) @@ -57,17 +66,19 @@ class ChannelGrid(StructuredGrid): def modify_mesh(self, dx, dy, dz): """Create grid skewed towards the walls located at y = 1 and y = -1""" - dy[1][:] = (arctan(pi * (dy[1][:] + self.origin[1])) / - arctan(pi) - self.origin[1]) + dy[1][:] = ( + arctan(pi * (dy[1][:] + self.origin[1])) / arctan(pi) - self.origin[1] + ) return dx, dy, dz def mesh(Nx, Ny, Nz, Lx, Ly, Lz, **params): # Function for creating stretched mesh in y-direction - m = BoxMesh(Point(0., -Ly / 2., -Lz / 2.), - Point(Lx, Ly / 2., Lz / 2.), Nx, Ny, Nz) + m = BoxMesh( + Point(0.0, -Ly / 2.0, -Lz / 2.0), Point(Lx, Ly / 2.0, Lz / 2.0), Nx, Ny, Nz + ) x = m.coordinates() - x[:, 1] = arctan(1. * pi * (x[:, 1])) / arctan(1. * pi) + x[:, 1] = arctan(1.0 * pi * (x[:, 1])) / arctan(1.0 * pi) return m @@ -79,11 +90,14 @@ def __init__(self, Lx, Lz): def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two slave edges - return bool((near(x[0], 0) or near(x[2], -self.Lz / 2.)) and - (not (near(x[0], self.Lx) or near(x[2], self.Lz / 2.))) and on_boundary) + return bool( + (near(x[0], 0) or near(x[2], -self.Lz / 2.0)) + and (not (near(x[0], self.Lx) or near(x[2], self.Lz / 2.0))) + and on_boundary + ) def map(self, x, y): - if near(x[0], self.Lx) and near(x[2], self.Lz / 2.): + if near(x[0], self.Lx) and near(x[2], self.Lz / 2.0): y[0] = x[0] - self.Lx y[1] = x[1] y[2] = x[2] - self.Lz @@ -96,15 +110,31 @@ def map(self, x, y): y[1] = x[1] y[2] = x[2] - self.Lz + def inlet(x, on_bnd): return on_bnd and near(x[0], 0) + # Specify body force def body_force(nu, Re_tau, utau, **NS_namespace): - return Constant((utau**2, 0., 0.)) - -def pre_solve_hook(V, u_, mesh, AssignedVectorFunction, newfolder, MPI, - Nx, Ny, Nz, Lx, Ly, Lz, **NS_namespace): + return Constant((utau ** 2, 0.0, 0.0)) + + +def pre_solve_hook( + V, + u_, + mesh, + AssignedVectorFunction, + newfolder, + MPI, + Nx, + Ny, + Nz, + Lx, + Ly, + Lz, + **NS_namespace +): """Called prior to time loop""" if MPI.rank(MPI.comm_world) == 0: makedirs(path.join(newfolder, "Stats")) @@ -113,27 +143,34 @@ def pre_solve_hook(V, u_, mesh, AssignedVectorFunction, newfolder, MPI, tol = 5e-8 # It's periodic so don't pick the same location twice for sampling statistics: - stats = ChannelGrid(V, [Nx, Ny + 1, Nz], [tol, -Ly / 2., -Lz / 2. + tol], [[1., 0., 0.], [ - 0., 1., 0.], [0., 0., 1.]], [Lx - Lx / Nx, Ly, Lz - Lz / Nz], statistics=True) + stats = ChannelGrid( + V, + [Nx, Ny + 1, Nz], + [tol, -Ly / 2.0, -Lz / 2.0 + tol], + [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + [Lx - Lx / Nx, Ly, Lz - Lz / Nz], + statistics=True, + ) # Create MeshFunction to compute flux Inlet = AutoSubDomain(inlet) - facets = MeshFunction('size_t', mesh, mesh.topology().dim() - 1, 0) + facets = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) Inlet.mark(facets, 1) normal = FacetNormal(mesh) return dict(uv=uv, stats=stats, facets=facets, normal=normal) + def create_bcs(V, q_, q_1, q_2, sys_comp, u_components, Ly, **NS_namespace): def walls(x, on_bnd): - return (near(x[1], -Ly / 2.) or near(x[1], Ly / 2.)) + return near(x[1], -Ly / 2.0) or near(x[1], Ly / 2.0) info_red("Creating boundary conditions") bcs = dict((ui, []) for ui in sys_comp) bc = [DirichletBC(V, Constant(0), walls)] - bcs['u0'] = bc - bcs['u1'] = bc - bcs['u2'] = bc + bcs["u0"] = bc + bcs["u1"] = bc + bcs["u2"] = bc return bcs @@ -148,36 +185,64 @@ def eval(self, values, x): def value_shape(self): return (3,) + def initialize(V, q_, q_1, q_2, bcs, restart_folder, utau, nu, **NS_namespace): if restart_folder is None: # Initialize using a perturbed flow. Create random streamfunction - Vv = VectorFunctionSpace(V.mesh(), V.ufl_element().family(), - V.ufl_element().degree()) + Vv = VectorFunctionSpace( + V.mesh(), V.ufl_element().family(), V.ufl_element().degree() + ) psi = interpolate(RandomStreamVector(element=Vv.ufl_element()), Vv) - u0 = project(curl(psi), Vv, solver_type='cg') - u0x = project(u0[0], V, bcs=bcs['u0'], solver_type='cg') - u1x = project(u0[1], V, bcs=bcs['u0'], solver_type='cg') - u2x = project(u0[2], V, bcs=bcs['u0'], solver_type='cg') + u0 = project(curl(psi), Vv, solver_type="cg") + u0x = project(u0[0], V, bcs=bcs["u0"], solver_type="cg") + u1x = project(u0[1], V, bcs=bcs["u0"], solver_type="cg") + u2x = project(u0[2], V, bcs=bcs["u0"], solver_type="cg") # Create base flow - y = interpolate(Expression("x[1] > 0 ? 1-x[1] : 1+x[1]", - element=V.ufl_element()), V) - uu = project((1.25 * (utau / 0.41 * ln(conditional(y < 1e-12, 1.e-12, y) * - utau / nu) + 5. * utau)), V, bcs=bcs['u0'], solver_type='cg') + y = interpolate( + Expression("x[1] > 0 ? 1-x[1] : 1+x[1]", element=V.ufl_element()), V + ) + uu = project( + ( + 1.25 + * ( + utau / 0.41 * ln(conditional(y < 1e-12, 1.0e-12, y) * utau / nu) + + 5.0 * utau + ) + ), + V, + bcs=bcs["u0"], + solver_type="cg", + ) # initialize vectors at two timesteps - q_1['u0'].vector()[:] = uu.vector()[:] - q_1['u0'].vector().axpy(1.0, u0x.vector()) - q_1['u1'].vector()[:] = u1x.vector()[:] - q_1['u2'].vector()[:] = u2x.vector()[:] - q_2['u0'].vector()[:] = q_1['u0'].vector()[:] - q_2['u1'].vector()[:] = q_1['u1'].vector()[:] - q_2['u2'].vector()[:] = q_1['u2'].vector()[:] - - -def temporal_hook(q_, u_, V, tstep, uv, stats, update_statistics, - newfolder, folder, check_flux, save_statistics, mesh, - facets, normal, check_if_reset_statistics, **NS_namespace): + q_1["u0"].vector()[:] = uu.vector()[:] + q_1["u0"].vector().axpy(1.0, u0x.vector()) + q_1["u1"].vector()[:] = u1x.vector()[:] + q_1["u2"].vector()[:] = u2x.vector()[:] + q_2["u0"].vector()[:] = q_1["u0"].vector()[:] + q_2["u1"].vector()[:] = q_1["u1"].vector()[:] + q_2["u2"].vector()[:] = q_1["u2"].vector()[:] + + +def temporal_hook( + q_, + u_, + V, + tstep, + uv, + stats, + update_statistics, + newfolder, + folder, + check_flux, + save_statistics, + mesh, + facets, + normal, + check_if_reset_statistics, + **NS_namespace +): # print timestep info_red("tstep = {}".format(tstep)) if check_if_reset_statistics(folder): @@ -185,24 +250,24 @@ def temporal_hook(q_, u_, V, tstep, uv, stats, update_statistics, stats.probes.clear() if tstep % update_statistics == 0: - stats(q_['u0'], q_['u1'], q_['u2']) + stats(q_["u0"], q_["u1"], q_["u2"]) if tstep % save_statistics == 0: statsfolder = path.join(newfolder, "Stats") - #stats.toh5(0, tstep, filename=statsfolder + + # stats.toh5(0, tstep, filename=statsfolder + # "/dump_mean_{}.h5".format(tstep)) - stats.tovtk(0, statsfolder+"/dump_mean_{}.vtk".format(tstep)) + stats.tovtk(0, statsfolder + "/dump_mean_{}.vtk".format(tstep)) if tstep % check_flux == 0: u1 = assemble(dot(u_, normal) * ds(1, domain=mesh, subdomain_data=facets)) u1 = assemble(dot(u_, normal) * ds(1, domain=mesh, subdomain_data=facets)) - normv = norm(q_['u1'].vector()) - normw = norm(q_['u2'].vector()) + normv = norm(q_["u1"].vector()) + normw = norm(q_["u2"].vector()) if MPI.rank(MPI.comm_world) == 0: print("Flux = ", u1, " tstep = ", tstep, " norm = ", normv, normw) + def theend(newfolder, tstep, stats, **NS_namespace): """Store statistics before exiting""" statsfolder = path.join(newfolder, "Stats") - stats.toh5(0, tstep, filename=statsfolder + - "/dump_mean_{}.h5".format(tstep)) + stats.toh5(0, tstep, filename=statsfolder + "/dump_mean_{}.h5".format(tstep)) diff --git a/oasis/problems/NSfracStep/Cylinder.py b/oasis/problems/NSfracStep/Cylinder.py index d0766ba3..af2105b5 100644 --- a/oasis/problems/NSfracStep/Cylinder.py +++ b/oasis/problems/NSfracStep/Cylinder.py @@ -5,12 +5,9 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -print(vars().keys()) from ..NSfracStep import * from ..Cylinder import * -print(vars().keys()) - # from oasis.NSfracStep import * # from oasis.problems.Cylinder import * from os import getcwd diff --git a/oasis/problems/NSfracStep/DrivenCavity3D.py b/oasis/problems/NSfracStep/DrivenCavity3D.py index 3d68c920..5cbf2c20 100644 --- a/oasis/problems/NSfracStep/DrivenCavity3D.py +++ b/oasis/problems/NSfracStep/DrivenCavity3D.py @@ -18,7 +18,8 @@ def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): Nz=15, plot_interval=20, print_intermediate_info=100, - use_krylov_solvers=True) + use_krylov_solvers=True, + ) NS_expressions.update(dict(constrained_domain=PeriodicDomain())) @@ -28,12 +29,11 @@ def mesh(Nx, Ny, Nz, **params): m = UnitCubeMesh(Nx, Ny, Nz) x = m.coordinates() x[:, :2] = (x[:, :2] - 0.5) * 2 - x[:, :2] = 0.5 * (cos(pi * (x[:, :2] - 1.) / 2.) + 1.) + x[:, :2] = 0.5 * (cos(pi * (x[:, :2] - 1.0) / 2.0) + 1.0) return m class PeriodicDomain(SubDomain): - def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two slave edges return bool(near(x[2], 0) and on_boundary) @@ -53,10 +53,7 @@ def create_bcs(V, **NS_namespace): bc00 = DirichletBC(V, 1, top) bc01 = DirichletBC(V, 0, top) - return dict(u0=[bc00, bc0], - u1=[bc01, bc0], - u2=[bc01, bc0], - p=[]) + return dict(u0=[bc00, bc0], u1=[bc01, bc0], u2=[bc01, bc0], p=[]) def initialize(x_1, x_2, bcs, **NS_namespace): @@ -65,19 +62,25 @@ def initialize(x_1, x_2, bcs, **NS_namespace): [bc.apply(x_2[ui]) for bc in bcs[ui]] -def pre_solve_hook(mesh, velocity_degree, constrained_domain, u_, - AssignedVectorFunction, **NS_namespace): +def pre_solve_hook( + mesh, + velocity_degree, + constrained_domain, + u_, + AssignedVectorFunction, + **NS_namespace +): return dict(uv=AssignedVectorFunction(u_)) def temporal_hook(tstep, u_, uv, p_, plot_interval, **NS_namespace): if tstep % plot_interval == 0: uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') + plot(uv, title="Velocity") + plot(p_, title="Pressure") def theend_hook(p_, uv, **NS_namespace): uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') + plot(uv, title="Velocity") + plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/EccentricStenosis.py b/oasis/problems/NSfracStep/EccentricStenosis.py index 6beca6a4..97b15dc7 100644 --- a/oasis/problems/NSfracStep/EccentricStenosis.py +++ b/oasis/problems/NSfracStep/EccentricStenosis.py @@ -28,32 +28,35 @@ import os import platform -def problem_parameters(NS_parameters, NS_expressions, commandline_kwargs, **NS_namespace): + +def problem_parameters( + NS_parameters, NS_expressions, commandline_kwargs, **NS_namespace +): Re = float(commandline_kwargs.get("Re", 600)) NS_parameters.update( - nu=0.0031078341013824886, # mm^2/ms #3.1078341E-6 m^2/s, #0.003372 Pa-s/1085 kg/m^3 this is nu_inf (m^2/s) - D=6.35, # 0.00635, - T=15e3, # ms - dt=0.1, # ms + nu=0.0031078341013824886, # mm^2/ms #3.1078341E-6 m^2/s, #0.003372 Pa-s/1085 kg/m^3 this is nu_inf (m^2/s) + D=6.35, # 0.00635, + T=15e3, # ms + dt=0.1, # ms Re=Re, - nn_model='ModifiedCross', + nn_model="ModifiedCross", ModifiedCross=dict( - lam=3.736e3, # ms - m_param=2.406, # for Non-Newtonian model - a_param=0.34, # for Non-Newtonian model - mu_inf=3.372e-6, # g/(mm*ms) for non-Newtonian model - mu_o=9e-5, # g/(mm*ms) for non-Newtonian model - rho=1085e-6, # g/mm^3 + lam=3.736e3, # ms + m_param=2.406, # for Non-Newtonian model + a_param=0.34, # for Non-Newtonian model + mu_inf=3.372e-6, # g/(mm*ms) for non-Newtonian model + mu_o=9e-5, # g/(mm*ms) for non-Newtonian model + rho=1085e-6, # g/mm^3 ), nu_nn_krylov_solver=dict( - method='default', - solver_type='cg', - preconditioner_type='jacobi', + method="default", + solver_type="cg", + preconditioner_type="jacobi", ), - mesh_file='eccentric_stenosis.xml.gz', + mesh_file="eccentric_stenosis.xml.gz", save_step=10, velocity_degree=1, - folder='eccentric_stenosis_results', + folder="eccentric_stenosis_results", krylov_solvers=dict( monitor_convergence=False, error_on_nonconvergence=True, @@ -63,19 +66,26 @@ def problem_parameters(NS_parameters, NS_expressions, commandline_kwargs, **NS_n checkpoint=1000, print_intermediate_info=100, print_velocity_pressure_convergence=False, - ) + ) - average_inlet_velocity = get_ave_inlet_velocity(NS_parameters['Re'], NS_parameters['nu'], NS_parameters['D']) + average_inlet_velocity = get_ave_inlet_velocity( + NS_parameters["Re"], NS_parameters["nu"], NS_parameters["D"] + ) NS_parameters.update(ave_inlet_velocity=average_inlet_velocity) - inflow_prof = get_inflow_prof(average_inlet_velocity, NS_parameters['D']) + inflow_prof = get_inflow_prof(average_inlet_velocity, NS_parameters["D"]) NS_expressions.update(dict(u_in=inflow_prof, noise=Noise())) + def mesh(mesh_file, **NS_namespace): if not os.path.isfile(mesh_file): if platform.system() == "Linux": - os.system(f"wget -O {mesh_file} https://ndownloader.figshare.com/files/28254414") + os.system( + f"wget -O {mesh_file} https://ndownloader.figshare.com/files/28254414" + ) elif platform.system() == "Darwin": - os.system(f"curl -L https://ndownloader.figshare.com/files/28254414 -o {mesh_file}") + os.system( + f"curl -L https://ndownloader.figshare.com/files/28254414 -o {mesh_file}" + ) else: raise ImportError("Could not determine platform") print(f"Downloaded mesh {mesh_file}") @@ -83,6 +93,7 @@ def mesh(mesh_file, **NS_namespace): mesh = Mesh(mesh_file) return mesh + class Noise(UserExpression): def __init__(self, **kwargs): super().__init__(**kwargs) @@ -90,26 +101,30 @@ def __init__(self, **kwargs): def eval(self, value, x): value[0] = np.random.normal(0, 0.001) + def create_bcs(V, Q, mesh, mesh_file, **NS_namespace): if MPI.rank(MPI.comm_world) == 0: print("Create bcs") boundaries = MeshFunction("size_t", mesh, 2, mesh.domains()) - boundaries.set_values(boundaries.array()+1) + boundaries.set_values(boundaries.array() + 1) wallId = 1 inletId = 2 outletId = 3 bc0 = DirichletBC(V, 0, boundaries, wallId) - bc1 = DirichletBC(V, NS_expressions['u_in'], boundaries, inletId) - bc2 = DirichletBC(V, NS_expressions['noise'], boundaries, inletId) - bc3 = DirichletBC(V, NS_expressions['noise'], boundaries, inletId) + bc1 = DirichletBC(V, NS_expressions["u_in"], boundaries, inletId) + bc2 = DirichletBC(V, NS_expressions["noise"], boundaries, inletId) + bc3 = DirichletBC(V, NS_expressions["noise"], boundaries, inletId) bc4 = DirichletBC(Q, 0, boundaries, outletId) - return dict(u0=[bc0, bc1], # 0 on the sides, u_in on inlet, zero gradient outlet - u1=[bc0, bc2], # 0 on sides and perturbed inlet, zero gradient outlet - u2=[bc0, bc3], # 0 on sides and perturbed inlet, zero gradient outlet - p=[bc4]) # 0 outlet + return dict( + u0=[bc0, bc1], # 0 on the sides, u_in on inlet, zero gradient outlet + u1=[bc0, bc2], # 0 on sides and perturbed inlet, zero gradient outlet + u2=[bc0, bc3], # 0 on sides and perturbed inlet, zero gradient outlet + p=[bc4], + ) # 0 outlet + def initialize(V, q_, q_1, q_2, x_1, x_2, bcs, restart_folder, **NS_namespace): for ui in x_1: @@ -117,32 +132,47 @@ def initialize(V, q_, q_1, q_2, x_1, x_2, bcs, restart_folder, **NS_namespace): for ui in x_2: [bc.apply(x_2[ui]) for bc in bcs[ui]] + def pre_solve_hook(u_, tstep, AssignedVectorFunction, folder, **NS_namespace): - visfile = XDMFFile(MPI.comm_world, path.join(folder, 'viscosity_from_tstep_{}.xdmf'.format(tstep))) + visfile = XDMFFile( + MPI.comm_world, path.join(folder, "viscosity_from_tstep_{}.xdmf".format(tstep)) + ) visfile.parameters["rewrite_function_mesh"] = False visfile.parameters["flush_output"] = True return dict(uv=AssignedVectorFunction(u_), visfile=visfile) + def velocity_tentative_hook(**NS_namespace): pass + def pressure_hook(**NS_namespace): pass + def start_timestep_hook(**NS_namespace): pass + def temporal_hook(tstep, save_step, visfile, nunn_, folder, **NS_namespace): if tstep % save_step == 0: visfile.write(nunn_, float(tstep)) + def theend_hook(**NS_namespace): pass -def get_ave_inlet_velocity(Re, nu, D,**NS_namespace): - average_inlet_velocity = Re*nu/D + +def get_ave_inlet_velocity(Re, nu, D, **NS_namespace): + average_inlet_velocity = Re * nu / D return average_inlet_velocity + def get_inflow_prof(average_inlet_velocity, D, **NS_namespace): - u_inflow = Expression('A*2*(1-((x[1]*x[1])+(x[2]*x[2]))*4/(D*D))', degree=2, A=average_inlet_velocity, D=D) + u_inflow = Expression( + "A*2*(1-((x[1]*x[1])+(x[2]*x[2]))*4/(D*D))", + degree=2, + A=average_inlet_velocity, + D=D, + ) return u_inflow diff --git a/oasis/problems/NSfracStep/FlowPastSphere3D.py b/oasis/problems/NSfracStep/FlowPastSphere3D.py index 5409ca64..13e8111b 100644 --- a/oasis/problems/NSfracStep/FlowPastSphere3D.py +++ b/oasis/problems/NSfracStep/FlowPastSphere3D.py @@ -11,7 +11,7 @@ # Create a mesh def mesh(**params): - m = Mesh('/home/mikael/MySoftware/Oasis/mymesh/boxwithsphererefined.xml') + m = Mesh("/home/mikael/MySoftware/Oasis/mymesh/boxwithsphererefined.xml") return m @@ -19,10 +19,10 @@ def problem_parameters(commandline_kwargs, NS_parameters, **NS_namespace): if "restart_folder" in commandline_kwargs.keys(): restart_folder = commandline_kwargs["restart_folder"] restart_folder = path.join(getcwd(), restart_folder) - f = open(path.join(restart_folder, 'params.dat'), 'r') + f = open(path.join(restart_folder, "params.dat"), "r") NS_parameters.update(pickle.load(f)) - NS_parameters['T'] = NS_parameters['T'] + 10 * NS_parameters['dt'] - NS_parameters['restart_folder'] = restart_folder + NS_parameters["T"] = NS_parameters["T"] + 10 * NS_parameters["dt"] + NS_parameters["restart_folder"] = restart_folder globals().update(NS_parameters) else: @@ -37,28 +37,34 @@ def problem_parameters(commandline_kwargs, NS_parameters, **NS_namespace): velocity_degree=2, plot_interval=10, print_intermediate_info=10, - use_krylov_solvers=True) - NS_parameters['krylov_solvers']['monitor_convergence'] = True + use_krylov_solvers=True, + ) + NS_parameters["krylov_solvers"]["monitor_convergence"] = True def create_bcs(V, Q, mesh, **NS_namespace): # Specify boundary conditions walls = "on_boundary && std::abs((x[1]-3)*(x[1]+3)*(x[2]-3)*(x[2]+3))<1e-8" - inners = "on_boundary && std::sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]) < 1.5*{}".format(h) + inners = "on_boundary && std::sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]) < 1.5*{}".format( + h + ) inlet = "x[0] < -3+1e-8 && on_boundary" outlet = "x[0] > 6-1e-8 && on_boundary" - bmesh = BoundaryMesh(mesh, 'exterior') - cc = MeshFunction('size_t', bmesh, bmesh.topology().dim(), 0) + bmesh = BoundaryMesh(mesh, "exterior") + cc = MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) ii = AutoSubDomain(lambda x, on_bnd: near(x[0], -3)) ii.mark(cc, 1) smesh = SubMesh(bmesh, cc, 1) - Vu = FunctionSpace(smesh, 'CG', 1) + Vu = FunctionSpace(smesh, "CG", 1) su = Function(Vu) us = TrialFunction(Vu) vs = TestFunction(Vu) - solve(inner(grad(us), grad(vs)) * dx == Constant(0.1) * vs * dx, su, - bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())]) + solve( + inner(grad(us), grad(vs)) * dx == Constant(0.1) * vs * dx, + su, + bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())], + ) lp = LagrangeInterpolator() sv = Function(V) @@ -69,25 +75,21 @@ def create_bcs(V, Q, mesh, **NS_namespace): bcp1 = DirichletBC(Q, 0, outlet) bc2 = DirichletBC(V, 0, inlet) bc3 = DirichletBC(V, sv, inlet) - return dict(u0=[bc0, bc1, bc3], - u1=[bc0, bc1, bc2], - u2=[bc0, bc1, bc2], - p=[bcp1]) + return dict(u0=[bc0, bc1, bc3], u1=[bc0, bc1, bc2], u2=[bc0, bc1, bc2], p=[bcp1]) -def pre_solve_hook(mesh, velocity_degree, u_, - AssignedVectorFunction, **NS_namespace): +def pre_solve_hook(mesh, velocity_degree, u_, AssignedVectorFunction, **NS_namespace): return dict(uv=AssignedVectorFunction(u_)) def temporal_hook(tstep, uv, p_, plot_interval, **NS_namespace): if tstep % plot_interval == 0: uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') + plot(uv, title="Velocity") + plot(p_, title="Pressure") def theend_hook(p_, uv, **NS_namespace): uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') + plot(uv, title="Velocity") + plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/LaminarChannel.py b/oasis/problems/NSfracStep/LaminarChannel.py index dcfa2510..cf22bfa2 100644 --- a/oasis/problems/NSfracStep/LaminarChannel.py +++ b/oasis/problems/NSfracStep/LaminarChannel.py @@ -1,4 +1,5 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2013-06-25" __copyright__ = "Copyright (C) 2013 " + __author__ @@ -6,38 +7,42 @@ from ..NSfracStep import * from numpy import pi, arctan, array -#set_log_active(False) + +# set_log_active(False) # Override some problem specific parameters def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): nu = 0.01 - Re = 1. / nu - L = 10. - NS_parameters.update(dict( - nu=nu, - L=L, - H=1., - T=10, - dt=0.01, - Re=Re, - Nx=40, - Ny=40, - folder="laminarchannel_results", - max_iter=1, - velocity_degree=1, - use_krylov_solvers=False)) + Re = 1.0 / nu + L = 10.0 + NS_parameters.update( + dict( + nu=nu, + L=L, + H=1.0, + T=10, + dt=0.01, + Re=Re, + Nx=40, + Ny=40, + folder="laminarchannel_results", + max_iter=1, + velocity_degree=1, + use_krylov_solvers=False, + ) + ) NS_expressions.update(dict(constrained_domain=PeriodicDomain(L))) # Create a mesh here def mesh(Nx, Ny, L, H, **params): - m = RectangleMesh(Point(0., -H), Point(L, H), Nx, Ny) + m = RectangleMesh(Point(0.0, -H), Point(L, H), Nx, Ny) # Squeeze towards walls x = m.coordinates() - x[:, 1] = arctan(1. * pi * (x[:, 1])) / arctan(1. * pi) + x[:, 1] = arctan(1.0 * pi * (x[:, 1])) / arctan(1.0 * pi) return m @@ -56,25 +61,25 @@ def map(self, x, y): def create_bcs(V, H, sys_comp, **NS_namespace): def walls(x, on_boundary): - return (on_boundary and (near(x[1], -H) or near(x[1], H))) + return on_boundary and (near(x[1], -H) or near(x[1], H)) bcs = dict((ui, []) for ui in sys_comp) - bc0 = DirichletBC(V, 0., walls) - bcs['u0'] = [bc0] - bcs['u1'] = [bc0] + bc0 = DirichletBC(V, 0.0, walls) + bcs["u0"] = [bc0] + bcs["u1"] = [bc0] return bcs def body_force(Re, **NS_namespace): - return Constant((2. / Re, 0.)) + return Constant((2.0 / Re, 0.0)) def reference(Re, t, num_terms=100): u = 1.0 c = 1.0 for n in range(1, 2 * num_terms, 2): - a = 32. / (pi**3 * n**3) - b = (0.25 / Re) * pi**2 * n**2 + a = 32.0 / (pi ** 3 * n ** 3) + b = (0.25 / Re) * pi ** 2 * n ** 2 c = -c u += a * exp(-b * t) * c return u @@ -82,10 +87,10 @@ def reference(Re, t, num_terms=100): def temporal_hook(tstep, q_, t, Re, L, **NS_namespace): if tstep % 20 == 0: - plot(q_['u0']) + plot(q_["u0"]) try: # point is found on one processor, the others pass - u_computed = q_['u0'](array([L, 0.])) + u_computed = q_["u0"](array([L, 0.0])) u_exact = reference(Re, t) print("Error = ", (u_exact - u_computed) / u_exact) except: diff --git a/oasis/problems/NSfracStep/Lshape.py b/oasis/problems/NSfracStep/Lshape.py index db8db4d1..204333b2 100644 --- a/oasis/problems/NSfracStep/Lshape.py +++ b/oasis/problems/NSfracStep/Lshape.py @@ -7,28 +7,33 @@ import matplotlib.pyplot as plt # Override some problem specific parameters -def problem_parameters(NS_parameters, commandline_kwargs, NS_expressions, **NS_namespace): - Re = 500. - nu = 1. / Re - NS_parameters.update(dict( - nu=nu, - T=10, - dt=0.01, - Re=Re, - Nx=40, - Ny=40, - folder="Lshape_results", - max_iter=1, - plot_interval=1, - velocity_degree=2, - use_krylov_solvers=True)) +def problem_parameters( + NS_parameters, commandline_kwargs, NS_expressions, **NS_namespace +): + Re = 500.0 + nu = 1.0 / Re + NS_parameters.update( + dict( + nu=nu, + T=10, + dt=0.01, + Re=Re, + Nx=40, + Ny=40, + folder="Lshape_results", + max_iter=1, + plot_interval=1, + velocity_degree=2, + use_krylov_solvers=True, + ) + ) if "pressure_degree" in commandline_kwargs.keys(): degree = commandline_kwargs["pressure_degree"] else: degree = NS_parameters["pressure_degree"] - NS_expressions.update(dict(p_in=Expression("sin(pi*t)", t=0., degree=degree))) + NS_expressions.update(dict(p_in=Expression("sin(pi*t)", t=0.0, degree=degree))) # Create a mesh here @@ -47,32 +52,35 @@ def mesh(Nx, Ny, **params): def inlet(x, on_boundary): - return near(x[1] - 1., 0.) and on_boundary + return near(x[1] - 1.0, 0.0) and on_boundary def outlet(x, on_boundary): - return near(x[0] - 1., 0.) and on_boundary + return near(x[0] - 1.0, 0.0) and on_boundary def walls(x, on_boundary): - return (near(x[0], 0.) or near(x[1], 0.) or - (x[0] > 0.25 - 5 * DOLFIN_EPS and - x[1] > 0.25 - 5 * DOLFIN_EPS) and on_boundary) + return ( + near(x[0], 0.0) + or near(x[1], 0.0) + or (x[0] > 0.25 - 5 * DOLFIN_EPS and x[1] > 0.25 - 5 * DOLFIN_EPS) + and on_boundary + ) def create_bcs(V, Q, sys_comp, p_in, **NS_namespace): bcs = dict((ui, []) for ui in sys_comp) - bc0 = DirichletBC(V, 0., walls) + bc0 = DirichletBC(V, 0.0, walls) pc0 = DirichletBC(Q, p_in, inlet) pc1 = DirichletBC(Q, 0.0, outlet) - bcs['u0'] = [bc0] - bcs['u1'] = [bc0] - bcs['p'] = [pc0, pc1] + bcs["u0"] = [bc0] + bcs["u1"] = [bc0] + bcs["p"] = [pc0, pc1] return bcs def pre_solve_hook(mesh, OasisFunction, u_, **NS_namespace): - Vv = VectorFunctionSpace(mesh, 'CG', 1) + Vv = VectorFunctionSpace(mesh, "CG", 1) return dict(Vv=Vv, uv=OasisFunction(u_, Vv)) @@ -82,7 +90,7 @@ def start_timestep_hook(t, p_in, **NS_namespace): def temporal_hook(tstep, q_, u_, uv, Vv, plot_interval, **NS_namespace): if tstep % plot_interval == 0: - plot(q_['p'], title="Pressure") + plot(q_["p"], title="Pressure") uv() # uv = project(u_, Vv) plot(uv, title="Velocity") plt.show() diff --git a/oasis/problems/NSfracStep/Skewed2D.py b/oasis/problems/NSfracStep/Skewed2D.py index e6b962c6..ac35c7be 100644 --- a/oasis/problems/NSfracStep/Skewed2D.py +++ b/oasis/problems/NSfracStep/Skewed2D.py @@ -1,4 +1,5 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2013-06-25" __copyright__ = "Copyright (C) 2013 " + __author__ @@ -14,7 +15,8 @@ def problem_parameters(NS_parameters, **NS_namespace): T=10.0, dt=0.05, use_krylov_solvers=True, - print_velocity_pressure_convergence=True) + print_velocity_pressure_convergence=True, + ) def create_bcs(V, Q, mesh, **NS_namespace): @@ -22,26 +24,26 @@ def create_bcs(V, Q, mesh, **NS_namespace): bc0 = DirichletBC(V, 0, walls) bc1 = DirichletBC(V, u_inlet, inlet) bc2 = DirichletBC(V, 0, inlet) - return dict(u0=[bc1, bc0], - u1=[bc2, bc0], - p=[DirichletBC(Q, 0, outlet)]) + return dict(u0=[bc1, bc0], u1=[bc2, bc0], p=[DirichletBC(Q, 0, outlet)]) def pre_solve_hook(mesh, u_, AssignedVectorFunction, **NS_namespace): return dict(uv=AssignedVectorFunction(u_, "Velocity"), n=FacetNormal(mesh)) -def temporal_hook(u_, p_, mesh, tstep, print_intermediate_info, - uv, n, plot_interval, **NS_namespace): + +def temporal_hook( + u_, p_, mesh, tstep, print_intermediate_info, uv, n, plot_interval, **NS_namespace +): if tstep % print_intermediate_info == 0: print("Continuity ", assemble(dot(u_, n) * ds())) if tstep % plot_interval == 0: uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') + plot(uv, title="Velocity") + plot(p_, title="Pressure") def theend_hook(uv, p_, **NS_namespace): uv() - plot(uv, title='Velocity') - plot(p_, title='Pressure') + plot(uv, title="Velocity") + plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/SkewedFlow.py b/oasis/problems/NSfracStep/SkewedFlow.py index e6554e01..18a4be5c 100644 --- a/oasis/problems/NSfracStep/SkewedFlow.py +++ b/oasis/problems/NSfracStep/SkewedFlow.py @@ -1,4 +1,5 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2013-06-25" __copyright__ = "Copyright (C) 2013 " + __author__ @@ -8,7 +9,8 @@ from ..SkewedFlow import * from numpy import cos, pi, cosh -print(""" +print( + """ This problem does not work well with IPCS since the outflow boundary condition @@ -22,7 +24,8 @@ or extrude outlet such that the outflow boundary condition becomes more realistic. -""") +""" +) # Override some problem specific parameters def problem_parameters(NS_parameters, **NS_namespace): @@ -31,22 +34,26 @@ def problem_parameters(NS_parameters, **NS_namespace): T=0.05, dt=0.01, use_krylov_solvers=True, - print_velocity_pressure_convergence=True) + print_velocity_pressure_convergence=True, + ) def create_bcs(V, Q, mesh, **NS_namespace): # Create inlet profile by solving Poisson equation on boundary - bmesh = BoundaryMesh(mesh, 'exterior') - cc = MeshFunction('size_t', bmesh, bmesh.topology().dim(), 0) + bmesh = BoundaryMesh(mesh, "exterior") + cc = MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) ii = AutoSubDomain(inlet) ii.mark(cc, 1) smesh = SubMesh(bmesh, cc, 1) - Vu = FunctionSpace(smesh, 'CG', 1) + Vu = FunctionSpace(smesh, "CG", 1) su = Function(Vu) us = TrialFunction(Vu) vs = TestFunction(Vu) - solve(inner(grad(us), grad(vs)) * dx == Constant(10.0) * vs * dx, su, - bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())]) + solve( + inner(grad(us), grad(vs)) * dx == Constant(10.0) * vs * dx, + su, + bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())], + ) # Wrap the boundary function in an Expression to avoid the need to interpolate it back to V class MyExp(UserExpression): @@ -59,22 +66,23 @@ def eval(self, values, x): bc0 = DirichletBC(V, 0, walls) bc1 = DirichletBC(V, MyExp(element=V.ufl_element()), inlet) bc2 = DirichletBC(V, 0, inlet) - return dict(u0=[bc0, bc1], - u1=[bc0, bc2], - u2=[bc0, bc2], - p=[DirichletBC(Q, 0, outlet)]) + return dict( + u0=[bc0, bc1], u1=[bc0, bc2], u2=[bc0, bc2], p=[DirichletBC(Q, 0, outlet)] + ) + -def temporal_hook(u_, mesh, tstep, print_intermediate_info, - plot_interval, **NS_namespace): +def temporal_hook( + u_, mesh, tstep, print_intermediate_info, plot_interval, **NS_namespace +): if tstep % print_intermediate_info == 0: print("Continuity ", assemble(dot(u_, FacetNormal(mesh)) * ds())) if tstep % plot_interval == 0: - plot(u_, title='Velocity') - plot(p_, title='Pressure') + plot(u_, title="Velocity") + plot(p_, title="Pressure") def theend_hook(u_, p_, **NS_namespace): - plot(u_, title='Velocity') - plot(p_, title='Pressure') + plot(u_, title="Velocity") + plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/TaylorGreen2D.py b/oasis/problems/NSfracStep/TaylorGreen2D.py index 1e09848f..f8d7f2f4 100644 --- a/oasis/problems/NSfracStep/TaylorGreen2D.py +++ b/oasis/problems/NSfracStep/TaylorGreen2D.py @@ -1,10 +1,12 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2013-06-25" __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" from ..NSfracStep import * + try: from matplotlib import pyplot as plt except: @@ -14,9 +16,10 @@ def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): NS_parameters.update( nu=0.01, - T=1., + T=1.0, dt=0.001, - Nx=20, Ny=20, + Nx=20, + Ny=20, folder="taylorgreen2D_results", plot_interval=1000, save_step=10000, @@ -26,21 +29,30 @@ def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): use_krylov_solvers=True, velocity_degree=1, pressure_degree=1, - krylov_report=False) - - NS_parameters['krylov_solvers'] = {'monitor_convergence': False, - 'report': False, - 'relative_tolerance': 1e-12, - 'absolute_tolerance': 1e-12} - NS_expressions.update(dict( - constrained_domain=PeriodicDomain(), - initial_fields=dict( - u0='-sin(pi*x[1])*cos(pi*x[0])*exp(-2.*pi*pi*nu*t)', - u1='sin(pi*x[0])*cos(pi*x[1])*exp(-2.*pi*pi*nu*t)', - p='-(cos(2*pi*x[0])+cos(2*pi*x[1]))*exp(-4.*pi*pi*nu*t)/4.'), - dpdx=('sin(2*pi*x[0])*2*pi*exp(-4.*pi*pi*nu*t)/4.', - 'sin(2*pi*x[1])*2*pi*exp(-4.*pi*pi*nu*t)/4.'), - total_error=zeros(3))) + krylov_report=False, + ) + + NS_parameters["krylov_solvers"] = { + "monitor_convergence": False, + "report": False, + "relative_tolerance": 1e-12, + "absolute_tolerance": 1e-12, + } + NS_expressions.update( + dict( + constrained_domain=PeriodicDomain(), + initial_fields=dict( + u0="-sin(pi*x[1])*cos(pi*x[0])*exp(-2.*pi*pi*nu*t)", + u1="sin(pi*x[0])*cos(pi*x[1])*exp(-2.*pi*pi*nu*t)", + p="-(cos(2*pi*x[0])+cos(2*pi*x[1]))*exp(-4.*pi*pi*nu*t)/4.", + ), + dpdx=( + "sin(2*pi*x[0])*2*pi*exp(-4.*pi*pi*nu*t)/4.", + "sin(2*pi*x[1])*2*pi*exp(-4.*pi*pi*nu*t)/4.", + ), + total_error=zeros(3), + ) + ) def mesh(Nx, Ny, **params): @@ -48,12 +60,18 @@ def mesh(Nx, Ny, **params): class PeriodicDomain(SubDomain): - def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two corners (0, 2) and (2, 0) - return bool((near(x[0], 0) or near(x[1], 0)) and - (not ((near(x[0], 0) and near(x[1], 2)) or - (near(x[0], 2) and near(x[1], 0)))) and on_boundary) + return bool( + (near(x[0], 0) or near(x[1], 0)) + and ( + not ( + (near(x[0], 0) and near(x[1], 2)) + or (near(x[0], 2) and near(x[1], 0)) + ) + ) + and on_boundary + ) def map(self, x, y): if near(x[0], 2) and near(x[1], 2): @@ -74,26 +92,47 @@ def initialize(q_, q_1, q_2, VV, t, nu, dt, initial_fields, **NS_namespace): """ for ui in q_: - if 'IPCS' in NS_parameters['solver']: - deltat = dt / 2. if ui is 'p' else 0. + if "IPCS" in NS_parameters["solver"]: + deltat = dt / 2.0 if ui is "p" else 0.0 else: - deltat = 0. - vv = interpolate(Expression((initial_fields[ui]), - element=VV[ui].ufl_element(), - t=t + deltat, nu=nu), VV[ui]) + deltat = 0.0 + vv = interpolate( + Expression( + (initial_fields[ui]), element=VV[ui].ufl_element(), t=t + deltat, nu=nu + ), + VV[ui], + ) q_[ui].vector()[:] = vv.vector()[:] - if not ui == 'p': + if not ui == "p": q_1[ui].vector()[:] = vv.vector()[:] deltat = -dt - vv = interpolate(Expression((initial_fields[ui]), - element=VV[ui].ufl_element(), - t=t + deltat, nu=nu), VV[ui]) + vv = interpolate( + Expression( + (initial_fields[ui]), + element=VV[ui].ufl_element(), + t=t + deltat, + nu=nu, + ), + VV[ui], + ) q_2[ui].vector()[:] = vv.vector()[:] - q_1['p'].vector()[:] = q_['p'].vector()[:] - - -def temporal_hook(q_, t, nu, VV, dt, plot_interval, initial_fields, tstep, sys_comp, - compute_error, total_error, **NS_namespace): + q_1["p"].vector()[:] = q_["p"].vector()[:] + + +def temporal_hook( + q_, + t, + nu, + VV, + dt, + plot_interval, + initial_fields, + tstep, + sys_comp, + compute_error, + total_error, + **NS_namespace +): """Function called at end of timestep. Plot solution and compute error by comparing to analytical solution. @@ -101,9 +140,9 @@ def temporal_hook(q_, t, nu, VV, dt, plot_interval, initial_fields, tstep, sys_c """ if tstep % plot_interval == 0: - plot(q_['u0'], title='u') - plot(q_['u1'], title='v') - plot(q_['p'], title='p') + plot(q_["u0"], title="u") + plot(q_["u1"], title="v") + plot(q_["p"], title="p") try: plt.show() except: @@ -112,13 +151,13 @@ def temporal_hook(q_, t, nu, VV, dt, plot_interval, initial_fields, tstep, sys_c if tstep % compute_error == 0: err = {} for i, ui in enumerate(sys_comp): - if 'IPCS' in NS_parameters['solver']: - deltat_ = dt / 2. if ui is 'p' else 0. + if "IPCS" in NS_parameters["solver"]: + deltat_ = dt / 2.0 if ui is "p" else 0.0 else: - deltat_ = 0. - ue = Expression((initial_fields[ui]), - element=VV[ui].ufl_element(), - t=t - deltat_, nu=nu) + deltat_ = 0.0 + ue = Expression( + (initial_fields[ui]), element=VV[ui].ufl_element(), t=t - deltat_, nu=nu + ) ue = interpolate(ue, VV[ui]) uen = norm(ue.vector()) ue.vector().axpy(-1, q_[ui].vector()) @@ -129,16 +168,18 @@ def temporal_hook(q_, t, nu, VV, dt, plot_interval, initial_fields, tstep, sys_c print("Error is ", err, " at time = ", t) -def theend_hook(mesh, q_, t, dt, nu, VV, sys_comp, total_error, initial_fields, **NS_namespace): +def theend_hook( + mesh, q_, t, dt, nu, VV, sys_comp, total_error, initial_fields, **NS_namespace +): final_error = zeros(len(sys_comp)) for i, ui in enumerate(sys_comp): - if 'IPCS' in NS_parameters['solver']: - deltat = dt / 2. if ui is 'p' else 0. + if "IPCS" in NS_parameters["solver"]: + deltat = dt / 2.0 if ui is "p" else 0.0 else: - deltat = 0. - ue = Expression((initial_fields[ui]), - element=VV[ui].ufl_element(), - t=t - deltat, nu=nu) + deltat = 0.0 + ue = Expression( + (initial_fields[ui]), element=VV[ui].ufl_element(), t=t - deltat, nu=nu + ) ue = interpolate(ue, VV[ui]) final_error[i] = errornorm(q_[ui], ue) diff --git a/oasis/problems/NSfracStep/TaylorGreen3D.py b/oasis/problems/NSfracStep/TaylorGreen3D.py index 4ee12425..402bad05 100644 --- a/oasis/problems/NSfracStep/TaylorGreen3D.py +++ b/oasis/problems/NSfracStep/TaylorGreen3D.py @@ -5,33 +5,42 @@ from ..NSfracStep import * + def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): # Override some problem specific parameters - recursive_update(NS_parameters, dict( - nu=0.005, - T=0.2, - dt=0.01, - Nx=33, - Ny=33, - Nz=33, - folder="taylorgreen3D_results", - max_iter=1, - velocity_degree=1, - save_step=10000, - checkpoint=10000, - plot_interval=10, - print_dkdt_info=10000, - use_krylov_solvers=True, - krylov_solvers=dict(monitor_convergence=True))) - - NS_expressions.update(dict( - constrained_domain=PeriodicDomain(), - kin=zeros(1), - initial_fields=dict( - u0='sin(x[0])*cos(x[1])*cos(x[2])', - u1='-cos(x[0])*sin(x[1])*cos(x[2])', - u2='0', - p='1./16.*(cos(2*x[0])+cos(2*x[1]))*(cos(2*x[2])+2)'))) + recursive_update( + NS_parameters, + dict( + nu=0.005, + T=0.2, + dt=0.01, + Nx=33, + Ny=33, + Nz=33, + folder="taylorgreen3D_results", + max_iter=1, + velocity_degree=1, + save_step=10000, + checkpoint=10000, + plot_interval=10, + print_dkdt_info=10000, + use_krylov_solvers=True, + krylov_solvers=dict(monitor_convergence=True), + ), + ) + + NS_expressions.update( + dict( + constrained_domain=PeriodicDomain(), + kin=zeros(1), + initial_fields=dict( + u0="sin(x[0])*cos(x[1])*cos(x[2])", + u1="-cos(x[0])*sin(x[1])*cos(x[2])", + u2="0", + p="1./16.*(cos(2*x[0])+cos(2*x[1]))*(cos(2*x[2])+2)", + ), + ) + ) def mesh(Nx, Ny, Nz, **params): @@ -43,10 +52,12 @@ def near(x, y, tol=1e-12): class PeriodicDomain(SubDomain): - def inside(self, x, on_boundary): - return bool((near(x[0], -pi) or near(x[1], -pi) or near(x[2], -pi)) and - (not (near(x[0], pi) or near(x[1], pi) or near(x[2], pi))) and on_boundary) + return bool( + (near(x[0], -pi) or near(x[1], -pi) or near(x[2], -pi)) + and (not (near(x[0], pi) or near(x[1], pi) or near(x[2], pi))) + and on_boundary + ) def map(self, x, y): if near(x[0], pi) and near(x[1], pi) and near(x[2], pi): @@ -81,30 +92,41 @@ def map(self, x, y): def initialize(q_, q_1, q_2, VV, initial_fields, OasisFunction, **NS_namespace): for ui in q_: - vv = OasisFunction(Expression((initial_fields[ui]), - element=VV[ui].ufl_element()), VV[ui]) + vv = OasisFunction( + Expression((initial_fields[ui]), element=VV[ui].ufl_element()), VV[ui] + ) vv() q_[ui].vector()[:] = vv.vector()[:] - if not ui == 'p': + if not ui == "p": q_1[ui].vector()[:] = q_[ui].vector()[:] q_2[ui].vector()[:] = q_[ui].vector()[:] -def temporal_hook(u_, p_, tstep, plot_interval, print_dkdt_info, nu, - dt, t, oasis_memory, kin, **NS_namespace): +def temporal_hook( + u_, + p_, + tstep, + plot_interval, + print_dkdt_info, + nu, + dt, + t, + oasis_memory, + kin, + **NS_namespace +): oasis_memory("tmp", True) - if (tstep % print_dkdt_info == 0 or - tstep % print_dkdt_info == 1): - kinetic = assemble(0.5 * dot(u_, u_) * dx) / (2 * pi)**3 + if tstep % print_dkdt_info == 0 or tstep % print_dkdt_info == 1: + kinetic = assemble(0.5 * dot(u_, u_) * dx) / (2 * pi) ** 3 if tstep % print_dkdt_info == 0: kin[0] = kinetic - dissipation = assemble(nu * inner(grad(u_), grad(u_)) * dx) / (2 * pi)**3 + dissipation = assemble(nu * inner(grad(u_), grad(u_)) * dx) / (2 * pi) ** 3 info_blue("Kinetic energy = {} at time = {}".format(kinetic, t)) info_blue("Energy dissipation rate = {}".format(dissipation)) else: info_blue("dk/dt = {} at time = {}".format((kinetic - kin[0]) / dt, t)) if tstep % plot_interval == 0: - plot(p_, title='pressure') - plot(u_[0], title='velocity-x') - plot(u_[1], title='velocity-y') + plot(p_, title="pressure") + plot(u_[0], title="velocity-x") + plot(u_[1], title="velocity-y") From c1b824c1704383e51b485122d840a8bec0d9b17b Mon Sep 17 00:00:00 2001 From: flabowski Date: Thu, 24 Feb 2022 17:27:49 +0100 Subject: [PATCH 06/10] made imports explicit and changed how NS_parameters is handled. Removed some function arguments that are imported on top. --- oasis/NSfracStep.py | 169 ++++++++---------- oasis/common/io.py | 5 +- oasis/problems/Cylinder.py | 57 +++--- oasis/problems/NSfracStep/Channel.py | 149 +++++++++------ oasis/problems/NSfracStep/Cylinder.py | 89 +++++++-- oasis/problems/NSfracStep/DrivenCavity.py | 86 ++------- oasis/problems/NSfracStep/DrivenCavity3D.py | 57 ++++-- .../problems/NSfracStep/EccentricStenosis.py | 67 ++++--- oasis/problems/NSfracStep/FlowPastSphere3D.py | 91 ++++++---- oasis/problems/NSfracStep/LaminarChannel.py | 81 ++++++--- oasis/problems/NSfracStep/Lshape.py | 100 +++++++---- oasis/problems/NSfracStep/Skewed2D.py | 59 ++++-- oasis/problems/NSfracStep/SkewedFlow.py | 82 ++++++--- oasis/problems/NSfracStep/TaylorGreen2D.py | 116 ++++++++---- oasis/problems/NSfracStep/TaylorGreen3D.py | 105 +++++++---- oasis/problems/NSfracStep/__init__.py | 15 +- oasis/problems/__init__.py | 36 ++-- 17 files changed, 827 insertions(+), 537 deletions(-) diff --git a/oasis/NSfracStep.py b/oasis/NSfracStep.py index d48a3f23..a4a6d969 100755 --- a/oasis/NSfracStep.py +++ b/oasis/NSfracStep.py @@ -41,6 +41,7 @@ from oasis.common import parse_command_line # ,convert import oasis.common.utilities as ut from ufl import Coefficient +from oasis.problems.NSfracStep import default_parameters from oasis.problems import ( info_blue, info_green, @@ -48,42 +49,54 @@ OasisTimer, initial_memory_use, oasis_memory, + post_import_problem, ) +# TODO: write a custom update function, that throws a warning when value is overwritten +# TODO: get rid of importlib + commandline_kwargs = parse_command_line() # Find the problem module default_problem = "DrivenCavity" # Cylinder, DrivenCavity problemname = commandline_kwargs.get("problem", default_problem) -pth = ".".join(("oasis.problems.NSfracStep", problemname)) -problemspec = importlib.util.find_spec(pth) -if problemspec is None: - problemspec = importlib.util.find_spec(problemname) -if problemspec is None: - raise RuntimeError(problemname + " not found") - # Import the problem module -print("Importing problem module " + problemname + ":\n" + problemspec.origin) -pblm = importlib.util.module_from_spec(problemspec) -problemspec.loader.exec_module(pblm) - -# what may be overwritten and what may not? -NS_parameters = pblm.NS_parameters -scalar_components = pblm.scalar_components # TODO: can that be in NS_parameters? -temporal_hook = pblm.temporal_hook -theend_hook = pblm.theend_hook - -# updates NS_parameters, scalar_components, Schmidt -pblm.problem_parameters(NS_parameters, scalar_components, pblm.Schmidt) - -# Update current namespace with NS_parameters and commandline_kwargs ++ -# updates NS_parameters! -mesh = pblm.post_import_problem( - NS_parameters, - pblm.mesh, - commandline_kwargs, - pblm.NS_expressions, -)["mesh"] +print("Importing problem module " + problemname) +if problemname == "Channel": + import oasis.problems.NSfracStep.Channel as pblm +elif problemname == "Cylinder": + import oasis.problems.NSfracStep.Cylinder as pblm +if problemname == "DrivenCavity": + import oasis.problems.NSfracStep.DrivenCavity as pblm +elif problemname == "DrivenCavity3D": + import oasis.problems.NSfracStep.DrivenCavity3D as pblm +elif problemname == "EccentricStenosis": + import oasis.problems.NSfracStep.EccentricStenosis as pblm +elif problemname == "FlowPastSphere3D": + import oasis.problems.NSfracStep.FlowPastSphere3D as pblm +elif problemname == "LaminarChannel": + import oasis.problems.NSfracStep.LaminarChannel as pblm +elif problemname == "Lshape": + import oasis.problems.NSfracStep.Lshape as pblm +elif problemname == "Skewed2D": + import oasis.problems.NSfracStep.Skewed2D as pblm +elif problemname == "SkewedFlow": + import oasis.problems.NSfracStep.SkewedFlow as pblm +elif problemname == "TaylorGreen2D": + import oasis.problems.NSfracStep.TaylorGreen2D as pblm +elif problemname == "TaylorGreen3D": + import oasis.problems.NSfracStep.TaylorGreen3D as pblm + +NS_parameters, NS_expressions = pblm.get_problem_parameters() +for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val + # print(key, "set to default value, which is", val) + +# merges everything into NS_parameters +post_import_problem(NS_parameters, NS_expressions, pblm.mesh, commandline_kwargs) +scalar_components = NS_parameters["scalar_components"] +mesh = NS_parameters["mesh"] # Use t and tstep from stored paramteres if restarting if NS_parameters["restart_folder"] is not None: @@ -95,6 +108,7 @@ tstep = params["tstep"] # Import chosen functionality from solvers +# TODO: make explicit pth = ".".join(("oasis.solvers.NSfracStep", NS_parameters["solver"])) solver = importlib.import_module(pth) @@ -106,13 +120,10 @@ # Set up initial folders for storing results newfolder, tstepfiles = io.create_initial_folders( - scalar_components=scalar_components, sys_comp=sys_comp, - info_red=info_red, **NS_parameters, ) -quantities = {} # Declare FunctionSpaces and arguments velocity_degree = NS_parameters["velocity_degree"] pressure_degree = NS_parameters["pressure_degree"] @@ -123,12 +134,12 @@ Q = df.FunctionSpace( mesh, "CG", pressure_degree, constrained_domain=pblm.constrained_domain ) -quantities["V"] = V -quantities["Q"] = Q -quantities["u"] = u = df.TrialFunction(V) -quantities["v"] = v = df.TestFunction(V) -quantities["p"] = p = df.TrialFunction(Q) -quantities["q"] = q = df.TestFunction(Q) +NS_parameters["V"] = V +NS_parameters["Q"] = Q +NS_parameters["u"] = u = df.TrialFunction(V) +NS_parameters["v"] = v = df.TestFunction(V) +NS_parameters["p"] = p = df.TrialFunction(Q) +NS_parameters["q"] = q = df.TestFunction(Q) # Use dictionary to hold all FunctionSpaces VV = dict((ui, V) for ui in uc_comp) @@ -138,14 +149,13 @@ q_ = dict((ui, df.Function(VV[ui], name=ui)) for ui in sys_comp) q_1 = dict((ui, df.Function(VV[ui], name=ui + "_1")) for ui in sys_comp) q_2 = dict((ui, df.Function(V, name=ui + "_2")) for ui in u_components) -quantities["q_"], quantities["q_1"], quantities["q_2"] = q_, q_1, q_2 +NS_parameters["q_"], NS_parameters["q_1"], NS_parameters["q_2"] = q_, q_1, q_2 # Read in previous solution if restarting io.init_from_restart( sys_comp=sys_comp, uc_comp=uc_comp, u_components=u_components, - **quantities, **NS_parameters, ) @@ -153,7 +163,7 @@ u_ = df.as_vector([q_[ui] for ui in u_components]) # Velocity vector at t u_1 = df.as_vector([q_1[ui] for ui in u_components]) # Velocity vector at t - dt u_2 = df.as_vector([q_2[ui] for ui in u_components]) # Velocity vector at t - 2*dt -quantities["u_"], quantities["u_1"], quantities["u_2"] = u_, u_1, u_2 +NS_parameters["u_"], NS_parameters["u_1"], NS_parameters["u_2"] = u_, u_1, u_2 # Adams Bashforth projection of velocity at t - dt/2 U_AB = 1.5 * u_1 - 0.5 * u_2 @@ -162,17 +172,17 @@ x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors t x_1 = dict((ui, q_1[ui].vector()) for ui in sys_comp) # Solution vectors t - dt x_2 = dict((ui, q_2[ui].vector()) for ui in u_components) # Solution vectors t - 2*dt -quantities["x_"], quantities["x_1"], quantities["x_2"] = x_, x_1, x_2 +NS_parameters["x_"], NS_parameters["x_1"], NS_parameters["x_2"] = x_, x_1, x_2 # Create vectors to hold rhs of equations b = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) # rhs vectors (final) b_tmp = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) # rhs temp storage vectors -quantities["b"], quantities["b_tmp"] = b, b_tmp +NS_parameters["b"], NS_parameters["b_tmp"] = b, b_tmp # Short forms pressure and scalars -quantities["p_"] = q_["p"] # pressure at t -quantities["p_1"] = q_1["p"] # pressure at t - dt -quantities["dp_"] = dp_ = df.Function(Q) # pressure correction +NS_parameters["p_"] = q_["p"] # pressure at t +NS_parameters["p_1"] = q_1["p"] # pressure at t - dt +NS_parameters["dp_"] = dp_ = df.Function(Q) # pressure correction for ci in scalar_components: exec("{}_ = q_ ['{}']".format(ci, ci)) exec("{}_1 = q_1['{}']".format(ci, ci)) @@ -182,46 +192,45 @@ print_solve_info = use_krylov_solvers and krylov_solvers["monitor_convergence"] # Boundary conditions -quantities["bcs"] = bcs = pblm.create_bcs(V=V) +NS_parameters["bcs"] = bcs = pblm.create_bcs(V=V) # LES setup +# TODO: make explicit pth = ".".join(("oasis.solvers.NSfracStep.LES", NS_parameters["les_model"])) lesmodel = importlib.import_module(pth) les_dict = lesmodel.les_setup() # FIXME: which dicts have to be passed? +NS_parameters.update(les_dict) # Non-Newtonian setup +# TODO: make explicit # exec("from oasis.solvers.NSfracStep.NNModel.{} import *".format(nn_model)) pth = ".".join(("oasis.solvers.NSfracStep.NNModel", NS_parameters["nn_model"])) nnmodel = importlib.import_module(pth) nn_dict = nnmodel.nn_setup() # FIXME: which dicts have to be passed? +NS_parameters.update(nn_dict) # Initialize solution -pblm.initialize(**quantities, **NS_parameters) +pblm.initialize(**NS_parameters) # Fetch linear algebra solvers -u_sol, p_sol, c_sol = solver.get_solvers( - **quantities, - scalar_components=scalar_components, - **NS_parameters, -) +u_sol, p_sol, c_sol = solver.get_solvers(**NS_parameters) # Get constant body forces -f = pblm.body_force(mesh=mesh, **NS_parameters) +f = pblm.body_force(**NS_parameters) assert isinstance(f, Coefficient) b0 = dict((ui, df.assemble(v * f[i] * df.dx)) for i, ui in enumerate(u_components)) -quantities["f"], quantities["b0"] = f, b0 +NS_parameters["f"], NS_parameters["b0"] = f, b0 # Get scalar sources -fs = pblm.scalar_source(scalar_components=scalar_components, **NS_parameters) +fs = pblm.scalar_source(**NS_parameters) for ci in scalar_components: assert isinstance(fs[ci], Coefficient) b0[ci] = df.assemble(v * fs[ci] * df.dx) -quantities["fs"] = fs +NS_parameters["fs"] = fs # Preassemble and allocate # TODO: ut.XXX should not be passed but raather imported in solver.py F_dict = solver.setup( - scalar_components=scalar_components, A_cache=ut.A_cache, homogenize=ut.homogenize, GradFunction=ut.GradFunction, @@ -230,11 +239,9 @@ NNsource=ut.NNsource, assemble_matrix=ut.assemble_matrix, u_components=u_components, - **nn_dict, - **les_dict, - **quantities, **NS_parameters, ) +NS_parameters.update(F_dict) t = NS_parameters["t"] tstep = NS_parameters["tstep"] @@ -247,6 +254,7 @@ # Anything problem specific psh_dict = pblm.pre_solve_hook(mesh=mesh, velocity_degree=velocity_degree) +NS_parameters.update(psh_dict) tx = OasisTimer("Timestep timer") tx.start() @@ -267,35 +275,28 @@ t0 = OasisTimer("Tentative velocity") if inner_iter == 1: - lesmodel.les_update(**les_dict, **NS_parameters) - nnmodel.nn_update(**nn_dict, **NS_parameters) + lesmodel.les_update(**NS_parameters) + nnmodel.nn_update(**NS_parameters) solver.assemble_first_inner_iter( - scalar_components=scalar_components, u_components=u_components, - **nn_dict, - **les_dict, - **F_dict, - **quantities, **NS_parameters, ) udiff[0] = 0.0 for i, ui in enumerate(u_components): t1 = OasisTimer("Solving tentative velocity " + ui, print_solve_info) - solver.velocity_tentative_assemble(ui=ui, **F_dict, **quantities) - pblm.velocity_tentative_hook(ui=ui, **quantities, **NS_parameters) + solver.velocity_tentative_assemble(ui=ui, **NS_parameters) + pblm.velocity_tentative_hook(ui=ui, **NS_parameters) solver.velocity_tentative_solve( udiff=udiff, ui=ui, u_sol=u_sol, - **F_dict, - **quantities, **NS_parameters, ) t1.stop() t0 = OasisTimer("Pressure solve", print_solve_info) - solver.pressure_assemble(**quantities, **F_dict, **NS_parameters) - pblm.pressure_hook(**quantities) - solver.pressure_solve(p_sol=p_sol, **quantities, **F_dict) + solver.pressure_assemble(**NS_parameters) + pblm.pressure_hook(**NS_parameters) + solver.pressure_solve(p_sol=p_sol, **NS_parameters) t0.stop() solver.print_velocity_pressure_info( @@ -304,7 +305,6 @@ info_blue=info_blue, inner_iter=inner_iter, udiff=udiff, - **quantities, **NS_parameters, ) @@ -312,8 +312,6 @@ t0 = OasisTimer("Velocity update") solver.velocity_update( u_components=u_components, - **quantities, - **F_dict, **NS_parameters, ) t0.stop() @@ -321,42 +319,29 @@ # Solve for scalars if len(scalar_components) > 0: solver.scalar_assemble( - scalar_components=scalar_components, - Schmidt_T=pblm.Schmidt_T, - Schmidt=pblm.Schmidt, - **quantities, - **F_dict, - **nn_dict, - **les_dict, **NS_parameters, ) for ci in scalar_components: t1 = OasisTimer("Solving scalar {}".format(ci), print_solve_info) pblm.scalar_hook() # FIXME: what do we need to pass here? solver.scalar_solve( - scalar_components=scalar_components, - Schmidt=pblm.Schmidt, c_sol=c_sol, ci=ci, - **quantities, - **F_dict, **NS_parameters, ) t1.stop() - pblm.temporal_hook(**psh_dict, **quantities, **NS_parameters) + pblm.temporal_hook(**NS_parameters) # Save solution if required and check for killoasis file stop = io.save_solution( newfolder=newfolder, tstepfiles=tstepfiles, u_components=u_components, - scalar_components=scalar_components, NS_parameters=NS_parameters, constrained_domain=pblm.constrained_domain, AssignedVectorFunction=ut.AssignedVectorFunction, total_timer=total_timer, **NS_parameters, - **quantities, ) # Update to a new timestep for ui in u_components: @@ -407,7 +392,7 @@ io.merge_visualization_files(newfolder=newfolder) # Final hook -theend_hook(mesh=mesh, **psh_dict, **quantities, **NS_parameters) +pblm.theend_hook(**NS_parameters) # F_dict.keys() = dict_keys(['A', 'M', 'K', 'Ap', 'divu', 'gradp', 'Ta', 'Tb', 'bb', 'bx', 'u_ab', 'a_conv', 'a_scalar', 'LT', 'KT', 'NT']) # nn_dict.keys() = dict_keys(['nunn_']) diff --git a/oasis/common/io.py b/oasis/common/io.py index 62febcf3..d3e687c6 100644 --- a/oasis/common/io.py +++ b/oasis/common/io.py @@ -29,7 +29,7 @@ def create_initial_folders( restart_folder, sys_comp, tstep, - info_red, + # info_red, # TODO: why is this an argument? its imported on top scalar_components, output_timeseries_as_vector, **NS_namespace @@ -82,6 +82,7 @@ def create_initial_folders( return newfolder, tstepfiles +# TODO: dont pass NS_parameters, but rather all def save_solution( tstep, t, @@ -98,7 +99,7 @@ def save_solution( scalar_components, output_timeseries_as_vector, constrained_domain, - AssignedVectorFunction, + AssignedVectorFunction, # TODO: why is this an argument? it can be imported from utilities killtime, total_timer, **NS_namespace diff --git a/oasis/problems/Cylinder.py b/oasis/problems/Cylinder.py index dbb7f81e..c6a9ce8d 100644 --- a/oasis/problems/Cylinder.py +++ b/oasis/problems/Cylinder.py @@ -9,19 +9,23 @@ if not os.path.isfile("cylinder.xml"): if platform.system() == "Linux": - os.system("wget -O cylinder.xml https://www.dropbox.com/s/d78g4cyjxl3ylay/cylinder.xml?dl=0") + os.system( + "wget -O cylinder.xml https://www.dropbox.com/s/d78g4cyjxl3ylay/cylinder.xml?dl=0" + ) elif platform.system() == "Darwin": - os.system("curl -L https://www.dropbox.com/s/d78g4cyjxl3ylay/cylinder.xml?dl=0 -o cylinder.xml") + os.system( + "curl -L https://www.dropbox.com/s/d78g4cyjxl3ylay/cylinder.xml?dl=0 -o cylinder.xml" + ) else: raise ImportError("Could not determine platform") # try: - #os.system("gmsh mesh/cylinder.geo -2 -o mesh/cylinder.msh") - #os.system("dolfin-convert mesh/cylinder.msh mesh/cylinder.xml") - #os.system("rm mesh/cylinder.msh") + # os.system("gmsh mesh/cylinder.geo -2 -o mesh/cylinder.msh") + # os.system("dolfin-convert mesh/cylinder.msh mesh/cylinder.xml") + # os.system("rm mesh/cylinder.msh") # except RuntimeError: - #os.system("wget -O cylinder.xml https://www.dropbox.com/s/d78g4cyjxl3ylay/cylinder.xml?dl=0") - ##raise "Gmsh is required to run this demo" + # os.system("wget -O cylinder.xml https://www.dropbox.com/s/d78g4cyjxl3ylay/cylinder.xml?dl=0") + ##raise "Gmsh is required to run this demo" mesh = Mesh("cylinder.xml") @@ -29,31 +33,30 @@ L = 2.2 D = 0.1 center = 0.2 -cases = { - 1: {'Um': 0.3, - 'Re': 20.0}, - - 2: {'Um': 1.5, - 'Re': 100.0} -} +cases = {1: {"Um": 0.3, "Re": 20.0}, 2: {"Um": 1.5, "Re": 100.0}} # Specify boundary conditions Inlet = AutoSubDomain(lambda x, on_bnd: on_bnd and x[0] < 1e-8) Wall = AutoSubDomain(lambda x, on_bnd: on_bnd and near(x[1] * (H - x[1]), 0)) -Cyl = AutoSubDomain(lambda x, on_bnd: (on_bnd and x[0] > 1e-6 and x[0] < 1 - and x[1] < 3 * H / 4 and x[1] > H / 4)) +Cyl = AutoSubDomain( + lambda x, on_bnd: ( + on_bnd and x[0] > 1e-6 and x[0] < 1 and x[1] < 3 * H / 4 and x[1] > H / 4 + ) +) Outlet = AutoSubDomain(lambda x, on_bnd: on_bnd and x[0] > L - 1e-8) -# Overload post_import_problem to choose between the two cases -def post_import_problem(NS_parameters, commandline_kwargs, **NS_namespace): - """ Choose case - case could be defined through command line.""" - NS_parameters.update(commandline_kwargs) - case = NS_parameters['case'] if 'case' in NS_parameters else 1 - Um = cases[case]["Um"] - Re = cases[case]["Re"] - Umean = 2. / 3. * Um - nu = Umean * D / Re - NS_parameters.update(nu=nu, Re=Re, Um=Um, Umean=Umean) +# TODO: why is that not in problem_parameters() ? + +# # Overload post_import_problem to choose between the two cases +# def post_import_problem(NS_parameters, commandline_kwargs, **NS_namespace): +# """Choose case - case could be defined through command line.""" +# NS_parameters.update(commandline_kwargs) +# case = NS_parameters["case"] if "case" in NS_parameters else 1 +# Um = cases[case]["Um"] +# Re = cases[case]["Re"] +# Umean = 2.0 / 3.0 * Um +# nu = Umean * D / Re +# NS_parameters.update(nu=nu, Re=Re, Um=Um, Umean=Umean) - return NS_parameters +# return NS_parameters diff --git a/oasis/problems/NSfracStep/Channel.py b/oasis/problems/NSfracStep/Channel.py index 3196cccc..362204b7 100644 --- a/oasis/problems/NSfracStep/Channel.py +++ b/oasis/problems/NSfracStep/Channel.py @@ -5,19 +5,44 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * + +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + info_red, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.Channel import mesh +import dolfin as df from fenicstools import StructuredGrid, Probes from numpy import arctan, array, cos, pi -from os import getcwd, makedirs +from os import getcwd, makedirs, path import pickle import random -def problem_parameters( - commandline_kwargs, NS_parameters, NS_expressions, **NS_namespace -): - if "restart_folder" in commandline_kwargs.keys(): - restart_folder = commandline_kwargs["restart_folder"] +def get_problem_parameters(**kwargs): + if "restart_folder" in kwargs.keys(): + # FIXME: this cant work, two different paths are joined. + restart_folder = kwargs["restart_folder"] + restart_folder = "my_restart_folder" restart_folder = path.join(getcwd(), restart_folder) f = open( path.join( @@ -25,24 +50,27 @@ def problem_parameters( ), "r", ) - NS_parameters.update(pickle.load(f)) + NS_parameters = pickle.load(f) NS_parameters["restart_folder"] = restart_folder - globals().update(NS_parameters) + # globals().update(NS_parameters) + NS_expressions = {} # should be loaded as well? else: - Lx = 4.0 * pi - Ly = 2.0 - Lz = 4.0 * pi / 3.0 - Nx = 16 - Ny = 16 - Nz = 16 - NS_parameters.update(Lx=Lx, Ly=Ly, Lz=Lz, Nx=Nx, Ny=Ny, Nz=Nz) - - # Override some problem specific parameters - T = 1.0 - dt = 0.2 nu = 2.0e-5 Re_tau = 178.12 - NS_parameters.update( + Lx = (4.0 * pi,) + Lz = (4.0 * pi / 3.0,) + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, + Lx=Lx, + Ly=2.0, + Lz=Lz, + Nx=16, + Ny=16, + Nz=16, + T=1.0, + dt=0.2, update_statistics=10, save_statistics=100, check_flux=10, @@ -51,14 +79,13 @@ def problem_parameters( save_step=100, nu=nu, Re_tau=Re_tau, - T=T, - dt=dt, velocity_degree=1, folder="channel_results", use_krylov_solvers=True, ) - NS_expressions.update(dict(constrained_domain=PeriodicDomain(Lx, Lz))) + NS_expressions = dict(constrained_domain=PeriodicDomain(Lx, Lz)) + return NS_parameters, NS_expressions class ChannelGrid(StructuredGrid): @@ -74,34 +101,38 @@ def modify_mesh(self, dx, dy, dz): def mesh(Nx, Ny, Nz, Lx, Ly, Lz, **params): # Function for creating stretched mesh in y-direction - m = BoxMesh( - Point(0.0, -Ly / 2.0, -Lz / 2.0), Point(Lx, Ly / 2.0, Lz / 2.0), Nx, Ny, Nz + m = df.BoxMesh( + df.Point(0.0, -Ly / 2.0, -Lz / 2.0), + df.Point(Lx, Ly / 2.0, Lz / 2.0), + Nx, + Ny, + Nz, ) x = m.coordinates() x[:, 1] = arctan(1.0 * pi * (x[:, 1])) / arctan(1.0 * pi) return m -class PeriodicDomain(SubDomain): +class PeriodicDomain(df.SubDomain): def __init__(self, Lx, Lz): self.Lx = Lx self.Lz = Lz - SubDomain.__init__(self) + df.SubDomain.__init__(self) def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two slave edges return bool( - (near(x[0], 0) or near(x[2], -self.Lz / 2.0)) - and (not (near(x[0], self.Lx) or near(x[2], self.Lz / 2.0))) + (df.near(x[0], 0) or df.near(x[2], -self.Lz / 2.0)) + and (not (df.near(x[0], self.Lx) or df.near(x[2], self.Lz / 2.0))) and on_boundary ) def map(self, x, y): - if near(x[0], self.Lx) and near(x[2], self.Lz / 2.0): + if df.near(x[0], self.Lx) and df.near(x[2], self.Lz / 2.0): y[0] = x[0] - self.Lx y[1] = x[1] y[2] = x[2] - self.Lz - elif near(x[0], self.Lx): + elif df.near(x[0], self.Lx): y[0] = x[0] - self.Lx y[1] = x[1] y[2] = x[2] @@ -112,12 +143,12 @@ def map(self, x, y): def inlet(x, on_bnd): - return on_bnd and near(x[0], 0) + return on_bnd and df.near(x[0], 0) # Specify body force def body_force(nu, Re_tau, utau, **NS_namespace): - return Constant((utau ** 2, 0.0, 0.0)) + return df.Constant((utau ** 2, 0.0, 0.0)) def pre_solve_hook( @@ -153,29 +184,29 @@ def pre_solve_hook( ) # Create MeshFunction to compute flux - Inlet = AutoSubDomain(inlet) - facets = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) + Inlet = df.AutoSubDomain(inlet) + facets = df.MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) Inlet.mark(facets, 1) - normal = FacetNormal(mesh) + normal = df.FacetNormal(mesh) return dict(uv=uv, stats=stats, facets=facets, normal=normal) def create_bcs(V, q_, q_1, q_2, sys_comp, u_components, Ly, **NS_namespace): def walls(x, on_bnd): - return near(x[1], -Ly / 2.0) or near(x[1], Ly / 2.0) + return df.near(x[1], -Ly / 2.0) or df.near(x[1], Ly / 2.0) info_red("Creating boundary conditions") bcs = dict((ui, []) for ui in sys_comp) - bc = [DirichletBC(V, Constant(0), walls)] + bc = [df.DirichletBC(V, df.Constant(0), walls)] bcs["u0"] = bc bcs["u1"] = bc bcs["u2"] = bc return bcs -class RandomStreamVector(UserExpression): - random.seed(2 + MPI.rank(MPI.comm_world)) +class RandomStreamVector(df.UserExpression): + random.seed(2 + df.MPI.rank(df.MPI.comm_world)) def eval(self, values, x): values[0] = 0.0005 * random.random() @@ -189,24 +220,26 @@ def value_shape(self): def initialize(V, q_, q_1, q_2, bcs, restart_folder, utau, nu, **NS_namespace): if restart_folder is None: # Initialize using a perturbed flow. Create random streamfunction - Vv = VectorFunctionSpace( + Vv = df.VectorFunctionSpace( V.mesh(), V.ufl_element().family(), V.ufl_element().degree() ) - psi = interpolate(RandomStreamVector(element=Vv.ufl_element()), Vv) - u0 = project(curl(psi), Vv, solver_type="cg") - u0x = project(u0[0], V, bcs=bcs["u0"], solver_type="cg") - u1x = project(u0[1], V, bcs=bcs["u0"], solver_type="cg") - u2x = project(u0[2], V, bcs=bcs["u0"], solver_type="cg") + psi = df.interpolate(RandomStreamVector(element=Vv.ufl_element()), Vv) + u0 = df.project(df.curl(psi), Vv, solver_type="cg") + u0x = df.project(u0[0], V, bcs=bcs["u0"], solver_type="cg") + u1x = df.project(u0[1], V, bcs=bcs["u0"], solver_type="cg") + u2x = df.project(u0[2], V, bcs=bcs["u0"], solver_type="cg") # Create base flow - y = interpolate( - Expression("x[1] > 0 ? 1-x[1] : 1+x[1]", element=V.ufl_element()), V + y = df.interpolate( + df.Expression("x[1] > 0 ? 1-x[1] : 1+x[1]", element=V.ufl_element()), V ) - uu = project( + uu = df.project( ( 1.25 * ( - utau / 0.41 * ln(conditional(y < 1e-12, 1.0e-12, y) * utau / nu) + utau + / 0.41 + * df.ln(df.conditional(y < 1e-12, 1.0e-12, y) * utau / nu) + 5.0 * utau ) ), @@ -259,11 +292,15 @@ def temporal_hook( stats.tovtk(0, statsfolder + "/dump_mean_{}.vtk".format(tstep)) if tstep % check_flux == 0: - u1 = assemble(dot(u_, normal) * ds(1, domain=mesh, subdomain_data=facets)) - u1 = assemble(dot(u_, normal) * ds(1, domain=mesh, subdomain_data=facets)) - normv = norm(q_["u1"].vector()) - normw = norm(q_["u2"].vector()) - if MPI.rank(MPI.comm_world) == 0: + u1 = df.assemble( + df.dot(u_, normal) * df.ds(1, domain=mesh, subdomain_data=facets) + ) + u1 = df.assemble( + df.dot(u_, normal) * df.ds(1, domain=mesh, subdomain_data=facets) + ) + normv = df.norm(q_["u1"].vector()) + normw = df.norm(q_["u2"].vector()) + if df.MPI.rank(df.MPI.comm_world) == 0: print("Flux = ", u1, " tstep = ", tstep, " norm = ", normv, normw) diff --git a/oasis/problems/NSfracStep/Cylinder.py b/oasis/problems/NSfracStep/Cylinder.py index af2105b5..20633ad1 100644 --- a/oasis/problems/NSfracStep/Cylinder.py +++ b/oasis/problems/NSfracStep/Cylinder.py @@ -5,31 +5,82 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * -from ..Cylinder import * -# from oasis.NSfracStep import * -# from oasis.problems.Cylinder import * -from os import getcwd +from oasis.problems import ( + add_function_to_tstepfiles, + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) +from oasis.problems.Cylinder import mesh, Inlet, Cyl, Wall, Outlet, center, cases, D +from dolfin import ( + Expression, + DirichletBC, + Function, + MeshFunction, + FacetNormal, + plot, + TestFunction, + Identity, + VectorFunctionSpace, + grad, + dot, + assemble, + project, + DirichletBC, + curl, + DomainBoundary, + Point, +) +from os import getcwd, path import pickle import matplotlib.pyplot as plt +Schmidt["alfa"] = 0.1 +scalar_components.append("alfa") -def problem_parameters( - commandline_kwargs, NS_parameters, scalar_components, Schmidt, **NS_namespace -): + +def get_problem_parameters(**kwargs): # Example: python NSfracstep.py [...] restart_folder="results/data/8/Checkpoint" - if "restart_folder" in commandline_kwargs.keys(): - restart_folder = commandline_kwargs["restart_folder"] + if "restart_folder" in kwargs.keys(): + restart_folder = kwargs["restart_folder"] restart_folder = path.join(getcwd(), restart_folder) f = open(path.join(restart_folder, "params.dat"), "rb") - NS_parameters.update(pickle.load(f)) + NS_parameters = pickle.load(f) NS_parameters["restart_folder"] = restart_folder globals().update(NS_parameters) else: # Override some problem specific parameters - NS_parameters.update( + case = kwargs["case"] if "case" in kwargs else 1 + Um = cases[case]["Um"] + Re = cases[case]["Re"] + Umean = 2.0 / 3.0 * Um + + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, + Um=Um, + Re=Re, + Umean=Umean, + nu=Umean * D / Re, T=100, dt=0.01, checkpoint=50, @@ -39,13 +90,15 @@ def problem_parameters( print_intermediate_info=100, use_krylov_solvers=True, ) - NS_parameters["krylov_solvers"].update(dict(monitor_convergence=True)) - NS_parameters["velocity_krylov_solver"].update( - dict(preconditioner_type="jacobi", solver_type="bicgstab") + # FIXME: + NS_parameters["krylov_solvers"] = dict(monitor_convergence=True) + + NS_parameters["velocity_krylov_solver"] = dict( + preconditioner_type="jacobi", solver_type="bicgstab" ) - scalar_components.append("alfa") - Schmidt["alfa"] = 0.1 + NS_expressions = {} + return NS_parameters, NS_expressions def create_bcs(V, Q, Um, H, **NS_namespace): @@ -143,7 +196,7 @@ def temporal_hook( ) -def theend_hook(q_, u_, p_, uv, mesh, ds, V, nu, Umean, D, **NS_namespace): +def theend_hook(q_, u_, p_, uv, mesh, ds, V, nu, Umean, D, L, **NS_namespace): uv() plot(uv, title="Velocity") plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/DrivenCavity.py b/oasis/problems/NSfracStep/DrivenCavity.py index 52baf854..a7aa72d5 100644 --- a/oasis/problems/NSfracStep/DrivenCavity.py +++ b/oasis/problems/NSfracStep/DrivenCavity.py @@ -6,99 +6,40 @@ # lots of unused imports, that are all imported here and used by the main script only # from ..NSfracStep import * from oasis.problems import ( - subprocess, - getpid, - path, - defaultdict, - array, - maximum, - zeros, - getMemoryUsage, - # NS_parameters, - NS_expressions, constrained_domain, scalar_components, Schmidt, Schmidt_T, - Scalar, - RED, - BLUE, - GREEN, - info_blue, - info_green, - info_red, - OasisTimer, - OasisMemoryUsage, - initial_memory_use, - oasis_memory, - strain, - omega, - Omega, - Strain, - QC, - recursive_update, - OasisXDMFFile, - add_function_to_tstepfiles, body_force, initialize, - create_bcs, scalar_hook, scalar_source, pre_solve_hook, theend_hook, - problem_parameters, + get_problem_parameters, post_import_problem, + create_bcs, ) -from dolfin import ( # oasis.problems also included whole dolfin namespace - as_vector, - assemble, - KrylovSolver, - LUSolver, - TrialFunction, - TestFunction, - dx, - Vector, - Matrix, - FunctionSpace, - Timer, - div, - Form, - inner, - grad, - as_backend_type, - VectorFunctionSpace, - FunctionAssigner, - PETScKrylovSolver, - PETScPreconditioner, - DirichletBC, - MPI, - Function, - XDMFFile, - HDF5File, - DOLFIN_EPS, - norm, - list_timings, - TimingClear, - TimingType, -) +from oasis.problems import create_bcs from oasis.problems.NSfracStep import ( - NS_parameters, velocity_tentative_hook, pressure_hook, start_timestep_hook, temporal_hook, ) - - -# from ..DrivenCavity import * from oasis.problems.DrivenCavity import noslip, top, bottom, mesh import dolfin as df # set_log_active(False) -# Override some problem specific parameters -def problem_parameters(NS_parameters, scalar_components, Schmidt, **NS_namespace): - NS_parameters.update( + +def get_problem_parameters(**kwargs): + Schmidt["alfa"] = 1.0 + Schmidt["beta"] = 10.0 + NS_parameters = dict( + Schmidt=Schmidt, + scalar_components=scalar_components + ["alfa", "beta"], + Schmidt_T=Schmidt_T, nu=0.001, T=1.0, dt=0.001, @@ -110,9 +51,8 @@ def problem_parameters(NS_parameters, scalar_components, Schmidt, **NS_namespace use_krylov_solvers=True, ) - scalar_components += ["alfa", "beta"] - Schmidt["alfa"] = 1.0 - Schmidt["beta"] = 10.0 + NS_expressions = {} + return NS_parameters, NS_expressions # NS_parameters['krylov_solvers'] = {'monitor_convergence': False, # 'report': False, diff --git a/oasis/problems/NSfracStep/DrivenCavity3D.py b/oasis/problems/NSfracStep/DrivenCavity3D.py index 5cbf2c20..26077bee 100644 --- a/oasis/problems/NSfracStep/DrivenCavity3D.py +++ b/oasis/problems/NSfracStep/DrivenCavity3D.py @@ -3,13 +3,39 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * + +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.DrivenCavity3D import mesh +import dolfin as df from numpy import cos, pi -# Override some problem specific parameters -def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): - NS_parameters.update( +def get_problem_parameters(**kwargs): + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, nu=0.01, T=1.0, dt=0.01, @@ -21,22 +47,23 @@ def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): use_krylov_solvers=True, ) - NS_expressions.update(dict(constrained_domain=PeriodicDomain())) + NS_expressions = dict(constrained_domain=PeriodicDomain()) + return NS_parameters, NS_expressions # Create a mesh def mesh(Nx, Ny, Nz, **params): - m = UnitCubeMesh(Nx, Ny, Nz) + m = df.UnitCubeMesh(Nx, Ny, Nz) x = m.coordinates() x[:, :2] = (x[:, :2] - 0.5) * 2 x[:, :2] = 0.5 * (cos(pi * (x[:, :2] - 1.0) / 2.0) + 1.0) return m -class PeriodicDomain(SubDomain): +class PeriodicDomain(df.SubDomain): def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two slave edges - return bool(near(x[2], 0) and on_boundary) + return bool(df.near(x[2], 0) and on_boundary) def map(self, x, y): y[0] = x[0] @@ -49,9 +76,9 @@ def create_bcs(V, **NS_namespace): noslip = "std::abs(x[0]*x[1]*(1-x[0]))<1e-8" top = "std::abs(x[1]-1) < 1e-8" - bc0 = DirichletBC(V, 0, noslip) - bc00 = DirichletBC(V, 1, top) - bc01 = DirichletBC(V, 0, top) + bc0 = df.DirichletBC(V, 0, noslip) + bc00 = df.DirichletBC(V, 1, top) + bc01 = df.DirichletBC(V, 0, top) return dict(u0=[bc00, bc0], u1=[bc01, bc0], u2=[bc01, bc0], p=[]) @@ -76,11 +103,11 @@ def pre_solve_hook( def temporal_hook(tstep, u_, uv, p_, plot_interval, **NS_namespace): if tstep % plot_interval == 0: uv() - plot(uv, title="Velocity") - plot(p_, title="Pressure") + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") def theend_hook(p_, uv, **NS_namespace): uv() - plot(uv, title="Velocity") - plot(p_, title="Pressure") + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/EccentricStenosis.py b/oasis/problems/NSfracStep/EccentricStenosis.py index 97b15dc7..9a6a7154 100644 --- a/oasis/problems/NSfracStep/EccentricStenosis.py +++ b/oasis/problems/NSfracStep/EccentricStenosis.py @@ -21,19 +21,42 @@ """ from __future__ import print_function -from oasis import * -from oasis.problems import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.EccentricStenosis import mesh +import dolfin as df import numpy as np import random import os import platform -def problem_parameters( - NS_parameters, NS_expressions, commandline_kwargs, **NS_namespace -): - Re = float(commandline_kwargs.get("Re", 600)) - NS_parameters.update( +def get_problem_parameters(**kwargs): + Re = float(kwargs.get("Re", 600)) + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, nu=0.0031078341013824886, # mm^2/ms #3.1078341E-6 m^2/s, #0.003372 Pa-s/1085 kg/m^3 this is nu_inf (m^2/s) D=6.35, # 0.00635, T=15e3, # ms @@ -73,7 +96,8 @@ def problem_parameters( ) NS_parameters.update(ave_inlet_velocity=average_inlet_velocity) inflow_prof = get_inflow_prof(average_inlet_velocity, NS_parameters["D"]) - NS_expressions.update(dict(u_in=inflow_prof, noise=Noise())) + NS_expressions = dict(u_in=inflow_prof, noise=Noise()) + return NS_parameters, NS_expressions def mesh(mesh_file, **NS_namespace): @@ -90,11 +114,11 @@ def mesh(mesh_file, **NS_namespace): raise ImportError("Could not determine platform") print(f"Downloaded mesh {mesh_file}") - mesh = Mesh(mesh_file) + mesh = df.Mesh(mesh_file) return mesh -class Noise(UserExpression): +class Noise(df.UserExpression): def __init__(self, **kwargs): super().__init__(**kwargs) @@ -102,22 +126,22 @@ def eval(self, value, x): value[0] = np.random.normal(0, 0.001) -def create_bcs(V, Q, mesh, mesh_file, **NS_namespace): - if MPI.rank(MPI.comm_world) == 0: +def create_bcs(V, Q, mesh, mesh_file, NS_expressions, **NS_namespace): + if df.MPI.rank(df.MPI.comm_world) == 0: print("Create bcs") - boundaries = MeshFunction("size_t", mesh, 2, mesh.domains()) + boundaries = df.MeshFunction("size_t", mesh, 2, mesh.domains()) boundaries.set_values(boundaries.array() + 1) wallId = 1 inletId = 2 outletId = 3 - bc0 = DirichletBC(V, 0, boundaries, wallId) - bc1 = DirichletBC(V, NS_expressions["u_in"], boundaries, inletId) - bc2 = DirichletBC(V, NS_expressions["noise"], boundaries, inletId) - bc3 = DirichletBC(V, NS_expressions["noise"], boundaries, inletId) - bc4 = DirichletBC(Q, 0, boundaries, outletId) + bc0 = df.DirichletBC(V, 0, boundaries, wallId) + bc1 = df.DirichletBC(V, NS_expressions["u_in"], boundaries, inletId) + bc2 = df.DirichletBC(V, NS_expressions["noise"], boundaries, inletId) + bc3 = df.DirichletBC(V, NS_expressions["noise"], boundaries, inletId) + bc4 = df.DirichletBC(Q, 0, boundaries, outletId) return dict( u0=[bc0, bc1], # 0 on the sides, u_in on inlet, zero gradient outlet u1=[bc0, bc2], # 0 on sides and perturbed inlet, zero gradient outlet @@ -134,8 +158,9 @@ def initialize(V, q_, q_1, q_2, x_1, x_2, bcs, restart_folder, **NS_namespace): def pre_solve_hook(u_, tstep, AssignedVectorFunction, folder, **NS_namespace): - visfile = XDMFFile( - MPI.comm_world, path.join(folder, "viscosity_from_tstep_{}.xdmf".format(tstep)) + visfile = df.XDMFFile( + df.MPI.comm_world, + os.path.join(folder, "viscosity_from_tstep_{}.xdmf".format(tstep)), ) visfile.parameters["rewrite_function_mesh"] = False visfile.parameters["flush_output"] = True @@ -169,7 +194,7 @@ def get_ave_inlet_velocity(Re, nu, D, **NS_namespace): def get_inflow_prof(average_inlet_velocity, D, **NS_namespace): - u_inflow = Expression( + u_inflow = df.Expression( "A*2*(1-((x[1]*x[1])+(x[2]*x[2]))*4/(D*D))", degree=2, A=average_inlet_velocity, diff --git a/oasis/problems/NSfracStep/FlowPastSphere3D.py b/oasis/problems/NSfracStep/FlowPastSphere3D.py index 13e8111b..9f752d60 100644 --- a/oasis/problems/NSfracStep/FlowPastSphere3D.py +++ b/oasis/problems/NSfracStep/FlowPastSphere3D.py @@ -3,31 +3,58 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * + +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.FlowPastSphere3D import mesh +import dolfin as df from numpy import cos, pi, cosh -from os import getcwd +from os import getcwd, path import pickle # Create a mesh def mesh(**params): - m = Mesh("/home/mikael/MySoftware/Oasis/mymesh/boxwithsphererefined.xml") + m = df.Mesh("/home/mikael/MySoftware/Oasis/mymesh/boxwithsphererefined.xml") return m -def problem_parameters(commandline_kwargs, NS_parameters, **NS_namespace): - if "restart_folder" in commandline_kwargs.keys(): - restart_folder = commandline_kwargs["restart_folder"] +def get_problem_parameters(**kwargs): + if "restart_folder" in kwargs.keys(): + restart_folder = kwargs["restart_folder"] restart_folder = path.join(getcwd(), restart_folder) f = open(path.join(restart_folder, "params.dat"), "r") - NS_parameters.update(pickle.load(f)) + NS_parameters = pickle.load(f) NS_parameters["T"] = NS_parameters["T"] + 10 * NS_parameters["dt"] NS_parameters["restart_folder"] = restart_folder globals().update(NS_parameters) else: # Override some problem specific parameters - NS_parameters.update( + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, nu=0.1, T=5.0, dt=0.01, @@ -40,9 +67,11 @@ def problem_parameters(commandline_kwargs, NS_parameters, **NS_namespace): use_krylov_solvers=True, ) NS_parameters["krylov_solvers"]["monitor_convergence"] = True + NS_expressions = {} + return NS_parameters, NS_expressions -def create_bcs(V, Q, mesh, **NS_namespace): +def create_bcs(V, Q, mesh, h, **NS_namespace): # Specify boundary conditions walls = "on_boundary && std::abs((x[1]-3)*(x[1]+3)*(x[2]-3)*(x[2]+3))<1e-8" inners = "on_boundary && std::sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]) < 1.5*{}".format( @@ -51,30 +80,30 @@ def create_bcs(V, Q, mesh, **NS_namespace): inlet = "x[0] < -3+1e-8 && on_boundary" outlet = "x[0] > 6-1e-8 && on_boundary" - bmesh = BoundaryMesh(mesh, "exterior") - cc = MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) - ii = AutoSubDomain(lambda x, on_bnd: near(x[0], -3)) + bmesh = df.BoundaryMesh(mesh, "exterior") + cc = df.MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) + ii = df.AutoSubDomain(lambda x, on_bnd: df.near(x[0], -3)) ii.mark(cc, 1) - smesh = SubMesh(bmesh, cc, 1) - Vu = FunctionSpace(smesh, "CG", 1) - su = Function(Vu) - us = TrialFunction(Vu) - vs = TestFunction(Vu) - solve( - inner(grad(us), grad(vs)) * dx == Constant(0.1) * vs * dx, + smesh = df.SubMesh(bmesh, cc, 1) + Vu = df.FunctionSpace(smesh, "CG", 1) + su = df.Function(Vu) + us = df.TrialFunction(Vu) + vs = df.TestFunction(Vu) + df.solve( + df.inner(df.grad(us), df.grad(vs)) * df.dx == df.Constant(0.1) * vs * df.dx, su, - bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())], + bcs=[df.DirichletBC(Vu, df.Constant(0), df.DomainBoundary())], ) - lp = LagrangeInterpolator() - sv = Function(V) + lp = df.LagrangeInterpolator() + sv = df.Function(V) lp.interpolate(sv, su) - bc0 = DirichletBC(V, 0, walls) - bc1 = DirichletBC(V, 0, inners) - bcp1 = DirichletBC(Q, 0, outlet) - bc2 = DirichletBC(V, 0, inlet) - bc3 = DirichletBC(V, sv, inlet) + bc0 = df.DirichletBC(V, 0, walls) + bc1 = df.DirichletBC(V, 0, inners) + bcp1 = df.DirichletBC(Q, 0, outlet) + bc2 = df.DirichletBC(V, 0, inlet) + bc3 = df.DirichletBC(V, sv, inlet) return dict(u0=[bc0, bc1, bc3], u1=[bc0, bc1, bc2], u2=[bc0, bc1, bc2], p=[bcp1]) @@ -85,11 +114,11 @@ def pre_solve_hook(mesh, velocity_degree, u_, AssignedVectorFunction, **NS_names def temporal_hook(tstep, uv, p_, plot_interval, **NS_namespace): if tstep % plot_interval == 0: uv() - plot(uv, title="Velocity") - plot(p_, title="Pressure") + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") def theend_hook(p_, uv, **NS_namespace): uv() - plot(uv, title="Velocity") - plot(p_, title="Pressure") + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/LaminarChannel.py b/oasis/problems/NSfracStep/LaminarChannel.py index cf22bfa2..71f95fad 100644 --- a/oasis/problems/NSfracStep/LaminarChannel.py +++ b/oasis/problems/NSfracStep/LaminarChannel.py @@ -5,40 +5,65 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * -from numpy import pi, arctan, array + +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.LaminarChannel import mesh +import dolfin as df +from numpy import pi, arctan, array, exp # set_log_active(False) -# Override some problem specific parameters -def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): +def get_problem_parameters(**kwargs): nu = 0.01 Re = 1.0 / nu L = 10.0 - NS_parameters.update( - dict( - nu=nu, - L=L, - H=1.0, - T=10, - dt=0.01, - Re=Re, - Nx=40, - Ny=40, - folder="laminarchannel_results", - max_iter=1, - velocity_degree=1, - use_krylov_solvers=False, - ) + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, + nu=nu, + L=L, + H=1.0, + T=10, + dt=0.01, + Re=Re, + Nx=40, + Ny=40, + folder="laminarchannel_results", + max_iter=1, + velocity_degree=1, + use_krylov_solvers=False, ) - NS_expressions.update(dict(constrained_domain=PeriodicDomain(L))) + NS_expressions = dict(constrained_domain=PeriodicDomain(L)) + return NS_parameters, NS_expressions # Create a mesh here def mesh(Nx, Ny, L, H, **params): - m = RectangleMesh(Point(0.0, -H), Point(L, H), Nx, Ny) + m = df.RectangleMesh(df.Point(0.0, -H), df.Point(L, H), Nx, Ny) # Squeeze towards walls x = m.coordinates() @@ -46,13 +71,13 @@ def mesh(Nx, Ny, L, H, **params): return m -class PeriodicDomain(SubDomain): +class PeriodicDomain(df.SubDomain): def __init__(self, L): self.L = L - SubDomain.__init__(self) + df.SubDomain.__init__(self) def inside(self, x, on_boundary): - return bool(near(x[0], 0) and on_boundary) + return bool(df.near(x[0], 0) and on_boundary) def map(self, x, y): y[0] = x[0] - self.L @@ -61,17 +86,17 @@ def map(self, x, y): def create_bcs(V, H, sys_comp, **NS_namespace): def walls(x, on_boundary): - return on_boundary and (near(x[1], -H) or near(x[1], H)) + return on_boundary and (df.near(x[1], -H) or df.near(x[1], H)) bcs = dict((ui, []) for ui in sys_comp) - bc0 = DirichletBC(V, 0.0, walls) + bc0 = df.DirichletBC(V, 0.0, walls) bcs["u0"] = [bc0] bcs["u1"] = [bc0] return bcs def body_force(Re, **NS_namespace): - return Constant((2.0 / Re, 0.0)) + return df.Constant((2.0 / Re, 0.0)) def reference(Re, t, num_terms=100): @@ -87,7 +112,7 @@ def reference(Re, t, num_terms=100): def temporal_hook(tstep, q_, t, Re, L, **NS_namespace): if tstep % 20 == 0: - plot(q_["u0"]) + df.plot(q_["u0"]) try: # point is found on one processor, the others pass u_computed = q_["u0"](array([L, 0.0])) diff --git a/oasis/problems/NSfracStep/Lshape.py b/oasis/problems/NSfracStep/Lshape.py index 204333b2..a5d3a70a 100644 --- a/oasis/problems/NSfracStep/Lshape.py +++ b/oasis/problems/NSfracStep/Lshape.py @@ -3,76 +3,100 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * + +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.Lshape import mesh +import dolfin as df import matplotlib.pyplot as plt -# Override some problem specific parameters -def problem_parameters( - NS_parameters, commandline_kwargs, NS_expressions, **NS_namespace -): + +def get_problem_parameters(**kwargs): Re = 500.0 nu = 1.0 / Re - NS_parameters.update( - dict( - nu=nu, - T=10, - dt=0.01, - Re=Re, - Nx=40, - Ny=40, - folder="Lshape_results", - max_iter=1, - plot_interval=1, - velocity_degree=2, - use_krylov_solvers=True, - ) + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, + nu=nu, + T=10, + dt=0.01, + Re=Re, + Nx=40, + Ny=40, + folder="Lshape_results", + max_iter=1, + plot_interval=1, + velocity_degree=2, + use_krylov_solvers=True, ) - if "pressure_degree" in commandline_kwargs.keys(): - degree = commandline_kwargs["pressure_degree"] + if "pressure_degree" in kwargs.keys(): + degree = kwargs["pressure_degree"] else: degree = NS_parameters["pressure_degree"] - NS_expressions.update(dict(p_in=Expression("sin(pi*t)", t=0.0, degree=degree))) + NS_expressions = dict(p_in=df.Expression("sin(pi*t)", t=0.0, degree=degree)) + return NS_parameters, NS_expressions # Create a mesh here -class Submesh(SubDomain): +class Submesh(df.SubDomain): def inside(self, x, on_boundary): - return x[0] > 0.25 - DOLFIN_EPS and x[1] > 0.25 - DOLFIN_EPS + return x[0] > 0.25 - df.DOLFIN_EPS and x[1] > 0.25 - df.DOLFIN_EPS def mesh(Nx, Ny, **params): - mesh_ = UnitSquareMesh(Nx, Ny) + mesh_ = df.UnitSquareMesh(Nx, Ny) subm = Submesh() - mf1 = MeshFunction("size_t", mesh_, 2) + mf1 = df.MeshFunction("size_t", mesh_, 2) mf1.set_all(0) subm.mark(mf1, 1) - return SubMesh(mesh_, mf1, 0) + return df.SubMesh(mesh_, mf1, 0) def inlet(x, on_boundary): - return near(x[1] - 1.0, 0.0) and on_boundary + return df.near(x[1] - 1.0, 0.0) and on_boundary def outlet(x, on_boundary): - return near(x[0] - 1.0, 0.0) and on_boundary + return df.near(x[0] - 1.0, 0.0) and on_boundary def walls(x, on_boundary): return ( - near(x[0], 0.0) - or near(x[1], 0.0) - or (x[0] > 0.25 - 5 * DOLFIN_EPS and x[1] > 0.25 - 5 * DOLFIN_EPS) + df.near(x[0], 0.0) + or df.near(x[1], 0.0) + or (x[0] > 0.25 - 5 * df.DOLFIN_EPS and x[1] > 0.25 - 5 * df.DOLFIN_EPS) and on_boundary ) def create_bcs(V, Q, sys_comp, p_in, **NS_namespace): bcs = dict((ui, []) for ui in sys_comp) - bc0 = DirichletBC(V, 0.0, walls) - pc0 = DirichletBC(Q, p_in, inlet) - pc1 = DirichletBC(Q, 0.0, outlet) + bc0 = df.DirichletBC(V, 0.0, walls) + pc0 = df.DirichletBC(Q, p_in, inlet) + pc1 = df.DirichletBC(Q, 0.0, outlet) bcs["u0"] = [bc0] bcs["u1"] = [bc0] bcs["p"] = [pc0, pc1] @@ -80,7 +104,7 @@ def create_bcs(V, Q, sys_comp, p_in, **NS_namespace): def pre_solve_hook(mesh, OasisFunction, u_, **NS_namespace): - Vv = VectorFunctionSpace(mesh, "CG", 1) + Vv = df.VectorFunctionSpace(mesh, "CG", 1) return dict(Vv=Vv, uv=OasisFunction(u_, Vv)) @@ -90,7 +114,7 @@ def start_timestep_hook(t, p_in, **NS_namespace): def temporal_hook(tstep, q_, u_, uv, Vv, plot_interval, **NS_namespace): if tstep % plot_interval == 0: - plot(q_["p"], title="Pressure") + df.plot(q_["p"], title="Pressure") uv() # uv = project(u_, Vv) - plot(uv, title="Velocity") + df.plot(uv, title="Velocity") plt.show() diff --git a/oasis/problems/NSfracStep/Skewed2D.py b/oasis/problems/NSfracStep/Skewed2D.py index ac35c7be..c3f5391e 100644 --- a/oasis/problems/NSfracStep/Skewed2D.py +++ b/oasis/problems/NSfracStep/Skewed2D.py @@ -5,45 +5,72 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * -from ..Skewed2D import * +# from ..Skewed2D import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) +from oasis.problems.Skewed2D import mesh, walls, inlet, outlet +import dolfin as df -# Override some problem specific parameters -def problem_parameters(NS_parameters, **NS_namespace): - NS_parameters.update( + +def get_problem_parameters(**kwargs): + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, nu=0.1, T=10.0, dt=0.05, use_krylov_solvers=True, print_velocity_pressure_convergence=True, ) + NS_expressions = {} + return NS_parameters, NS_expressions def create_bcs(V, Q, mesh, **NS_namespace): - u_inlet = Expression("10*x[1]*(0.2-x[1])", element=V.ufl_element()) - bc0 = DirichletBC(V, 0, walls) - bc1 = DirichletBC(V, u_inlet, inlet) - bc2 = DirichletBC(V, 0, inlet) - return dict(u0=[bc1, bc0], u1=[bc2, bc0], p=[DirichletBC(Q, 0, outlet)]) + u_inlet = df.Expression("10*x[1]*(0.2-x[1])", element=V.ufl_element()) + bc0 = df.DirichletBC(V, 0, walls) + bc1 = df.DirichletBC(V, u_inlet, inlet) + bc2 = df.DirichletBC(V, 0, inlet) + return dict(u0=[bc1, bc0], u1=[bc2, bc0], p=[df.DirichletBC(Q, 0, outlet)]) def pre_solve_hook(mesh, u_, AssignedVectorFunction, **NS_namespace): - return dict(uv=AssignedVectorFunction(u_, "Velocity"), n=FacetNormal(mesh)) + return dict(uv=AssignedVectorFunction(u_, "Velocity"), n=df.FacetNormal(mesh)) def temporal_hook( u_, p_, mesh, tstep, print_intermediate_info, uv, n, plot_interval, **NS_namespace ): if tstep % print_intermediate_info == 0: - print("Continuity ", assemble(dot(u_, n) * ds())) + print("Continuity ", df.assemble(df.dot(u_, n) * df.ds())) if tstep % plot_interval == 0: uv() - plot(uv, title="Velocity") - plot(p_, title="Pressure") + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") def theend_hook(uv, p_, **NS_namespace): uv() - plot(uv, title="Velocity") - plot(p_, title="Pressure") + df.plot(uv, title="Velocity") + df.plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/SkewedFlow.py b/oasis/problems/NSfracStep/SkewedFlow.py index 18a4be5c..36efe07e 100644 --- a/oasis/problems/NSfracStep/SkewedFlow.py +++ b/oasis/problems/NSfracStep/SkewedFlow.py @@ -5,8 +5,31 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * -from ..SkewedFlow import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) +from oasis.problems.SkewedFlow import mesh, inlet, walls, outlet +import dolfin as df + +# from ..SkewedFlow import * from numpy import cos, pi, cosh print( @@ -27,62 +50,67 @@ """ ) -# Override some problem specific parameters -def problem_parameters(NS_parameters, **NS_namespace): - NS_parameters.update( + +def get_problem_parameters(**kwargs): + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, nu=0.001, T=0.05, dt=0.01, use_krylov_solvers=True, print_velocity_pressure_convergence=True, ) + NS_expressions = {} + return NS_parameters, NS_expressions def create_bcs(V, Q, mesh, **NS_namespace): # Create inlet profile by solving Poisson equation on boundary - bmesh = BoundaryMesh(mesh, "exterior") - cc = MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) - ii = AutoSubDomain(inlet) + bmesh = df.BoundaryMesh(mesh, "exterior") + cc = df.MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) + ii = df.AutoSubDomain(inlet) ii.mark(cc, 1) - smesh = SubMesh(bmesh, cc, 1) - Vu = FunctionSpace(smesh, "CG", 1) - su = Function(Vu) - us = TrialFunction(Vu) - vs = TestFunction(Vu) - solve( - inner(grad(us), grad(vs)) * dx == Constant(10.0) * vs * dx, + smesh = df.SubMesh(bmesh, cc, 1) + Vu = df.FunctionSpace(smesh, "CG", 1) + su = df.Function(Vu) + us = df.TrialFunction(Vu) + vs = df.TestFunction(Vu) + df.solve( + df.inner(df.grad(us), df.grad(vs)) * df.dx == df.Constant(10.0) * vs * df.dx, su, - bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())], + bcs=[df.DirichletBC(Vu, df.Constant(0), df.DomainBoundary())], ) # Wrap the boundary function in an Expression to avoid the need to interpolate it back to V - class MyExp(UserExpression): + class MyExp(df.UserExpression): def eval(self, values, x): try: values[0] = su(x) except: values[0] = 0 - bc0 = DirichletBC(V, 0, walls) - bc1 = DirichletBC(V, MyExp(element=V.ufl_element()), inlet) - bc2 = DirichletBC(V, 0, inlet) + bc0 = df.DirichletBC(V, 0, walls) + bc1 = df.DirichletBC(V, MyExp(element=V.ufl_element()), inlet) + bc2 = df.DirichletBC(V, 0, inlet) return dict( - u0=[bc0, bc1], u1=[bc0, bc2], u2=[bc0, bc2], p=[DirichletBC(Q, 0, outlet)] + u0=[bc0, bc1], u1=[bc0, bc2], u2=[bc0, bc2], p=[df.DirichletBC(Q, 0, outlet)] ) def temporal_hook( - u_, mesh, tstep, print_intermediate_info, plot_interval, **NS_namespace + u_, p_, mesh, tstep, print_intermediate_info, plot_interval, **NS_namespace ): if tstep % print_intermediate_info == 0: - print("Continuity ", assemble(dot(u_, FacetNormal(mesh)) * ds())) + print("Continuity ", df.assemble(df.dot(u_, df.FacetNormal(mesh)) * df.ds())) if tstep % plot_interval == 0: - plot(u_, title="Velocity") - plot(p_, title="Pressure") + df.plot(u_, title="Velocity") + df.plot(p_, title="Pressure") def theend_hook(u_, p_, **NS_namespace): - plot(u_, title="Velocity") - plot(p_, title="Pressure") + df.plot(u_, title="Velocity") + df.plot(p_, title="Pressure") diff --git a/oasis/problems/NSfracStep/TaylorGreen2D.py b/oasis/problems/NSfracStep/TaylorGreen2D.py index f8d7f2f4..dcbbb568 100644 --- a/oasis/problems/NSfracStep/TaylorGreen2D.py +++ b/oasis/problems/NSfracStep/TaylorGreen2D.py @@ -5,16 +5,43 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) +import numpy as np + +# from oasis.problems.TaylorGreen2D import mesh +import dolfin as df try: from matplotlib import pyplot as plt except: pass -# Override some problem specific parameters -def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): - NS_parameters.update( + +def get_problem_parameters(**kwargs): + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, nu=0.01, T=1.0, dt=0.001, @@ -38,7 +65,7 @@ def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): "relative_tolerance": 1e-12, "absolute_tolerance": 1e-12, } - NS_expressions.update( + NS_expressions = dict( dict( constrained_domain=PeriodicDomain(), initial_fields=dict( @@ -50,34 +77,35 @@ def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): "sin(2*pi*x[0])*2*pi*exp(-4.*pi*pi*nu*t)/4.", "sin(2*pi*x[1])*2*pi*exp(-4.*pi*pi*nu*t)/4.", ), - total_error=zeros(3), + total_error=np.zeros(3), ) ) + return NS_parameters, NS_expressions def mesh(Nx, Ny, **params): - return RectangleMesh(Point(0, 0), Point(2, 2), Nx, Ny) + return df.RectangleMesh(df.Point(0, 0), df.Point(2, 2), Nx, Ny) -class PeriodicDomain(SubDomain): +class PeriodicDomain(df.SubDomain): def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two corners (0, 2) and (2, 0) return bool( - (near(x[0], 0) or near(x[1], 0)) + (df.near(x[0], 0) or df.near(x[1], 0)) and ( not ( - (near(x[0], 0) and near(x[1], 2)) - or (near(x[0], 2) and near(x[1], 0)) + (df.near(x[0], 0) and df.near(x[1], 2)) + or (df.near(x[0], 2) and df.near(x[1], 0)) ) ) and on_boundary ) def map(self, x, y): - if near(x[0], 2) and near(x[1], 2): + if df.near(x[0], 2) and df.near(x[1], 2): y[0] = x[0] - 2.0 y[1] = x[1] - 2.0 - elif near(x[0], 2): + elif df.near(x[0], 2): y[0] = x[0] - 2.0 y[1] = x[1] else: @@ -85,19 +113,20 @@ def map(self, x, y): y[1] = x[1] - 2.0 -def initialize(q_, q_1, q_2, VV, t, nu, dt, initial_fields, **NS_namespace): +def initialize(q_, q_1, q_2, VV, t, nu, dt, initial_fields, solver, **NS_namespace): """Initialize solution. Use t=dt/2 for pressure since pressure is computed in between timesteps. """ for ui in q_: - if "IPCS" in NS_parameters["solver"]: + if "IPCS" in solver: + # if "IPCS" in NS_parameters["solver"]: deltat = dt / 2.0 if ui is "p" else 0.0 else: deltat = 0.0 - vv = interpolate( - Expression( + vv = df.interpolate( + df.Expression( (initial_fields[ui]), element=VV[ui].ufl_element(), t=t + deltat, nu=nu ), VV[ui], @@ -106,8 +135,8 @@ def initialize(q_, q_1, q_2, VV, t, nu, dt, initial_fields, **NS_namespace): if not ui == "p": q_1[ui].vector()[:] = vv.vector()[:] deltat = -dt - vv = interpolate( - Expression( + vv = df.interpolate( + df.Expression( (initial_fields[ui]), element=VV[ui].ufl_element(), t=t + deltat, @@ -131,6 +160,7 @@ def temporal_hook( sys_comp, compute_error, total_error, + solver, **NS_namespace ): """Function called at end of timestep. @@ -140,9 +170,9 @@ def temporal_hook( """ if tstep % plot_interval == 0: - plot(q_["u0"], title="u") - plot(q_["u1"], title="v") - plot(q_["p"], title="p") + df.plot(q_["u0"], title="u") + df.plot(q_["u1"], title="v") + df.plot(q_["p"], title="p") try: plt.show() except: @@ -151,40 +181,52 @@ def temporal_hook( if tstep % compute_error == 0: err = {} for i, ui in enumerate(sys_comp): - if "IPCS" in NS_parameters["solver"]: + if "IPCS" in solver: + # if "IPCS" in NS_parameters["solver"]: deltat_ = dt / 2.0 if ui is "p" else 0.0 else: deltat_ = 0.0 - ue = Expression( + ue = df.Expression( (initial_fields[ui]), element=VV[ui].ufl_element(), t=t - deltat_, nu=nu ) - ue = interpolate(ue, VV[ui]) - uen = norm(ue.vector()) + ue = df.interpolate(ue, VV[ui]) + uen = df.norm(ue.vector()) ue.vector().axpy(-1, q_[ui].vector()) - error = norm(ue.vector()) / uen - err[ui] = "{0:2.6e}".format(norm(ue.vector()) / uen) + error = df.norm(ue.vector()) / uen + err[ui] = "{0:2.6e}".format(df.norm(ue.vector()) / uen) total_error[i] += error * dt - if MPI.rank(MPI.comm_world) == 0: + if df.MPI.rank(df.MPI.comm_world) == 0: print("Error is ", err, " at time = ", t) def theend_hook( - mesh, q_, t, dt, nu, VV, sys_comp, total_error, initial_fields, **NS_namespace + mesh, + q_, + t, + dt, + nu, + VV, + sys_comp, + total_error, + initial_fields, + solver, + **NS_namespace ): - final_error = zeros(len(sys_comp)) + final_error = np.zeros(len(sys_comp)) for i, ui in enumerate(sys_comp): - if "IPCS" in NS_parameters["solver"]: + if "IPCS" in solver: + # if "IPCS" in NS_parameters["solver"]: deltat = dt / 2.0 if ui is "p" else 0.0 else: deltat = 0.0 - ue = Expression( + ue = df.Expression( (initial_fields[ui]), element=VV[ui].ufl_element(), t=t - deltat, nu=nu ) - ue = interpolate(ue, VV[ui]) - final_error[i] = errornorm(q_[ui], ue) + ue = df.interpolate(ue, VV[ui]) + final_error[i] = df.errornorm(q_[ui], ue) hmin = mesh.hmin() - if MPI.rank(MPI.comm_world) == 0: + if df.MPI.rank(df.MPI.comm_world) == 0: print("hmin = {}".format(hmin)) s0 = "Total Error:" s1 = "Final Error:" @@ -192,6 +234,6 @@ def theend_hook( s0 += " {0:}={1:2.6e}".format(ui, total_error[i]) s1 += " {0:}={1:2.6e}".format(ui, final_error[i]) - if MPI.rank(MPI.comm_world) == 0: + if df.MPI.rank(df.MPI.comm_world) == 0: print(s0) print(s1) diff --git a/oasis/problems/NSfracStep/TaylorGreen3D.py b/oasis/problems/NSfracStep/TaylorGreen3D.py index 402bad05..9a63b487 100644 --- a/oasis/problems/NSfracStep/TaylorGreen3D.py +++ b/oasis/problems/NSfracStep/TaylorGreen3D.py @@ -3,44 +3,81 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSfracStep import * - - -def problem_parameters(NS_parameters, NS_expressions, **NS_namespace): +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + info_blue, + create_bcs, +) +from oasis.problems.NSfracStep import ( + velocity_tentative_hook, + pressure_hook, + start_timestep_hook, + temporal_hook, +) + +# from oasis.problems.TaylorGreen3D import mesh +from dolfin import ( + pi, + near, + dot, + assemble, + grad, + dx, + inner, + Expression, + SubDomain, + plot, + BoxMesh, + Point, +) +import numpy as np + + +def get_problem_parameters(**kwargs): # Override some problem specific parameters - recursive_update( - NS_parameters, - dict( - nu=0.005, - T=0.2, - dt=0.01, - Nx=33, - Ny=33, - Nz=33, - folder="taylorgreen3D_results", - max_iter=1, - velocity_degree=1, - save_step=10000, - checkpoint=10000, - plot_interval=10, - print_dkdt_info=10000, - use_krylov_solvers=True, - krylov_solvers=dict(monitor_convergence=True), - ), + NS_parameters = dict( + scalar_components=scalar_components, + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, + nu=0.005, + T=0.2, + dt=0.01, + Nx=33, + Ny=33, + Nz=33, + folder="taylorgreen3D_results", + max_iter=1, + velocity_degree=1, + save_step=10000, + checkpoint=10000, + plot_interval=10, + print_dkdt_info=10000, + use_krylov_solvers=True, + krylov_solvers=dict(monitor_convergence=True), ) - NS_expressions.update( - dict( - constrained_domain=PeriodicDomain(), - kin=zeros(1), - initial_fields=dict( - u0="sin(x[0])*cos(x[1])*cos(x[2])", - u1="-cos(x[0])*sin(x[1])*cos(x[2])", - u2="0", - p="1./16.*(cos(2*x[0])+cos(2*x[1]))*(cos(2*x[2])+2)", - ), - ) + NS_expressions = dict( + constrained_domain=PeriodicDomain(), + kin=np.zeros(1), + initial_fields=dict( + u0="sin(x[0])*cos(x[1])*cos(x[2])", + u1="-cos(x[0])*sin(x[1])*cos(x[2])", + u2="0", + p="1./16.*(cos(2*x[0])+cos(2*x[1]))*(cos(2*x[2])+2)", + ), ) + return NS_parameters, NS_expressions def mesh(Nx, Ny, Nz, **params): diff --git a/oasis/problems/NSfracStep/__init__.py b/oasis/problems/NSfracStep/__init__.py index c84c416f..34b85b97 100644 --- a/oasis/problems/NSfracStep/__init__.py +++ b/oasis/problems/NSfracStep/__init__.py @@ -13,8 +13,8 @@ maximum, zeros, getMemoryUsage, - NS_parameters, - NS_expressions, + # NS_parameters, + # NS_expressions, constrained_domain, scalar_components, Schmidt, @@ -40,17 +40,22 @@ add_function_to_tstepfiles, body_force, initialize, - create_bcs, + # create_bcs, scalar_hook, scalar_source, pre_solve_hook, theend_hook, - problem_parameters, + get_problem_parameters, post_import_problem, ) # Default parameters NSfracStep solver -NS_parameters.update( +NS_expressions = {} +default_parameters = dict( + nu=0.01, # Kinematic viscosity + folder="results", # Relative folder for storing results + velocity_degree=2, # default velocity degree + pressure_degree=1, # default pressure degree # Physical constants and solver parameters t=0.0, # Time tstep=0, # Timestep diff --git a/oasis/problems/__init__.py b/oasis/problems/__init__.py index 0522f627..6045286b 100644 --- a/oasis/problems/__init__.py +++ b/oasis/problems/__init__.py @@ -38,15 +38,15 @@ def getMemoryUsage(rss=True): # df.parameters["form_compiler"].add("no_ferari", True) # df.set_log_active(False) -# Default parameters for all solvers -NS_parameters = dict( - nu=0.01, # Kinematic viscosity - folder="results", # Relative folder for storing results - velocity_degree=2, # default velocity degree - pressure_degree=1, # default pressure degree -) +# Default parameters for all solvers should not be defined here, but rather in NSfrac.py or NScoupled.__init__.py with the rest +# NS_parameters = dict( +# nu=0.01, # Kinematic viscosity +# folder="results", # Relative folder for storing results +# velocity_degree=2, # default velocity degree +# pressure_degree=1, # default pressure degree +# ) -NS_expressions = {} +# NS_expressions = {} constrained_domain = None @@ -55,7 +55,7 @@ def getMemoryUsage(rss=True): # With diffusivities given as a Schmidt number defined by: # Schmidt = nu / D (= momentum diffusivity / mass diffusivity) -Schmidt = defaultdict(lambda: 1.0) +Schmidt = defaultdict(lambda: 1.0) # Schmidt["any_key"] returns 1.0 Schmidt_T = defaultdict(lambda: 0.7) # Turbulent Schmidt number (LES) Scalar = defaultdict(lambda: dict(Schmidt=1.0, family="CG", degree=1)) @@ -137,6 +137,7 @@ def QC(u): return Omega(u) - Strain(u) +# dont use this def recursive_update(dst, src): """Update dict dst with items from src deeply ("deep update").""" for key, val in src.items(): @@ -198,18 +199,18 @@ def theend_hook(**NS_namespace): pass -def problem_parameters(**NS_namespace): +def get_problem_parameters(**NS_namespace): """Updates problem specific parameters, and handles restart""" pass -def post_import_problem( - NS_parameters, mesh, commandline_kwargs, NS_expressions, **NS_namespace -): +def post_import_problem(NS_parameters, NS_expressions, mesh, commandline_kwargs): """Called after importing from problem.""" # Update NS_parameters with all parameters modified through command line for key, val in commandline_kwargs.items(): + if key not in NS_parameters.keys(): + raise KeyError("unknown key", key) if isinstance(val, dict): NS_parameters[key].update(val) else: @@ -222,7 +223,8 @@ def post_import_problem( assert isinstance(mesh, df.Mesh) # Returned dictionary to be updated in the NS namespace - d = dict(mesh=mesh) - d.update(NS_parameters) - d.update(NS_expressions) - return d + NS_parameters["mesh"] = mesh + # d = dict(mesh=mesh) + # d.update(NS_parameters) + NS_expressions.update(NS_expressions) + return NS_expressions From 3278190e6f5f12cdbcf360f1097d018c5ba7c02f Mon Sep 17 00:00:00 2001 From: flabowski Date: Fri, 25 Feb 2022 14:31:51 +0100 Subject: [PATCH 07/10] splitted NS_parameters and changed how default values and commandline args are loaded. explicit imports. --- oasis/NSfracStep.py | 213 ++++++++++-------- oasis/common/io.py | 35 +-- oasis/problems/NSfracStep/Channel.py | 6 + oasis/problems/NSfracStep/Cylinder.py | 34 ++- oasis/problems/NSfracStep/DrivenCavity.py | 6 +- oasis/problems/NSfracStep/DrivenCavity3D.py | 6 +- .../problems/NSfracStep/EccentricStenosis.py | 5 + oasis/problems/NSfracStep/FlowPastSphere3D.py | 5 + oasis/problems/NSfracStep/LaminarChannel.py | 5 + oasis/problems/NSfracStep/Lshape.py | 5 + oasis/problems/NSfracStep/Skewed2D.py | 5 + oasis/problems/NSfracStep/SkewedFlow.py | 5 + oasis/problems/NSfracStep/TaylorGreen2D.py | 5 + oasis/problems/NSfracStep/TaylorGreen3D.py | 5 + oasis/problems/__init__.py | 44 +++- 15 files changed, 257 insertions(+), 127 deletions(-) diff --git a/oasis/NSfracStep.py b/oasis/NSfracStep.py index a4a6d969..41c11c7c 100755 --- a/oasis/NSfracStep.py +++ b/oasis/NSfracStep.py @@ -36,12 +36,13 @@ import oasis.common.io as io import pickle from os import path +import copy import dolfin as df import numpy as np from oasis.common import parse_command_line # ,convert import oasis.common.utilities as ut from ufl import Coefficient -from oasis.problems.NSfracStep import default_parameters + from oasis.problems import ( info_blue, info_green, @@ -52,13 +53,10 @@ post_import_problem, ) -# TODO: write a custom update function, that throws a warning when value is overwritten -# TODO: get rid of importlib - commandline_kwargs = parse_command_line() # Find the problem module -default_problem = "DrivenCavity" # Cylinder, DrivenCavity +default_problem = "DrivenCavity" problemname = commandline_kwargs.get("problem", default_problem) # Import the problem module print("Importing problem module " + problemname) @@ -87,20 +85,18 @@ elif problemname == "TaylorGreen3D": import oasis.problems.NSfracStep.TaylorGreen3D as pblm -NS_parameters, NS_expressions = pblm.get_problem_parameters() -for key, val in default_parameters.items(): - if key not in NS_parameters.keys(): - NS_parameters[key] = val - # print(key, "set to default value, which is", val) +NS_namespace, NS_expressions = pblm.get_problem_parameters() -# merges everything into NS_parameters -post_import_problem(NS_parameters, NS_expressions, pblm.mesh, commandline_kwargs) -scalar_components = NS_parameters["scalar_components"] -mesh = NS_parameters["mesh"] +# problem_parameters used to be NS_parameters +NS_namespace, problem_parameters = post_import_problem( + NS_namespace, NS_expressions, pblm.mesh, commandline_kwargs +) +scalar_components = problem_parameters["scalar_components"] +mesh = NS_namespace["mesh"] # Use t and tstep from stored paramteres if restarting -if NS_parameters["restart_folder"] is not None: - folder = path.abspath(NS_parameters["restart_folder"]) +if problem_parameters["restart_folder"] is not None: + folder = path.abspath(NS_namespace["restart_folder"]) f = open(path.join(folder, "params.dat"), "rb") params = pickle.load(f) f.close() @@ -108,9 +104,19 @@ tstep = params["tstep"] # Import chosen functionality from solvers -# TODO: make explicit -pth = ".".join(("oasis.solvers.NSfracStep", NS_parameters["solver"])) -solver = importlib.import_module(pth) +solvername = problem_parameters["solver"] +if solvername == "BDFPC": + import oasis.solvers.NSfracStep.BDFPC as solver +elif solvername == "BDFPC_Fast": + import oasis.solvers.NSfracStep.BDFPC_Fast as solver +elif solvername == "Chorin": + import oasis.solvers.NSfracStep.Chorin as solver +elif solvername == "IPCS": + import oasis.solvers.NSfracStep.IPCS as solver +elif solvername == "IPCS_ABCN": + import oasis.solvers.NSfracStep.IPCS_ABCN as solver +elif solvername == "IPCS_ABE": + import oasis.solvers.NSfracStep.IPCS_ABE as solver # Create lists of components solved for dim = mesh.geometry().dim() @@ -121,12 +127,14 @@ # Set up initial folders for storing results newfolder, tstepfiles = io.create_initial_folders( sys_comp=sys_comp, - **NS_parameters, + **problem_parameters, ) +NS_namespace["newfolder"] = newfolder +NS_namespace["tstepfiles"] = tstepfiles # Declare FunctionSpaces and arguments -velocity_degree = NS_parameters["velocity_degree"] -pressure_degree = NS_parameters["pressure_degree"] +velocity_degree = problem_parameters["velocity_degree"] +pressure_degree = problem_parameters["pressure_degree"] V = Q = df.FunctionSpace( mesh, "CG", velocity_degree, constrained_domain=pblm.constrained_domain ) @@ -134,12 +142,12 @@ Q = df.FunctionSpace( mesh, "CG", pressure_degree, constrained_domain=pblm.constrained_domain ) -NS_parameters["V"] = V -NS_parameters["Q"] = Q -NS_parameters["u"] = u = df.TrialFunction(V) -NS_parameters["v"] = v = df.TestFunction(V) -NS_parameters["p"] = p = df.TrialFunction(Q) -NS_parameters["q"] = q = df.TestFunction(Q) +NS_namespace["V"] = V +NS_namespace["Q"] = Q +NS_namespace["u"] = u = df.TrialFunction(V) +NS_namespace["v"] = v = df.TestFunction(V) +NS_namespace["p"] = p = df.TrialFunction(Q) +NS_namespace["q"] = q = df.TestFunction(Q) # Use dictionary to hold all FunctionSpaces VV = dict((ui, V) for ui in uc_comp) @@ -149,21 +157,22 @@ q_ = dict((ui, df.Function(VV[ui], name=ui)) for ui in sys_comp) q_1 = dict((ui, df.Function(VV[ui], name=ui + "_1")) for ui in sys_comp) q_2 = dict((ui, df.Function(V, name=ui + "_2")) for ui in u_components) -NS_parameters["q_"], NS_parameters["q_1"], NS_parameters["q_2"] = q_, q_1, q_2 +NS_namespace["q_"], NS_namespace["q_1"], NS_namespace["q_2"] = q_, q_1, q_2 # Read in previous solution if restarting io.init_from_restart( sys_comp=sys_comp, uc_comp=uc_comp, u_components=u_components, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) # Create vectors of the segregated velocity components u_ = df.as_vector([q_[ui] for ui in u_components]) # Velocity vector at t u_1 = df.as_vector([q_1[ui] for ui in u_components]) # Velocity vector at t - dt u_2 = df.as_vector([q_2[ui] for ui in u_components]) # Velocity vector at t - 2*dt -NS_parameters["u_"], NS_parameters["u_1"], NS_parameters["u_2"] = u_, u_1, u_2 +NS_namespace["u_"], NS_namespace["u_1"], NS_namespace["u_2"] = u_, u_1, u_2 # Adams Bashforth projection of velocity at t - dt/2 U_AB = 1.5 * u_1 - 0.5 * u_2 @@ -172,61 +181,76 @@ x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors t x_1 = dict((ui, q_1[ui].vector()) for ui in sys_comp) # Solution vectors t - dt x_2 = dict((ui, q_2[ui].vector()) for ui in u_components) # Solution vectors t - 2*dt -NS_parameters["x_"], NS_parameters["x_1"], NS_parameters["x_2"] = x_, x_1, x_2 +NS_namespace["x_"], NS_namespace["x_1"], NS_namespace["x_2"] = x_, x_1, x_2 # Create vectors to hold rhs of equations b = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) # rhs vectors (final) b_tmp = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) # rhs temp storage vectors -NS_parameters["b"], NS_parameters["b_tmp"] = b, b_tmp +NS_namespace["b"], NS_namespace["b_tmp"] = b, b_tmp # Short forms pressure and scalars -NS_parameters["p_"] = q_["p"] # pressure at t -NS_parameters["p_1"] = q_1["p"] # pressure at t - dt -NS_parameters["dp_"] = dp_ = df.Function(Q) # pressure correction +NS_namespace["p_"] = q_["p"] # pressure at t +NS_namespace["p_1"] = q_1["p"] # pressure at t - dt +NS_namespace["dp_"] = dp_ = df.Function(Q) # pressure correction for ci in scalar_components: exec("{}_ = q_ ['{}']".format(ci, ci)) exec("{}_1 = q_1['{}']".format(ci, ci)) -krylov_solvers = NS_parameters["krylov_solvers"] -use_krylov_solvers = NS_parameters["use_krylov_solvers"] +krylov_solvers = problem_parameters["krylov_solvers"] +use_krylov_solvers = problem_parameters["use_krylov_solvers"] print_solve_info = use_krylov_solvers and krylov_solvers["monitor_convergence"] # Boundary conditions -NS_parameters["bcs"] = bcs = pblm.create_bcs(V=V) +NS_namespace["bcs"] = bcs = pblm.create_bcs(**problem_parameters, **NS_namespace) # LES setup -# TODO: make explicit -pth = ".".join(("oasis.solvers.NSfracStep.LES", NS_parameters["les_model"])) -lesmodel = importlib.import_module(pth) +les_modelname = problem_parameters["les_model"] +if les_modelname == "DynamicLagrangian": + import oasis.solvers.NSfracStep.LES.DynamicLagrangian as lesmodel +elif les_modelname == "DynamicModules": + import oasis.solvers.NSfracStep.LES.DynamicModules as lesmodel +elif les_modelname == "KineticEnergySGS": + import oasis.solvers.NSfracStep.LES.KineticEnergySGS as lesmodel +elif les_modelname == "NoModel": + import oasis.solvers.NSfracStep.LES.NoModel as lesmodel +elif les_modelname == "ScaleDepDynamicLagrangian": + import oasis.solvers.NSfracStep.LES.ScaleDepDynamicLagrangian as lesmodel +elif les_modelname == "Smagorinsky": + import oasis.solvers.NSfracStep.LES.Smagorinsky as lesmodel +elif les_modelname == "Wale": + import oasis.solvers.NSfracStep.LES.Wale as lesmodel + les_dict = lesmodel.les_setup() # FIXME: which dicts have to be passed? -NS_parameters.update(les_dict) +NS_namespace.update(les_dict) # Non-Newtonian setup -# TODO: make explicit -# exec("from oasis.solvers.NSfracStep.NNModel.{} import *".format(nn_model)) -pth = ".".join(("oasis.solvers.NSfracStep.NNModel", NS_parameters["nn_model"])) -nnmodel = importlib.import_module(pth) +nn_modelname = problem_parameters["nn_model"] +if nn_modelname == "NoModel": + import oasis.solvers.NSfracStep.NNModel.NoModel as nnmodel +elif nn_modelname == "ModifiedCross": + import oasis.solvers.NSfracStep.NNModel.ModifiedCross as nnmodel + nn_dict = nnmodel.nn_setup() # FIXME: which dicts have to be passed? -NS_parameters.update(nn_dict) +NS_namespace.update(nn_dict) # Initialize solution -pblm.initialize(**NS_parameters) +pblm.initialize(**NS_namespace) # Fetch linear algebra solvers -u_sol, p_sol, c_sol = solver.get_solvers(**NS_parameters) +u_sol, p_sol, c_sol = solver.get_solvers(**problem_parameters, **NS_namespace) # Get constant body forces -f = pblm.body_force(**NS_parameters) +f = pblm.body_force(**NS_namespace) assert isinstance(f, Coefficient) b0 = dict((ui, df.assemble(v * f[i] * df.dx)) for i, ui in enumerate(u_components)) -NS_parameters["f"], NS_parameters["b0"] = f, b0 +NS_namespace["f"], NS_namespace["b0"] = f, b0 # Get scalar sources -fs = pblm.scalar_source(**NS_parameters) +fs = pblm.scalar_source(**problem_parameters) for ci in scalar_components: assert isinstance(fs[ci], Coefficient) b0[ci] = df.assemble(v * fs[ci] * df.dx) -NS_parameters["fs"] = fs +NS_namespace["fs"] = fs # Preassemble and allocate # TODO: ut.XXX should not be passed but raather imported in solver.py @@ -239,32 +263,34 @@ NNsource=ut.NNsource, assemble_matrix=ut.assemble_matrix, u_components=u_components, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) -NS_parameters.update(F_dict) +NS_namespace.update(F_dict) -t = NS_parameters["t"] -tstep = NS_parameters["tstep"] -T = NS_parameters["T"] -max_iter = NS_parameters["max_iter"] -it0 = NS_parameters["iters_on_first_timestep"] -max_error = NS_parameters["max_error"] -print_intermediate_info = NS_parameters["print_intermediate_info"] -AB_projection_pressure = NS_parameters["AB_projection_pressure"] +t = problem_parameters["t"] +tstep = problem_parameters["tstep"] +T = problem_parameters["T"] +max_iter = problem_parameters["max_iter"] +it0 = problem_parameters["iters_on_first_timestep"] +max_error = problem_parameters["max_error"] +print_intermediate_info = problem_parameters["print_intermediate_info"] +AB_projection_pressure = problem_parameters["AB_projection_pressure"] # Anything problem specific -psh_dict = pblm.pre_solve_hook(mesh=mesh, velocity_degree=velocity_degree) -NS_parameters.update(psh_dict) +psh_dict = pblm.pre_solve_hook(**problem_parameters, **NS_namespace) +NS_namespace.update(psh_dict) tx = OasisTimer("Timestep timer") tx.start() stop = False total_timer = OasisTimer("Start simulations", True) while t < (T - tstep * df.DOLFIN_EPS) and not stop: - t += NS_parameters["dt"] + t += problem_parameters["dt"] tstep += 1 - NS_parameters["t"] = t - NS_parameters["tstep"] = tstep + # TODO: maybe t and tstep should not be in any dictionary, since it changes + problem_parameters["t"] = t + problem_parameters["tstep"] = tstep inner_iter = 0 udiff = np.array([1e8]) # Norm of velocity change over last inner iter num_iter = max(it0, max_iter) if tstep <= 10 else max_iter @@ -275,28 +301,30 @@ t0 = OasisTimer("Tentative velocity") if inner_iter == 1: - lesmodel.les_update(**NS_parameters) - nnmodel.nn_update(**NS_parameters) + lesmodel.les_update(**NS_namespace) + nnmodel.nn_update(**NS_namespace) solver.assemble_first_inner_iter( u_components=u_components, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) udiff[0] = 0.0 for i, ui in enumerate(u_components): t1 = OasisTimer("Solving tentative velocity " + ui, print_solve_info) - solver.velocity_tentative_assemble(ui=ui, **NS_parameters) - pblm.velocity_tentative_hook(ui=ui, **NS_parameters) + solver.velocity_tentative_assemble(ui=ui, **NS_namespace) + pblm.velocity_tentative_hook(ui=ui, **NS_namespace) solver.velocity_tentative_solve( udiff=udiff, ui=ui, u_sol=u_sol, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) t1.stop() t0 = OasisTimer("Pressure solve", print_solve_info) - solver.pressure_assemble(**NS_parameters) - pblm.pressure_hook(**NS_parameters) - solver.pressure_solve(p_sol=p_sol, **NS_parameters) + solver.pressure_assemble(**problem_parameters, **NS_namespace) + pblm.pressure_hook(**NS_namespace) + solver.pressure_solve(p_sol=p_sol, **NS_namespace) t0.stop() solver.print_velocity_pressure_info( @@ -305,43 +333,40 @@ info_blue=info_blue, inner_iter=inner_iter, udiff=udiff, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) # Update velocity t0 = OasisTimer("Velocity update") solver.velocity_update( u_components=u_components, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) t0.stop() # Solve for scalars if len(scalar_components) > 0: - solver.scalar_assemble( - **NS_parameters, - ) + solver.scalar_assemble(**problem_parameters, **NS_namespace) for ci in scalar_components: t1 = OasisTimer("Solving scalar {}".format(ci), print_solve_info) pblm.scalar_hook() # FIXME: what do we need to pass here? solver.scalar_solve( - c_sol=c_sol, - ci=ci, - **NS_parameters, + c_sol=c_sol, ci=ci, **problem_parameters, **NS_namespace ) t1.stop() - pblm.temporal_hook(**NS_parameters) + pblm.temporal_hook(**problem_parameters, **NS_namespace) # Save solution if required and check for killoasis file stop = io.save_solution( - newfolder=newfolder, - tstepfiles=tstepfiles, u_components=u_components, - NS_parameters=NS_parameters, + NS_parameters=problem_parameters, constrained_domain=pblm.constrained_domain, AssignedVectorFunction=ut.AssignedVectorFunction, total_timer=total_timer, - **NS_parameters, + **problem_parameters, + **NS_namespace, ) # Update to a new timestep for ui in u_components: @@ -388,11 +413,11 @@ + " MB (RSS)" ) -if NS_parameters["restart_folder"] is not None: +if problem_parameters["restart_folder"] is not None: io.merge_visualization_files(newfolder=newfolder) # Final hook -pblm.theend_hook(**NS_parameters) +pblm.theend_hook(**problem_parameters, **NS_namespace) # F_dict.keys() = dict_keys(['A', 'M', 'K', 'Ap', 'divu', 'gradp', 'Ta', 'Tb', 'bb', 'bx', 'u_ab', 'a_conv', 'a_scalar', 'LT', 'KT', 'NT']) # nn_dict.keys() = dict_keys(['nunn_']) @@ -400,3 +425,5 @@ # quantities.keys() = dict_keys(['u', 'u_', 'u_1', 'u_2', 'x_', 'x_1', 'x_2', 'b', 'b_tmp', 'p', 'p_', 'p_1', 'dp_', 'q', 'q_', 'q_1', 'q_2', 'v', 'V', 'Q', 'f', 'fs', 'bcs', 'b0']) # NS_parameters.keys() = dict_keys(['nu', 'folder', 'velocity_degree', 'pressure_degree', 't', 'tstep', 'T', 'dt', 'AB_projection_pressure', 'solver', 'max_iter', 'max_error', 'iters_on_first_timestep', 'use_krylov_solvers', 'print_intermediate_info', 'print_velocity_pressure_convergence', 'plot_interval', 'checkpoint', 'save_step', 'restart_folder', 'output_timeseries_as_vector', 'killtime', 'les_model', 'Smagorinsky', 'Wale', 'DynamicSmagorinsky', 'KineticEnergySGS', 'nn_model', 'ModifiedCross', 'testing', 'krylov_solvers', 'velocity_update_solver', 'velocity_krylov_solver', 'pressure_krylov_solver', 'scalar_krylov_solver', 'nut_krylov_solver', 'nu_nn_krylov_solver']) # psh_dict.keys() = dict_keys(['uv']) +# NS_parameters.keys() = dict_keys(['nu', 'folder', 'velocity_degree', 'pressure_degree', 't', 'tstep', 'T', 'dt', 'AB_projection_pressure', 'solver', 'max_iter', 'max_error', 'iters_on_first_timestep', 'use_krylov_solvers', 'print_intermediate_info', 'print_velocity_pressure_convergence', 'plot_interval', 'checkpoint', 'save_step', 'restart_folder', 'output_timeseries_as_vector', 'killtime', 'les_model', 'Smagorinsky', 'Wale', 'DynamicSmagorinsky', 'KineticEnergySGS', 'nn_model', 'ModifiedCross', 'testing', 'krylov_solvers', 'velocity_update_solver', 'velocity_krylov_solver', 'pressure_krylov_solver', 'scalar_krylov_solver', 'nut_krylov_solver', 'nu_nn_krylov_solver']) +# psh_dict.keys() = dict_keys(['uv']) diff --git a/oasis/common/io.py b/oasis/common/io.py index d3e687c6..e64e73af 100644 --- a/oasis/common/io.py +++ b/oasis/common/io.py @@ -82,25 +82,25 @@ def create_initial_folders( return newfolder, tstepfiles -# TODO: dont pass NS_parameters, but rather all +# FIXME def save_solution( - tstep, - t, + tstep, # is in NS_parameters + t, # is in NS_parameters q_, q_1, - folder, + folder, # is in NS_parameters newfolder, - save_step, + save_step, # is in NS_parameters checkpoint, NS_parameters, tstepfiles, u_, u_components, - scalar_components, - output_timeseries_as_vector, + scalar_components, # is in NS_parameters + output_timeseries_as_vector, # is in NS_parameters constrained_domain, - AssignedVectorFunction, # TODO: why is this an argument? it can be imported from utilities - killtime, + AssignedVectorFunction, # it can be imported from utilities + killtime, # is in NS_parameters total_timer, **NS_namespace ): @@ -108,16 +108,16 @@ def save_solution( NS_parameters.update(t=t, tstep=tstep) if tstep % save_step == 0: save_tstep_solution_h5( - tstep, + tstep, # is in NS_parameters q_, u_, newfolder, tstepfiles, constrained_domain, - output_timeseries_as_vector, + output_timeseries_as_vector, # is in NS_parameters u_components, - AssignedVectorFunction, - scalar_components, + AssignedVectorFunction, # it can be imported from utilities + scalar_components, # is in NS_parameters NS_parameters, ) @@ -135,17 +135,18 @@ def save_solution( return killoasis +# FIXME def save_tstep_solution_h5( - tstep, + tstep, # is in NS_parameters q_, u_, newfolder, tstepfiles, constrained_domain, - output_timeseries_as_vector, + output_timeseries_as_vector, # is in NS_parameters u_components, - AssignedVectorFunction, - scalar_components, + AssignedVectorFunction, # it can be imported from utilities + scalar_components, # is in NS_parameters NS_parameters, ): """Store solution on current timestep to XDMF file.""" diff --git a/oasis/problems/NSfracStep/Channel.py b/oasis/problems/NSfracStep/Channel.py index 362204b7..8d660c2f 100644 --- a/oasis/problems/NSfracStep/Channel.py +++ b/oasis/problems/NSfracStep/Channel.py @@ -23,10 +23,12 @@ create_bcs, ) from oasis.problems.NSfracStep import ( + default_parameters, velocity_tentative_hook, pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.Channel import mesh @@ -85,6 +87,10 @@ def get_problem_parameters(**kwargs): ) NS_expressions = dict(constrained_domain=PeriodicDomain(Lx, Lz)) + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/Cylinder.py b/oasis/problems/NSfracStep/Cylinder.py index 20633ad1..5505b014 100644 --- a/oasis/problems/NSfracStep/Cylinder.py +++ b/oasis/problems/NSfracStep/Cylinder.py @@ -22,13 +22,26 @@ post_import_problem, create_bcs, ) +import oasis.common.utilities as ut from oasis.problems.NSfracStep import ( velocity_tentative_hook, pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, +) +from oasis.problems.Cylinder import ( + mesh, + Inlet, + Cyl, + Wall, + Outlet, + center, + cases, + H, + L, + D, ) -from oasis.problems.Cylinder import mesh, Inlet, Cyl, Wall, Outlet, center, cases, D from dolfin import ( Expression, DirichletBC, @@ -47,6 +60,7 @@ curl, DomainBoundary, Point, + ds, ) from os import getcwd, path import pickle @@ -81,6 +95,9 @@ def get_problem_parameters(**kwargs): Re=Re, Umean=Umean, nu=Umean * D / Re, + H=H, + L=L, + D=D, T=100, dt=0.01, checkpoint=50, @@ -90,12 +107,15 @@ def get_problem_parameters(**kwargs): print_intermediate_info=100, use_krylov_solvers=True, ) - # FIXME: NS_parameters["krylov_solvers"] = dict(monitor_convergence=True) NS_parameters["velocity_krylov_solver"] = dict( preconditioner_type="jacobi", solver_type="bicgstab" ) + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = {} return NS_parameters, NS_expressions @@ -128,21 +148,21 @@ def pre_solve_hook( newfolder, tstepfiles, tstep, - ds, + # ds, # defined in dolfin -> import u_, - AssignedVectorFunction, + # AssignedVectorFunction, # defined in utilities -> import **NS_namespace ): - uv = AssignedVectorFunction(u_, name="Velocity") + uv = ut.AssignedVectorFunction(u_, name="Velocity") omega = Function(V, name="omega") # Store omega each save_step add_function_to_tstepfiles(omega, newfolder, tstepfiles, tstep) ff = MeshFunction("size_t", mesh, mesh.ufl_cell().geometric_dimension() - 1) Cyl.mark(ff, 1) n = FacetNormal(mesh) - ds = ds[ff] + ds_ = ds[ff] - return dict(uv=uv, omega=omega, ds=ds, ff=ff, n=n) + return dict(uv=uv, omega=omega, ds=ds_, ff=ff, n=n) def temporal_hook( diff --git a/oasis/problems/NSfracStep/DrivenCavity.py b/oasis/problems/NSfracStep/DrivenCavity.py index a7aa72d5..565fb6e9 100644 --- a/oasis/problems/NSfracStep/DrivenCavity.py +++ b/oasis/problems/NSfracStep/DrivenCavity.py @@ -26,6 +26,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) from oasis.problems.DrivenCavity import noslip, top, bottom, mesh import dolfin as df @@ -50,7 +51,10 @@ def get_problem_parameters(**kwargs): print_intermediate_info=100, use_krylov_solvers=True, ) - + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = {} return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/DrivenCavity3D.py b/oasis/problems/NSfracStep/DrivenCavity3D.py index 26077bee..e3894efa 100644 --- a/oasis/problems/NSfracStep/DrivenCavity3D.py +++ b/oasis/problems/NSfracStep/DrivenCavity3D.py @@ -24,6 +24,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.DrivenCavity3D import mesh @@ -46,7 +47,10 @@ def get_problem_parameters(**kwargs): print_intermediate_info=100, use_krylov_solvers=True, ) - + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = dict(constrained_domain=PeriodicDomain()) return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/EccentricStenosis.py b/oasis/problems/NSfracStep/EccentricStenosis.py index 9a6a7154..a9708d72 100644 --- a/oasis/problems/NSfracStep/EccentricStenosis.py +++ b/oasis/problems/NSfracStep/EccentricStenosis.py @@ -41,6 +41,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.EccentricStenosis import mesh @@ -90,6 +91,10 @@ def get_problem_parameters(**kwargs): print_intermediate_info=100, print_velocity_pressure_convergence=False, ) + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val average_inlet_velocity = get_ave_inlet_velocity( NS_parameters["Re"], NS_parameters["nu"], NS_parameters["D"] diff --git a/oasis/problems/NSfracStep/FlowPastSphere3D.py b/oasis/problems/NSfracStep/FlowPastSphere3D.py index 9f752d60..84a31749 100644 --- a/oasis/problems/NSfracStep/FlowPastSphere3D.py +++ b/oasis/problems/NSfracStep/FlowPastSphere3D.py @@ -24,6 +24,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.FlowPastSphere3D import mesh @@ -67,6 +68,10 @@ def get_problem_parameters(**kwargs): use_krylov_solvers=True, ) NS_parameters["krylov_solvers"]["monitor_convergence"] = True + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = {} return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/LaminarChannel.py b/oasis/problems/NSfracStep/LaminarChannel.py index 71f95fad..00ea91be 100644 --- a/oasis/problems/NSfracStep/LaminarChannel.py +++ b/oasis/problems/NSfracStep/LaminarChannel.py @@ -26,6 +26,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.LaminarChannel import mesh @@ -56,6 +57,10 @@ def get_problem_parameters(**kwargs): velocity_degree=1, use_krylov_solvers=False, ) + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = dict(constrained_domain=PeriodicDomain(L)) return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/Lshape.py b/oasis/problems/NSfracStep/Lshape.py index a5d3a70a..29c0eb7f 100644 --- a/oasis/problems/NSfracStep/Lshape.py +++ b/oasis/problems/NSfracStep/Lshape.py @@ -24,6 +24,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.Lshape import mesh @@ -55,6 +56,10 @@ def get_problem_parameters(**kwargs): degree = kwargs["pressure_degree"] else: degree = NS_parameters["pressure_degree"] + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = dict(p_in=df.Expression("sin(pi*t)", t=0.0, degree=degree)) return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/Skewed2D.py b/oasis/problems/NSfracStep/Skewed2D.py index c3f5391e..e0d7ece1 100644 --- a/oasis/problems/NSfracStep/Skewed2D.py +++ b/oasis/problems/NSfracStep/Skewed2D.py @@ -26,6 +26,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) from oasis.problems.Skewed2D import mesh, walls, inlet, outlet import dolfin as df @@ -43,6 +44,10 @@ def get_problem_parameters(**kwargs): print_velocity_pressure_convergence=True, ) NS_expressions = {} + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/SkewedFlow.py b/oasis/problems/NSfracStep/SkewedFlow.py index 36efe07e..751662ff 100644 --- a/oasis/problems/NSfracStep/SkewedFlow.py +++ b/oasis/problems/NSfracStep/SkewedFlow.py @@ -25,6 +25,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) from oasis.problems.SkewedFlow import mesh, inlet, walls, outlet import dolfin as df @@ -62,6 +63,10 @@ def get_problem_parameters(**kwargs): use_krylov_solvers=True, print_velocity_pressure_convergence=True, ) + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = {} return NS_parameters, NS_expressions diff --git a/oasis/problems/NSfracStep/TaylorGreen2D.py b/oasis/problems/NSfracStep/TaylorGreen2D.py index dcbbb568..8ebb7cf4 100644 --- a/oasis/problems/NSfracStep/TaylorGreen2D.py +++ b/oasis/problems/NSfracStep/TaylorGreen2D.py @@ -25,6 +25,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) import numpy as np @@ -65,6 +66,10 @@ def get_problem_parameters(**kwargs): "relative_tolerance": 1e-12, "absolute_tolerance": 1e-12, } + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = dict( dict( constrained_domain=PeriodicDomain(), diff --git a/oasis/problems/NSfracStep/TaylorGreen3D.py b/oasis/problems/NSfracStep/TaylorGreen3D.py index 9a63b487..03560b01 100644 --- a/oasis/problems/NSfracStep/TaylorGreen3D.py +++ b/oasis/problems/NSfracStep/TaylorGreen3D.py @@ -24,6 +24,7 @@ pressure_hook, start_timestep_hook, temporal_hook, + default_parameters, ) # from oasis.problems.TaylorGreen3D import mesh @@ -66,6 +67,10 @@ def get_problem_parameters(**kwargs): use_krylov_solvers=True, krylov_solvers=dict(monitor_convergence=True), ) + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val NS_expressions = dict( constrained_domain=PeriodicDomain(), diff --git a/oasis/problems/__init__.py b/oasis/problems/__init__.py index 6045286b..60d1fd1e 100644 --- a/oasis/problems/__init__.py +++ b/oasis/problems/__init__.py @@ -10,6 +10,7 @@ from collections import defaultdict from numpy import array, maximum, zeros + # UnitSquareMesh(20, 20) # Just due to MPI bug on Scinet # try: @@ -207,7 +208,12 @@ def get_problem_parameters(**NS_namespace): def post_import_problem(NS_parameters, NS_expressions, mesh, commandline_kwargs): """Called after importing from problem.""" - # Update NS_parameters with all parameters modified through command line + # # set default parameters + # for key, val in NS_parameters.items(): + # if key not in NS_parameters.keys(): + # NS_parameters[key] = val + + # Update NS_namespace with all parameters modified through command line for key, val in commandline_kwargs.items(): if key not in NS_parameters.keys(): raise KeyError("unknown key", key) @@ -216,15 +222,37 @@ def post_import_problem(NS_parameters, NS_expressions, mesh, commandline_kwargs) else: NS_parameters[key] = val + NS_parameters.update(NS_expressions) + # If the mesh is a callable function, then create the mesh here. if callable(mesh): mesh = mesh(**NS_parameters) - assert isinstance(mesh, df.Mesh) - # Returned dictionary to be updated in the NS namespace - NS_parameters["mesh"] = mesh - # d = dict(mesh=mesh) - # d.update(NS_parameters) - NS_expressions.update(NS_expressions) - return NS_expressions + # split : + # this is the dictionary that will be saved, it should not be changed + problem_parameters = {} # problem specific parameters + NS_namespace = {} # objects, functions, ... that are needed to solve the problem + NS_namespace["mesh"] = mesh + + for key, val in NS_parameters.items(): + if type(val) in [str, bool, type(None), float, int]: + problem_parameters[key] = val + elif type(val) == dict: + k0 = list(val.keys())[0] + if type(val[k0]) in [str, bool, type(None), float, int]: + problem_parameters[key] = val + else: + print(key, val) + NS_namespace[key] = val + elif type(val) == list: + k0 = val[0] + if type(val[0]) in [str, bool, type(None), float, int]: + problem_parameters[key] = val + else: + print(key, val) + NS_namespace[key] = val + else: + print(key, val) + NS_namespace[key] = val + return NS_namespace, problem_parameters From 6b75c1b0930c60079efe6e16d1f6884fa435b609 Mon Sep 17 00:00:00 2001 From: flabowski Date: Fri, 25 Feb 2022 14:42:17 +0100 Subject: [PATCH 08/10] Autoformat for conformance to the PEP 8 convention. --- oasis/NSCoupled.py | 93 +++++++++++++----------- oasis/problems/NSCoupled/Cylinder.py | 43 ++++++----- oasis/problems/NSCoupled/DrivenCavity.py | 11 ++- oasis/problems/NSCoupled/Nozzle2D.py | 26 ++++--- oasis/problems/NSCoupled/Skewed2D.py | 11 +-- oasis/problems/NSCoupled/SkewedFlow.py | 25 ++++--- oasis/problems/NSCoupled/__init__.py | 13 ++-- 7 files changed, 115 insertions(+), 107 deletions(-) diff --git a/oasis/NSCoupled.py b/oasis/NSCoupled.py index 5bf251eb..34244f2b 100755 --- a/oasis/NSCoupled.py +++ b/oasis/NSCoupled.py @@ -1,7 +1,7 @@ -__author__ = 'Mikael Mortensen ' -__date__ = '2014-04-04' -__copyright__ = 'Copyright (C) 2014 ' + __author__ -__license__ = 'GNU Lesser GPL version 3 or any later version' +__author__ = "Mikael Mortensen " +__date__ = "2014-04-04" +__copyright__ = "Copyright (C) 2014 " + __author__ +__license__ = "GNU Lesser GPL version 3 or any later version" import importlib from oasis.common import * @@ -26,16 +26,18 @@ commandline_kwargs = parse_command_line() # Find the problem module -default_problem = 'DrivenCavity' -problemname = commandline_kwargs.get('problem', default_problem) -problemspec = importlib.util.find_spec('.'.join(('oasis.problems.NSCoupled', problemname))) +default_problem = "DrivenCavity" +problemname = commandline_kwargs.get("problem", default_problem) +problemspec = importlib.util.find_spec( + ".".join(("oasis.problems.NSCoupled", problemname)) +) if problemspec is None: problemspec = importlib.util.find_spec(problemname) if problemspec is None: - raise RuntimeError(problemname+' not found') + raise RuntimeError(problemname + " not found") # Import the problem module -print('Importing problem module '+problemname+':\n'+problemspec.origin) +print("Importing problem module " + problemname + ":\n" + problemspec.origin) problemmod = importlib.util.module_from_spec(problemspec) problemspec.loader.exec_module(problemmod) @@ -48,33 +50,34 @@ vars().update(post_import_problem(**vars())) # Import chosen functionality from solvers -solver = importlib.import_module('.'.join(('oasis.solvers.NSCoupled', solver))) -vars().update({name:solver.__dict__[name] for name in solver.__all__}) +solver = importlib.import_module(".".join(("oasis.solvers.NSCoupled", solver))) +vars().update({name: solver.__dict__[name] for name in solver.__all__}) # Create lists of components solved for -u_components = ['u'] -sys_comp = ['up'] + scalar_components +u_components = ["u"] +sys_comp = ["up"] + scalar_components # Get the chosen mixed elment -element = commandline_kwargs.get('element', 'TaylorHood') +element = commandline_kwargs.get("element", "TaylorHood") vars().update(elements[element]) # TaylorHood may overload degree of elements -if element == 'TaylorHood': - degree['u'] = commandline_kwargs.get('velocity_degree', degree['u']) - degree['p'] = commandline_kwargs.get('pressure_degree', degree['p']) +if element == "TaylorHood": + degree["u"] = commandline_kwargs.get("velocity_degree", degree["u"]) + degree["p"] = commandline_kwargs.get("pressure_degree", degree["p"]) # Should assert that degree['p'] = degree['u']-1 ?? # Declare Elements -V = VectorElement(family['u'], mesh.ufl_cell(), degree['u']) -Q = FiniteElement(family['p'], mesh.ufl_cell(), degree['p']) +V = VectorElement(family["u"], mesh.ufl_cell(), degree["u"]) +Q = FiniteElement(family["p"], mesh.ufl_cell(), degree["p"]) # Create Mixed space # MINI element has bubble, add to V if bubble: B = VectorElement("Bubble", mesh.ufl_cell(), mesh.geometry().dim() + 1) - VQ = FunctionSpace(mesh, MixedElement(V+B, Q), - constrained_domain=constrained_domain) + VQ = FunctionSpace( + mesh, MixedElement(V + B, Q), constrained_domain=constrained_domain + ) else: VQ = FunctionSpace(mesh, V * Q, constrained_domain=constrained_domain) @@ -85,7 +88,7 @@ v, q = TestFunctions(VQ) # For scalars use CG space -CG = FunctionSpace(mesh, 'CG', 1, constrained_domain=constrained_domain) +CG = FunctionSpace(mesh, "CG", 1, constrained_domain=constrained_domain) c = TrialFunction(CG) ct = TestFunction(CG) @@ -94,17 +97,19 @@ # Create dictionaries for the solutions at two timesteps q_ = dict((ui, Function(VV[ui], name=ui)) for ui in sys_comp) -q_1 = dict((ui, Function(VV[ui], name=ui + '_1')) for ui in sys_comp) +q_1 = dict((ui, Function(VV[ui], name=ui + "_1")) for ui in sys_comp) # Short forms -up_ = q_['up'] # Solution at next iteration -up_1 = q_1['up'] # Solution at previous iteration +up_ = q_["up"] # Solution at next iteration +up_1 = q_1["up"] # Solution at previous iteration u_, p_ = split(up_) u_1, p_1 = split(up_1) # Create short forms for accessing the solution vectors -x_ = dict((ui, q_ [ui].vector()) for ui in sys_comp) # Solution vectors -x_1 = dict((ui, q_1[ui].vector()) for ui in sys_comp) # Solution vectors previous iteration +x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors +x_1 = dict( + (ui, q_1[ui].vector()) for ui in sys_comp +) # Solution vectors previous iteration # Create vectors to hold rhs of equations b = dict((ui, Vector(x_[ui])) for ui in sys_comp) @@ -153,11 +158,12 @@ def iterate(iters=max_iter): x_1[ui].zero() x_1[ui].axpy(1.0, x_[ui]) - error = b['up'].norm('l2') + error = b["up"].norm("l2") print_velocity_pressure_info(**locals()) iter += 1 + def iterate_scalar(iters=max_iter, errors=max_error): # Newton iterations for scalars if len(scalar_components) > 0: @@ -169,18 +175,17 @@ def iterate_scalar(iters=max_iter, errors=max_error): scalar_assemble(**globals()) scalar_hook(**globals()) scalar_solve(**globals()) - err[ci] = b[ci].norm('l2') + err[ci] = b[ci].norm("l2") if MPI.rank(MPI.comm_world) == 0: - print('Iter {}, Error {} = {}'.format(citer, ci, err[ci])) + print("Iter {}, Error {} = {}".format(citer, ci, err[ci])) citer += 1 - -timer = OasisTimer('Start Newton iterations flow', True) +timer = OasisTimer("Start Newton iterations flow", True) # Assemble rhs once, before entering iterations (velocity components) -b['up'] = assemble(Fs['up'], tensor=b['up']) -for bc in bcs['up']: - bc.apply(b['up'], x_['up']) +b["up"] = assemble(Fs["up"], tensor=b["up"]) +for bc in bcs["up"]: + bc.apply(b["up"], x_["up"]) iterate(max_iter) timer.stop() @@ -188,7 +193,7 @@ def iterate_scalar(iters=max_iter, errors=max_error): # Assuming there is no feedback to the flow solver from the scalar field, # we solve the scalar only after converging the flow if len(scalar_components) > 0: - scalar_timer = OasisTimer('Start Newton iterations scalars', True) + scalar_timer = OasisTimer("Start Newton iterations scalars", True) # Assemble rhs once, before entering iterations (velocity components) for scalar in scalar_components: b[scalar] = assemble(Fs[scalar], tensor=b[scalar]) @@ -199,13 +204,17 @@ def iterate_scalar(iters=max_iter, errors=max_error): scalar_timer.stop() list_timings(TimingClear.keep, [TimingType.wall]) -info_red('Total computing time = {0:f}'.format(timer.elapsed()[0])) -oasis_memory('Final memory use ') +info_red("Total computing time = {0:f}".format(timer.elapsed()[0])) +oasis_memory("Final memory use ") total_initial_dolfin_memory = MPI.sum(MPI.comm_world, initial_memory_use) -info_red('Memory use for importing dolfin = {} MB (RSS)'.format( - total_initial_dolfin_memory)) -info_red('Total memory use of solver = ' + - str(oasis_memory.memory - total_initial_dolfin_memory) + ' MB (RSS)') +info_red( + "Memory use for importing dolfin = {} MB (RSS)".format(total_initial_dolfin_memory) +) +info_red( + "Total memory use of solver = " + + str(oasis_memory.memory - total_initial_dolfin_memory) + + " MB (RSS)" +) # Final hook theend_hook(**vars()) diff --git a/oasis/problems/NSCoupled/Cylinder.py b/oasis/problems/NSCoupled/Cylinder.py index 61b6fdbf..9260f80d 100644 --- a/oasis/problems/NSCoupled/Cylinder.py +++ b/oasis/problems/NSCoupled/Cylinder.py @@ -1,4 +1,5 @@ from __future__ import print_function + __author__ = "Mikael Mortensen " __date__ = "2014-04-04" __copyright__ = "Copyright (C) 2014 " + __author__ @@ -9,11 +10,7 @@ # Override some problem specific parameters def problem_parameters(NS_parameters, scalar_components, **NS_namespace): - NS_parameters.update( - omega=1.0, - max_iter=100, - plot_interval=10, - velocity_degree=2) + NS_parameters.update(omega=1.0, max_iter=100, plot_interval=10, velocity_degree=2) scalar_components += ["c", "d"] @@ -23,13 +20,15 @@ def scalar_source(c_, d_, **NS_namespace): def create_bcs(VQ, Um, CG, V, element, **NS_namespace): - inlet = Expression(("4.*{0}*x[1]*({1}-x[1])/pow({1}, 2)".format(Um, H), "0"), element=V) + inlet = Expression( + ("4.*{0}*x[1]*({1}-x[1])/pow({1}, 2)".format(Um, H), "0"), element=V + ) ux = Expression(("0.00*x[1]", "-0.00*(x[0]-{})".format(center)), element=V) if element == "MINI": # This is an inefficient solution due to FFC issue #69, solfin issue #489 inlet0 = project(inlet, VQ.sub(0).collapse()) - ux0 = project(ux, VQ.sub(0).collapse(), solver_type='cg') - wall = project(Constant((0, 0)), VQ.sub(0).collapse(), solver_type='cg') + ux0 = project(ux, VQ.sub(0).collapse(), solver_type="cg") + wall = project(Constant((0, 0)), VQ.sub(0).collapse(), solver_type="cg") bc0 = DirichletBC(VQ.sub(0), inlet0, Inlet) bc1 = DirichletBC(VQ.sub(0), ux0, Cyl) bc2 = DirichletBC(VQ.sub(0), wall, Wall) @@ -38,27 +37,27 @@ def create_bcs(VQ, Um, CG, V, element, **NS_namespace): bc0 = DirichletBC(VQ.sub(0), inlet, Inlet) bc1 = DirichletBC(VQ.sub(0), ux, Cyl) bc2 = DirichletBC(VQ.sub(0), (0, 0), Wall) - return dict(up=[bc0, bc1, bc2], - c=[DirichletBC(CG, 1, Cyl), - DirichletBC(CG, 0, Inlet)], - d=[DirichletBC(CG, 2, Cyl), - DirichletBC(CG, 0, Inlet)]) + return dict( + up=[bc0, bc1, bc2], + c=[DirichletBC(CG, 1, Cyl), DirichletBC(CG, 0, Inlet)], + d=[DirichletBC(CG, 2, Cyl), DirichletBC(CG, 0, Inlet)], + ) def theend_hook(u_, p_, up_, mesh, ds, VQ, nu, Umean, c_, testing, **NS_namespace): if not testing: - plot(u_, title='Velocity') - plot(p_, title='Pressure') - plot(c_, title='Scalar') + plot(u_, title="Velocity") + plot(p_, title="Pressure") + plot(c_, title="Scalar") - R = VectorFunctionSpace(mesh, 'R', 0) + R = VectorFunctionSpace(mesh, "R", 0) c = TestFunction(R) tau = -p_ * Identity(2) + nu * (grad(u_) + grad(u_).T) ff = MeshFunction("size_t", mesh, 1, 0) Cyl.mark(ff, 1) n = FacetNormal(mesh) ds = ds(subdomain_data=ff) - forces = assemble(dot(dot(tau, n), c) * ds(1)).get_local() * 2 / Umean**2 / D + forces = assemble(dot(dot(tau, n), c) * ds(1)).get_local() * 2 / Umean ** 2 / D try: print("Cd = {0:2.6e}, CL = {1:2.6e}".format(*forces)) @@ -69,6 +68,7 @@ def theend_hook(u_, p_, up_, mesh, ds, VQ, nu, Umean, c_, testing, **NS_namespac if not testing: from fenicstools import Probes from numpy import linspace, repeat, where, resize + xx = linspace(0, L, 10000) x = resize(repeat(xx, 2), (10000, 2)) x[:, 1] = 0.2 @@ -77,5 +77,8 @@ def theend_hook(u_, p_, up_, mesh, ds, VQ, nu, Umean, c_, testing, **NS_namespac nmax = where(probes.array()[:, 0] < 0)[0][-1] print("L = ", x[nmax, 0] - 0.25) print("dP = ", up_(Point(0.15, 0.2))[2] - up_(Point(0.25, 0.2))[2]) - print("Global divergence error ", assemble( - dot(u_, n) * ds()), assemble(div(u_) * div(u_) * dx())) + print( + "Global divergence error ", + assemble(dot(u_, n) * ds()), + assemble(div(u_) * div(u_) * dx()), + ) diff --git a/oasis/problems/NSCoupled/DrivenCavity.py b/oasis/problems/NSCoupled/DrivenCavity.py index df2b53aa..59d7e112 100644 --- a/oasis/problems/NSCoupled/DrivenCavity.py +++ b/oasis/problems/NSCoupled/DrivenCavity.py @@ -8,9 +8,7 @@ # Override some problem specific parameters def problem_parameters(NS_parameters, **NS_namespace): - NS_parameters.update( - nu=0.002, - max_iter=100) + NS_parameters.update(nu=0.002, max_iter=100) # Specify boundary conditions @@ -21,14 +19,15 @@ def create_bcs(VQ, **NS_namespace): def theend_hook(u_, p_, mesh, **NS_namespace): - plot(u_, title='Velocity') - plot(p_, title='Pressure') + plot(u_, title="Velocity") + plot(p_, title="Pressure") try: from fenicstools import StreamFunction import matplotlib.pyplot as plt + psi = StreamFunction(u_, [], mesh, use_strong_bc=True) - plot(psi, title='Streamfunction') + plot(psi, title="Streamfunction") plt.show() except: pass diff --git a/oasis/problems/NSCoupled/Nozzle2D.py b/oasis/problems/NSCoupled/Nozzle2D.py index db4a6e6e..a0798165 100644 --- a/oasis/problems/NSCoupled/Nozzle2D.py +++ b/oasis/problems/NSCoupled/Nozzle2D.py @@ -11,25 +11,28 @@ def problem_parameters(NS_parameters, **NS_namespace): re_high = False NS_parameters.update( omega=0.4, - nu=0.0035 / 1056., + nu=0.0035 / 1056.0, folder="nozzle_results", max_error=1e-13, max_iter=25, re_high=re_high, - solver='cylindrical') + solver="cylindrical", + ) def create_bcs(VQ, mesh, sys_comp, re_high, **NS_namespce): # Q = 5.21E-6 if not re_high else 6.77E-5 # From FDA - Q = 5.21E-6 if not re_high else 3E-5 # From FDA + Q = 5.21e-6 if not re_high else 3e-5 # From FDA r_0 = 0.006 # Analytical, could be more exact numerical, different r_0 - u_maks = Q / (4. * r_0 * r_0 * (1. - 2. / pi)) - #inn = Expression(("u_maks * cos(sqrt(pow(x[1],2))/r_0/2.*pi)", "0"), u_maks=u_maks, r_0=r_0) - inn = Expression(("u_maks * (1-x[1]*x[1]/r_0/r_0)", "0"), u_maks=u_maks, r_0=r_0, degree=2) - - bc0 = DirichletBC(VQ.sub(0), inn, inlet) - bc1 = DirichletBC(VQ.sub(0), (0, 0), walls) + u_maks = Q / (4.0 * r_0 * r_0 * (1.0 - 2.0 / pi)) + # inn = Expression(("u_maks * cos(sqrt(pow(x[1],2))/r_0/2.*pi)", "0"), u_maks=u_maks, r_0=r_0) + inn = Expression( + ("u_maks * (1-x[1]*x[1]/r_0/r_0)", "0"), u_maks=u_maks, r_0=r_0, degree=2 + ) + + bc0 = DirichletBC(VQ.sub(0), inn, inlet) + bc1 = DirichletBC(VQ.sub(0), (0, 0), walls) bc2 = DirichletBC(VQ.sub(0).sub(1), 0, centerline) return dict(up=[bc0, bc1, bc2]) @@ -42,7 +45,7 @@ def pre_solve_hook(mesh, V, **NS_namespace): Outlet = AutoSubDomain(outlet) Walls = AutoSubDomain(walls) Centerline = AutoSubDomain(centerline) - facets = MeshFunction('size_t', mesh, mesh.topology().dim() - 1, 0) + facets = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) Inlet.mark(facets, 1) Outlet.mark(facets, 2) Walls.mark(facets, 3) @@ -52,8 +55,7 @@ def pre_solve_hook(mesh, V, **NS_namespace): x = array([[i, 0.0] for i in z_senterline]) senterline = StatisticsProbes(x.flatten(), V) - return dict(uv=Function(V), senterline=senterline, facets=facets, - normal=normal) + return dict(uv=Function(V), senterline=senterline, facets=facets, normal=normal) def temporal_hook(**NS_namespace): diff --git a/oasis/problems/NSCoupled/Skewed2D.py b/oasis/problems/NSCoupled/Skewed2D.py index 8981b1c5..8cf7f968 100644 --- a/oasis/problems/NSCoupled/Skewed2D.py +++ b/oasis/problems/NSCoupled/Skewed2D.py @@ -9,11 +9,8 @@ # Override some problem specific parameters def problem_parameters(NS_parameters, **NS_namespace): NS_parameters.update( - nu=0.1, - omega=1.0, - plot_interval=10, - max_iter=100, - max_error=1e-12) + nu=0.1, omega=1.0, plot_interval=10, max_iter=100, max_error=1e-12 + ) def create_bcs(VQ, mesh, **NS_namespace): @@ -24,5 +21,5 @@ def create_bcs(VQ, mesh, **NS_namespace): def theend_hook(u_, p_, **NS_namespace): - plot(u_, title='Velocity') - plot(p_, title='Pressure') + plot(u_, title="Velocity") + plot(p_, title="Pressure") diff --git a/oasis/problems/NSCoupled/SkewedFlow.py b/oasis/problems/NSCoupled/SkewedFlow.py index 547ff3cf..789eeb57 100644 --- a/oasis/problems/NSCoupled/SkewedFlow.py +++ b/oasis/problems/NSCoupled/SkewedFlow.py @@ -5,31 +5,32 @@ from ..NSCoupled import * from ..SkewedFlow import * + # set_log_active(False) # Override some problem specific parameters def problem_parameters(NS_parameters, **NS_namespace): NS_parameters.update( - nu=0.1, - omega=1.0, - plot_interval=10, - max_iter=100, - max_error=1e-12) + nu=0.1, omega=1.0, plot_interval=10, max_iter=100, max_error=1e-12 + ) def create_bcs(V, VQ, mesh, **NS_namespace): # Create inlet profile by solving Poisson equation on boundary - bmesh = BoundaryMesh(mesh, 'exterior') - cc = MeshFunction('size_t', bmesh, bmesh.topology().dim(), 0) + bmesh = BoundaryMesh(mesh, "exterior") + cc = MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) ii = AutoSubDomain(inlet) ii.mark(cc, 1) smesh = SubMesh(bmesh, cc, 1) - Vu = FunctionSpace(smesh, 'CG', 1) + Vu = FunctionSpace(smesh, "CG", 1) su = Function(Vu) us = TrialFunction(Vu) vs = TestFunction(Vu) - solve(inner(grad(us), grad(vs)) * dx == Constant(10.0) * vs * dx, su, - bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())]) + solve( + inner(grad(us), grad(vs)) * dx == Constant(10.0) * vs * dx, + su, + bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())], + ) # Wrap the boundary function in an Expression to avoid the need to interpolate it back to V class MyExp(UserExpression): @@ -50,5 +51,5 @@ def value_shape(self): def theend_hook(u_, p_, **NS_namespace): - plot(u_, title='Velocity') - plot(p_, title='Pressure') + plot(u_, title="Velocity") + plot(p_, title="Pressure") diff --git a/oasis/problems/NSCoupled/__init__.py b/oasis/problems/NSCoupled/__init__.py index 0d556d0f..23b1439c 100644 --- a/oasis/problems/NSCoupled/__init__.py +++ b/oasis/problems/NSCoupled/__init__.py @@ -8,19 +8,15 @@ # Default parameters NSCoupled solver NS_parameters.update( # Solver parameters - omega=1.0, # Underrelaxation factor - + omega=1.0, # Underrelaxation factor # Some discretization options - solver="default", # "default", "naive" - + solver="default", # "default", "naive" # Parameters used to tweek solver - max_iter=10, # Maximum number of iterations - max_error=1e-8, # Tolerance for absolute error + max_iter=10, # Maximum number of iterations + max_error=1e-8, # Tolerance for absolute error print_velocity_pressure_convergence=False, - # Parameter set when enabling test mode testing=False, - # Parameters used to tweek output plot_interval=10, output_timeseries_as_vector=True, # Store velocity as vector in Timeseries @@ -34,5 +30,6 @@ def NS_hook(**NS_namespace): def start_iter_hook(**NS_namespace): pass + def end_iter_hook(**NS_namespace): pass From 742ba1530260344f15b5c44e377bf8bc45dfdec0 Mon Sep 17 00:00:00 2001 From: flabowski Date: Fri, 25 Feb 2022 16:28:02 +0100 Subject: [PATCH 09/10] fixed imports and the way vars()/ NS_parameters is handled for NSCoupled problems too. --- oasis/NSCoupled.py | 176 +++++++++++++++-------- oasis/problems/NSCoupled/Cylinder.py | 95 +++++++++++- oasis/problems/NSCoupled/DrivenCavity.py | 51 +++++-- oasis/problems/NSCoupled/Nozzle2D.py | 62 +++++--- oasis/problems/NSCoupled/Skewed2D.py | 50 +++++-- oasis/problems/NSCoupled/SkewedFlow.py | 73 +++++++--- oasis/problems/NSCoupled/__init__.py | 7 +- oasis/problems/__init__.py | 7 +- 8 files changed, 394 insertions(+), 127 deletions(-) diff --git a/oasis/NSCoupled.py b/oasis/NSCoupled.py index 34244f2b..1328f554 100755 --- a/oasis/NSCoupled.py +++ b/oasis/NSCoupled.py @@ -4,7 +4,24 @@ __license__ = "GNU Lesser GPL version 3 or any later version" import importlib -from oasis.common import * +import oasis.common.io as io +import pickle +from os import path +import dolfin as df +import numpy as np +from oasis.common import parse_command_line # ,convert +import oasis.common.utilities as ut +from ufl import Coefficient + +from oasis.problems import ( + info_blue, + info_green, + info_red, + OasisTimer, + initial_memory_use, + oasis_memory, + post_import_problem, +) """ This module implements a generic steady state coupled solver for the @@ -26,32 +43,46 @@ commandline_kwargs = parse_command_line() # Find the problem module -default_problem = "DrivenCavity" +default_problem = "Cylinder" problemname = commandline_kwargs.get("problem", default_problem) -problemspec = importlib.util.find_spec( - ".".join(("oasis.problems.NSCoupled", problemname)) -) -if problemspec is None: - problemspec = importlib.util.find_spec(problemname) -if problemspec is None: - raise RuntimeError(problemname + " not found") # Import the problem module -print("Importing problem module " + problemname + ":\n" + problemspec.origin) -problemmod = importlib.util.module_from_spec(problemspec) -problemspec.loader.exec_module(problemmod) - -vars().update(**vars(problemmod)) +print("Importing problem module " + problemname) +if problemname == "Cylinder": + import oasis.problems.NSCoupled.Cylinder as pblm +if problemname == "DrivenCavity": + import oasis.problems.NSCoupled.DrivenCavity as pblm +elif problemname == "Nozzle2D": + import oasis.problems.NSCoupled.Nozzle2D as pblm +elif problemname == "Skewed2D": + import oasis.problems.NSCoupled.Skewed2D as pblm +elif problemname == "SkewedFlow": + import oasis.problems.NSCoupled.SkewedFlow as pblm + +NS_namespace = pblm.get_problem_parameters() + +# vars().update(**vars(pblm)) # Update problem spesific parameters -problem_parameters(**vars()) +# pblm.problem_parameters(**vars()) # Update current namespace with NS_parameters and commandline_kwargs ++ -vars().update(post_import_problem(**vars())) +# vars().update(pblm.post_import_problem(**vars())) + +NS_namespace, problem_parameters = post_import_problem( + NS_namespace, {}, pblm.mesh, commandline_kwargs +) +scalar_components = problem_parameters["scalar_components"] +mesh = NS_namespace["mesh"] # Import chosen functionality from solvers -solver = importlib.import_module(".".join(("oasis.solvers.NSCoupled", solver))) -vars().update({name: solver.__dict__[name] for name in solver.__all__}) +solvername = problem_parameters["solver"] +if solvername == "cylindrical": + import oasis.solvers.NSCoupled.cylindrical as solver +elif solvername == "default": + import oasis.solvers.NSCoupled.default as solver +elif solvername == "naive": + import oasis.solvers.NSCoupled.naive as solver # Create lists of components solved for u_components = ["u"] @@ -59,7 +90,9 @@ # Get the chosen mixed elment element = commandline_kwargs.get("element", "TaylorHood") -vars().update(elements[element]) +degree = solver.elements[element]["degree"] +family = solver.elements[element]["family"] +bubble = solver.elements[element]["bubble"] # TaylorHood may overload degree of elements if element == "TaylorHood": @@ -68,77 +101,95 @@ # Should assert that degree['p'] = degree['u']-1 ?? # Declare Elements -V = VectorElement(family["u"], mesh.ufl_cell(), degree["u"]) -Q = FiniteElement(family["p"], mesh.ufl_cell(), degree["p"]) +V = df.VectorElement(family["u"], mesh.ufl_cell(), degree["u"]) +Q = df.FiniteElement(family["p"], mesh.ufl_cell(), degree["p"]) +NS_namespace["V"] = V +NS_namespace["Q"] = Q + # Create Mixed space # MINI element has bubble, add to V if bubble: - B = VectorElement("Bubble", mesh.ufl_cell(), mesh.geometry().dim() + 1) - VQ = FunctionSpace( - mesh, MixedElement(V + B, Q), constrained_domain=constrained_domain + B = df.VectorElement("Bubble", mesh.ufl_cell(), mesh.geometry().dim() + 1) + VQ = df.FunctionSpace( + mesh, df.MixedElement(V + B, Q), constrained_domain=pblm.constrained_domain ) else: - VQ = FunctionSpace(mesh, V * Q, constrained_domain=constrained_domain) - + VQ = df.FunctionSpace(mesh, V * Q, constrained_domain=pblm.constrained_domain) +NS_namespace["VQ"] = VQ # Create trial and test functions -up = TrialFunction(VQ) -u, p = split(up) -v, q = TestFunctions(VQ) +NS_namespace["up"] = up = df.TrialFunction(VQ) +NS_namespace["u"], NS_namespace["p"] = u, p = df.split(up) +NS_namespace["v"], NS_namespace["q"] = v, q = df.TestFunctions(VQ) # For scalars use CG space -CG = FunctionSpace(mesh, "CG", 1, constrained_domain=constrained_domain) -c = TrialFunction(CG) -ct = TestFunction(CG) +CG = df.FunctionSpace(mesh, "CG", 1, constrained_domain=pblm.constrained_domain) +NS_namespace["CG"] = CG +NS_namespace["c"] = c = df.TrialFunction(CG) +NS_namespace["ct"] = ct = df.TestFunction(CG) VV = dict(up=VQ) VV.update(dict((ui, CG) for ui in scalar_components)) # Create dictionaries for the solutions at two timesteps -q_ = dict((ui, Function(VV[ui], name=ui)) for ui in sys_comp) -q_1 = dict((ui, Function(VV[ui], name=ui + "_1")) for ui in sys_comp) +q_ = dict((ui, df.Function(VV[ui], name=ui)) for ui in sys_comp) +q_1 = dict((ui, df.Function(VV[ui], name=ui + "_1")) for ui in sys_comp) +NS_namespace["q_"], NS_namespace["q_1"] = q_, q_1 # Short forms -up_ = q_["up"] # Solution at next iteration -up_1 = q_1["up"] # Solution at previous iteration -u_, p_ = split(up_) -u_1, p_1 = split(up_1) +NS_namespace["up_"] = up_ = q_["up"] # Solution at next iteration +NS_namespace["up_1"] = up_1 = q_1["up"] # Solution at previous iteration +NS_namespace["u_"], NS_namespace["p_"] = u_, p_ = df.split(up_) +NS_namespace["u_1"], NS_namespace["p_1"] = u_1, p_1 = df.split(up_1) # Create short forms for accessing the solution vectors x_ = dict((ui, q_[ui].vector()) for ui in sys_comp) # Solution vectors x_1 = dict( (ui, q_1[ui].vector()) for ui in sys_comp ) # Solution vectors previous iteration +NS_namespace["x_"], NS_namespace["x_1"] = x_, x_1 # Create vectors to hold rhs of equations -b = dict((ui, Vector(x_[ui])) for ui in sys_comp) +b = dict((ui, df.Vector(x_[ui])) for ui in sys_comp) +NS_namespace["b"] = b # Short form scalars for ci in scalar_components: + print("{}_ = q_ ['{}']".format(ci, ci)) + print("{}_1 = q_1 ['{}']".format(ci, ci)) exec("{}_ = q_ ['{}']".format(ci, ci)) exec("{}_1 = q_1['{}']".format(ci, ci)) # Boundary conditions -bcs = create_bcs(**vars()) +bcs = pblm.create_bcs(element=element, **problem_parameters, **NS_namespace) +NS_namespace["bcs"] = bcs # Initialize solution -initialize(**vars()) +pblm.initialize(**problem_parameters, **NS_namespace) # Fetch linear algebra solvers -up_sol, c_sol = get_solvers(**vars()) +up_sol, c_sol = solver.get_solvers(**problem_parameters, **NS_namespace) +NS_namespace["up_sol"], NS_namespace["c_sol"] = up_sol, c_sol # Get constant body forces -f = body_force(**vars()) +f = pblm.body_force(**problem_parameters, **NS_namespace) # Get scalar sources -fs = scalar_source(**vars()) +fs = pblm.scalar_source(**vars()) +NS_namespace["f"], NS_namespace["fs"] = f, fs # Preassemble and allocate -vars().update(setup(**vars())) +F_dict = solver.setup(**problem_parameters, **NS_namespace) +NS_namespace.update(F_dict) +Fs = F_dict["Fs"] # Anything problem specific -vars().update(pre_solve_hook(**vars())) +psh_dict = pblm.pre_solve_hook(**problem_parameters, **NS_namespace) +NS_namespace.update(psh_dict) + +max_iter = problem_parameters["max_iter"] +max_error = problem_parameters["max_error"] def iterate(iters=max_iter): @@ -147,11 +198,11 @@ def iterate(iters=max_iter): error = 1 while iter < iters and error > max_error: - start_iter_hook(**globals()) - NS_assemble(**globals()) - NS_hook(**globals()) - NS_solve(**globals()) - end_iter_hook(**globals()) + pblm.start_iter_hook(**problem_parameters, **NS_namespace) + solver.NS_assemble(**problem_parameters, **NS_namespace) + pblm.NS_hook(**problem_parameters, **NS_namespace) + solver.NS_solve(**problem_parameters, **NS_namespace) + pblm.end_iter_hook(**problem_parameters, **NS_namespace) # Update to next iteration for ui in sys_comp: @@ -159,7 +210,9 @@ def iterate(iters=max_iter): x_1[ui].axpy(1.0, x_[ui]) error = b["up"].norm("l2") - print_velocity_pressure_info(**locals()) + solver.print_velocity_pressure_info( + iter=iter, error=error, **problem_parameters, **NS_namespace + ) iter += 1 @@ -172,18 +225,18 @@ def iterate_scalar(iters=max_iter, errors=max_error): globals().update(ci=ci) citer = 0 while citer < iters and err[ci] > errors: - scalar_assemble(**globals()) - scalar_hook(**globals()) - scalar_solve(**globals()) + solver.scalar_assemble(**problem_parameters, **NS_namespace) + pblm.scalar_hook(**problem_parameters, **NS_namespace) + solver.scalar_solve(**problem_parameters, **NS_namespace) err[ci] = b[ci].norm("l2") - if MPI.rank(MPI.comm_world) == 0: + if df.MPI.rank(df.MPI.comm_world) == 0: print("Iter {}, Error {} = {}".format(citer, ci, err[ci])) citer += 1 timer = OasisTimer("Start Newton iterations flow", True) # Assemble rhs once, before entering iterations (velocity components) -b["up"] = assemble(Fs["up"], tensor=b["up"]) +b["up"] = df.assemble(Fs["up"], tensor=b["up"]) for bc in bcs["up"]: bc.apply(b["up"], x_["up"]) @@ -196,17 +249,17 @@ def iterate_scalar(iters=max_iter, errors=max_error): scalar_timer = OasisTimer("Start Newton iterations scalars", True) # Assemble rhs once, before entering iterations (velocity components) for scalar in scalar_components: - b[scalar] = assemble(Fs[scalar], tensor=b[scalar]) + b[scalar] = df.assemble(Fs[scalar], tensor=b[scalar]) for bc in bcs[scalar]: bc.apply(b[scalar], x_[scalar]) iterate_scalar() scalar_timer.stop() -list_timings(TimingClear.keep, [TimingType.wall]) +solver.list_timings(df.TimingClear.keep, [df.TimingType.wall]) info_red("Total computing time = {0:f}".format(timer.elapsed()[0])) oasis_memory("Final memory use ") -total_initial_dolfin_memory = MPI.sum(MPI.comm_world, initial_memory_use) +total_initial_dolfin_memory = df.MPI.sum(df.MPI.comm_world, initial_memory_use) info_red( "Memory use for importing dolfin = {} MB (RSS)".format(total_initial_dolfin_memory) ) @@ -217,4 +270,5 @@ def iterate_scalar(iters=max_iter, errors=max_error): ) # Final hook -theend_hook(**vars()) +pblm.theend_hook(**vars()) +pblm.theend_hook(**vars()) diff --git a/oasis/problems/NSCoupled/Cylinder.py b/oasis/problems/NSCoupled/Cylinder.py index 9260f80d..b2c7d31a 100644 --- a/oasis/problems/NSCoupled/Cylinder.py +++ b/oasis/problems/NSCoupled/Cylinder.py @@ -5,14 +5,97 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSCoupled import * -from ..Cylinder import * -# Override some problem specific parameters -def problem_parameters(NS_parameters, scalar_components, **NS_namespace): - NS_parameters.update(omega=1.0, max_iter=100, plot_interval=10, velocity_degree=2) +from oasis.problems import ( + add_function_to_tstepfiles, + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +import oasis.common.utilities as ut +from oasis.problems.NSCoupled import ( + NS_hook, + start_iter_hook, + end_iter_hook, + default_parameters, +) +from oasis.problems.Cylinder import ( + mesh, + Inlet, + Cyl, + Wall, + Outlet, + center, + cases, + H, + L, + D, +) +from dolfin import ( + Expression, + DirichletBC, + Function, + MeshFunction, + FacetNormal, + plot, + TestFunction, + Identity, + VectorFunctionSpace, + grad, + dot, + assemble, + project, + DirichletBC, + curl, + DomainBoundary, + Point, + ds, + Constant, + div, + dx, +) +from os import getcwd, path +import pickle +import matplotlib.pyplot as plt + + +def get_problem_parameters(**kwargs): + case = kwargs["case"] if "case" in kwargs else 1 + Um = cases[case]["Um"] + Re = cases[case]["Re"] + Umean = 2.0 / 3.0 * Um + NS_parameters = dict( + scalar_components=scalar_components + ["c", "d"], + Schmidt=Schmidt, + Schmidt_T=Schmidt_T, + Um=Um, + Re=Re, + Umean=Umean, + H=H, + L=L, + D=D, + nu=Umean * D / Re, + omega=1.0, + max_iter=100, + plot_interval=10, + velocity_degree=2, + ) - scalar_components += ["c", "d"] + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val + return NS_parameters def scalar_source(c_, d_, **NS_namespace): diff --git a/oasis/problems/NSCoupled/DrivenCavity.py b/oasis/problems/NSCoupled/DrivenCavity.py index 59d7e112..35f49f7f 100644 --- a/oasis/problems/NSCoupled/DrivenCavity.py +++ b/oasis/problems/NSCoupled/DrivenCavity.py @@ -3,31 +3,62 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSCoupled import * -from ..DrivenCavity import * -# Override some problem specific parameters -def problem_parameters(NS_parameters, **NS_namespace): - NS_parameters.update(nu=0.002, max_iter=100) +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems import create_bcs +from oasis.problems.NSCoupled import ( + NS_hook, + start_iter_hook, + end_iter_hook, + default_parameters, +) +from oasis.problems.DrivenCavity import noslip, top, bottom, mesh +import dolfin as df + + +def get_problem_parameters(**kwargs): + NS_parameters = dict(nu=0.002, max_iter=100) + NS_parameters["scalar_components"] = scalar_components + NS_parameters["Schmidt"] = Schmidt + NS_parameters["Schmidt_T"] = Schmidt_T + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val + return NS_parameters # Specify boundary conditions def create_bcs(VQ, **NS_namespace): - bc0 = DirichletBC(VQ.sub(0), (0, 0), noslip) - bc1 = DirichletBC(VQ.sub(0), (1, 0), top) + bc0 = df.DirichletBC(VQ.sub(0), (0, 0), noslip) + bc1 = df.DirichletBC(VQ.sub(0), (1, 0), top) return dict(up=[bc0, bc1]) def theend_hook(u_, p_, mesh, **NS_namespace): - plot(u_, title="Velocity") - plot(p_, title="Pressure") + df.plot(u_, title="Velocity") + df.plot(p_, title="Pressure") try: from fenicstools import StreamFunction import matplotlib.pyplot as plt psi = StreamFunction(u_, [], mesh, use_strong_bc=True) - plot(psi, title="Streamfunction") + df.plot(psi, title="Streamfunction") plt.show() except: pass diff --git a/oasis/problems/NSCoupled/Nozzle2D.py b/oasis/problems/NSCoupled/Nozzle2D.py index a0798165..74ac9261 100644 --- a/oasis/problems/NSCoupled/Nozzle2D.py +++ b/oasis/problems/NSCoupled/Nozzle2D.py @@ -1,15 +1,37 @@ -from ..NSCoupled import * -from ..Nozzle2D import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems import create_bcs +from oasis.problems.NSCoupled import ( + NS_hook, + start_iter_hook, + end_iter_hook, + default_parameters, +) +from oasis.problems.Nozzle2D import mesh, walls, inlet, outlet, centerline +import dolfin as df from math import sqrt, pi from fenicstools import StructuredGrid, StatisticsProbes import sys from numpy import array, linspace -# Override some problem specific parameters -def problem_parameters(NS_parameters, **NS_namespace): + +def get_problem_parameters(**kwargs): re_high = False - NS_parameters.update( + NS_parameters = dict( omega=0.4, nu=0.0035 / 1056.0, folder="nozzle_results", @@ -18,6 +40,14 @@ def problem_parameters(NS_parameters, **NS_namespace): re_high=re_high, solver="cylindrical", ) + NS_parameters["scalar_components"] = scalar_components + NS_parameters["Schmidt"] = Schmidt + NS_parameters["Schmidt_T"] = Schmidt_T + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val + return NS_parameters def create_bcs(VQ, mesh, sys_comp, re_high, **NS_namespce): @@ -27,25 +57,25 @@ def create_bcs(VQ, mesh, sys_comp, re_high, **NS_namespce): # Analytical, could be more exact numerical, different r_0 u_maks = Q / (4.0 * r_0 * r_0 * (1.0 - 2.0 / pi)) # inn = Expression(("u_maks * cos(sqrt(pow(x[1],2))/r_0/2.*pi)", "0"), u_maks=u_maks, r_0=r_0) - inn = Expression( + inn = df.Expression( ("u_maks * (1-x[1]*x[1]/r_0/r_0)", "0"), u_maks=u_maks, r_0=r_0, degree=2 ) - bc0 = DirichletBC(VQ.sub(0), inn, inlet) - bc1 = DirichletBC(VQ.sub(0), (0, 0), walls) - bc2 = DirichletBC(VQ.sub(0).sub(1), 0, centerline) + bc0 = df.DirichletBC(VQ.sub(0), inn, inlet) + bc1 = df.DirichletBC(VQ.sub(0), (0, 0), walls) + bc2 = df.DirichletBC(VQ.sub(0).sub(1), 0, centerline) return dict(up=[bc0, bc1, bc2]) def pre_solve_hook(mesh, V, **NS_namespace): # Normals and facets to compute flux at inlet and outlet - normal = FacetNormal(mesh) - Inlet = AutoSubDomain(inlet) - Outlet = AutoSubDomain(outlet) - Walls = AutoSubDomain(walls) - Centerline = AutoSubDomain(centerline) - facets = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) + normal = df.FacetNormal(mesh) + Inlet = df.AutoSubDomain(inlet) + Outlet = df.AutoSubDomain(outlet) + Walls = df.AutoSubDomain(walls) + Centerline = df.AutoSubDomain(centerline) + facets = df.MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) Inlet.mark(facets, 1) Outlet.mark(facets, 2) Walls.mark(facets, 3) @@ -55,7 +85,7 @@ def pre_solve_hook(mesh, V, **NS_namespace): x = array([[i, 0.0] for i in z_senterline]) senterline = StatisticsProbes(x.flatten(), V) - return dict(uv=Function(V), senterline=senterline, facets=facets, normal=normal) + return dict(uv=df.Function(V), senterline=senterline, facets=facets, normal=normal) def temporal_hook(**NS_namespace): diff --git a/oasis/problems/NSCoupled/Skewed2D.py b/oasis/problems/NSCoupled/Skewed2D.py index 8cf7f968..da0d0f25 100644 --- a/oasis/problems/NSCoupled/Skewed2D.py +++ b/oasis/problems/NSCoupled/Skewed2D.py @@ -3,23 +3,55 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSCoupled import * -from ..Skewed2D import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems import create_bcs +from oasis.problems.NSCoupled import ( + NS_hook, + start_iter_hook, + end_iter_hook, + default_parameters, +) +from oasis.problems.Skewed2D import mesh, walls, inlet, outlet, tol, L +import dolfin as df # Override some problem specific parameters -def problem_parameters(NS_parameters, **NS_namespace): - NS_parameters.update( +def get_problem_parameters(**kwargs): + NS_parameters = dict( nu=0.1, omega=1.0, plot_interval=10, max_iter=100, max_error=1e-12 ) + NS_parameters["scalar_components"] = scalar_components + NS_parameters["Schmidt"] = Schmidt + NS_parameters["Schmidt_T"] = Schmidt_T + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val + return NS_parameters def create_bcs(VQ, mesh, **NS_namespace): - u_inlet = Expression(("10*x[1]*(0.2-x[1])", "0"), element=VQ.sub(0).ufl_element()) - bc0 = DirichletBC(VQ.sub(0), (0, 0), walls) - bc1 = DirichletBC(VQ.sub(0), u_inlet, inlet) + u_inlet = df.Expression( + ("10*x[1]*(0.2-x[1])", "0"), element=VQ.sub(0).ufl_element() + ) + bc0 = df.DirichletBC(VQ.sub(0), (0, 0), walls) + bc1 = df.DirichletBC(VQ.sub(0), u_inlet, inlet) return dict(up=[bc1, bc0]) def theend_hook(u_, p_, **NS_namespace): - plot(u_, title="Velocity") - plot(p_, title="Pressure") + df.plot(u_, title="Velocity") + df.plot(p_, title="Pressure") diff --git a/oasis/problems/NSCoupled/SkewedFlow.py b/oasis/problems/NSCoupled/SkewedFlow.py index 789eeb57..66a1e791 100644 --- a/oasis/problems/NSCoupled/SkewedFlow.py +++ b/oasis/problems/NSCoupled/SkewedFlow.py @@ -3,37 +3,68 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from ..NSCoupled import * -from ..SkewedFlow import * +from oasis.problems import ( + constrained_domain, + scalar_components, + Schmidt, + Schmidt_T, + body_force, + initialize, + scalar_hook, + scalar_source, + pre_solve_hook, + theend_hook, + get_problem_parameters, + post_import_problem, + create_bcs, +) +from oasis.problems import create_bcs +from oasis.problems.NSCoupled import ( + NS_hook, + start_iter_hook, + end_iter_hook, + default_parameters, +) +from oasis.problems.SkewedFlow import mesh, walls, inlet, outlet, tol, L, h +import dolfin as df +from dolfin import inner, grad, dx # set_log_active(False) -# Override some problem specific parameters -def problem_parameters(NS_parameters, **NS_namespace): - NS_parameters.update( + +def get_problem_parameters(**kwargs): + NS_parameters = dict( nu=0.1, omega=1.0, plot_interval=10, max_iter=100, max_error=1e-12 ) + NS_parameters["scalar_components"] = scalar_components + NS_parameters["Schmidt"] = Schmidt + NS_parameters["Schmidt_T"] = Schmidt_T + # set default parameters + for key, val in default_parameters.items(): + if key not in NS_parameters.keys(): + NS_parameters[key] = val + return NS_parameters def create_bcs(V, VQ, mesh, **NS_namespace): # Create inlet profile by solving Poisson equation on boundary - bmesh = BoundaryMesh(mesh, "exterior") - cc = MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) - ii = AutoSubDomain(inlet) + bmesh = df.BoundaryMesh(mesh, "exterior") + cc = df.MeshFunction("size_t", bmesh, bmesh.topology().dim(), 0) + ii = df.AutoSubDomain(inlet) ii.mark(cc, 1) - smesh = SubMesh(bmesh, cc, 1) - Vu = FunctionSpace(smesh, "CG", 1) - su = Function(Vu) - us = TrialFunction(Vu) - vs = TestFunction(Vu) - solve( - inner(grad(us), grad(vs)) * dx == Constant(10.0) * vs * dx, + smesh = df.SubMesh(bmesh, cc, 1) + Vu = df.FunctionSpace(smesh, "CG", 1) + su = df.Function(Vu) + us = df.TrialFunction(Vu) + vs = df.TestFunction(Vu) + df.solve( + inner(grad(us), grad(vs)) * dx == df.Constant(10.0) * vs * dx, su, - bcs=[DirichletBC(Vu, Constant(0), DomainBoundary())], + bcs=[df.DirichletBC(Vu, df.Constant(0), df.DomainBoundary())], ) # Wrap the boundary function in an Expression to avoid the need to interpolate it back to V - class MyExp(UserExpression): + class MyExp(df.UserExpression): def eval(self, values, x): try: values[0] = su(x) @@ -45,11 +76,11 @@ def eval(self, values, x): def value_shape(self): return (3,) - bc0 = DirichletBC(VQ.sub(0), (0, 0, 0), walls) - bc1 = DirichletBC(VQ.sub(0), MyExp(element=VQ.sub(0).ufl_element()), inlet) + bc0 = df.DirichletBC(VQ.sub(0), (0, 0, 0), walls) + bc1 = df.DirichletBC(VQ.sub(0), MyExp(element=VQ.sub(0).ufl_element()), inlet) return dict(up=[bc0, bc1]) def theend_hook(u_, p_, **NS_namespace): - plot(u_, title="Velocity") - plot(p_, title="Pressure") + df.plot(u_, title="Velocity") + df.plot(p_, title="Pressure") diff --git a/oasis/problems/NSCoupled/__init__.py b/oasis/problems/NSCoupled/__init__.py index 23b1439c..fb407e3f 100644 --- a/oasis/problems/NSCoupled/__init__.py +++ b/oasis/problems/NSCoupled/__init__.py @@ -3,10 +3,13 @@ __copyright__ = "Copyright (C) 2014 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from oasis.problems import * # Default parameters NSCoupled solver -NS_parameters.update( +default_parameters = dict( + nu=0.01, # Kinematic viscosity + folder="results", # Relative folder for storing results + velocity_degree=2, # default velocity degree + pressure_degree=1, # default pressure degree # Solver parameters omega=1.0, # Underrelaxation factor # Some discretization options diff --git a/oasis/problems/__init__.py b/oasis/problems/__init__.py index 60d1fd1e..20bebc27 100644 --- a/oasis/problems/__init__.py +++ b/oasis/problems/__init__.py @@ -246,8 +246,11 @@ def post_import_problem(NS_parameters, NS_expressions, mesh, commandline_kwargs) print(key, val) NS_namespace[key] = val elif type(val) == list: - k0 = val[0] - if type(val[0]) in [str, bool, type(None), float, int]: + if len(val) == 0: + problem_parameters[key] = val + elif (len(val) == 0) | ( + type(val[0]) in [str, bool, type(None), float, int] + ): problem_parameters[key] = val else: print(key, val) From 191fc817774612ec52455cf2b7a046e4fb4067f1 Mon Sep 17 00:00:00 2001 From: flabowski Date: Fri, 4 Mar 2022 14:26:44 +0100 Subject: [PATCH 10/10] class based IPCS_ABCN solver --- oasis/NSfracStep_class_based.py | 147 +++++++ oasis/problems/NSfracStep/Cylinder.py | 206 ++++++++-- oasis/problems/NSfracStep/__init__.py | 231 +++++++++++ oasis/problems/__init__.py | 65 +++ oasis/solvers/NSfracStep/IPCS_ABCN.py | 545 +++++++++++++++++++++----- 5 files changed, 1058 insertions(+), 136 deletions(-) create mode 100644 oasis/NSfracStep_class_based.py diff --git a/oasis/NSfracStep_class_based.py b/oasis/NSfracStep_class_based.py new file mode 100644 index 00000000..b5eebe4b --- /dev/null +++ b/oasis/NSfracStep_class_based.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Mar 3 13:45:42 2022 + +@author: florianma +""" +import dolfin as df +import numpy as np +from oasis.common import parse_command_line +from oasis.problems import ( + info_green, + info_red, + OasisTimer, + initial_memory_use, + oasis_memory, +) +from oasis.problems.NSfracStep.Cylinder import Cylinder as ProblemDomain +import oasis.solvers.NSfracStep.IPCS_ABCN as solver + +# TODO: implement ScalarSolver +commandline_kwargs = parse_command_line() +default_problem = "Cylinder" +problemname = commandline_kwargs.get("problem", default_problem) +# Import the problem module +print("Importing problem module " + problemname) +# TODO: import the right ProblemDomain based on problemname: +# solver = NSfracStep.get_domain(problemname) + +commandline_kwargs["dt"] = 0.001 +my_domain = ProblemDomain(case=2) +my_domain.set_parameters_from_commandline(commandline_kwargs) +my_domain.mesh_from_file(mesh_name="../mesh.xdmf", facet_name="../mf.xdmf") +df.plot(my_domain.mesh) +my_domain.recommend_dt() +# Create lists of components solved for +my_domain.initialize_problem_components() +# Declare FunctionSpaces and arguments +my_domain.dolfin_variable_declaration() +# Boundary conditions +my_domain.create_bcs() +# TODO: Read in previous solution if restarting +# TODO: LES setup +# TODO: Non-Newtonian setup. +# Initialize solution +my_domain.apply_bcs() +solvername = my_domain.solver +# TODO: import the right solver based on solvername: +# solver = NSfracStep.get_solver(solvername) + +cond = my_domain.krylov_solvers["monitor_convergence"] +psi = my_domain.use_krylov_solvers and cond # = print_solve_info + +tx = OasisTimer("Timestep timer") +tx.start() +total_timer = OasisTimer("Start simulations", True) + +it0 = my_domain.iters_on_first_timestep +max_iter = my_domain.max_iter + +fit = solver.FirstInner(my_domain) +tvs = solver.TentativeVelocityStep(my_domain) +ps = solver.PressureStep(my_domain) + +stop = False +t = 0.0 +tstep = 0 +while t < (my_domain.T - tstep * df.DOLFIN_EPS) and not stop: + t += my_domain.dt + tstep += 1 + + inner_iter = 0 + udiff = np.array([1e8]) # Norm of velocity change over last inner iter + num_iter = max(it0, max_iter) if tstep <= 10 else max_iter + my_domain.start_timestep_hook() # FIXME: what do we need to pass here? + + while udiff[0] > my_domain.max_error and inner_iter < num_iter: + inner_iter += 1 + + t0 = OasisTimer("Tentative velocity") + if inner_iter == 1: + # lesmodel.les_update(**NS_namespace) + # nnmodel.nn_update(**NS_namespace) + fit.assemble_first_inner_iter() + tvs.A = fit.A + udiff[0] = 0.0 + for i, ui in enumerate(my_domain.u_components): + t1 = OasisTimer("Solving tentative velocity " + ui, psi) + tvs.assemble(ui=ui) + my_domain.velocity_tentative_hook(ui=ui) + tvs.solve(ui=ui, udiff=udiff) + t1.stop() + t0.stop() + t2 = OasisTimer("Pressure solve", psi) + ps.assemble() + my_domain.pressure_hook() + ps.solve() + t2.stop() + + my_domain.print_velocity_pressure_info(num_iter, inner_iter, udiff) + + # Update velocity + t3 = OasisTimer("Velocity update") + for i, ui in enumerate(my_domain.u_components): + tvs.velocity_update(ui=ui) + t3.stop() + + # TODO: Solve for scalars + # if len(scalar_components) > 0: + # solver.scalar_assemble() + # for ci in scalar_components: + # t1 = OasisTimer("Solving scalar {}".format(ci), print_solve_info) + # pblm.scalar_hook() + # solver.scalar_solve() + # t1.stop() + my_domain.temporal_hook(t=t, tstep=tstep) + + # TODO: Save solution if required and check for killoasis file + # stop = io.save_solution() + my_domain.advance() + + # Print some information + if tstep % my_domain.print_intermediate_info == 0: + toc = tx.stop() + my_domain.show_info(t, tstep, toc) + df.list_timings(df.TimingClear.clear, [df.TimingType.wall]) + tx.start() + + # AB projection for pressure on next timestep + if ( + my_domain.AB_projection_pressure + and t < (my_domain.T - tstep * df.DOLFIN_EPS) + and not stop + ): + my_domain.q_["p"].vector().axpy(0.5, my_domain.dp_.vector()) + +total_timer.stop() +df.list_timings(df.TimingClear.keep, [df.TimingType.wall]) +info_red("Total computing time = {0:f}".format(total_timer.elapsed()[0])) +oasis_memory("Final memory use ") +# total_initial_dolfin_memory +m = df.MPI.sum(df.MPI.comm_world, initial_memory_use) +info_red("Memory use for importing dolfin = {} MB (RSS)".format(m)) +info_red("Total memory use of solver = " + str(oasis_memory.memory - m) + " MB (RSS)") + +# Final hook +my_domain.theend_hook() diff --git a/oasis/problems/NSfracStep/Cylinder.py b/oasis/problems/NSfracStep/Cylinder.py index 5505b014..56568a14 100644 --- a/oasis/problems/NSfracStep/Cylinder.py +++ b/oasis/problems/NSfracStep/Cylinder.py @@ -1,4 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Mar 4 10:01:22 2022 + +@author: florianma +""" from __future__ import print_function +import matplotlib.pyplot as plt +import numpy as np __author__ = "Mikael Mortensen " __date__ = "2014-03-21" @@ -8,18 +17,18 @@ from oasis.problems import ( add_function_to_tstepfiles, - constrained_domain, + constrained_domain, # might get overloaded scalar_components, Schmidt, Schmidt_T, - body_force, + body_force, # might get overloaded initialize, - scalar_hook, - scalar_source, + scalar_hook, # might get overloaded + scalar_source, # might get overloaded pre_solve_hook, theend_hook, - get_problem_parameters, - post_import_problem, + # get_problem_parameters, # alwas overloaded + # post_import_problem, # never overloaded create_bcs, ) import oasis.common.utilities as ut @@ -29,6 +38,7 @@ start_timestep_hook, temporal_hook, default_parameters, + FracDomain, ) from oasis.problems.Cylinder import ( mesh, @@ -56,19 +66,20 @@ dot, assemble, project, - DirichletBC, curl, DomainBoundary, Point, ds, + Mesh, + XDMFFile, + MeshValueCollection, + Constant, + cpp, ) from os import getcwd, path import pickle import matplotlib.pyplot as plt -Schmidt["alfa"] = 0.1 -scalar_components.append("alfa") - def get_problem_parameters(**kwargs): # Example: python NSfracstep.py [...] restart_folder="results/data/8/Checkpoint" @@ -81,42 +92,36 @@ def get_problem_parameters(**kwargs): globals().update(NS_parameters) else: - # Override some problem specific parameters case = kwargs["case"] if "case" in kwargs else 1 - Um = cases[case]["Um"] - Re = cases[case]["Re"] + Um = cases[case]["Um"] # 0.3 or 1.5 + # Re = cases[case]["Re"] # 20 or 100 Umean = 2.0 / 3.0 * Um + rho = 1.0 + mu = 0.001 + Re = rho * Umean * D / mu + nu = mu / rho + NS_parameters = default_parameters + NS_parameters["Schmidt"] = Schmidt + NS_parameters["Schmidt_T"] = Schmidt_T + NS_parameters["H"] = H + NS_parameters["Um"] = Um + NS_parameters["Re"] = Re + NS_parameters["nu"] = nu + NS_parameters["Umean"] = Umean + NS_parameters["T"] = 100 + NS_parameters["dt"] = 0.01 + NS_parameters["checkpoint"] = 50 + NS_parameters["save_step"] = 50 + NS_parameters["plot_interval"] = 10 + NS_parameters["velocity_degree"] = 2 + NS_parameters["print_intermediate_info"] = 100 + NS_parameters["use_krylov_solvers"] = True - NS_parameters = dict( - scalar_components=scalar_components, - Schmidt=Schmidt, - Schmidt_T=Schmidt_T, - Um=Um, - Re=Re, - Umean=Umean, - nu=Umean * D / Re, - H=H, - L=L, - D=D, - T=100, - dt=0.01, - checkpoint=50, - save_step=50, - plot_interval=10, - velocity_degree=2, - print_intermediate_info=100, - use_krylov_solvers=True, - ) - NS_parameters["krylov_solvers"] = dict(monitor_convergence=True) - - NS_parameters["velocity_krylov_solver"] = dict( - preconditioner_type="jacobi", solver_type="bicgstab" - ) - # set default parameters - for key, val in default_parameters.items(): - if key not in NS_parameters.keys(): - NS_parameters[key] = val - + NS_parameters["scalar_components"] = scalar_components + ["alfa"] + NS_parameters["Schmidt"]["alfa"] = 0.1 + NS_parameters["krylov_solvers"]["monitor_convergence"] = True + NS_parameters["velocity_krylov_solver"]["preconditioner_type"] = "jacobi" + NS_parameters["velocity_krylov_solver"]["solver_type"] = "bicgstab" NS_expressions = {} return NS_parameters, NS_expressions @@ -244,3 +249,118 @@ def theend_hook(q_, u_, p_, uv, mesh, ds, V, nu, Umean, D, L, **NS_namespace): print("L = ", x[nmax, 0] - 0.25) print("dP = ", p_(Point(0.15, 0.2)) - p_(Point(0.25, 0.2))) print("dP = ", p_(Point(0.15, 0.2)) - p_(Point(0.25, 0.2))) + + +class Cylinder(FracDomain): + # run for Um in [0.2, 0.5, 0.6, 0.75, 1.0, 1.5, 2.0] + # or for Re in [20., 50., 60., 75.0, 100, 150, 200] + def __init__(self, case=1): + """ + Create the required function spaces, functions and boundary conditions + for a channel flow problem + """ + super().__init__() + # problem parameters + # case = parameters["case"] if "case" in parameters else 1 + Umax = cases[case]["Um"] # 0.3 or 1.5 + # Re = cases[case]["Re"] # 20 or 100 + Umean = 2.0 / 3.0 * Umax + rho = 1.0 + mu = 0.001 + self.H = 0.41 + Re = rho * Umean * D / mu + print("Re", Re) + nu = mu / rho + self.Umean = Umean + self.Umax = Umax + self.Schmidt = {} + self.Schmidt_T = {} + self.nu = nu + self.T = 10 + self.dt = 0.01 + self.checkpoint = 50 + self.save_step = 50 + self.plot_interval = 10 + self.velocity_degree = 2 + self.print_intermediate_info = 100 + self.use_krylov_solvers = True + # self.krylov_solvers["monitor_convergence"] = True + self.velocity_krylov_solver["preconditioner_type"] = "jacobi" + self.velocity_krylov_solver["solver_type"] = "bicgstab" + self.NS_expressions = {} + self.scalar_components = [] + return + + def mesh_from_file(self, mesh_name, facet_name): + self.mesh = Mesh() + with XDMFFile(mesh_name) as infile: + infile.read(self.mesh) + + mvc = MeshValueCollection("size_t", self.mesh, self.mesh.topology().dim() - 1) + with XDMFFile(facet_name) as infile: + infile.read(mvc, "name_to_read") + mf = self.mf = cpp.mesh.MeshFunctionSizet(self.mesh, mvc) + self.bc_dict = { + "fluid": 0, + "channel_walls": 1, + "cylinderwall": 2, + "inlet": 3, + "outlet": 4, + } + return + + def create_bcs(self): + mf, bc_dict = self.mf, self.bc_dict + V, Q, Umax, H = self.V, self.Q, self.Umax, self.H + # U0_str = "4.0*x[1]*(0.41-x[1])/0.1681" + U0_str = "4.*{0}*x[1]*({1}-x[1])/pow({1}, 2)".format(Umax, H) + inlet = Expression(U0_str, degree=2) + bc00 = DirichletBC(V, inlet, mf, bc_dict["inlet"]) + bc01 = DirichletBC(V, 0.0, mf, bc_dict["inlet"]) + bc10 = bc11 = DirichletBC(V, 0.0, mf, bc_dict["cylinderwall"]) + bc2 = DirichletBC(V, 0.0, mf, bc_dict["channel_walls"]) + bcp = DirichletBC(Q, 0.0, mf, bc_dict["outlet"]) + self.bcs = { + "u0": [bc00, bc10, bc2], + "u1": [bc01, bc11, bc2], + "p": [bcp], + } + return + + def temporal_hook(self, t, tstep, **kvargs): + if tstep % 100 == 0: + fig, (ax1, ax2) = self.plot() + plt.savefig("../results/frame_{:06d}.png".format(tstep)) + plt.close() + return + + def theend_hook(self): + print("finished :)") + + def plot(self): + # u, p = self.u_, self.p_ + mesh = self.mesh + u = self.q_["u0"].compute_vertex_values(mesh) + v = self.q_["u1"].compute_vertex_values(mesh) + p = self.q_["p"].compute_vertex_values(mesh) + # print(u.shape, v.shape, p.shape) + magnitude = (u ** 2 + v ** 2) ** 0.5 + # print(u.shape, v.shape, p.shape, magnitude.shape) + + # velocity = u.compute_vertex_values(mesh) + # velocity.shape = (2, -1) + # magnitude = np.linalg.norm(velocity, axis=0) + x, y = mesh.coordinates().T + # u, v = velocity + tri = mesh.cells() + # pressure = p.compute_vertex_values(mesh) + # print(x.shape, y.shape, u.shape, v.shape) + + fig, (ax1, ax2) = plt.subplots(2, sharex=True, sharey=True, figsize=(12, 6)) + ax1.quiver(x, y, u, v, magnitude) + ax2.tricontourf(x, y, tri, p, levels=40) + ax1.set_aspect("equal") + ax2.set_aspect("equal") + ax1.set_title("velocity") + ax2.set_title("pressure") + return fig, (ax1, ax2) diff --git a/oasis/problems/NSfracStep/__init__.py b/oasis/problems/NSfracStep/__init__.py index 34b85b97..b45e0d8b 100644 --- a/oasis/problems/NSfracStep/__init__.py +++ b/oasis/problems/NSfracStep/__init__.py @@ -47,7 +47,10 @@ theend_hook, get_problem_parameters, post_import_problem, + Domain, ) +import dolfin as df +from ufl import Coefficient # Default parameters NSfracStep solver NS_expressions = {} @@ -155,3 +158,231 @@ def start_timestep_hook(**NS_namespace): def temporal_hook(**NS_namespace): """Called at end of a timestep.""" pass + + +class FracDomain(Domain): + def __init__(self): + # self.nu = 0.01 # Kinematic viscosity + self.folder = "results" # Relative folder for storing results + self.velocity_degree = 2 # default velocity degree + self.pressure_degree = 1 # default pressure degree + + # Physical constants and solver parameters + # self.t = 0.0 # Time + # self.tstep = 0 # Timestep + self.T = 1.0 # End time + self.dt = 0.01 # Time interval on each timestep + + # Some discretization options + # Use Adams Bashforth projection as first estimate for pressure on new timestep + self.AB_projection_pressure = False + # "IPCS_ABCN", "IPCS_ABE", "IPCS", "Chorin", "BDFPC", "BDFPC_Fast" + self.solver = "IPCS_ABCN" + + # Parameters used to tweek solver + # Number of inner pressure velocity iterations on timestep + self.max_iter = 1 + # Tolerance for inner iterations pressure velocity iterations + self.max_error = 1e-6 + # Number of iterations on first timestep + self.iters_on_first_timestep = 2 + self.use_krylov_solvers = True # Otherwise use LU-solver + self.print_intermediate_info = 10 + self.print_velocity_pressure_convergence = False + + # Parameters used to tweek output + self.plot_interval = 10 + # Overwrite solution in Checkpoint folder each checkpoint + self.checkpoint = 10 + self.save_step = 10 # Store solution each save_step + # If restarting solution, set the folder holding the solution to start from here + self.restart_folder = None + # Store velocity as vector in Timeseries + self.output_timeseries_as_vector = True + # Stop simulations cleanly after the given number of seconds + self.killtime = None + + # Choose LES model and set default parameters + # NoModel, Smagorinsky, Wale, DynamicLagrangian, ScaleDepDynamicLagrangian + self.les_model = "NoModel" + # LES model parameters + self.Smagorinsky = {"Cs": 0.1677} # Standard Cs, same as OpenFOAM + self.Wale = {"Cw": 0.325} + # Time step interval for Cs to be recomputed + self.DynamicSmagorinsky = {"Cs_comp_step": 1} + self.KineticEnergySGS = {"Ck": 0.08, "Ce": 1.05} + + # Choose Non-Newtonian model and set default parameters + # NoModel, ModifiedCross + self.nn_model = "NoModel" + # Non-Newtonian model parameters + self.ModifiedCross = { + "lam": 3.736, # s + "m_param": 2.406, # for Non-Newtonian model + "a_param": 0.34, # for Non-Newtonian model + "mu_inf": 0.00372, # Pa-s for non-Newtonian model + "mu_o": 0.09, # Pa-s for non-Newtonian model + "rho": 1085, # kg/m^3 + } + # Parameter set when enabling test mode + self.testing = False + # Solver parameters that will be transferred to dolfins parameters['krylov_solver'] + self.krylov_solvers = { + "monitor_convergence": False, + "report": False, + "error_on_nonconvergence": False, + "nonzero_initial_guess": True, + "maximum_iterations": 200, + "relative_tolerance": 1e-8, + "absolute_tolerance": 1e-8, + } + # Velocity update + self.velocity_update_solver = { + "method": "default", # "lumping", "gradient_matrix" + "solver_type": "cg", + "preconditioner_type": "jacobi", + "low_memory_version": False, + } + self.velocity_krylov_solver = { + "solver_type": "bicgstab", + "preconditioner_type": "jacobi", + } + self.pressure_krylov_solver = { + "solver_type": "gmres", + "preconditioner_type": "hypre_amg", + } + self.scalar_krylov_solver = { + "solver_type": "bicgstab", + "preconditioner_type": "jacobi", + } + self.nut_krylov_solver = { + "method": "WeightedAverage", # Or 'default' + "solver_type": "cg", + "preconditioner_type": "jacobi", + } + self.nu_nn_krylov_solver = { + "method": "WeightedAverage", # Or 'default' + "solver_type": "cg", + "preconditioner_type": "jacobi", + } + + self.constrained_domain = None + return + + def initialize_problem_components(self): + # Create lists of components solved for + # self.scalar_components = scalar_components + if self.mesh.geometry().dim() == 1: + self.u_components = ["u0"] + elif self.mesh.geometry().dim() == 2: + self.u_components = ["u0", "u1"] + elif self.mesh.geometry().dim() == 3: + self.u_components = ["u0", "u1", "u2"] + self.sys_comp = self.u_components + ["p"] + self.scalar_components + self.uc_comp = self.u_components + self.scalar_components + # sys_comp = ['u0', 'u1', 'p', 'alfa'] + # u_components = ['u0', 'u1'] + # uc_comp = ['u0', 'u1', 'alfa'] + return + + def dolfin_variable_declaration(self): + cd = self.constrained_domain + mesh = self.mesh + sys_comp = self.sys_comp + deg_v, deg_p = self.velocity_degree, self.pressure_degree + V = Q = df.FunctionSpace(mesh, "CG", deg_v, constrained_domain=cd) + if deg_v != deg_p: + Q = df.FunctionSpace(mesh, "CG", deg_p, constrained_domain=cd) + self.V, self.Q = V, Q + self.u, self.v = u, v = df.TrialFunction(V), df.TestFunction(V) + self.p, self.q = p, q = df.TrialFunction(Q), df.TestFunction(Q) + + # Use dictionary to hold all FunctionSpaces + VV = dict((ui, V) for ui in self.uc_comp) + VV["p"] = Q + + # removed unused name argument and reassigning q_...[...].vector() to x_... + # Create dictionaries for the solutions at three timesteps + self.q_ = dict((ui, df.Function(VV[ui])) for ui in sys_comp) + self.q_1 = dict((ui, df.Function(VV[ui])) for ui in sys_comp) + self.q_2 = dict((ui, df.Function(V)) for ui in self.u_components) + # Create vectors of the segregated velocity components + self.u_ = df.as_vector([self.q_[ui] for ui in self.u_components]) + self.u_1 = df.as_vector([self.q_1[ui] for ui in self.u_components]) + self.u_2 = df.as_vector([self.q_2[ui] for ui in self.u_components]) + # Adams Bashforth projection of velocity at t - dt/2 + self.U_AB = 1.5 * self.u_1 - 0.5 * self.u_2 + # Create vectors to hold rhs of equations + self.b = dict((ui, df.Vector(self.q_[ui].vector())) for ui in sys_comp) + self.b_tmp = dict((ui, df.Vector(self.q_[ui].vector())) for ui in sys_comp) + self.dp_ = df.Function(Q) # pressure correction + + # TODO: remove u_, u_1, u_w -> redundand! + # x_, x_1, x_2 removed, they are in q_[...].vector(), q_1[...].vector(), q_2[...].vector() + # alpha_, alpha_1 removed, they are in q_ and q_1 + # p_, p_1 removed, they are in q_, q_1 + + # Get constant body forces + self.f = f = self.body_force() + assert isinstance(f, Coefficient) + self.b0 = b0 = {} + for i, ui in enumerate(self.u_components): + b0[ui] = df.assemble(v * f[i] * df.dx) + + # Get scalar sources + self.fs = fs = self.scalar_source() + for ci in scalar_components: + assert isinstance(fs[ci], Coefficient) + b0[ci] = df.assemble(v * fs[ci] * df.dx) + + def apply_bcs(self): + # used to be initialize(x_1, x_2, bcs, **NS_namespace) + for ui in self.sys_comp: + [bc.apply(self.q_1[ui].vector()) for bc in self.bcs[ui]] + for ui in self.u_components: + [bc.apply(self.q_2[ui].vector()) for bc in self.bcs[ui]] + return + + def advance(self): + # Update to a new timestep + # replaced axpy with assign + for ui in self.u_components: + self.q_2[ui].assign(self.q_1[ui]) + self.q_1[ui].assign(self.q_[ui]) + # self.q_2[ui].vector().zero() + # self.q_2[ui].vector().axpy(1.0, self.q_1[ui].vector()) + # self.q_1[ui].vector().zero() + # self.q_1[ui].vector().axpy(1.0, self.q_[ui].vector()) + + for ci in self.scalar_components: + self.q_1[ci].assign(self.q_[ci]) + # self.q_1[ci].vector().zero() + # self.q_1[ci].vector().axpy(1.0, self.q_[ci].vector()) + return + + def velocity_tentative_hook(self, **kvargs): + """Called just prior to solving for tentative velocity.""" + pass + + def pressure_hook(self, **kvargs): + """Called prior to pressure solve.""" + pass + + def start_timestep_hook(self, **kvargs): + """Called at start of new timestep""" + pass + + def temporal_hook(self, **kvargs): + """Called at end of a timestep.""" + pass + + def print_velocity_pressure_info(self, num_iter, inner_iter, udiff): + if num_iter > 1 and self.print_velocity_pressure_convergence: + if inner_iter == 1: + info_blue(" Inner iterations velocity pressure:") + info_blue(" error u error p") + info_blue( + " Iter = {0:4d}, {1:2.2e} {2:2.2e}".format( + inner_iter, udiff[0], df.norm(self.dp_.vector()) + ) + ) diff --git a/oasis/problems/__init__.py b/oasis/problems/__init__.py index 20bebc27..c8c18690 100644 --- a/oasis/problems/__init__.py +++ b/oasis/problems/__init__.py @@ -259,3 +259,68 @@ def post_import_problem(NS_parameters, NS_expressions, mesh, commandline_kwargs) print(key, val) NS_namespace[key] = val return NS_namespace, problem_parameters + + +class Domain: + def __init__(self): + # + return + + def get_problem_parameters(self): + raise NotImplementedError() + + def scalar_source(self): + self.scalar_components + return dict((ci, df.Constant(0)) for ci in scalar_components) + + def create_bcs(self): + sys_comp = self.sys_comp + return dict((ui, []) for ui in sys_comp) + + def initialize(self): + raise NotImplementedError() + + def body_force(self): + """Specify body force""" + mesh = self.mesh + return df.Constant((0,) * mesh.geometry().dim()) + + def pre_solve_hook(self): + raise NotImplementedError() + + def scalar_hook(self): + raise NotImplementedError() + + def theend_hook(self): + raise NotImplementedError() + + def recommend_dt(self): + Cmax = 0.05 + dt = Cmax * self.mesh.hmin() / self.Umean + print("recommended dt =", dt) + return dt + + def set_parameters_from_commandline(self, commandline_kwargs): + # Update NS_namespace with all parameters modified through command line + for key, val in commandline_kwargs.items(): + setattr(self, key, commandline_kwargs[key]) + if key not in self.__dict__.keys(): + raise KeyError("unknown key", key) + elif isinstance(val, dict): + setattr(self, key, commandline_kwargs[key]) + else: + setattr(self, key, commandline_kwargs[key]) + return + + def show_info(self, t, tstep, toc): + + info_green( + "Time = {0:2.4e}, timestep = {1:6d}, End time = {2:2.4e}".format( + t, tstep, self.T + ) + ) + info_red( + "Total computing time on previous {0:d} timesteps = {1:f}".format( + self.print_intermediate_info, toc + ) + ) diff --git a/oasis/solvers/NSfracStep/IPCS_ABCN.py b/oasis/solvers/NSfracStep/IPCS_ABCN.py index 0fb6fcd2..3aeee082 100644 --- a/oasis/solvers/NSfracStep/IPCS_ABCN.py +++ b/oasis/solvers/NSfracStep/IPCS_ABCN.py @@ -3,15 +3,42 @@ __copyright__ = "Copyright (C) 2013 " + __author__ __license__ = "GNU Lesser GPL version 3 or any later version" -from dolfin import * -from ..NSfracStep import * -from ..NSfracStep import __all__ - - -def setup(u_components, u, v, p, q, bcs, les_model, nn_model, nu, nut_,nunn_, - scalar_components, V, Q, x_, p_, u_, A_cache, - velocity_update_solver, assemble_matrix, homogenize, - GradFunction, DivFunction, LESsource, NNsource, **NS_namespace): +import dolfin as df +from dolfin import inner, dx, grad, dot, nabla_grad, assemble, norm, normalize +from dolfin import Matrix, Vector, Function, VectorSpaceBasis, Timer +from dolfin import PETScPreconditioner, PETScKrylovSolver, LUSolver +from dolfin import as_backend_type, as_vector +import oasis.common.utilities as ut + + +def setup( + u_components, + u, + v, + p, + q, + bcs, + les_model, + nn_model, + nu, + nut_, + nunn_, + scalar_components, + V, + Q, + x_, + p_, + u_, + A_cache, + velocity_update_solver, + assemble_matrix, + homogenize, + GradFunction, + DivFunction, + LESsource, + NNsource, + **NS_namespace +): """Preassemble mass and diffusion matrices. Set up and prepare all equations to be solved. Called once, before @@ -25,33 +52,42 @@ def setup(u_components, u, v, p, q, bcs, les_model, nn_model, nu, nut_,nunn_, K = assemble_matrix(inner(grad(u), grad(v)) * dx) # Allocate stiffness matrix for LES that changes with time - KT = None if les_model == "NoModel" and nn_model == "NoModel" else ( - Matrix(M), inner(grad(u), grad(v))) + KT = ( + None + if les_model == "NoModel" and nn_model == "NoModel" + else (Matrix(M), inner(grad(u), grad(v))) + ) # Pressure Laplacian. - Ap = assemble_matrix(inner(grad(q), grad(p)) * dx, bcs['p']) + Ap = assemble_matrix(inner(grad(q), grad(p)) * dx, bcs["p"]) # if les_model == "NoModel": # if not Ap.id() == K.id(): # Compress matrix (creates new matrix) - #Bp = Matrix() + # Bp = Matrix() # Ap.compressed(Bp) - #Ap = Bp + # Ap = Bp # Replace cached matrix with compressed version - #A_cache[(inner(grad(q), grad(p))*dx, tuple(bcs['p']))] = Ap + # A_cache[(inner(grad(q), grad(p))*dx, tuple(bcs['p']))] = Ap # Allocate coefficient matrix (needs reassembling) A = Matrix(M) # Allocate Function for holding and computing the velocity divergence on Q - divu = DivFunction(u_, Q, name='divu', - method=velocity_update_solver) + divu = DivFunction(u_, Q, name="divu", method=velocity_update_solver) # Allocate a dictionary of Functions for holding and computing pressure gradients - gradp = {ui: GradFunction(p_, V, i=i, name='dpd' + ('x', 'y', 'z')[i], - bcs=homogenize(bcs[ui]), - method=velocity_update_solver) - for i, ui in enumerate(u_components)} + gradp = { + ui: GradFunction( + p_, + V, + i=i, + name="dpd" + ("x", "y", "z")[i], + bcs=homogenize(bcs[ui]), + method=velocity_update_solver, + ) + for i, ui in enumerate(u_components) + } # Create dictionary to be returned into global NS namespace d = dict(A=A, M=M, K=K, Ap=Ap, divu=divu, gradp=gradp) @@ -73,21 +109,29 @@ def setup(u_components, u, v, p, q, bcs, les_model, nn_model, nu, nut_,nunn_, u_ab = as_vector([Function(V) for i in range(len(u_components))]) a_conv = inner(v, dot(u_ab, nabla_grad(u))) * dx a_scalar = a_conv - LT = None if les_model == "NoModel" else LESsource( - nut_, u_ab, V, name='LTd') + LT = None if les_model == "NoModel" else LESsource(nut_, u_ab, V, name="LTd") - NT = None if nn_model == "NoModel" else NNsource( - nunn_, u_ab, V, name='NTd') + NT = None if nn_model == "NoModel" else NNsource(nunn_, u_ab, V, name="NTd") - if bcs['p'] == []: + if bcs["p"] == []: attach_pressure_nullspace(Ap, x_, Q) d.update(u_ab=u_ab, a_conv=a_conv, a_scalar=a_scalar, LT=LT, KT=KT, NT=NT) return d -def get_solvers(use_krylov_solvers, krylov_solvers, bcs, - x_, Q, scalar_components, velocity_krylov_solver, - pressure_krylov_solver, scalar_krylov_solver, **NS_namespace): + +def get_solvers( + use_krylov_solvers, + krylov_solvers, + bcs, + x_, + Q, + scalar_components, + velocity_krylov_solver, + pressure_krylov_solver, + scalar_krylov_solver, + **NS_namespace +): """Return linear solvers. We are solving for @@ -100,16 +144,16 @@ def get_solvers(use_krylov_solvers, krylov_solvers, bcs, """ if use_krylov_solvers: ## tentative velocity solver ## - u_prec = PETScPreconditioner(velocity_krylov_solver['preconditioner_type']) - u_sol = PETScKrylovSolver(velocity_krylov_solver['solver_type'], u_prec) - #u_sol = KrylovSolver(velocity_krylov_solver['solver_type'], + u_prec = PETScPreconditioner(velocity_krylov_solver["preconditioner_type"]) + u_sol = PETScKrylovSolver(velocity_krylov_solver["solver_type"], u_prec) + # u_sol = KrylovSolver(velocity_krylov_solver['solver_type'], # velocity_krylov_solver['preconditioner_type']) u_sol.parameters.update(krylov_solvers) ## pressure solver ## - p_prec = PETScPreconditioner(pressure_krylov_solver['preconditioner_type']) - p_sol = PETScKrylovSolver(pressure_krylov_solver['solver_type'], p_prec) - #p_sol = KrylovSolver(pressure_krylov_solver['solver_type'], + p_prec = PETScPreconditioner(pressure_krylov_solver["preconditioner_type"]) + p_sol = PETScKrylovSolver(pressure_krylov_solver["solver_type"], p_prec) + # p_sol = KrylovSolver(pressure_krylov_solver['solver_type'], # pressure_krylov_solver['preconditioner_type']) p_sol.parameters.update(krylov_solvers) p_sol.set_reuse_preconditioner(True) @@ -117,8 +161,8 @@ def get_solvers(use_krylov_solvers, krylov_solvers, bcs, sols = [u_sol, p_sol] ## scalar solver ## if len(scalar_components) > 0: - c_prec = PETScPreconditioner(scalar_krylov_solver['preconditioner_type']) - c_sol = PETScKrylovSolver(scalar_krylov_solver['solver_type'], c_prec) + c_prec = PETScPreconditioner(scalar_krylov_solver["preconditioner_type"]) + c_sol = PETScKrylovSolver(scalar_krylov_solver["solver_type"], c_prec) c_sol.parameters.update(krylov_solvers) sols.append(c_sol) else: @@ -126,10 +170,10 @@ def get_solvers(use_krylov_solvers, krylov_solvers, bcs, else: ## tentative velocity solver ## u_sol = LUSolver() - #u_sol.parameters['same_nonzero_pattern'] = True + # u_sol.parameters['same_nonzero_pattern'] = True ## pressure solver ## p_sol = LUSolver() - #p_sol.parameters['reuse_factorization'] = True + # p_sol.parameters['reuse_factorization'] = True sols = [u_sol, p_sol] ## scalar solver ## if len(scalar_components) > 0: @@ -141,9 +185,31 @@ def get_solvers(use_krylov_solvers, krylov_solvers, bcs, return sols -def assemble_first_inner_iter(A, a_conv, dt, M, scalar_components, les_model, nn_model, - a_scalar, K, nu, nut_, nunn_, u_components, LT, KT, NT, - b_tmp, b0, x_1, x_2, u_ab, bcs, **NS_namespace): +def assemble_first_inner_iter( + A, + a_conv, + dt, + M, + scalar_components, + les_model, + nn_model, + a_scalar, + K, + nu, + nut_, + nunn_, + u_components, + LT, + KT, + NT, + b_tmp, + b0, + x_1, + x_2, + u_ab, + bcs, + **NS_namespace +): """Called on first inner iteration of velocity/pressure system. Assemble convection matrix, compute rhs of tentative velocity and @@ -158,15 +224,15 @@ def assemble_first_inner_iter(A, a_conv, dt, M, scalar_components, les_model, nn u_ab[i].vector().axpy(-0.5, x_2[ui]) A = assemble(a_conv, tensor=A) - A *= -0.5 # Negative convection on the rhs - A.axpy(1. / dt, M, True) # Add mass + A *= -0.5 # Negative convection on the rhs + A.axpy(1.0 / dt, M, True) # Add mass # Set up scalar matrix for rhs using the same convection as velocity if len(scalar_components) > 0: - Ta = NS_namespace['Ta'] + Ta = NS_namespace["Ta"] if a_scalar is a_conv: Ta.zero() - Ta.axpy(1., A, True) + Ta.axpy(1.0, A, True) # Add diffusion and compute rhs for all velocity components A.axpy(-0.5 * nu, K, True) @@ -181,26 +247,28 @@ def assemble_first_inner_iter(A, a_conv, dt, M, scalar_components, les_model, nn for i, ui in enumerate(u_components): # Start with body force b_tmp[ui].zero() - b_tmp[ui].axpy(1., b0[ui]) + b_tmp[ui].axpy(1.0, b0[ui]) # Add transient, convection and diffusion - b_tmp[ui].axpy(1., A * x_1[ui]) + b_tmp[ui].axpy(1.0, A * x_1[ui]) if les_model != "NoModel": LT.assemble_rhs(i) - b_tmp[ui].axpy(1., LT.vector()) + b_tmp[ui].axpy(1.0, LT.vector()) if nn_model != "NoModel": NT.assemble_rhs(i) - b_tmp[ui].axpy(1., NT.vector()) + b_tmp[ui].axpy(1.0, NT.vector()) # Reset matrix for lhs - A *= -1. - A.axpy(2. / dt, M, True) - [bc.apply(A) for bc in bcs['u0']] + A *= -1.0 + A.axpy(2.0 / dt, M, True) + [bc.apply(A) for bc in bcs["u0"]] + t0.stop() + def attach_pressure_nullspace(Ap, x_, Q): """Create null space basis object and attach to Krylov solver.""" - null_vec = Vector(x_['p']) + null_vec = Vector(x_["p"]) Q.dofmap().set(null_vec, 1.0) - null_vec *= 1.0 / null_vec.norm('l2') + null_vec *= 1.0 / null_vec.norm("l2") Aa = as_backend_type(Ap) null_space = VectorSpaceBasis([null_vec]) Aa.set_nullspace(null_space) @@ -210,22 +278,24 @@ def attach_pressure_nullspace(Ap, x_, Q): def velocity_tentative_assemble(ui, b, b_tmp, p_, gradp, **NS_namespace): """Add pressure gradient to rhs of tentative velocity system.""" b[ui].zero() - b[ui].axpy(1., b_tmp[ui]) + b[ui].axpy(1.0, b_tmp[ui]) gradp[ui].assemble_rhs(p_) - b[ui].axpy(-1., gradp[ui].rhs) + b[ui].axpy(-1.0, gradp[ui].rhs) + -def velocity_tentative_solve(ui, A, bcs, x_, x_2, u_sol, b, udiff, - use_krylov_solvers, **NS_namespace): +def velocity_tentative_solve( + ui, A, bcs, x_, x_2, u_sol, b, udiff, use_krylov_solvers, **NS_namespace +): """Linear algebra solve of tentative velocity component.""" - #if use_krylov_solvers: - #if ui == 'u0': - #u_sol.parameters['preconditioner']['structure'] = 'same_nonzero_pattern' - #else: - #u_sol.parameters['preconditioner']['structure'] = 'same' + # if use_krylov_solvers: + # if ui == 'u0': + # u_sol.parameters['preconditioner']['structure'] = 'same_nonzero_pattern' + # else: + # u_sol.parameters['preconditioner']['structure'] = 'same' [bc.apply(b[ui]) for bc in bcs[ui]] # x_2 only used on inner_iter 1, so use here as work vector x_2[ui].zero() - x_2[ui].axpy(1., x_[ui]) + x_2[ui].axpy(1.0, x_[ui]) t1 = Timer("Tentative Linear Algebra Solve") u_sol.solve(A, x_[ui], b[ui]) t1.stop() @@ -235,30 +305,30 @@ def velocity_tentative_solve(ui, A, bcs, x_, x_2, u_sol, b, udiff, def pressure_assemble(b, x_, dt, Ap, divu, **NS_namespace): """Assemble rhs of pressure equation.""" divu.assemble_rhs() # Computes div(u_)*q*dx - b['p'][:] = divu.rhs - b['p'] *= (-1. / dt) - b['p'].axpy(1., Ap * x_['p']) + b["p"][:] = divu.rhs + b["p"] *= -1.0 / dt + b["p"].axpy(1.0, Ap * x_["p"]) def pressure_solve(dp_, x_, Ap, b, p_sol, bcs, **NS_namespace): """Solve pressure equation.""" - [bc.apply(b['p']) for bc in bcs['p']] + [bc.apply(b["p"]) for bc in bcs["p"]] dp_.vector().zero() - dp_.vector().axpy(1., x_['p']) + dp_.vector().axpy(1.0, x_["p"]) # KrylovSolvers use nullspace for normalization of pressure - if hasattr(Ap, 'null_space'): - p_sol.null_space.orthogonalize(b['p']) + if hasattr(Ap, "null_space"): + p_sol.null_space.orthogonalize(b["p"]) t1 = Timer("Pressure Linear Algebra Solve") - p_sol.solve(Ap, x_['p'], b['p']) + p_sol.solve(Ap, x_["p"], b["p"]) t1.stop() # LUSolver use normalize directly for normalization of pressure - if bcs['p'] == []: - normalize(x_['p']) + if bcs["p"] == []: + normalize(x_["p"]) dpv = dp_.vector() - dpv.axpy(-1., x_['p']) - dpv *= -1. + dpv.axpy(-1.0, x_["p"]) + dpv *= -1.0 def velocity_update(u_components, bcs, gradp, dp_, dt, x_, **NS_namespace): @@ -268,14 +338,34 @@ def velocity_update(u_components, bcs, gradp, dp_, dt, x_, **NS_namespace): x_[ui].axpy(-dt, gradp[ui].vector()) [bc.apply(x_[ui]) for bc in bcs[ui]] -def scalar_assemble(a_scalar, a_conv, Ta, dt, M, scalar_components, Schmidt_T, KT, - nu, nut_, nunn_, Schmidt, b, K, x_1, b0, les_model, nn_model, **NS_namespace): + +def scalar_assemble( + a_scalar, + a_conv, + Ta, + dt, + M, + scalar_components, + Schmidt_T, + KT, + nu, + nut_, + nunn_, + Schmidt, + b, + K, + x_1, + b0, + les_model, + nn_model, + **NS_namespace +): """Assemble scalar equation.""" # Just in case you want to use a different scalar convection if not a_scalar is a_conv: assemble(a_scalar, tensor=Ta) - Ta *= -0.5 # Negative convection on the rhs - Ta.axpy(1. / dt, M, True) # Add mass + Ta *= -0.5 # Negative convection on the rhs + Ta.axpy(1.0 / dt, M, True) # Add mass # Compute rhs for all scalars for ci in scalar_components: @@ -288,8 +378,8 @@ def scalar_assemble(a_scalar, a_conv, Ta, dt, M, scalar_components, Schmidt_T, K # Compute rhs b[ci].zero() - b[ci].axpy(1., Ta * x_1[ci]) - b[ci].axpy(1., b0[ci]) + b[ci].axpy(1.0, Ta * x_1[ci]) + b[ci].axpy(1.0, b0[ci]) # Subtract diffusion Ta.axpy(0.5 * nu / Schmidt[ci], K, True) @@ -299,33 +389,302 @@ def scalar_assemble(a_scalar, a_conv, Ta, dt, M, scalar_components, Schmidt_T, K Ta.axpy(0.5 / Schmidt_T[ci], KT[0], True) # Reset matrix for lhs - Note scalar matrix does not contain diffusion - Ta *= -1. - Ta.axpy(2. / dt, M, True) + Ta *= -1.0 + Ta.axpy(2.0 / dt, M, True) -def scalar_solve(ci, scalar_components, Ta, b, x_, bcs, c_sol, - nu, Schmidt, K, **NS_namespace): +def scalar_solve( + ci, scalar_components, Ta, b, x_, bcs, c_sol, nu, Schmidt, K, **NS_namespace +): """Solve scalar equation.""" Ta.axpy(0.5 * nu / Schmidt[ci], K, True) # Add diffusion if len(scalar_components) > 1: # Reuse solver for all scalars. This requires the same matrix and vectors to be used by c_sol. - Tb, bb, bx = NS_namespace['Tb'], NS_namespace['bb'], NS_namespace['bx'] + Tb, bb, bx = NS_namespace["Tb"], NS_namespace["bb"], NS_namespace["bx"] Tb.zero() - Tb.axpy(1., Ta, True) + Tb.axpy(1.0, Ta, True) bb.zero() - bb.axpy(1., b[ci]) + bb.axpy(1.0, b[ci]) bx.zero() - bx.axpy(1., x_[ci]) + bx.axpy(1.0, x_[ci]) [bc.apply(Tb, bb) for bc in bcs[ci]] c_sol.solve(Tb, bx, bb) x_[ci].zero() - x_[ci].axpy(1., bx) + x_[ci].axpy(1.0, bx) else: [bc.apply(Ta, b[ci]) for bc in bcs[ci]] c_sol.solve(Ta, x_[ci], b[ci]) Ta.axpy(-0.5 * nu / Schmidt[ci], K, True) # Subtract diffusion # x_[ci][x_[ci] < 0] = 0. # Bounded solution - #x_[ci].set_local(maximum(0., x_[ci].array())) + # x_[ci].set_local(maximum(0., x_[ci].array())) # x_[ci].apply("insert") + + +class FirstInner: + def __init__(self, domain): + u, v = domain.u, domain.v + q, p = domain.q, domain.p + dmn = self.domain = domain + # - - - - - - - - - - - - -SETUP- - - - - - - - - - - - - - - - - - + # Mass matrix + M = ut.assemble_matrix(inner(u, v) * dx) + # Stiffness matrix (without viscosity coefficient) + K = ut.assemble_matrix(inner(grad(u), grad(v)) * dx) + # Allocate stiffness matrix for LES that changes with time + KT = ( + None + if dmn.les_model == "NoModel" and dmn.nn_model == "NoModel" + else (Matrix(M), inner(grad(u), grad(v))) + ) + # Pressure Laplacian. + # Allocate coefficient matrix (needs reassembling) + A = Matrix(M) + # Setup for solving convection + u_ab = as_vector([Function(dmn.V) for i in range(len(dmn.u_components))]) + a_conv = inner(v, dot(u_ab, nabla_grad(u))) * dx + a_scalar = a_conv + LT = ( + None + if dmn.les_model == "NoModel" + else ut.LESsource(dmn.nut_, u_ab, dmn.V, name="LTd") + ) + NT = ( + None + if dmn.nn_model == "NoModel" + else ut.NNsource(dmn.nunn_, u_ab, dmn.V, name="NTd") + ) + # for first iter: + self.A = A + self.a_conv = a_conv + self.M = M + self.a_scalar = a_scalar + self.K = K + self.LT = LT + self.KT = KT + self.NT = NT + self.u_ab = u_ab + return + + def assemble_first_inner_iter(self): + """Called on first inner iteration of velocity/pressure system. + + Assemble convection matrix, compute rhs of tentative velocity and + reset coefficient matrix for solve. + """ + Ta = 123 + dmn = self.domain + A = self.A + a_conv = self.a_conv + M = self.M + a_scalar = self.a_scalar + K = self.K + LT = self.LT + KT = self.KT + NT = self.NT + u_ab = self.u_ab + t0 = Timer("Assemble first inner iter") + # Update u_ab used as convecting velocity + for i, ui in enumerate(dmn.u_components): + u_ab[i].vector().zero() + u_ab[i].vector().axpy(1.5, dmn.q_1[ui].vector()) + u_ab[i].vector().axpy(-0.5, dmn.q_2[ui].vector()) + + A = assemble(a_conv, tensor=A) + A *= -0.5 # Negative convection on the rhs + A.axpy(1.0 / dmn.dt, M, True) # Add mass + + # Set up scalar matrix for rhs using the same convection as velocity + if len(dmn.scalar_components) > 0: + # Ta = NS_namespace["Ta"] + if a_scalar is a_conv: + Ta.zero() + Ta.axpy(1.0, A, True) + + # Add diffusion and compute rhs for all velocity components + A.axpy(-0.5 * dmn.nu, K, True) + if dmn.les_model != "NoModel": + assemble(dmn.nut_ * KT[1] * dx, tensor=KT[0]) + A.axpy(-0.5, KT[0], True) + + if dmn.nn_model != "NoModel": + assemble(dmn.nunn_ * KT[1] * dx, tensor=KT[0]) + A.axpy(-0.5, KT[0], True) + + for i, ui in enumerate(dmn.u_components): + # Start with body force + # TODO: dmn.b_tmp[ui].assign(dmn.b0[ui]) + dmn.b_tmp[ui].zero() + dmn.b_tmp[ui].axpy(1.0, dmn.b0[ui]) + # Add transient, convection and diffusion + dmn.b_tmp[ui].axpy(1.0, A * dmn.q_1[ui].vector()) + if dmn.les_model != "NoModel": + LT.assemble_rhs(i) + dmn.b_tmp[ui].axpy(1.0, LT.vector()) + if dmn.nn_model != "NoModel": + NT.assemble_rhs(i) + dmn.b_tmp[ui].axpy(1.0, NT.vector()) + + # Reset matrix for lhs + A *= -1.0 + A.axpy(2.0 / dmn.dt, M, True) + [bc.apply(A) for bc in dmn.bcs["u0"]] + t0.stop() + return + + +class TentativeVelocityStep: + def __init__(self, domain): + u, v = domain.u, domain.v + q, p = domain.q, domain.p + dmn = self.domain = domain + + # - - - - - - - - - - - - -SETUP- - - - - - - - - - - - - - - - - - + # Allocate a dictionary of Functions for holding and computing pressure gradients + gradp = { + ui: ut.GradFunction( + dmn.q_["p"], + dmn.V, + i=i, + name="dpd" + ("x", "y", "z")[i], + bcs=ut.homogenize(dmn.bcs[ui]), + method=dmn.velocity_update_solver, + ) + for i, ui in enumerate(dmn.u_components) + } + # - - - - - - - - - -get_solvers - - - - - - - - - - - - - - - - - - + if domain.use_krylov_solvers: + # tentative velocity solver ## + u_prec = PETScPreconditioner( + dmn.velocity_krylov_solver["preconditioner_type"] + ) + u_sol = PETScKrylovSolver(dmn.velocity_krylov_solver["solver_type"], u_prec) + u_sol.parameters.update(dmn.krylov_solvers) + else: + # tentative velocity solver # + u_sol = LUSolver() + self.u_sol = u_sol + self.gradp = gradp + return + + def assemble(self, ui): + # ui, b, b_tmp, p_, gradp + dmn = self.domain + dmn.b[ui].zero() + dmn.b[ui].axpy(1.0, dmn.b_tmp[ui]) + self.gradp[ui].assemble_rhs(dmn.q_["p"]) + dmn.b[ui].axpy(-1.0, self.gradp[ui].rhs) + return + + def solve(self, ui, udiff): + # ui, A, bcs, x_, x_2, u_sol, b, udiff, use_krylov_solvers + """Linear algebra solve of tentative velocity component.""" + dmn = self.domain + [bc.apply(dmn.b[ui]) for bc in dmn.bcs[ui]] + # q_2 only used on inner_iter 1, so use here as work vector + dmn.q_2[ui].assign(dmn.q_[ui]) + t1 = Timer("Tentative Linear Algebra Solve") + self.u_sol.solve(self.A, dmn.q_[ui].vector(), dmn.b[ui]) + t1.stop() + udiff[0] += norm(dmn.q_2[ui].vector() - dmn.q_[ui].vector()) + return + + def velocity_update(self, ui): + # u_components, bcs, gradp, dp_, dt, x_ + """Update the velocity after regular pressure velocity iterations.""" + dmn = self.domain + # for ui in u_components: + self.gradp[ui](dmn.dp_) + dmn.q_[ui].vector().axpy(-dmn.dt, self.gradp[ui].vector()) + [bc.apply(dmn.q_[ui].vector()) for bc in dmn.bcs[ui]] + return + + +class PressureStep: + def __init__(self, domain): + # u, v = domain.u, domain.v + q, p = domain.q, domain.p + dmn = self.domain = domain + # - - - - - - - - - - - - -SETUP- - - - - - - - - - - - - - - - - - + divu = ut.DivFunction( + dmn.u_, dmn.Q, name="divu", method=dmn.velocity_update_solver + ) + # Pressure Laplacian. + Ap = ut.assemble_matrix(inner(grad(q), grad(p)) * dx, dmn.bcs["p"]) + if dmn.bcs["p"] == []: + attach_pressure_nullspace(Ap, dmn.x_, dmn.Q) + if domain.use_krylov_solvers: + # pressure solver ## + p_prec = PETScPreconditioner( + dmn.pressure_krylov_solver["preconditioner_type"] + ) + p_sol = PETScKrylovSolver(dmn.pressure_krylov_solver["solver_type"], p_prec) + p_sol.parameters.update(dmn.krylov_solvers) + p_sol.set_reuse_preconditioner(True) + else: + # pressure solver ## + p_sol = LUSolver() + self.divu = divu + self.Ap = Ap + self.p_sol = p_sol + return + + def assemble(self): + # b, x_, dt, Ap, divu + """Assemble rhs of pressure equation.""" + dmn = self.domain + self.divu.assemble_rhs() # Computes div(u_)*q*dx + dmn.b["p"][:] = self.divu.rhs + dmn.b["p"] *= -1.0 / dmn.dt + dmn.b["p"].axpy(1.0, self.Ap * dmn.q_["p"].vector()) + + def solve(self): + # dp_, x_, Ap, b, p_sol, bcs + """Solve pressure equation.""" + dmn = self.domain + + [bc.apply(dmn.b["p"]) for bc in dmn.bcs["p"]] + dmn.dp_.vector().zero() + dmn.dp_.vector().axpy(1.0, dmn.q_["p"].vector()) + # KrylovSolvers use nullspace for normalization of pressure + if hasattr(self.Ap, "null_space"): + self.p_sol.null_space.orthogonalize(dmn.b["p"]) + + t1 = Timer("Pressure Linear Algebra Solve") + self.p_sol.solve(self.Ap, dmn.q_["p"].vector(), dmn.b["p"]) + t1.stop() + # LUSolver use normalize directly for normalization of pressure + if dmn.bcs["p"] == []: + normalize(dmn.q_["p"].vector()) + dpv = dmn.dp_.vector() + dpv.axpy(-1.0, dmn.q_["p"].vector()) + dpv *= -1.0 + return + + +# TODO: +class ScalarSolver: + def __init__(self, domain): + # u, v = domain.u, domain.v + q, p = domain.q, domain.p + dmn = self.domain = domain + # scalar solver ## + if len(dmn.scalar_components) > 0: + c_prec = PETScPreconditioner( + dmn.scalar_krylov_solver["preconditioner_type"] + ) + c_sol = PETScKrylovSolver(dmn.scalar_krylov_solver["solver_type"], c_prec) + c_sol.parameters.update(dmn.krylov_solvers) + # Allocate Function for holding and computing the velocity divergence on Q + # Allocate coefficient matrix and work vectors for scalars. Matrix differs + # from velocity in boundary conditions only + if len(dmn.scalar_components) > 0: + # d.update(Ta=Matrix(M)) + if len(dmn.scalar_components) > 1: + # For more than one scalar we use the same linear algebra solver for all. + # For this to work we need some additional tensors. The extra matrix + # is required since different scalars may have different boundary conditions + Tb = Matrix(M) + bb = Vector(dmn.x_[dmn.scalar_components[0]]) + bx = Vector(dmn.x_[dmn.scalar_components[0]])